Writing a simple energy program to run on the quantum hardware
Contents
Section 1
Section 2
Aim, audience and required background
The aim of this document is to demonstrate how programming quantum computers is different from programming conventional machines, and introduce the reader to the idea of crafting an energy program.
This material was developed to help software developers interested in learning how to program D-Wave quantum computing systems to get started. Our goal is to introduce you to quantum computer programming using a practical, tutorial based approach. This tutorial covers the basics of understanding how to go from a simple real world problem to an energy program that can be solved using D-Wave's quantum computer. All of the software necessary for developers to begin learning how to program D-Wave quantum computing systems can be downloaded from the DOWNLOAD DEVKITS page. As the developer portal is currently in BETA test stage, you will need to have a D-Wave developer account to download these packs. To follow this tutorial it may be helpful to have read the two previous installments: Quantum Computing and Energy Programming Primer and Getting Started: Installing the D-Wave developer pack and an introductory 'hello multiverse' tutorial. This document will assume through reading these previous tutorials that the reader has the developer pack installed, is familiar with the concept of an energy program and can send a problem to the quantum hardware. The high level programming language used in the examples here and the source code is written in Python 2.6. Experience of using the Python programming language is helpful but not required.
What you will learn
By following through the material in this primer, you will learn:
Software requirements
n order to proceed you should install several free software packages.
SECTION 1
Setting up the energy function
1.1 - Introduction
Energy programming is radically different from other programming conventions. However, the essence of why you would want to energy program something is the same. There is a real world problem that you are interested in solving, and it is more easily solvable by using computing power to help you along the way. In this example, we will pick a real world problem which is very simple but can reveal a lot of complexity and deep insights into energy programming, and into computation in general. The example that we will program will involve simulating a small, basic logic block known as a NAND gate.
Figure 1. The 2-input NAND gate circuit diagram and its truth table. The True, False convention used
here will be mapped onto qubit state values later in the tutorial.
1.2 - The logical NAND gate
A depiction of the NAND gate is shown in figure 1 on the left. The truth table associated with the gate is shown on the right. The NAND produces a False output if and only if both inputs are True. Conventionally, truth tables are drawn with 0 and 1 representing the False and True states respectively. Here we will avoid that convention and just use F and T, as later on we will map the -1 and +1 convention of the quantum hardware machine language to the gate.
Figure 2. The 2-input NAND gate written as an energy function.
Allowed combinations of A, B, and C correspond to the lowest energies found
when the function is evaluated. To evaluate the function, use the values T=1 and F=-1.
1.3 - Energy NAND gate
Imagine that we were asked to forget about the NAND gate for a moment and write out all the possible combinations of T and F values for the variables A, B and C, even if they did not conform to the NAND table above. This list is shown in the first 3 columns of figure 2. We can see that rows belonging to the NAND gate are encapsulated in this table, and have been highlighted in color. So to start thinking in terms of energy programming, what we need to do is craft an energy function that somehow 'captures' the behaviour of the A, B and C variables involved in the gate's functioning. Here the answer is given - it is shown in the top of the rightmost column of figure 2 - but normally it is also the job of the energy programmer to craft that function themselves. The numbers in the righthand column show the result of evaluating this energy function for each combination of A, B and C variables. In this example, the variables are considered to be F=-1 and T=+1. The reason that this convention is used rather than the more familiar 0 and 1 is that the machine language of the quantum hardware uses +1's and -1's to represent the individual bit states. This is known as the ISING notation. So if you want to check that the energy function does indeed produce the output in the righthand column, remember to use +1 and -1! Later on we'll find out how to send things to the hardware in terms of 0's and 1's (QUBO notation) too, but for now we will stick with the ISING convention. We can see that this energy function gives us low values when the combinations of A, B and C corespond to an allowed state of the NAND gate. We have crafted an function whose minima capture the essence of the NAND gate. Quantum hardware is designed to find the minimum of things, so all we need to do now is to figure out how to map this energy function onto the quantum hardware.
1.4 - Mapping the energy function to hardware
We start by noting that there are 3 variables, A, B and C in the problem, so we need to map these variables onto qubits in the processor hardware. We can also see that in the energy function there are product terms such as AB, AC and BC. These product terms tell us how to program the elements that connect the qubits together. Mapping the energy function to an energy program is straightforward in this example. Figure 3 again shows the energy function, and this time the co-efficients of the terms have been highlighted in green and pink. The pink terms apply to qubits and the green terms apply to connectors, and this set of numbers together forms the complete energy program to be sent to the quantum hardware. The diagram in the right part of Figure 3 shows these numbers applied to a group of 3 qubits and connectors. Note that the values have all been scaled by a factor of 0.1. The remainder of this section will explain why.
Figure 3.The energy function with the co-efficients highlighted and mapped
onto the qubit and connector variables. The values are all scaled by a factor of
0.1 when applied to the qubits.
1.5 - Embedding the variables
Readers familiar with the 'Hello Multiverse' tutorial will remember that the block of qubits used formed a square. In this NAND example, we require the qubits to be connected in a triangle. This is not possible to do directly using the quantum hardware, as there are no explicit connections on-chip that form triangles in this way. It is however, possible to make a triangle from a square by joining together two of the corners. Figure 4 shows how we do this in the NAND example. We lock together two of the qubits by making the value on the connector between them much stronger than the other values in the problem. This causes the two qubits to 'follow' each other and effectively act as a single variable. In this example, we have chosen to lock together qubits 52 and 49 to encode the single variable B. Placing a logical variable over a series of physical qubits in this way is a process known as embedding.
Figure 4. Using an additional variable to obtain the connectivity needed to
map a triangle of qubits into the hardware. The connection between qubits 52 and 49 is set
to be much stronger than all other qubit and connector values in the problem.
Figuring out whether or not different shapes or groups are 'allowed' in the hardware and finding ways to embed them is out of the scope of this tutorial, but there are functions in the developer pack that one can use to find this information in order to code more complex energy programs.
Code Snippet 1: NAND gate implementation
# Import D-Wave's Python API
from dwave_sapi import local_connection
solver = local_connection.get_solver('c4-sw_sample')
#define the problem
h = [0]*128
J = dict()
h[48] = -0.1
h[49] = -0.1
h[53] = -0.2
J[(48,53)] = 0.2
J[(48,52)] = 0.1
J[(49,52)] = -1
J[(49,53)] = 0.2
#send the problem to hardware
answer = solver.solve_ising(h,J,num_reads = 100)['solutions'][0]
print '48 = ', answer[48]
print '49 = ', answer[49]
print '52 = ', answer[52]
print '53 = ', answer[53]
SECTION 2
Implementing the energy function
2.1 - Running the program
Now that we have assigned valuesd to each of our qubits and the connectors between them in a way that is compatible with the quantum hardware, we can code the problem. Code snippet 1 shows the Python code that is sent to the hardware to write the energy program, and return an answer. Readers who have downloaded the D-Wave developer pack are encouraged to now try out this example code. The first 14 lines of code set up the connection to the hardware and define the energy program. The last 6 lines of code grab the answer from the hardware and allow us to inspect the result.
Figure 5. Left: The output of the code snippet above. Right: The corresponding answer
from the energy NAND table, showing that the energy program is working correctly.
Figure 5 shows the answer returned when this Python code is run. Qubit 48 (variable A) returns F, qubit 52/49 (the joint variable B) returns T, and qubit 53 (variable C) returns T. As we see from the table on the right, the calculation has returned FTT, which is a valid state of the NAND gate. Attentive readers may have noticed that in figure 5 there is only one solution returned from the hardware (qubits encode the answer 'FTT'). To encode the full NAND gate however, there are 4 valid answers. Looking at the code snippet, we see that in the line that returns the answer, we pick ['solutions'][0]. There are actually more solutions, we just returned the first one. In order to see the other solutions, we can look at other elements of this array, such as ['solutions'][1]. The solutions in the array are ordered in terms of their energy, so the first 4 elements of the array should all have the same energy, and it should be the lowest. A good exercise for the reader at this point is to modify the code to print out all 4 solutions which correspons to the correct operation of the NAND gate. It might also be useful to print out elements of the solutions array that occur at positions [5], [6], etc. These should correspond to solutions that are not allowed. In order to see the energy of a solution, one can use the following code:
answer = solver.solve_ising(h,J,num_reads = 100)['energies'][0]
2.2 - Why a NAND gate?
At this point you may be wondering why a NAND gate was chosen for this tutorial. Simulating a NAND gate doesn't seem like a very useful thing to do - after all, we already have NAND gates that work quite well. But there are two important points that this tutorial demonstrates about quantum computing. The first is that given that NAND gates can be used to build ANY conventional digital logic circuit, the quantum computer can actually be used to simualate conventional computers. This means that with a quantum computer we can build any conventional computer given enough qubits. The second point is a little more subtle. Looking back at the table in figure 5 we see that in the energy NAND gate formulation, there is now no notion of 'inputs' and 'outputs' - they simply become variables A, B and C. The quantum computer doesn't care whether your variables are inputs or outputs anymore, they are just numbers in an energy function. What does this mean' If inputs and outputs are treated equally, it means that you can run the computation in reverse. This is a surprising fact - you cannot do this with the NAND gates in conventional computers, as they simply won't work. Reversible computing is a very interesting discipline. Computer hardware that can be made reversible or near-reversible does not consume as much energy as our conventional digital logic and is therefore much more efficient.
2.3 - Coding at a higher level
Although the NAND gate is interesting in itself, it really only serves as an introduction to energy programming. Setting the energy program in this way is the equivalent of writing machine code for your desktop computer, which is not feasible for a complex application. To solve real world problems, you need to be able to energy program at a much higher level than this. D-Wave have toolkits and libraries that have been built on top of this basic developer pack framework which enable you to start experimenting with this programming paradigm. These libraries, along with the complex applicaitons that they enable, will be described in subsequent tutorials.