Practical use of the D-Wave 2000Q: A steep learning curve for quantum computing
- Transfer
It’s hard to rethink the concept of a task, but the result is worth it.
Author's note : I know that I incorrectly calculated the Bragg transfer in both the classical and quantum cases; however, it is close enough to the truth in order to understand the difference between programming classical and quantum computers.
Time: somewhere in 2018. Location: rotten channel in Slaka.
“Do you know Python?”
The questions of John Timmer, the scientific director of Ars Technica, can sometimes be taken by surprise. If it were possible to impregnate letters in Slaka with caution, then my answer “Yes” would simply ooze with it.
It turns out that D-Wave decided to give the world access to its quantum optimizer through the API. Ars invited him to try, but you needed to know Python. I was ready for it.
I assumed that D-Wave would release some kind of fantastic API that could take my proprietary code that makes programmers cry, and turn it into quantum-optimized lines. Alas, when I got to the quantum optimizer, it turned out that it wasn’t. I quickly found myself immersed in the documentation, trying to figure out what I needed to do at all.
I think that the representative of D-Wave public relations had in mind a person who knew enough to run ready-made examples. But I'm stubborn. I needed to come up with three or four possible tasks that I wanted to test. I wanted to find out: can I master the process of solving these problems on a D-Wave computer? How easy is it to make a conceptual leap from classical programming to working with quantum annealing? Will at least some of my tasks fit this machine?
Revealing an amazing conclusion right away, I’ll say that the answers were as follows: maybe it’s not quite “mastering”; difficult; not all tasks.
Choice of tasks for programming
Despite the way you imagine me, I can be called a practicing programmer. Essentially, anyone with a good understanding of programming would grimace (and possibly commit murder) when I saw my Python code.
However, I can come up with tasks that require writing a program to solve them. I need, for example, something that calculates the electric field of a set of electrodes. Something that finds a state with a minimal helium atom energy. Or something that counts the increase in light intensity at the start of the laser. These tasks interest me the most. And starting this project, I had no idea if the D-Wave architecture could solve these problems.
I chose two problems that, in my opinion, could work: finding members of the Mandelbrot set and calculating potential contours of a set of electrodes. The advantage of these problems was that I could quickly solve them using the classic code and compare the answers. But I quickly ran into problems trying to figure out how to start solving these problems on a machine from D-Wave. It requires a major shift in understanding tasks, and my thinking works quite straightforwardly.
For example, one of the problems that I encountered is that we are dealing with low-level binary numbers (despite the fact that they are expressed in the form of qubits, not bits). This means that, in fact, the program has no types. Almost all of my programming experience has been to solve physical problems using floating point numeric types.
You have to think differently about the task: the answer should be expressed as a binary number (ideally, true or false), and all physics (for example, all floating point numbers) should be expressed through a combination of qubits. Even if my life depended on it, I would not be able to figure out how this can be done for any of my tasks. Immersed in teaching, I allowed this problem to boil a little in my own juice.
Six months later, I finally came across a problem that I was familiar with that I could solve with a D-Wave computer. The passage of light through a fiber Bragg grating can be expressed as a binary problem: did a photon come out of the filter, or not? All physics is contained in qubit compounds, and the answer is extracted from the energy of the solution.
Bragg gratings
A one-dimensional Bragg grating is a multilayer material. Each gap between the two layers reflects a small amount of light. The total penetration through the entire structure is determined by the distance between the gaps. For the light to pass through, it is necessary that the waves from different intervals add up in phase. The pass spectrum of an ideal Bragg grating with 50 layers and a reflectance of 0.1% is shown below.
The following code generates data for this graph:
ld = np.linspace(ld_center-3e-9, ld_center+3e-9, num_ld)
k = 2*np.pi/ld
T = np.ones(ld.shape)
for j in range(num_layers):
T = T*(1-A)*np.cos(j*k*layer_sep)**2
Here we explicitly calculate the relative contributions of each gap, expressed in optical power, which reach the next gap. Constructive and destructive interference are taken into account by reducing or increasing the contribution of the gap, depending on how close the distance between the layers coincides with half the wavelength.
This hack is necessary because the connection of qubits is expressed only in real and not in complex numbers (physics is best expressed through complex numbers containing the amplitude and phase of the light). Nevertheless, the output of the classical code looks approximately correct - the absence of side frequency bands worries a little, which indicates the incompleteness of the model, but so far it does not matter.
The classic model code lacks consistency checks. I calculated the result, suggesting exactly how the wave would propagate. Even if this assumption turns out to be incorrect, the calculation result will be the same - although all the equations are based on physics, it is impossible to guarantee in the code that they describe it correctly.
We pass to quanta
In the D-Wave system, it is necessary to create a chain of qubits, each of which represents the light intensity in the gap. Each qubit is associated with its neighbors, and the weight of the connection represents the passage from one gap to another, taking into account the distance between the interfaces. If the distance between the interfaces is equal to half the wavelength, light can resonate between the two interfaces and pass on. If the distance is a quarter of the wavelength, destructive interference is triggered, and the connection should be minimal.
Passing through one gap is indicated in 99.9%, so the connection between the zero and first qubits is
Between the first and second:
Between the second and third:
In this formula, d is the physical distance between the layers, and λ is the wavelength. If d / λ = 0.5, then the cosine is equal to unity, and we can hope for the ideal transmission of light.
In the D-Wave system, this means that every two neighboring qubits must be connected as follows:
In this expression, the degree u takes into account the influence of previous qubits and simplifies the connection scheme.
Task implementation
Now, knowing how to connect qubits, we must look at the physical connection of qubits to decide how to complete this task. This is called a minor embedding.
We must give the computer a list of connections between qubits with their weights. We must also specify deviations indicating the importance of each qubit. In our case, all qubits are equally important, therefore they are set as -1 for all qubits (I took this number from the standard example). Deviations and connections must be associated with physical qubits and the relationships between them. In the case of large tasks, the search for such a mapping can take a long time.
The code for generating relationships and deviations is pretty simple.
#qubit labels (q[j], q[j]) используются как ключи в словаре связей
linear.update({(q[j], q[j]): -1}) # отклонения одинаковы
#у ближайших соседей связь ненулевая
if j-k == -1:
quad.update({(q[j], q[k]): (J_vals[j])**k})
#все остальные связи нулевые
else:
quad.update({(q[j], q[k]): 0})
Fortunately, the D-Wave API will try to find a small implementation on its own. I found that it worked for a filter with 50 layers, but could not cope with 100 layers. This seems rather strange to me, since having 2,000 qubits and a chain length of 1 (we do not need to combine several physical qubits to create one logical one), the system must be able to implement even larger problems. Looking back, I believe that the failure was due to the fact that I asked too many zero connections.
An alternative approach is simply not to explicitly define null bonds. This gives the algorithm the freedom to find more implementation options where qubits have no connections. I have not tried this, but this option seems to me the next logical step.
In any case, starting the D-Wave machine is very simple:
response = EmbeddingComposite(DWaveSampler()).sample_qubo(Q_auto, num_reads=num_runs)
Learning to speak cubitly
The difference between my classic algorithm and the D-Wave solution is that the D-Wave computer does not directly return a clear result. It turns out broken into many parts. We get a list of energies, and the smallest of them should be the solution. For several runs (say 1000) for each energy, we get the number of times that it appeared in the answer. And for each run we get a “response”, the value of qubits. It was not immediately clear to me which of these values can (and can) be interpreted as passing through a filter.
In the end, I decided that the minimum solution energy would be the best answer, since this value in some sense represents the amount of energy stored in the filter. Therefore, a solution with higher energy represents a greater permeability of the filter, as shown below. Turning this answer into a real passage of light is left as homework for those who understand this.
It is also possible to obtain a physical representation of the process by examining the values of qubits in a solution with the lowest energy. Below you can see the bit values of the solutions corresponding to the peak of the transmission curve (500 nm), 50% transmission (500.6 nm) and 5% transmission (501.4 nm).
At the edge of the transmission peak, qubits tend to accumulate in groups of units. At the peak, the qubits alternate between 0 and 1. This last solution is a binary picture of how the light intensity in the Bragg grating varies. In other words, the D-Wave solution also presents physics directly, which cannot be said about my classic code.
This is the real strength of quantum annealing. Yes, I can perfectly derive the curve of passing through the filter from classical calculations. But to get a picture of what is really happening inside, you need more complex code. And in quantum annealing, this is completely free. In my opinion, this is very cool.
Another advantage of quantum annealing is that it guarantees a consistent solution within the framework of my choice of qubit bond weights. This means that the solution of a quantum computer is likely to be more reliable than the solution obtained from classical code.
Discussions about quantum programming
The hardest part about programming a D-Wave machine is that you need to think differently about tasks. For example, I got used to minimization problems when the curve coincides with the data. But I found it very difficult to change the way you think about a physical problem so that you start writing code to solve it. It does not help that most of the examples given by the company seem abstract and not adaptable to physical problems for me. But this situation will change when more and more users start publishing their code.
Also, difficulties may arise with the interpretation of the answer. Basically, I liked the simplicity of the API, and it's great to get additional ideas for free. In the near future, I could use D-Wave to solve real problems.