Jekyll2024-03-05T16:03:33+01:00https://dakk.github.io//feed.xmlDavide Gessa @dakkI'm Davide Gessa, a software developer, computer scientist and sailor from Sardinia, Italy.Davide Gessa @dakkOptimizing quantum circuit using boolean algebra2024-03-05T15:00:01+01:002024-03-05T15:00:01+01:00https://dakk.github.io//quantumcomputing/2024/03/05/optimizing_quantum_circuit<p>Since the latest v0.1.18 version, the <a href="https://github.com/dakk/qlasskit"><strong>Qlasskit</strong></a> library offers two useful tool for circuit analysis and optimization.</p>
<ul>
<li>
<p><em>Decompiler</em>: given a quantum circuit is able to detect section that can be represented as boolean expressions</p>
</li>
<li>
<p><em>circuit_boolean_optimizer</em>: a pipeline that given a quantum circuit, decompose it in boolean expressions form and optimize it using boolean algebra</p>
</li>
</ul>
<p>Let’s have a look on how to use these features. We first create the following quantum circuit:</p>
<p><img src="/assets/2024-03-05-qoptimize/unoptimized.png" alt="" /></p>
<p>Now, using the <em>decompile</em> function we can detect “classical parts” and decode them as boolean expression;
this is the result for the previous quantum circuit.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dc</span> <span class="o">=</span> <span class="n">Decompiler</span><span class="p">().</span><span class="n">decompile</span><span class="p">(</span><span class="n">qcircuit</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DecompiledResults[
(
(0, 7)
(X, [2], None), (CCX, [0, 2, 3], None), (CCX, [1, 3, 4], None), (CX, [4, 5], None), (CCX, [1, 3, 4], None), (CCX, [0, 2, 3], None), (X, [2], None)
(q5, q4 ^ q5 ^ (q1 & (q3 ^ (q0 & ~q2))))
)
]
</code></pre></div></div>
<p>Reading the resulting boolean expression <code class="language-plaintext highlighter-rouge">(q5, q4 ^ q5 ^ (q1 & (q3 ^ (q0 & ~q2))))</code>, and knowing that q0 and q1 are inputs, while the other qubits are used as ancilla and output qubits, it is clear that the circuit can be optimized.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">qc</span> <span class="o">=</span> <span class="n">circuit_boolean_optimizer</span><span class="p">(</span><span class="n">qf</span><span class="p">.</span><span class="n">circuit</span><span class="p">(),</span> <span class="n">preserve</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span>
</code></pre></div></div>
<p>The <em>circuit_boolean_optimizer</em> allows us to perform boolean optimizations in a quantum circuit; from the previous unoptimized example, we then get the following optimized circuit:</p>
<p><img src="/assets/2024-03-05-qoptimize/optimized.png" alt="" /></p>
<p><strong>Useful Links:</strong></p>
<p>The Python notebook for this blog post is available here: <a href="https://dakk.github.io/qlasskit/decompiler_and_optimizer.html"></a></p>
<ul>
<li><a href="https://github.com/dakk/qlasskit">Qlasskit library on github</a></li>
<li><a href="https://dakk.github.io/qlasskit">Qlasskit docs</a></li>
<li><a href="https://twitter.com/dagide">My Twitter Profile</a></li>
</ul>Davide Gessa @dakkSince the latest v0.1.18 version, the Qlasskit library offers two useful tool for circuit analysis and optimization.Factorization using Qlasskit and DWave Quantum Annealer2024-02-16T09:28:01+01:002024-02-16T09:28:01+01:00https://dakk.github.io//quantumcomputing/2024/02/16/annealing_factorization<p>In the last release of <em>Qlasskit</em>, I introduced a new feature able to export a <code class="language-plaintext highlighter-rouge">qlassf</code> function to a binary quadratic model (as bqm, qubo or ising model).
This feature introduces <em>qlasskit</em> to the realm of quantum annealer like the ones manufactered by DWave; in this blog post, we’ll explore this
new feature, using Qlasskit and the DWave quantum annealer for prime factorization.</p>
<p><img src="/assets/2024-02-16-annealing_factorization.jpg" alt="" /></p>
<p>Instead of employing the traditional <em>Shor algorithm</em> utilized in circuit-base quantum computers, we opt to frame our problem as a minimization problem
and we exploit the <em>adiabatic quantum computing</em> for searching a solution.</p>
<p>We begin defining a Qlasskit function called <code class="language-plaintext highlighter-rouge">test_factor_generic</code> which takes the number <code class="language-plaintext highlighter-rouge">num</code> to be factorized along with its two factors <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code> as inputs.
It returns 0 if <code class="language-plaintext highlighter-rouge">a</code> multiplied by <code class="language-plaintext highlighter-rouge">b</code> equals <code class="language-plaintext highlighter-rouge">num</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qlasskit</span> <span class="kn">import</span> <span class="n">qlassf</span><span class="p">,</span> <span class="n">Qint4</span><span class="p">,</span> <span class="n">Qint3</span><span class="p">,</span> <span class="n">Parameter</span>
<span class="o">@</span><span class="n">qlassf</span>
<span class="k">def</span> <span class="nf">test_factor_generic</span><span class="p">(</span><span class="n">num</span><span class="p">:</span> <span class="n">Parameter</span><span class="p">[</span><span class="n">Qint4</span><span class="p">],</span> <span class="n">a</span><span class="p">:</span> <span class="n">Qint3</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="n">Qint3</span><span class="p">)</span> <span class="o">-></span> <span class="n">Qint4</span><span class="p">:</span>
<span class="k">return</span> <span class="n">num</span> <span class="o">-</span> <span class="p">(</span><span class="n">a</span> <span class="o">*</span> <span class="n">b</span><span class="p">)</span>
</code></pre></div></div>
<p>Next, we bind the <code class="language-plaintext highlighter-rouge">num</code> parameter to the number 15 and convert the Qlasskit function to a binary quadratic model (BQM) using the <code class="language-plaintext highlighter-rouge">to_bqm</code> function.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">test_factor</span> <span class="o">=</span> <span class="n">test_factor_generic</span><span class="p">.</span><span class="n">bind</span><span class="p">(</span><span class="n">num</span><span class="o">=</span><span class="mi">15</span><span class="p">)</span>
<span class="n">bqm</span> <span class="o">=</span> <span class="n">test_factor</span><span class="p">.</span><span class="n">to_bqm</span><span class="p">()</span>
</code></pre></div></div>
<p>This BQM represents the optimization problem of finding the factors of 15.</p>
<h2 id="running-the-sampler">Running the sampler</h2>
<p>With our problem encoded into a BQM, we’re now poised to execute it on a real quantum annealer. Here’s how:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">dwave.system</span> <span class="kn">import</span> <span class="n">DWaveSampler</span><span class="p">,</span> <span class="n">EmbeddingComposite</span>
<span class="kn">from</span> <span class="nn">qlasskit.bqm</span> <span class="kn">import</span> <span class="n">decode_samples</span>
<span class="n">sampler</span> <span class="o">=</span> <span class="n">EmbeddingComposite</span><span class="p">(</span><span class="n">DWaveSampler</span><span class="p">())</span>
<span class="n">sampleset</span> <span class="o">=</span> <span class="n">sampler</span><span class="p">.</span><span class="n">sample</span><span class="p">(</span><span class="n">bqm</span><span class="p">,</span> <span class="n">num_reads</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">decoded_samples</span> <span class="o">=</span> <span class="n">decode_samples</span><span class="p">(</span><span class="n">test_factor</span><span class="p">,</span> <span class="n">sampleset</span><span class="p">)</span>
<span class="n">best_sample</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">decoded_samples</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">.</span><span class="n">energy</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">best_sample</span><span class="p">.</span><span class="n">sample</span><span class="p">)</span>
</code></pre></div></div>
<p>This code snippet runs the BQM on a <strong>DWave</strong> quantum annealer and prints the best solution found, which, as expected, yields <code class="language-plaintext highlighter-rouge">{'a': 3, 'b': 5}</code>, since 5 times 3 equals 15.</p>
<p>If you don’t have access to a DWave account, you can still run smaller problems like this one using a simulated annealing sampler as follows:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">neal</span>
<span class="n">sa</span> <span class="o">=</span> <span class="n">neal</span><span class="p">.</span><span class="n">SimulatedAnnealingSampler</span><span class="p">()</span>
<span class="n">sampleset</span> <span class="o">=</span> <span class="n">sa</span><span class="p">.</span><span class="n">sample</span><span class="p">(</span><span class="n">bqm</span><span class="p">,</span> <span class="n">num_reads</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">decoded_samples</span> <span class="o">=</span> <span class="n">decode_samples</span><span class="p">(</span><span class="n">test_factor</span><span class="p">,</span> <span class="n">sampleset</span><span class="p">)</span>
<span class="n">best_sample</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">decoded_samples</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">.</span><span class="n">energy</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">best_sample</span><span class="p">.</span><span class="n">sample</span><span class="p">)</span>
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>In this post, we’ve demonstrated how to leverage Qlasskit and the DWave quantum annealer to factorize a number. Although this example is relatively straightforward, it underscores the potential of the qlasskit library in describing optimization problems using high-level abstractions.</p>
<p><strong>Useful Links:</strong></p>
<ul>
<li><a href="https://github.com/dakk/qlasskit">Qlasskit library on github</a></li>
<li><a href="https://dakk.github.io/qlasskit">Qlasskit docs</a></li>
<li><a href="https://twitter.com/dagide">My Twitter Profile</a></li>
</ul>Davide Gessa @dakkIn the last release of Qlasskit, I introduced a new feature able to export a qlassf function to a binary quadratic model (as bqm, qubo or ising model). This feature introduces qlasskit to the realm of quantum annealer like the ones manufactered by DWave; in this blog post, we’ll explore this new feature, using Qlasskit and the DWave quantum annealer for prime factorization.The Time I Built a Probabilistic Computer2024-01-31T11:33:01+01:002024-01-31T11:33:01+01:00https://dakk.github.io//unconventionalcomputing/2024/01/31/pbits<p>In early 2023, I embarked on a journey to explore the field of probabilistic computing. This endeavor culminated in the construction of a hardware prototype, and this is its story.</p>
<p><img src="/assets/2024-01-31-pbits/pbit_comp.jpg" alt="" /></p>
<p>The evolution of <strong>unconventional computing</strong> models, from the analog computing of yesteryears to the promises of quantum computing, has opened doors to new possibilities. Analog computers, with their continuous range of values, offered solutions to certain problems that were computationally intractable for digital systems. Quantum computing, on the other hand, harnesses the principles of superposition and entanglement to perform complex calculations at speeds unattainable by classical computers.</p>
<p>In this ever-expanding landscape of computing paradigms, my curiosity led me to explore the uncharted territory of <strong>probabilistic computing</strong>. Embracing the inherent uncertainty of probabilistic bits, I embarked on a journey to build a hardware prototype that could compute in a fundamentally different way. This endeavor, while not seeking to overshadow the achievements of traditional and quantum computing, aimed to carve out its niche in addressing specific challenges with a unique perspective.</p>
<p>In the upcoming chapters of this post, I will share the intricacies of my probabilistic computing prototype – the challenges encountered, the design choices made, and the insights gained along the way. Join me on this expedition into the world of probabilities, where the binary certainty of 0s and 1s gives way to a nuanced landscape of potentialities.</p>
<h2 id="probabilistic-bits">Probabilistic bits</h2>
<p>A probabilistic bit, also known as a <strong>p-bit</strong>, is a new type of computational unit that lies between classical bits and quantum bits (qubits). Unlike classical bits, which can only be either 0 or 1, p-bits can <strong>fluctuate</strong> between the states of 0 and 1. This means that they can represent and process information with greater efficiency than classical computers, and they can also perform certain computational tasks way better than a classical computers.</p>
<p>P-bits were introduced by <strong>Supriyo Datta</strong>, a professor at Purdue University. <a href="https://www.purdue.edu/p-bit/">Datta’s research</a> suggests that p-bits could be used to create a new type of computer that is more powerful and energy-efficient than current computers.</p>
<p><img src="/assets/2024-01-31-pbits/pbit.gif" alt="Source: https://www.purdue.edu/p-bit/" /></p>
<p>Here are some of the key properties of p-bits:</p>
<ul>
<li>Fluctuation: P-bits can fluctuate between the states of 0 and 1. This means that they can represent a range of values between 0 and 1, rather than just two discrete values.</li>
<li>Pinning: P-bits can be pinned to the state of 0 or 1 with a certain probability. This allows them to perform computations in a probabilistic manner, which can be more efficient than classical computations.</li>
</ul>
<p>Datta has proposed a number of potential applications for p-bits, including optimization, machine learning and invertible logic.</p>
<p>The application of p-bits that caught my attention the most, is the <strong>invertible logic</strong>; using p-bits we are able to implement any boolean function and find the input that produces a specific output in an efficient way. This process resembles the one performed by a <strong>Grover search</strong> in a quantum computer.</p>
<h2 id="implementing-p-bits">Implementing p-bits</h2>
<p>There are several potential hardware approaches for implementing p-bits, but one of the most promising is to use spintronics. Spintronics is a field of electronics that utilizes the spin of electrons, in addition to their charge, to store and process information. Spintronics offers several advantages for implementing p-bits, including:</p>
<ul>
<li>Room-temperature operation: Spintronics devices can operate at room temperature, which is a significant advantage over quantum computers, which require cryogenic temperatures.</li>
<li>Scalability: Spintronics devices can be scaled to large sizes, which is necessary for building practical computers.</li>
<li>Low power consumption: Spintronics devices are relatively low-power consumers, which is important for energy-efficient computing.</li>
</ul>
<p>One specific approach to implementing p-bits using spintronics is to use <strong>magnetic tunnel junctions</strong> (MTJs), where the spin is able to fluctuate randomly between the two orientation million of times in a second.</p>
<h3 id="zener-diode-as-p-bits-entropy-source">Zener diode as p-bits entropy source</h3>
<p><em>Zener diode avalanche breakdown</em> is a phenomenon that occurs when a reverse-biased zener diode is subjected to a sufficiently high reverse voltage. The high electric field across the depletion region of the diode causes electrons to gain enough energy to break away from their covalent bonds and become free electrons. These free electrons collide with other electrons and atoms, creating a chain reaction that releases a large amount of energy in the form of heat and light.</p>
<p><img src="/assets/2024-01-31-pbits/just-zener.png" alt="Source: http://www.reallyreallyrandom.com" /></p>
<p>The avalanche breakdown process is a <strong>random event</strong>, and the amount of current that flows through the diode is not directly proportional to the applied voltage. This makes zener diodes a good source of entropy, which is a measure of randomness or uncertainty. For my prototype I choose to use this effect to generate the random oscillations of the p-bits.</p>
<h2 id="the-prototype">The prototype</h2>
<p>The first step in building the prototype was to design the PCB layout. This was done using the free and open-source electronic design automation (EDA) tool KiCad. The PCB layout for the prototype was relatively simple, consisting of a handful of components, including <em>TL072 op-amps</em>, zener diodes, and passive components like resistors and capacitors. The op-amps were used to amplify the random signals generated by the zener diodes and to combine them with p-bit inputs, while the passive components were used to condition the signals and provide biasing for the op-amps.</p>
<p>Once the PCB layout was finalized, it was exported to a Gerber file, which is the standard file format used for PCB printing. The Gerber file was then sent to a PCB fabrication service, where five copies of the PCB were printed on a high-quality circuit board material.</p>
<p><img src="/assets/2024-01-31-pbits/pcb.jpg" alt="" /></p>
<p>With the PCBs in hand, the next step was to assemble the circuit. This involved carefully placing the components onto the PCBs and soldering them in place. The process was relatively straightforward, but it required patience and attention to detail to ensure that the components were properly aligned and soldered.</p>
<p><img src="/assets/2024-01-31-pbits/assembly.jpg" alt="" /></p>
<h2 id="testing-the-prototype">Testing the prototype</h2>
<p>With the hardware prototype assembled, I was eager to put it to the test and explore the computational capabilities of probabilistic computing. To begin, I focused on implementing fundamental reversible logic gates in the probabilistic domain.</p>
<p><img src="/assets/2024-01-31-pbits/testing.jpg" alt="Not gate" /></p>
<p>The reversible AND gate is a crucial component of probabilistic computing, enabling the manipulation of probabilistic states in a reversible manner. I designed a circuit that could implement the reversible AND gate using my probabilistic computing prototype.</p>
<p><img src="/assets/2024-01-31-pbits/testing_osc.jpg" alt="" /></p>
<p>In this video I show the probabilistic not gate implemented using two p-bits.</p>
<p><a href="https://youtu.be/shorts/GNX7OaAMqR0"><img src="https://img.youtube.com/vi/GNX7OaAMqR0/0.jpg" alt="Watch the video" /></a></p>
<h2 id="conclusion">Conclusion</h2>
<p>The successful construction of my probabilistic computing prototype marked a significant milestone in my exploration of this emerging technology. While the prototype demonstrated the feasibility of probabilistic computing principles, scaling up to larger-scale systems remains a challenge.</p>
<p>The current design employed a centralized approach, where all p-bits were interconnected (using a breadboard), making it impractical to scale to millions of p-bits. To address this scalability issue, decentralizing the p-bit circuitry and employing communication protocols to exchange information between p-bit clusters could be promising strategies.</p>
<p>Further research is needed to optimize the hardware architecture and develop efficient communication protocols to enable scalable probabilistic computing systems. The potential of probabilistic computing to tackle complex problems with enhanced efficiency and robustness remains a compelling motivation for continued exploration and innovation.</p>
<p><strong>Useful Links:</strong></p>
<ul>
<li><a href="https://www.purdue.edu/p-bit/">https://www.purdue.edu/p-bit/</a></li>
<li><a href="https://rebootingcomputing.ieee.org/archived-articles-and-videos/feature-articles/probabilistic-bits-p-bits">ieee.org/probabilistic-bits-p-bits</a></li>
<li><a href="http://www.reallyreallyrandom.com/zener/">http://www.reallyreallyrandom.com/zener/</a></li>
<li><a href="https://twitter.com/dagide">My Twitter Profile</a></li>
</ul>Davide Gessa @dakkIn early 2023, I embarked on a journey to explore the field of probabilistic computing. This endeavor culminated in the construction of a hardware prototype, and this is its story.Solving Sudoku Puzzles on a Quantum Computer2024-01-19T10:19:01+01:002024-01-19T10:19:01+01:00https://dakk.github.io//quantumcomputing/2024/01/19/quantum_sudoku<p>Today, I’m going to show you how to use <em>Qlasskit</em> to create a quantum circuit able to search for
<a href="https://it.wikipedia.org/wiki/Sudoku">Sudoku puzzle</a> solutions.</p>
<p><a href="https://github.com/dakk/qlasskit"><em>Qlasskit</em></a>, is an open-source Python library developed with the support of a Unitary Fund microgrant, addresses this challenge head-on by allowing direct translation of standard Python code into invertible quantum circuits without any modification to the original code.</p>
<p>Using qlasskit for this use case, will allow us to write and execute a quantum circuit, writing
only python code without any quantum related primitives.</p>
<p>Since current quantum computers are very limited machines, we cannot solve a real 9x9 sudoku puzzle; our
toy examples uses a 2x2 matrix where a valid solution is when in every row and every column there are no
repeated values (<code class="language-plaintext highlighter-rouge">0</code> or <code class="language-plaintext highlighter-rouge">1</code>). We encode these xor-ing the values for each row and column.</p>
<p>Since we want a specific solution, we add a constraint <code class="language-plaintext highlighter-rouge">constr</code>: we want the <code class="language-plaintext highlighter-rouge">[0][0]</code> element to be <code class="language-plaintext highlighter-rouge">True</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qlasskit</span> <span class="kn">import</span> <span class="n">qlassf</span><span class="p">,</span> <span class="n">Qmatrix</span>
<span class="kn">from</span> <span class="nn">qlasskit.algorithms</span> <span class="kn">import</span> <span class="n">Grover</span>
<span class="o">@</span><span class="n">qlassf</span>
<span class="k">def</span> <span class="nf">sudoku_check</span><span class="p">(</span><span class="n">m</span><span class="p">:</span> <span class="n">Qmatrix</span><span class="p">[</span><span class="nb">bool</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="n">constr</span> <span class="o">=</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="n">sub0</span> <span class="o">=</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">^</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="n">sub1</span> <span class="o">=</span> <span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">^</span> <span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="n">sub2</span> <span class="o">=</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">^</span> <span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="n">sub3</span> <span class="o">=</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">^</span> <span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span>
<span class="k">return</span> <span class="n">sub0</span> <span class="ow">and</span> <span class="n">sub1</span> <span class="ow">and</span> <span class="n">sub2</span> <span class="ow">and</span> <span class="n">sub3</span> <span class="ow">and</span> <span class="n">constr</span>
</code></pre></div></div>
<p>Now that we have an oracle, we can instantiate the Grover search algorithm:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">q_algo</span> <span class="o">=</span> <span class="n">Grover</span><span class="p">(</span><span class="n">sudoku_check</span><span class="p">)</span>
</code></pre></div></div>
<p>Then we use our prefered framework and simulator for sampling the result; this is an example using <code class="language-plaintext highlighter-rouge">qiskit</code> with <code class="language-plaintext highlighter-rouge">aer_simulator</code>.</p>
<p>We obtain that the solution for this puzzle is the matrix <code class="language-plaintext highlighter-rouge">[[True, False], [False, True]]</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qiskit</span> <span class="kn">import</span> <span class="n">Aer</span><span class="p">,</span> <span class="n">QuantumCircuit</span><span class="p">,</span> <span class="n">transpile</span>
<span class="kn">from</span> <span class="nn">qiskit.visualization</span> <span class="kn">import</span> <span class="n">plot_histogram</span>
<span class="n">qc</span> <span class="o">=</span> <span class="n">q_algo</span><span class="p">.</span><span class="n">export</span><span class="p">(</span><span class="s">"qiskit"</span><span class="p">)</span>
<span class="n">qc</span><span class="p">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">simulator</span> <span class="o">=</span> <span class="n">Aer</span><span class="p">.</span><span class="n">get_backend</span><span class="p">(</span><span class="s">"aer_simulator"</span><span class="p">)</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">transpile</span><span class="p">(</span><span class="n">qc</span><span class="p">,</span> <span class="n">simulator</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">simulator</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">circ</span><span class="p">).</span><span class="n">result</span><span class="p">()</span>
<span class="n">counts</span> <span class="o">=</span> <span class="n">result</span><span class="p">.</span><span class="n">get_counts</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="n">counts_readable</span> <span class="o">=</span> <span class="n">q_algo</span><span class="p">.</span><span class="n">decode_counts</span><span class="p">(</span><span class="n">counts</span><span class="p">,</span> <span class="n">discard_lower</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>
<span class="n">plot_histogram</span><span class="p">(</span><span class="n">counts_readable</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="/assets/2024-01-19-qsudoku/sudoku_counts.png" alt="" /></p>
<p>We can exploit <em>matplotlib</em> for drawing the result sudoku matrix as follows:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="k">def</span> <span class="nf">draw_matrix</span><span class="p">(</span><span class="n">matrix</span><span class="p">):</span>
<span class="n">fig</span><span class="p">,</span> <span class="n">ax</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">subplots</span><span class="p">()</span>
<span class="n">ax</span><span class="p">.</span><span class="n">matshow</span><span class="p">(</span><span class="n">matrix</span><span class="p">,</span> <span class="n">cmap</span><span class="o">=</span><span class="s">'viridis'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">matrix</span><span class="p">)):</span>
<span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">matrix</span><span class="p">[</span><span class="mi">0</span><span class="p">])):</span>
<span class="n">ax</span><span class="p">.</span><span class="n">text</span><span class="p">(</span><span class="n">j</span><span class="p">,</span> <span class="n">i</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">matrix</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]),</span> <span class="n">va</span><span class="o">=</span><span class="s">'center'</span><span class="p">,</span> <span class="n">ha</span><span class="o">=</span><span class="s">'center'</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">'black'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
<span class="n">m_res</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">></span> <span class="mi">500</span><span class="p">,</span> <span class="n">counts_readable</span><span class="p">.</span><span class="n">items</span><span class="p">()))[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
<span class="n">draw_matrix</span><span class="p">(</span><span class="n">m_res</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="/assets/2024-01-19-qsudoku/sudoku_matrix.png" alt="" /></p>
<p>We can create a more realistic sudoku game using numbers instead of booleans, but the resources required will scale exponentially. In the following code snippets, we recreate <code class="language-plaintext highlighter-rouge">sudoku_check</code> using <code class="language-plaintext highlighter-rouge">Qint2</code> and a 4x4 matrix. The sum of each column and row must be equal to 6 (3+2+1+0). As we can see, the resulting circuit of the checker requires more than 100 qubits, way above our simulation capabilities.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qlasskit</span> <span class="kn">import</span> <span class="n">Qint2</span><span class="p">,</span> <span class="n">Qint4</span>
<span class="o">@</span><span class="n">qlassf</span>
<span class="k">def</span> <span class="nf">sudoku_check</span><span class="p">(</span><span class="n">m</span><span class="p">:</span> <span class="n">Qmatrix</span><span class="p">[</span><span class="n">Qint2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">4</span><span class="p">])</span> <span class="o">-></span> <span class="nb">bool</span><span class="p">:</span>
<span class="n">res</span> <span class="o">=</span> <span class="bp">True</span>
<span class="c1"># Constraints
</span> <span class="n">res</span> <span class="o">=</span> <span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">==</span> <span class="mi">3</span><span class="p">)</span> <span class="ow">and</span> <span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1"># Check every row and column
</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">4</span><span class="p">):</span>
<span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="n">Qint4</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">3</span><span class="p">])</span> <span class="o">==</span> <span class="mi">6</span>
<span class="n">r</span> <span class="o">=</span> <span class="p">(</span><span class="n">Qint4</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">m</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="n">i</span><span class="p">])</span> <span class="o">==</span> <span class="mi">6</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">res</span> <span class="ow">and</span> <span class="n">c</span> <span class="ow">and</span> <span class="n">r</span>
<span class="k">return</span> <span class="n">res</span>
<span class="k">print</span><span class="p">(</span><span class="n">sudoku_check</span><span class="p">.</span><span class="n">circuit</span><span class="p">())</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>QCircuit<sudoku_check>(1309 gates, 178 qubits)
</code></pre></div></div>
<p><strong>Useful Links:</strong></p>
<ul>
<li><a href="https://github.com/dakk/qlasskit">Qlasskit library on github</a></li>
<li><a href="https://dakk.github.io/qlasskit">Qlasskit docs</a></li>
<li><a href="https://dakk.github.io/qlasskit/how_it_works.html">How qlasskit works</a></li>
<li><a href="https://twitter.com/dagide">My Twitter Profile</a></li>
</ul>Davide Gessa @dakkToday, I’m going to show you how to use Qlasskit to create a quantum circuit able to search for Sudoku puzzle solutions.Expanding the Commodore 64 Quantum Emulator2023-12-13T11:18:22+01:002023-12-13T11:18:22+01:00https://dakk.github.io//quantumcomputing/2023/12/13/qc64_followup<p>In a recent article I wrote, <em>“Quantum Computing on a Commodore 64 in 200 Lines of BASIC”</em>, published both on <a href="https://medium.com/@dakk/quantum-computing-on-a-commodore-64-in-200-lines-of-basic-eda7658b32a4">Medium</a> and <a href="https://hackaday.com/2023/07/04/quantum-computing-on-a-commodore-64-in-200-lines-of-basic/#comments">Hackaday.com</a>, shows a two-qubit quantum circuit emulator on the venerable Commodore 64, writing only 200 lines of code. The source code, available on <a href="https://github.com/dakk/qc64">GitHub</a>, sparked a flurry of activity in the retro-computing community. Notably, enthusiasts have ported this proof-of-concept (POC) to <strong>6502 assembly</strong>, <strong>Fortran</strong>, and even the <strong>ZX Spectrum</strong>. This follow-up article delves into the implications and the burgeoning community interest.</p>
<p><img src="/assets/2023-12-13-qc64_followup.png" alt="" /></p>
<h2 id="the-quantum-challenge-on-retro-platforms">The Quantum Challenge on Retro Platforms</h2>
<p>The initial project was a testament to the versatility and enduring relevance of classic computing platforms. The Commodore 64, with its limited resources, was pushed to simulate quantum mechanics, a domain typically reserved for high-powered modern computers. This endeavor not only showcases the potential for educational tools in quantum computing but also ignites a conversation about the untapped capabilities of vintage technology.</p>
<h2 id="community-response-and-expansions">Community Response and Expansions</h2>
<p>Since the article’s publication, the community response has been phenomenal. Programmers and hobbyists have taken the original BASIC code and adapted it to other languages and platforms. Notably:</p>
<ul>
<li><a href="https://github.com/dakk/qc64/pull/4"><em>6502 Assembly Version</em></a>: A more efficient, lower-level implementation that runs faster and uses less memory.</li>
<li><a href="https://github.com/dakk/qc64/pull/11"><em>Fortran Iteration</em></a>: Leveraging older scientific computers, this version brings quantum emulation to a range of vintage systems.</li>
<li><a href="https://github.com/dakk/qc64/pull/10"><em>ZX Spectrum Adaptation</em></a>: Demonstrating the cross-platform potential, this port brings quantum concepts to a beloved British microcomputer.</li>
</ul>
<p>These ports are more than just technical achievements; they represent a bridge between the past and future of computing.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The broad interest in these projects highlights a growing trend: using nostalgic tech to teach cutting-edge concepts. Schools and educational programs, often constrained by budgets, can utilize accessible retro hardware to introduce students to quantum computing principles. This hands-on approach, using tangible and less intimidating platforms, could demystify quantum computing and inspire the next generation of computer scientists.</p>
<p>The journey from a two-qubit quantum circuit emulator on a Commodore 64 to its adaptation across various old-school platforms is just the beginning. This fusion of past and future opens up new avenues for both education and hobbyist exploration. As we continue to push the boundaries of what these vintage machines can do, we’re not just revisiting the past; we’re redefining the future.</p>Davide Gessa @dakkIn a recent article I wrote, “Quantum Computing on a Commodore 64 in 200 Lines of BASIC”, published both on Medium and Hackaday.com, shows a two-qubit quantum circuit emulator on the venerable Commodore 64, writing only 200 lines of code. The source code, available on GitHub, sparked a flurry of activity in the retro-computing community. Notably, enthusiasts have ported this proof-of-concept (POC) to 6502 assembly, Fortran, and even the ZX Spectrum. This follow-up article delves into the implications and the burgeoning community interest.Qlasskit - a bridge between Python and Quantum algorithms2023-11-29T13:50:28+01:002023-11-29T13:50:28+01:00https://dakk.github.io//quantumcomputing/2023/11/29/qlasskit<p>Traditionally, creating quantum circuits requires specialized knowledge in quantum programming. This requirement holds true when encoding a classical algorithm inside a quantum circuit, for instance, for an oracle or a black-box component of a quantum algorithm. This often becomes a time wasting job, since we almost always already have a classical implementation in a traditional high level language.</p>
<p><img src="/assets/2023-11-09-qlasskit/head.jpg" alt="" /></p>
<p><em>Qlasskit</em>, an open-source Python library developed with the support of a Unitary Fund microgrant, addresses this challenge head-on by allowing direct translation of standard Python code into invertible quantum circuits without any modification to the original code. Furthermore, <em>qlasskit</em> implements some well-known quantum algorithms and offers a comprehensive interface for implementing new ones.</p>
<p>To illustrate <em>qlasskit</em>’s capabilities, we will demonstrate its use in performing a pre-image attack on a cryptographic hash function using Grover’s search algorithm, obtaining a quadratic speedup compared to classical approaches. The beauty of <em>qlasskit</em> lies in its simplicity – you can write the entire software without needing to understand any concept of quantum computing.</p>
<p>A pre-image attack, in cryptography, targets a hash function <code class="language-plaintext highlighter-rouge">h(m)</code> with the aim to discover an original message <code class="language-plaintext highlighter-rouge">m</code> that corresponds to a specific hash value. On a traditional computer, to perform this attack without any hints, we must run <code class="language-plaintext highlighter-rouge">h(m)</code> with every possible input (<code class="language-plaintext highlighter-rouge">N=2**n</code>).</p>
<p>Thanks to the Grover search algorithm, we are able to find a pre-image with only <code class="language-plaintext highlighter-rouge">pi/2 * sqrt(N)</code> iterations, obtaining the quadratic speedup I mentioned before.</p>
<p>We write a toy hash function <code class="language-plaintext highlighter-rouge">hash_simp</code> which operates on messages composed of two 4 bit values and uses bitwise xor to create an 8 bit hash value.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qlasskit</span> <span class="kn">import</span> <span class="n">qlassf</span><span class="p">,</span> <span class="n">Qint4</span><span class="p">,</span> <span class="n">Qint8</span><span class="p">,</span> <span class="n">Qlist</span>
<span class="o">@</span><span class="n">qlassf</span>
<span class="k">def</span> <span class="nf">hash_simp</span><span class="p">(</span><span class="n">m</span><span class="p">:</span> <span class="n">Qlist</span><span class="p">[</span><span class="n">Qint4</span><span class="p">,</span> <span class="mi">2</span><span class="p">])</span> <span class="o">-></span> <span class="n">Qint8</span><span class="p">:</span>
<span class="n">hv</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">m</span><span class="p">:</span>
<span class="n">hv</span> <span class="o">=</span> <span class="p">((</span><span class="n">hv</span> <span class="o"><<</span> <span class="mi">4</span><span class="p">)</span> <span class="o">^</span> <span class="p">(</span><span class="n">hv</span> <span class="o">>></span> <span class="mi">1</span><span class="p">)</span> <span class="o">^</span> <span class="n">i</span><span class="p">)</span> <span class="o">&</span> <span class="mh">0xff</span>
<span class="k">return</span> <span class="n">hv</span>
</code></pre></div></div>
<p>The first things you can notice in this code are:</p>
<ul>
<li>the <code class="language-plaintext highlighter-rouge">qlassf</code> decorators, indicating that the function will be translated to a quantum circuit.</li>
<li>special bit-sized types Qlist, Qint4, and Qint8. These are required as qubits are a precious resource, and we want to use as few as possible.</li>
<li>and, it is normal Python code.</li>
</ul>
<p>To see the resulting quantum circuit we can export and draw in qiskit:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">hash_simp</span><span class="p">.</span><span class="n">export</span><span class="p">(</span><span class="s">'qiskit'</span><span class="p">).</span><span class="n">draw</span><span class="p">(</span><span class="s">'mpl'</span><span class="p">)</span>
</code></pre></div></div>
<p>And this is the resulting circuit, produced by the <em>qlasskit</em> internal compiler:</p>
<p><img src="/assets/2023-11-09-qlasskit/circuit_result.png" alt="" /></p>
<p>Thanks to the fact that <em>qlasskit</em> function are standard Python functions, we can call the <code class="language-plaintext highlighter-rouge">original_f</code> to perform some kind of analysis and test on the hash function. Since the input space is tiny (it is a toy hash function), we can check if the hash function is uniform (if it maps equally to the output space).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">Counter</span>
<span class="n">d</span> <span class="o">=</span> <span class="n">Counter</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">hash_simp</span><span class="p">.</span><span class="n">original_f</span><span class="p">((</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)))</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="o">**</span><span class="mi">4</span><span class="p">)</span> <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="o">**</span><span class="mi">4</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">'Hash function output space:'</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">d</span><span class="p">))</span>
</code></pre></div></div>
<p><img src="/assets/2023-11-09-qlasskit/output_space_result.png" alt="" /></p>
<p>We got that <code class="language-plaintext highlighter-rouge">hash_simp</code> is following an uniform distribution.</p>
<p>Now we use our quantum function as an oracle for a Grover search, in order to find which input maps to the value <code class="language-plaintext highlighter-rouge">0xca</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qlasskit.algorithms</span> <span class="kn">import</span> <span class="n">Grover</span>
<span class="n">q_algo</span> <span class="o">=</span> <span class="n">Grover</span><span class="p">(</span><span class="n">hash_simp</span><span class="p">,</span> <span class="n">Qint8</span><span class="p">(</span><span class="mh">0xca</span><span class="p">))</span>
</code></pre></div></div>
<p>Then we use our preferred framework and simulator for sampling the result; this is an example using <code class="language-plaintext highlighter-rouge">qiskit</code> with <code class="language-plaintext highlighter-rouge">aer_simulator</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">qiskit</span> <span class="kn">import</span> <span class="n">Aer</span><span class="p">,</span> <span class="n">QuantumCircuit</span><span class="p">,</span> <span class="n">transpile</span>
<span class="kn">from</span> <span class="nn">qiskit.visualization</span> <span class="kn">import</span> <span class="n">plot_histogram</span>
<span class="n">qc</span> <span class="o">=</span> <span class="n">q_algo</span><span class="p">.</span><span class="n">export</span><span class="p">(</span><span class="s">'qiskit'</span><span class="p">)</span>
<span class="n">qc</span><span class="p">.</span><span class="n">measure_all</span><span class="p">()</span>
<span class="n">simulator</span> <span class="o">=</span> <span class="n">Aer</span><span class="p">.</span><span class="n">get_backend</span><span class="p">(</span><span class="s">"aer_simulator"</span><span class="p">)</span>
<span class="n">circ</span> <span class="o">=</span> <span class="n">transpile</span><span class="p">(</span><span class="n">qc</span><span class="p">,</span> <span class="n">simulator</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">simulator</span><span class="p">.</span><span class="n">run</span><span class="p">(</span><span class="n">circ</span><span class="p">).</span><span class="n">result</span><span class="p">()</span>
<span class="n">counts</span> <span class="o">=</span> <span class="n">result</span><span class="p">.</span><span class="n">get_counts</span><span class="p">(</span><span class="n">circ</span><span class="p">)</span>
<span class="n">counts_readable</span> <span class="o">=</span> <span class="n">q_algo</span><span class="p">.</span><span class="n">decode_counts</span><span class="p">(</span><span class="n">counts</span><span class="p">,</span> <span class="n">discard_lower</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span>
<span class="n">plot_histogram</span><span class="p">(</span><span class="n">counts_readable</span><span class="p">)</span>
</code></pre></div></div>
<p>And this is the result of the simulation, where we can see that the pre-image that leads to <code class="language-plaintext highlighter-rouge">h(x) = 0xca</code> is the list <code class="language-plaintext highlighter-rouge">[12,12]</code>.</p>
<p><img src="/assets/2023-11-09-qlasskit/simulation_result.png" alt="" /></p>
<p>Using <code class="language-plaintext highlighter-rouge">QlassF.original_f</code> we can double check the result without invoking a quantum simulator; calling it with the list <code class="language-plaintext highlighter-rouge">[12,12]</code> must result in the hash value <code class="language-plaintext highlighter-rouge">0xca</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="nb">hex</span><span class="p">(</span><span class="n">hash_simp</span><span class="p">.</span><span class="n">original_f</span><span class="p">((</span><span class="mi">12</span><span class="p">,</span><span class="mi">12</span><span class="p">))))</span>
</code></pre></div></div>
<p><img src="/assets/2023-11-09-qlasskit/result.png" alt="" /></p>
<p>Although <em>qlasskit</em> can handle hundreds of qubits, in this post we use a toy hash function because currently, we lack a simulator or quantum computer capable of handling hundreds of qubits. Using these same tools, in the near future we may be able to perform a Grover search on real hash functions like <code class="language-plaintext highlighter-rouge">md5</code> or <code class="language-plaintext highlighter-rouge">sha2</code>.</p>
<p>A special thanks to the <a href="https://unitary.fund/">Unitary Fund</a> that funded this idea. If you have any questions or comments, feel free to reach out to me on twitter <a href="https://twitter.com/dagide">dagide</a>, linkedin <a href="https://linkedin.com/in/davide-gessa-71798b80">Davide Gessa</a> and medium <a href="https://medium.com/@dakk">@dakk</a>.</p>
<p>Original post on Unitary.fund: <a href="https://unitary.fund/posts/2023_qlasskit/">https://unitary.fund/posts/2023_qlasskit/</a></p>
<p>Useful Links:</p>
<ul>
<li><a href="https://github.com/dakk/qlasskit">Qlasskit library on github</a></li>
<li><a href="https://dakk.github.io/qlasskit">Qlasskit docs</a></li>
<li><a href="https://dakk.github.io/qlasskit/how_it_works.html">How qlasskit works</a></li>
</ul>Davide Gessa @dakkTraditionally, creating quantum circuits requires specialized knowledge in quantum programming. This requirement holds true when encoding a classical algorithm inside a quantum circuit, for instance, for an oracle or a black-box component of a quantum algorithm. This often becomes a time wasting job, since we almost always already have a classical implementation in a traditional high level language.Quantum Computing on a Commodore 64 in 200 Lines of BASIC2023-07-02T18:02:28+02:002023-07-02T18:02:28+02:00https://dakk.github.io//quantumcomputing/2023/07/02/qc64<p>In an age where companies are selling two-qubit quantum computers for a <a href="https://www.beyondgames.biz/29903/spinq-is-selling-quantum-computers-to-consumers/">sum of money</a> that would make your wallet recoil in horror, here we are, stepping off the beaten path and walking down memory lane to a time when computers were, well, somewhat simpler.</p>
<p><img src="/assets/2023-07-02-bellstate.gif" alt="QC64 preparing a Bell’s state" /></p>
<p>Join me on this delightful journey where we shatter the belief that quantum simulations need groundbreaking technologies. Get ready to be amazed as we simulate two-qubit quantum computing operations on none other than our retro powerhouse, the Commodore 64.</p>
<p>You heard it right! Our beloved Commodore 64, an 8-bit home computer introduced in January 1982, is ready to show those fancy, pricey quantum computers how it’s done. Let’s roll up our sleeves, dust off those old systems, and dive into the world of quantum simulations!</p>
<h2 id="the-commodore-quantum-simulator">The Commodore Quantum Simulator</h2>
<p>The Commodore Quantum Simulator is a BASIC program capable of simulating various quantum gate operations on a two-qubit system. With this system, you can simulate operations such as Pauli-X, Pauli-Y, Pauli-Z, Hadamard, CNOT, and he SWAP gate.</p>
<p>Upon launching the simulator, it defaults to the initial state of <code class="language-plaintext highlighter-rouge">|00></code>. The simulator then prompts for a sequence of quantum gates to be applied. For instance, inputting “H0CX” instructs the simulator to apply the Hadamard gate on qubit 0, followed by a CNOT gate operation. Subsequent to this state manipulation, the simulator proceeds to run a defined number of iterations, simulating the quantum state’s evolution with each step. At the end of this process, it then provides the user with the distribution of quantum states, offering a tangible insight into the fascinating probabilistic nature of quantum mechanics.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Quantum computing might seem like a domain only for the most advanced hardware on the planet. But at its heart, it’s a series of mathematical transformations, all of which are perfectly suited for our good old Commodore 64.</p>
<p>So next time when someone brags about their ultra-advanced quantum computer, remind them gently of the time when you performed quantum simulations on an 8-bit computer from the 1980s. The Commodore 64 might not break any speed records, but it will definitely break some preconceived notions about quantum computing.</p>
<div class="language-perl highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mo">05</span> <span class="nv">rem</span> <span class="nv">r</span><span class="o">*</span> <span class="nv">are</span> <span class="nv">real</span> <span class="nv">parts</span> <span class="ow">and</span> <span class="nv">i</span><span class="o">*</span> <span class="nv">are</span> <span class="nv">imagenary</span> <span class="nv">parts</span> <span class="nv">of</span> <span class="nv">the</span> <span class="nv">sv</span>
<span class="mi">10</span> <span class="nv">r0</span> <span class="o">=</span> <span class="mi">1</span> <span class="p">:</span> <span class="nv">i0</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">r1</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">i1</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">15</span> <span class="nv">r2</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">i2</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">r3</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">i3</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">20</span> <span class="nv">a0</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">25</span> <span class="nv">shots</span> <span class="o">=</span> <span class="mi">28</span>
<span class="mi">30</span> <span class="k">print</span> <span class="nb">chr</span><span class="nv">$</span><span class="err">(</span><span class="nv">147</span><span class="p">)</span>
<span class="mi">40</span> <span class="k">print</span> <span class="p">"</span><span class="s2">c64 quantum simulator</span><span class="p">"</span>
<span class="mi">45</span> <span class="k">print</span> <span class="p">"</span><span class="s2">created by davide gessa (dakk)</span><span class="p">"</span>
<span class="mi">50</span> <span class="k">print</span> <span class="p">"</span><span class="s2">enter gate seq (x0,x1,y0,y1,z0,z1,h0,h1,cx,sw)</span><span class="p">"</span>
<span class="mi">60</span> <span class="nv">input</span> <span class="nv">g$</span>
<span class="nv">65</span> <span class="k">print</span> <span class="p">"</span><span class="s2">calculating the statevector...</span><span class="p">";</span>
<span class="mi">70</span> <span class="k">for</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="nv">to</span> <span class="nv">len</span><span class="p">(</span><span class="nv">g$</span><span class="p">)</span> <span class="nv">step</span> <span class="mi">2</span>
<span class="mi">80</span> <span class="nv">gate$</span> <span class="err">=</span> <span class="nv">mid$</span><span class="err">(</span><span class="nv">g</span><span class="vg">$,</span> <span class="nv">i</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>
<span class="mi">90</span> <span class="nv">gosub</span> <span class="mi">200</span>
<span class="mi">91</span> <span class="k">print</span> <span class="p">"</span><span class="s2">.</span><span class="p">";</span>
<span class="mi">100</span> <span class="k">next</span> <span class="nv">i</span>
<span class="mi">101</span> <span class="k">print</span>
<span class="mi">102</span> <span class="nv">sq</span> <span class="o">=</span> <span class="nv">r0</span><span class="o">*</span><span class="nv">r0</span> <span class="o">+</span> <span class="nv">i0</span><span class="o">*</span><span class="nv">i0</span> <span class="o">+</span> <span class="nv">r1</span><span class="o">*</span><span class="nv">r1</span> <span class="o">+</span> <span class="nv">i1</span><span class="o">*</span><span class="nv">i1</span> <span class="o">+</span> <span class="nv">r2</span><span class="o">*</span><span class="nv">r2</span> <span class="o">+</span> <span class="nv">i2</span><span class="o">*</span><span class="nv">i2</span> <span class="o">+</span> <span class="nv">r3</span><span class="o">*</span><span class="nv">r3</span> <span class="o">+</span> <span class="nv">i3</span><span class="o">*</span><span class="nv">i3</span>
<span class="mi">103</span> <span class="k">if</span> <span class="nb">abs</span><span class="p">(</span><span class="nv">sq</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">></span> <span class="mf">0.00001</span> <span class="k">then</span> <span class="nv">gosub</span> <span class="mi">600</span>
<span class="mi">105</span> <span class="k">print</span> <span class="p">"</span><span class="s2">running</span><span class="p">"</span> <span class="nv">shots</span> <span class="p">"</span><span class="s2">iterations...</span><span class="p">"</span>
<span class="mi">110</span> <span class="nv">z0</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">z1</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">z2</span> <span class="o">=</span> <span class="mi">0</span> <span class="p">:</span> <span class="nv">z3</span> <span class="o">=</span> <span class="mi">0</span>
<span class="mi">115</span> <span class="nv">p0</span> <span class="o">=</span> <span class="p">(</span><span class="nv">r0</span> <span class="o">*</span> <span class="nv">r0</span> <span class="o">+</span> <span class="nv">i0</span> <span class="o">*</span> <span class="nv">i0</span><span class="p">)</span>
<span class="mi">120</span> <span class="nv">p1</span> <span class="o">=</span> <span class="p">(</span><span class="nv">r1</span> <span class="o">*</span> <span class="nv">r1</span> <span class="o">+</span> <span class="nv">i1</span> <span class="o">*</span> <span class="nv">i1</span><span class="p">)</span> <span class="o">+</span> <span class="nv">p0</span>
<span class="mi">125</span> <span class="nv">p2</span> <span class="o">=</span> <span class="p">(</span><span class="nv">r2</span> <span class="o">*</span> <span class="nv">r2</span> <span class="o">+</span> <span class="nv">i2</span> <span class="o">*</span> <span class="nv">i2</span><span class="p">)</span> <span class="o">+</span> <span class="nv">p1</span>
<span class="mi">130</span> <span class="nv">p3</span> <span class="o">=</span> <span class="p">(</span><span class="nv">r3</span> <span class="o">*</span> <span class="nv">r3</span> <span class="o">+</span> <span class="nv">i3</span> <span class="o">*</span> <span class="nv">i3</span><span class="p">)</span> <span class="o">+</span> <span class="nv">p2</span>
<span class="mi">135</span> <span class="k">for</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="nv">to</span> <span class="nv">shots</span>
<span class="mi">140</span> <span class="nv">r</span> <span class="o">=</span> <span class="nv">rnd</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="mi">141</span> <span class="k">if</span> <span class="nv">r</span> <span class="o"><</span> <span class="nv">p0</span> <span class="k">then</span> <span class="nv">z0</span> <span class="o">=</span> <span class="nv">z0</span> <span class="o">+</span> <span class="mi">1</span>
<span class="mi">142</span> <span class="k">if</span> <span class="nv">r</span> <span class="o">>=</span> <span class="nv">p0</span> <span class="ow">and</span> <span class="nv">r</span> <span class="o"><</span> <span class="nv">p1</span> <span class="k">then</span> <span class="nv">z1</span> <span class="o">=</span> <span class="nv">z1</span> <span class="o">+</span> <span class="mi">1</span>
<span class="mi">143</span> <span class="k">if</span> <span class="nv">r</span> <span class="o">>=</span> <span class="nv">p1</span> <span class="ow">and</span> <span class="nv">r</span> <span class="o"><</span> <span class="nv">p2</span> <span class="k">then</span> <span class="nv">z2</span> <span class="o">=</span> <span class="nv">z2</span> <span class="o">+</span> <span class="mi">1</span>
<span class="mi">144</span> <span class="k">if</span> <span class="nv">r</span> <span class="o">>=</span> <span class="nv">p2</span> <span class="ow">and</span> <span class="nv">r</span> <span class="o"><</span> <span class="nv">p3</span> <span class="k">then</span> <span class="nv">z3</span> <span class="o">=</span> <span class="nv">z3</span> <span class="o">+</span> <span class="mi">1</span>
<span class="mi">146</span> <span class="k">next</span> <span class="nv">i</span>
<span class="mi">150</span> <span class="k">print</span> <span class="p">"</span><span class="s2">results:</span><span class="p">"</span>
<span class="mi">155</span> <span class="k">print</span> <span class="p">"</span><span class="s2">00: [</span><span class="p">"</span><span class="nv">z0</span><span class="p">"</span><span class="s2">] </span><span class="p">";</span> <span class="p">:</span> <span class="k">for</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="nv">to</span> <span class="nv">z0</span> <span class="p">:</span> <span class="k">print</span> <span class="p">"</span><span class="s2">Q</span><span class="p">";</span> <span class="p">:</span> <span class="k">next</span> <span class="nv">i</span> <span class="p">:</span> <span class="k">print</span>
<span class="mi">165</span> <span class="k">print</span> <span class="p">"</span><span class="s2">01: [</span><span class="p">"</span><span class="nv">z2</span><span class="p">"</span><span class="s2">] </span><span class="p">";</span> <span class="p">:</span> <span class="k">for</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="nv">to</span> <span class="nv">z2</span> <span class="p">:</span> <span class="k">print</span> <span class="p">"</span><span class="s2">Q</span><span class="p">";</span> <span class="p">:</span> <span class="k">next</span> <span class="nv">i</span> <span class="p">:</span> <span class="k">print</span>
<span class="mi">160</span> <span class="k">print</span> <span class="p">"</span><span class="s2">10: [</span><span class="p">"</span><span class="nv">z1</span><span class="p">"</span><span class="s2">] </span><span class="p">";</span> <span class="p">:</span> <span class="k">for</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="nv">to</span> <span class="nv">z1</span> <span class="p">:</span> <span class="k">print</span> <span class="p">"</span><span class="s2">Q</span><span class="p">";</span> <span class="p">:</span> <span class="k">next</span> <span class="nv">i</span> <span class="p">:</span> <span class="k">print</span>
<span class="mi">170</span> <span class="k">print</span> <span class="p">"</span><span class="s2">11: [</span><span class="p">"</span><span class="nv">z3</span><span class="p">"</span><span class="s2">] </span><span class="p">";</span> <span class="p">:</span> <span class="k">for</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="nv">to</span> <span class="nv">z3</span> <span class="p">:</span> <span class="k">print</span> <span class="p">"</span><span class="s2">Q</span><span class="p">";</span> <span class="p">:</span> <span class="k">next</span> <span class="nv">i</span> <span class="p">:</span> <span class="k">print</span>
<span class="mi">175</span> <span class="nb">goto</span> <span class="mi">1000</span>
<span class="mi">200</span> <span class="nv">rem</span> <span class="nv">simulate</span> <span class="nv">gate</span> <span class="nv">operation</span>
<span class="mi">210</span> <span class="k">if</span> <span class="nv">gate$</span> <span class="err">=</span> <span class="err">"</span><span class="nv">x0</span><span class="p">"</span><span class="s2"> then gosub 400
220 if gate$ = </span><span class="p">"</span><span class="nv">x1</span><span class="p">"</span><span class="s2"> then gosub 420
230 if gate$ = </span><span class="p">"</span><span class="nv">y0</span><span class="p">"</span><span class="s2"> then gosub 440
240 if gate$ = </span><span class="p">"</span><span class="nv">y1</span><span class="p">"</span><span class="s2"> then gosub 460
250 if gate$ = </span><span class="p">"</span><span class="nv">z0</span><span class="p">"</span><span class="s2"> then gosub 480
260 if gate$ = </span><span class="p">"</span><span class="nv">z1</span><span class="p">"</span><span class="s2"> then gosub 500
270 if gate$ = </span><span class="p">"</span><span class="nv">h0</span><span class="p">"</span><span class="s2"> then gosub 520
280 if gate$ = </span><span class="p">"</span><span class="nv">h1</span><span class="p">"</span><span class="s2"> then gosub 540
290 if gate$ = </span><span class="p">"</span><span class="nv">cx</span><span class="p">"</span><span class="s2"> then gosub 560
300 if gate$ = </span><span class="p">"</span><span class="nv">sw</span><span class="p">"</span><span class="s2"> then gosub 580
310 return
400 rem x0 gate
410 a0 = r0 : r0 = r1 : r1 = a0
411 a0 = i0 : i0 = i1 : i1 = a0
412 a0 = r2 : r2 = r3 : r3 = a0
413 a0 = i2 : i2 = i3 : i3 = a0
416 return
420 rem x1 gate
425 a0 = r1 : r1 = r3 : r3 = a0
426 a0 = i1 : i1 = i3 : i3 = a0
427 a0 = r0 : r0 = r2 : r2 = a0
428 a0 = i0 : i0 = i2 : i2 = a0
440 rem y0 gate
446 a0 = i0 : i0 = -r0 : r0 = a0
447 a0 = i1 : i1 = -r1 : r1 = a0
448 a0 = i2 : i2 = -r2 : r2 = a0
449 a0 = i3 : i3 = -r3 : r3 = a0
450 return
460 rem y1 gate
466 a0 = i1 : i1 = -r1 : r1 = a0
467 a0 = i3 : i3 = -r3 : r3 = a0
468 return
480 rem z0 gate
482 i2 = -i2 : i3 = -i3
483 return
500 rem z1 gate
502 i1 = -i1 : i3 = -i3
503 return
520 rem h0 gate
521 a0 = (r0 + r1) / sqr(2) : a1 = (i0 + i1) / sqr(2)
522 b0 = (r0 - r1) / sqr(2) : b1 = (i0 - i1) / sqr(2)
523 r0 = a0 : i0 = a1 : r1 = b0 : i1 = b1
525 a0 = (r2 + r3) / sqr(2) : a1 = (i2 + i3) / sqr(2)
526 b0 = (r2 - r3) / sqr(2) : b1 = (i2 - i3) / sqr(2)
527 r2 = a0 : i2 = a1 : r3 = b0 : i3 = b1
528 return
540 rem h1 gate
541 a0 = (r0 + r2) / sqr(2) : a1 = (i0 + i2) / sqr(2)
542 b0 = (r0 - r2) / sqr(2) : b1 = (i0 - i2) / sqr(2)
543 r0 = a0 : i0 = a1 : r2 = b0 : i2 = b1
545 a0 = (r1 + r3) / sqr(2) : a1 = (i1 + i3) / sqr(2)
546 b0 = (r1 - r3) / sqr(2) : b1 = (i1 - i3) / sqr(2)
547 r1 = a0 : i1 = a1 : r3 = b0 : i3 = b1
548 return
560 rem cx gate
561 a0 = r1 : r1 = r3 : r3 = a0
562 a0 = i1 : i1 = i3 : i3 = a0
579 return
580 rem sw gate
581 a0 = r1 : r1 = r2 : r2 = a0
582 a0 = i1 : i1 = i2 : i2 = a0
590 return
600 rem statevcector normalization
601 nf = sqr(1 / sq)
602 r0 = r0 * nf
603 i0 = i0 * nf
604 r1 = r1 * nf
605 i1 = i1 * nf
606 r2 = r2 * nf
607 i2 = i2 * nf
608 r3 = r3 * nf
609 i3 = i3 * nf
610 return
1000 end
</span></code></pre></div></div>
<p>The source code is accessible here: <a href="https://github.com/dakk/qc64">https://github.com/dakk/qc64</a>
Twitter: <a href="https://twitter.com/dagide">@dagide</a></p>
<p>Article on <a href="https://medium.com/@dakk/quantum-computing-on-a-commodore-64-in-200-lines-of-basic-eda7658b32a4">medium</a>.</p>Davide Gessa @dakkIn an age where companies are selling two-qubit quantum computers for a sum of money that would make your wallet recoil in horror, here we are, stepping off the beaten path and walking down memory lane to a time when computers were, well, somewhat simpler.Free near real-time 10-meter resolution satellite imagery with 5 lines of code2023-05-24T17:02:28+02:002023-05-24T17:02:28+02:00https://dakk.github.io//python/2023/05/24/sentinelsat_download<p><img src="/assets/2023-05-24-image.webp" alt="Satellite image" /></p>
<p>Satellite imagery has been a game-changer in many fields, from meteorology and environmental sciences to city planning and real estate. The ability to look at our planet from above offers insights that ground-based observation cannot provide. However, accessibility to such high-resolution imagery has often been perceived as costly and complicated. It doesn’t have to be!
The European Space Agency (ESA) has a wealth of satellite imagery that is not just high resolution (up to 10 meters) but also free to access, download, and use. This resource is provided through their Earth Observation Program, with the Copernicus mission at its heart.
Imagine the potential of this! Whether you’re an environmental researcher looking to analyze deforestation, an urban planner in need of accurate city topography, or a tech enthusiast eager to experiment with satellite imagery data, you now have a powerful tool at your fingertips.</p>
<h2 id="getting-started-sign-up-at-copernicus-scihub">Getting Started: Sign Up at Copernicus Scihub</h2>
<p>To get started, you first need to sign up on Copernicus Scihub. This is ESA’s gateway for satellite data distribution, offering petabytes of information just a few clicks away. The sign-up process is straightforward: go to the Copernicus Open Access Hub, click on the sign-up button, and fill in the required details. Make sure to remember your username and password because you will need them in the next steps.</p>
<h2 id="access-satellite-imagery-withcode">Access Satellite Imagery With Code</h2>
<p>Now, let’s get to the exciting part. First install sentinelsat with the following command:
<code class="language-plaintext highlighter-rouge">pip install sentinelsat</code></p>
<p>Now with just 4 lines of Python code, you can access this treasure trove of satellite data. Here’s the basic script:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">fnmatch</span>
<span class="kn">from</span> <span class="nn">sentinelsat</span> <span class="kn">import</span> <span class="n">SentinelAPI</span><span class="p">,</span> <span class="n">make_path_filter</span>
<span class="n">sapi</span> <span class="o">=</span> <span class="n">SentinelAPI</span><span class="p">(</span><span class="s">'user'</span><span class="p">,</span> <span class="s">'password'</span><span class="p">,</span> <span class="s">'https://scihub.copernicus.eu/dhus/'</span><span class="p">)</span>
<span class="n">products</span> <span class="o">=</span> <span class="n">sapi</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="n">date</span><span class="o">=</span><span class="p">(</span><span class="s">'NOW-1DAYS'</span><span class="p">,</span> <span class="s">'NOW'</span><span class="p">),</span> <span class="n">platformname</span><span class="o">=</span><span class="s">'Sentinel-2'</span><span class="p">,</span> <span class="n">processinglevel</span><span class="o">=</span><span class="s">'Level-2A'</span><span class="p">)</span>
<span class="n">sapi</span><span class="p">.</span><span class="n">download_all</span><span class="p">(</span><span class="n">products</span><span class="p">,</span> <span class="s">'./tempdataset'</span><span class="p">,</span> <span class="n">nodefilter</span><span class="o">=</span><span class="k">lambda</span> <span class="n">a</span><span class="p">:</span> <span class="n">fnmatch</span><span class="p">.</span><span class="n">fnmatch</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="s">'node_path'</span><span class="p">],</span> <span class="s">'*_TCI_10m.jp2'</span><span class="p">))</span>
</code></pre></div></div>
<p>In these four lines of code:</p>
<ul>
<li>We import the SentinelAPI module from the sentinelsat library. If you don’t have the sentinelsat library installed yet, you can easily add it to your Python environment using pip: pip install sentinelsat.</li>
<li>We create an instance of the SentinelAPI class, providing our Copernicus Scihub credentials and the URL of the Scihub server.</li>
<li>We use the query method to search for available satellite imagery based on specific criteria.
Finally, we use the download_all method to download all the images that matched our query.</li>
</ul>
<p>The beauty of this approach is its flexibility. You can adjust the query parameters based on your specific needs, like the date range, the satellite platform, or the acceptable cloud cover percentage.
It’s that simple! Now, you can start exploring, analyzing, and using high-resolution satellite imagery, free of charge, and with just a few lines of code. The sky is not the limit; it’s the starting point!</p>
<p>Article on <a href="https://medium.com/@dakk/free-near-real-time-10-meter-resolution-satellite-imagery-with-5-lines-of-code-d1f155778cab">medium</a>.</p>Davide Gessa @dakkMy Journey at the UnitaryHack Hackathon: A Quantum Computing Adventure2023-05-24T17:02:28+02:002023-05-24T17:02:28+02:00https://dakk.github.io//quantum-computing/2023/05/24/unitaryhack<p>This June I emerged as one of the top participants with 9 bounties collected (alongside another exceptional contributor) in the <a href="https://unitaryhack.dev">#UnitaryHack</a> Hackathon, hosted by the <a href="https://unitary.fund/">Unitary Fund</a>.</p>
<p>For those unfamiliar, the UnitaryHack Hackathon is an event that gathers quantum computing enthusiasts from across the globe to work together and address exciting challenges in the field. It was an journey where I had the opportunity to explore, learn, and contribute to the burgeoning open-source ecosystem of quantum computing.</p>
<p>Here is the list of bounties that I tackled:</p>
<ul>
<li><a href="https://github.com/Qiskit/qiskit-aer/issues/1632">qiskit-aer: Qiskit Aer still uses execute</a></li>
<li><a href="https://github.com/bqskit/bqskit/issues/150">bqskit: Non-deterministic circuit iteration for regions</a></li>
<li><a href="https://github.com/qiskit-community/qiskit-braket-provider/issues/47">qiskit-braket-provider: add get_statevector support for BraketLocalBackend</a></li>
<li><a href="https://github.com/qiskit-community/qiskit-braket-provider/issues/37">qiskit-braket-provider: Updates for Qiskit to Braket circuit conversion</a></li>
<li><a href="https://github.com/pasqal-io/Pulser/issues/522">pulser: Adding a function to draw SequenceSamples</a></li>
<li><a href="https://github.com/pasqal-io/Pulser/issues/501">pulser: Drawing of Register goes out of window boundaries</a></li>
<li><a href="https://github.com/pasqal-io/Pulser/issues/497">pulser: Add an error when a Channel is called with an eom_config but without a modulation bandwidth</a></li>
<li><a href="https://github.com/pasqal-io/Pulser/issues/352">pulser: SPAM errors introduce large simulation overhead</a></li>
<li><a href="https://github.com/aws/amazon-braket-sdk-python/issues/320">amazon-braket-sdk-python: Support for the run_batch() method on LocalSimulator</a></li>
</ul>
<p>Each of these projects allowed me to dive deeper into quantum computing, tackle real-world problems, and collaborate with an incredible community of passionate learners and experienced professionals. This experience reaffirmed my belief in the power of open-source collaborations and their transformative role in shaping the future of technology.</p>Davide Gessa @dakkThis June I emerged as one of the top participants with 9 bounties collected (alongside another exceptional contributor) in the #UnitaryHack Hackathon, hosted by the Unitary Fund.Ship detection from Sentinel-2 satellite images2023-05-15T15:30:28+02:002023-05-15T15:30:28+02:00https://dakk.github.io//ml/2023/05/15/sentinel_ship_detection<p>A few days ago I came across a yt video discussing the ESA Copernicus program, a European initiative for monitoring earth via a satellite constellation. This constellation is composed of numerous satellites called Sentinels, which scan the Earth daily for different parameters.
What astonished mew as the fact that all the produced data is open to public and updated every day, so anyone can download and utilize it.</p>
<p>So, on a rather dull Monday, I embarked on: to create something using this data. Given my fondness for ships, I decided to create something ship-related, a software to download and recognize ships using machine learning.</p>
<p>Since Sentinel-2 images have thebest resolution of 1 pixel x 10 meters, I chose to detect only moving ships because their wakes are easier to spot and less likely to result in a false positive.</p>
<p>Furthermore, wakes provide additional information, such as the vessel’s direction and its approximated speed.</p>
<p><img src="/assets/2023-05-15-image.webp" alt="Moving vessels, Sentinel-2" /></p>
<h2 id="step-1-getting-data">Step 1: Getting data</h2>
<p>The first thing to do is to programmatically download the data. I chose Sentinel-2 satellites as my data source, which cover the whole Earth every five days and offer ready-to-use True Color Image (TCI) in jp2 format (jpeg 2000).</p>
<p>Downloading data from Copernicus is straightforward. Just signup at <a href="https://scihub.copernicus.eu">https://scihub.copernicus.eu</a>, select the area, and download. Using the code is easy as well, as can be seen in the following snippet.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">fnmatch</span>
<span class="kn">from</span> <span class="nn">sentinelsat</span> <span class="kn">import</span> <span class="n">SentinelAPI</span><span class="p">,</span> <span class="n">make_path_filter</span>
<span class="n">sapi</span> <span class="o">=</span> <span class="n">SentinelAPI</span><span class="p">(</span><span class="n">SUSER</span><span class="p">,</span> <span class="n">SPASSWORD</span><span class="p">,</span> <span class="s">'https://scihub.copernicus.eu/dhus/'</span><span class="p">)</span>
<span class="c1"># Query scihub for Sentinel2 data from the last 24h
</span><span class="n">p</span> <span class="o">=</span> <span class="n">sapi</span><span class="p">.</span><span class="n">query</span><span class="p">(</span><span class="n">date</span><span class="o">=</span><span class="p">(</span><span class="s">'NOW-1DAYS'</span><span class="p">,</span> <span class="s">'NOW'</span><span class="p">),</span> <span class="n">area_relation</span><span class="o">=</span><span class="s">"Intersects"</span><span class="p">,</span> <span class="n">platformname</span><span class="o">=</span><span class="s">'Sentinel-2'</span><span class="p">,</span>
<span class="n">processinglevel</span><span class="o">=</span><span class="s">'Level-2A'</span><span class="p">)</span>
<span class="c1"># Create a pathfilter for downloading only TCI at 10m resolution
</span><span class="k">def</span> <span class="nf">path_filter</span><span class="p">(</span><span class="n">a</span><span class="p">):</span>
<span class="n">npath</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="s">'node_path'</span><span class="p">]</span>
<span class="k">return</span> <span class="n">fnmatch</span><span class="p">.</span><span class="n">fnmatch</span><span class="p">(</span><span class="n">npath</span><span class="p">,</span> <span class="s">'*_TCI_10m.jp2'</span><span class="p">)</span>
<span class="c1"># Download only if the cloud coverage is less than 30%
</span><span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">p</span><span class="p">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">cov</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="s">'cloudcoverpercentage'</span><span class="p">]</span>
<span class="k">if</span> <span class="n">cov</span> <span class="o">></span> <span class="mf">30.</span><span class="p">:</span>
<span class="k">print</span> <span class="p">(</span><span class="s">'skipping for cloud coverage'</span><span class="p">,</span> <span class="n">size</span><span class="p">,</span> <span class="n">cov</span><span class="p">)</span>
<span class="k">continue</span>
<span class="n">sapi</span><span class="p">.</span><span class="n">download</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="s">'./tempdataset'</span><span class="p">,</span> <span class="n">nodefilter</span><span class="o">=</span><span class="n">path_filter</span><span class="p">)</span>
</code></pre></div></div>
<p>Once you run it, you’ll have jp2 images from Sentinel-2 from the last day.</p>
<h2 id="step-2-creating-the-training-dataset">Step 2: Creating the training Dataset</h2>
<p>For this step, I used QGIS which supports JP2 rasters. First, open the jp2 file, create a polygon shapefile layer, switch to edit mode and press “Add a Polygon”. Now we have to select the boundary of a ship (including the wake); finding them is easier than you might think.</p>
<p>After doing this to a good number of ships, export the layer as a GeoJSON. Repeat the process with at least other file, which will be used for validating the training on new data.</p>
<p><img src="/assets/2023-05-15-qgis.gif" alt="QGIS" /></p>
<h2 id="step-3-training--validating">Step 3: Training & Validating</h2>
<p>Now that we have a substantial amount of training data, we can start to create and train our model. Luckily for us, there’s a fantastic open-source library and framework called <a href="https://rastervision.io/">RasterVision</a> which offers a powerful tool for semantic segmentation and object detection on raster data.</p>
<p>For my proof of concept, I used it as a framework as follows: I defined two scenes, one for training and the other for validating the results. Then, I created all the configurations for the training, returning an ObjectDetectionConfig object.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">os.path</span> <span class="kn">import</span> <span class="n">join</span><span class="p">,</span> <span class="n">dirname</span>
<span class="kn">from</span> <span class="nn">rastervision.core.rv_pipeline</span> <span class="kn">import</span> <span class="p">(</span><span class="n">ObjectDetectionConfig</span><span class="p">,</span>
<span class="n">ObjectDetectionChipOptions</span><span class="p">,</span>
<span class="n">ObjectDetectionPredictOptions</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">rastervision.core.data</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">ClassConfig</span><span class="p">,</span> <span class="n">ObjectDetectionLabelSourceConfig</span><span class="p">,</span> <span class="n">GeoJSONVectorSourceConfig</span><span class="p">,</span>
<span class="n">RasterioSourceConfig</span><span class="p">,</span> <span class="n">SceneConfig</span><span class="p">,</span> <span class="n">DatasetConfig</span><span class="p">,</span> <span class="n">ClassInferenceTransformerConfig</span><span class="p">)</span>
<span class="kn">from</span> <span class="nn">rastervision.pytorch_backend</span> <span class="kn">import</span> <span class="n">PyTorchObjectDetectionConfig</span>
<span class="kn">from</span> <span class="nn">rastervision.pytorch_learner</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Backbone</span><span class="p">,</span> <span class="n">SolverConfig</span><span class="p">,</span> <span class="n">ObjectDetectionModelConfig</span><span class="p">,</span>
<span class="n">ObjectDetectionImageDataConfig</span><span class="p">,</span> <span class="n">ObjectDetectionGeoDataConfig</span><span class="p">,</span>
<span class="n">ObjectDetectionGeoDataWindowConfig</span><span class="p">,</span> <span class="n">GeoDataWindowMethod</span><span class="p">)</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="k">def</span> <span class="nf">get_config</span><span class="p">(</span><span class="n">runner</span><span class="p">,</span> <span class="n">data_uri</span><span class="o">=</span><span class="s">'./dataset'</span><span class="p">,</span> <span class="n">full_train</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">nochip</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">get_path</span><span class="p">(</span><span class="n">part</span><span class="p">):</span>
<span class="k">return</span> <span class="n">join</span><span class="p">(</span><span class="n">data_uri</span><span class="p">,</span> <span class="n">part</span><span class="p">)</span>
<span class="n">class_config</span> <span class="o">=</span> <span class="n">ClassConfig</span><span class="p">(</span>
<span class="n">names</span><span class="o">=</span><span class="p">[</span><span class="s">'ship'</span><span class="p">],</span> <span class="n">colors</span><span class="o">=</span><span class="p">[</span><span class="s">'red'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">make_scene</span><span class="p">(</span><span class="n">scene_id</span><span class="p">,</span> <span class="n">img_path</span><span class="p">,</span> <span class="n">label_path</span><span class="p">):</span>
<span class="n">raster_source</span> <span class="o">=</span> <span class="n">RasterioSourceConfig</span><span class="p">(</span>
<span class="n">channel_order</span><span class="o">=</span><span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">uris</span><span class="o">=</span><span class="p">[</span><span class="n">img_path</span><span class="p">])</span>
<span class="n">label_source</span> <span class="o">=</span> <span class="n">ObjectDetectionLabelSourceConfig</span><span class="p">(</span>
<span class="n">vector_source</span><span class="o">=</span><span class="n">GeoJSONVectorSourceConfig</span><span class="p">(</span>
<span class="n">uri</span><span class="o">=</span><span class="n">label_path</span><span class="p">,</span>
<span class="n">ignore_crs_field</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">transformers</span><span class="o">=</span><span class="p">[</span>
<span class="n">ClassInferenceTransformerConfig</span><span class="p">(</span><span class="n">default_class_id</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="p">])</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">SceneConfig</span><span class="p">(</span>
<span class="nb">id</span><span class="o">=</span><span class="n">scene_id</span><span class="p">,</span>
<span class="n">raster_source</span><span class="o">=</span><span class="n">raster_source</span><span class="p">,</span>
<span class="n">label_source</span><span class="o">=</span><span class="n">label_source</span><span class="p">)</span>
<span class="n">chip_sz</span> <span class="o">=</span> <span class="mi">300</span>
<span class="n">img_sz</span> <span class="o">=</span> <span class="n">chip_sz</span>
<span class="n">scenes</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">make_scene</span><span class="p">(</span><span class="s">'od_test'</span><span class="p">,</span> <span class="n">get_path</span><span class="p">(</span><span class="s">'t1.jp2'</span><span class="p">),</span>
<span class="n">get_path</span><span class="p">(</span><span class="s">'t1.geojson'</span><span class="p">)),</span>
<span class="n">make_scene</span><span class="p">(</span><span class="s">'od_test-2'</span><span class="p">,</span> <span class="n">get_path</span><span class="p">(</span><span class="s">'t2.jp2'</span><span class="p">),</span>
<span class="n">get_path</span><span class="p">(</span><span class="s">'t2.geojson'</span><span class="p">))</span>
<span class="p">]</span>
<span class="n">scene_dataset</span> <span class="o">=</span> <span class="n">DatasetConfig</span><span class="p">(</span>
<span class="n">class_config</span><span class="o">=</span><span class="n">class_config</span><span class="p">,</span>
<span class="n">train_scenes</span><span class="o">=</span><span class="n">scenes</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">1</span><span class="p">],</span>
<span class="n">validation_scenes</span><span class="o">=</span><span class="n">scenes</span><span class="p">[</span><span class="mi">1</span><span class="p">:])</span>
<span class="n">chip_options</span> <span class="o">=</span> <span class="n">ObjectDetectionChipOptions</span><span class="p">(</span><span class="n">neg_ratio</span><span class="o">=</span><span class="mf">1.0</span><span class="p">,</span> <span class="n">ioa_thresh</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="k">if</span> <span class="n">nochip</span><span class="p">:</span>
<span class="n">window_opts</span> <span class="o">=</span> <span class="n">ObjectDetectionGeoDataWindowConfig</span><span class="p">(</span>
<span class="n">method</span><span class="o">=</span><span class="n">GeoDataWindowMethod</span><span class="p">.</span><span class="n">sliding</span><span class="p">,</span>
<span class="n">stride</span><span class="o">=</span><span class="n">chip_sz</span><span class="p">,</span>
<span class="n">size</span><span class="o">=</span><span class="n">chip_sz</span><span class="p">,</span>
<span class="n">neg_ratio</span><span class="o">=</span><span class="n">chip_options</span><span class="p">.</span><span class="n">neg_ratio</span><span class="p">,</span>
<span class="n">ioa_thresh</span><span class="o">=</span><span class="n">chip_options</span><span class="p">.</span><span class="n">ioa_thresh</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">ObjectDetectionGeoDataConfig</span><span class="p">(</span>
<span class="n">scene_dataset</span><span class="o">=</span><span class="n">scene_dataset</span><span class="p">,</span>
<span class="n">window_opts</span><span class="o">=</span><span class="n">window_opts</span><span class="p">,</span>
<span class="n">img_sz</span><span class="o">=</span><span class="n">img_sz</span><span class="p">,</span>
<span class="n">augmentors</span><span class="o">=</span><span class="p">[])</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">ObjectDetectionImageDataConfig</span><span class="p">(</span><span class="n">img_sz</span><span class="o">=</span><span class="n">img_sz</span><span class="p">,</span> <span class="n">augmentors</span><span class="o">=</span><span class="p">[])</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">ObjectDetectionModelConfig</span><span class="p">(</span><span class="n">backbone</span><span class="o">=</span><span class="n">Backbone</span><span class="p">.</span><span class="n">resnet18</span><span class="p">)</span>
<span class="n">solver</span> <span class="o">=</span> <span class="n">SolverConfig</span><span class="p">(</span>
<span class="n">lr</span><span class="o">=</span><span class="mf">1e-4</span><span class="p">,</span>
<span class="n">num_epochs</span><span class="o">=</span><span class="mi">12</span><span class="p">,</span>
<span class="n">batch_sz</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span>
<span class="n">one_cycle</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">sync_interval</span><span class="o">=</span><span class="mi">300</span><span class="p">)</span>
<span class="n">backend</span> <span class="o">=</span> <span class="n">PyTorchObjectDetectionConfig</span><span class="p">(</span>
<span class="n">data</span><span class="o">=</span><span class="n">data</span><span class="p">,</span>
<span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
<span class="n">solver</span><span class="o">=</span><span class="n">solver</span><span class="p">,</span>
<span class="n">log_tensorboard</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">run_tensorboard</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">predict_options</span> <span class="o">=</span> <span class="n">ObjectDetectionPredictOptions</span><span class="p">(</span>
<span class="n">merge_thresh</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">score_thresh</span><span class="o">=</span><span class="mf">0.5</span><span class="p">)</span>
<span class="k">return</span> <span class="n">ObjectDetectionConfig</span><span class="p">(</span>
<span class="n">root_uri</span><span class="o">=</span><span class="s">'.'</span><span class="p">,</span>
<span class="n">dataset</span><span class="o">=</span><span class="n">scene_dataset</span><span class="p">,</span>
<span class="n">backend</span><span class="o">=</span><span class="n">backend</span><span class="p">,</span>
<span class="n">train_chip_sz</span><span class="o">=</span><span class="n">chip_sz</span><span class="p">,</span>
<span class="n">predict_chip_sz</span><span class="o">=</span><span class="n">chip_sz</span><span class="p">,</span>
<span class="n">chip_options</span><span class="o">=</span><span class="n">chip_options</span><span class="p">,</span>
<span class="n">predict_options</span><span class="o">=</span><span class="n">predict_options</span><span class="p">)</span>
</code></pre></div></div>
<p>And finally I run it with:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rastervision run sentiship.py
</code></pre></div></div>
<p>After 12 epochs of training, it was already able to detect ships — easy peasy!</p>
<p><img src="/assets/2023-05-15-result.webp" alt="Result" /></p>
<p>Moving forward, I am keen to explore how to put this model to further use. One intriguing possibility that springs to mind is to employ it for detecting ‘ghost ships’ — vessels that don’t have an Automatic Identification System (AIS). These elusive ships, often engaged in illicit activities or abandoned, pose significant challenges for maritime authorities. By harnessing the power of machine learning and the vast amount of data provided by the Copernicus program, we may be able to shed more light on these maritime mysteries. Stay tuned for more updates as I delve deeper into this exciting venture!</p>
<p>Github repo: <a href="https://github.com/dakk/sentiship">https://github.com/dakk/sentiship</a></p>
<p>Article on <a href="https://medium.com/@dakk/ship-detection-from-sentinel-2-satellite-images-3312d8930df6">medium</a>.</p>Davide Gessa @dakkA few days ago I came across a yt video discussing the ESA Copernicus program, a European initiative for monitoring earth via a satellite constellation. This constellation is composed of numerous satellites called Sentinels, which scan the Earth daily for different parameters. What astonished mew as the fact that all the produced data is open to public and updated every day, so anyone can download and utilize it.