Before quantum computers existed, quantum algorithms were defined either mathematically, in terms of the transitions on quantum states, or using a graphical circuit notation for individual gates. Nowadays, quantum computers can be programmed using a GUI for the graphical notation, an assembly language-like text notation for the equivalent gates, or richer programming languages that may also provide low-level access.
The effects of the gates described earlier are similar to the logic gates we use to build a classical computer, like AND and OR. These days, few people bother designing their own programs for classical computers using those low-level gates. In fact, due to the fixed structure of a classical computer, it is hard to select which gates are used. Instead, we program computers using programming languages that humans can read, which are then turned into instructions for the computer, like ADD or MULTIPLY.
When we construct quantum algorithms, we will use gates. Each gate will operate on one, two or three qubits, and we will apply a sequence of gates to our register to form a complete circuit, an implementation of an algorithm. In most quantum computer implementations, the qubits are stationary, and gates are executed on the qubits where they sit, allowing us to treat them something like low-level computer instructions.
Each of the gates discussed back in Step 2.15 has a symbol, shown in the figure at the top of this article. Circuits are composed to run left to right, with a horizontal line for each qubit. The visual resemblance to music has lead IBM to referring to such a diagram as a “score”. IBM’s web-based interface uses drag-and-drop programming with colorful, stylized gate symbols.
This approach can show conditional operation, basing the choice to execute individual gates on the outcome of prior measurements. It is also common to draw circuits in terms of blocks of primitive gates. However, it is inherently difficult to create a loop or complex control structures.
A Simple “Assembly” Language
During my (Van Meter’s) Ph.D. thesis work, I developed a simple “assembly” language that lists gates by name, and the qubits on which they operate by a variable name, rather than a physical location. Other low-level languages might make similar choices, or might more directly specify the unitary transform and might identify qubits by physical location, but the goal and program structure will be similar. One unique feature of my language is that the programmer explicitly specifies which gates may be executed at the same time, denoted by the numeric labels. Other assembly languages depend on the compilation tools to determine this parallelism.
1: CCNOT A0 B0 C0 CCNOT A1 B1 C1 CCNOT A2 B2 C2 2: CNOT A1 B1 CNOT A2 B2 CNOT A3 B3 3: CCNOT C0 B1 C1 4: CCNOT C1 B2 C2
One modern tool is OpenQASM, developed by Andrew Cross and others at IBM.
The notion of quantum programming languages goes back to the earliest days of quantum computing research, but much of the early work was very abstract. Omer’s QCL was one of the first concrete, publicly available languages, and also provided a simple simulator.
Several years ago, the IARPA Quantum Computer Science program resulted in the development of several languages. Quipper (by a team from Dalhousie University, U. Penn, and IAS in Princeton) builds on the Haskell programming language. Scaffold (from a team including Princeton University) is a C-like language. QuaFL (from BBN) is a from-scratch functional language.
Microsoft is now on their second-generation language, known as Q# (Q-sharp).
More recently, efforts have turned toward simple library extensions for the popular programming language Python. QISKit and OpenQASM, for connecting to the IBM machines, looks like this:
# quantum circuit to make an entangled bell state bell = Q_program.create_circuit('bell', [qr], [cr]) # H (Hadamard) gate to qubit 0 in the Quantum Register "qr" bell.h(qr) # CNOT (Controlled-NOT) gate from qubit 0 to qubit 1 bell.cx(qr, qr)
Of course, quantum algorithms depend on a number of common building blocks, or subroutines. (Just to confuse things, quantum researchers occasionally call an entire block of gates a “gate”, also.) Some of these build on classical notions of simple circuits such as adders, or are quantum-specific routines such as the quantum Fourier transform (QFT).
The image below is a circuit for adding two eight-qubit registers together. This design, by Vedral, Barenco and Ekert, is based on a classical form of circuit known as a ripple-carry adder, a binary form of the right-to-left method you learned as a child. Extra qubits are used to hold partial, temporary results. The “V” shape comes from the need to disentangle those temporary qubits from the important data qubits, and the severe restriction that the entire block must be unitary, or reversible.
We can expect that such low-level routines will be provided as libraries of functions in programming toolkits, allowing us to compose our own algorithms at a high level of abstraction.
© Keio University