Source code: Q-Gate.js


Gates to walk through

A quantum computer is just a collection of qubits. These qubits hold values like 1, 0, or some value inbetween. A quantum computer is able to calculate things by changing the value of its qubits over time. We tell the computer exactly how it should change the value of a qubit by instructing it to “walk through” a series of quantum gates. As the qubit “walks through” each gate its value is changed based on the type of gate it is passing through.

Contrary to what pop-science might tell you, there is nothing random or unpredictable about this process. Mathematically, a qubit is just a matrix. Similarly, a quantum gate is also just a matrix. To apply a gate to a qubit is to multiply these matrices together. To demonstrate this, let’s begin with a “Horizontal” qubit—commonly thought of as representing “off.” It has the following matrix form:

1
0
Horizontal qubit

We would like to flip the value of this qubit from “off” to “on.” The result will be a “Vertical” qubit with the following matrix form:

0
1
Vertical qubit

In order to achieve this we must apply a Pauli X gate to our Horizontal qubit. Pauli X gates have the effect of “flipping” the value of a qubit. They are often thought of as the quantum equivalent of a classical NOT gate. Pauli X gates have the following matrix form:

01
10
Pauli X gate

We can now apply the Pauli X gate to the Horizontal qubit by multiplying their matrices together.

01
10
×
1
0
=
0
1

As anticipated, the resulting product matrix represents a Vertical qubit. (Warm fuzzies all around.)

Note how the gate’s matrix is the first factor and the qubit’s matrix is the second factor. The order matters because matrix multiplication is not commutative. With plain numbers the order of the factors does not change the product outcome. a × b = b × a. But with matrices the order does matter. [ a ] × [ b ] ≠ [ b ] × [ a ]. See matrix multiplication for an in-depth explanation.

Applying gates with code

Let’s look at three different ways to apply a gate to a qubit using Q’s API. In this first example we will access our gate’s matrix directly and multiply it against our qubit—which is itself a matrix. (Q.Qubit extends Q.Matrix and thereby inherits Q.Matrix’s methods. Meanwhile, Q.Gate does not extend Q.Matrix, as it is sometimes desirable to create gates without matrices. See Gates without matrices below for more details.)


Q.Gate.PAULI_X
	.matrix
	.multiply( Q.Qubit.HORIZONTAL )
	.isEqualTo( Q.Qubit.VERTICAL )
true

Rather than access our gate’s matrix directly, we can instead call the instance method applyToQubit.


Q.Gate.PAULI_X
	.applyToQubit( Q.Qubit.HORIZONTAL )
	.isEqualTo( Q.Qubit.VERTICAL )
true

We can also begin with the qubit rather than the gate.


Q.Qubit.HORIZONTAL
	.applyGate( Q.Gate.PAULI_X )
	.isEqualTo( Q.Qubit.VERTICAL )
true

Gates without matrices

In quantum computing theory a quantum gate is a matrix. But Q expands this notion of a “gate” to the more abstract notion of an “operation”—any function that is performed upon a qubit. This allows us to build custom “gates” that perform data visualizations, trigger interface changes, and so on.

The punchline

While applying gates to qubits in the above fashion is useful for some debugging and for building single-qubit state visualizations, it has no practical use for full circuit evaluation as it cannot represent the state of a multiple-qubit system, let alone quantum entanglement. For that we will need a proper Circuit class for simulating multi-qubit states.


Constructor

Gate Function( params: Object ) => Q.Gate
Expects a single object whose properties will be applied directly to this gate instance. No particular properties are required and even the object argument itself is optional. The properties not listed as “optional” below are ones that will be assigned defaults upon instantiation by the constructor. Any remaining properties listed below would be undefined unless supplied as arguments.

Here we will create a “gup” gate that borrows its matrix property from the pre-existing PAULI_X gate constant. This will enable our custom gate to flip qubits from a horizontal state, ie. “off” or 0, to a vertical state, ie. “on” or 1, and back again—just like a PAULI_X gate.


var gup = new Q.Gate({

	symbol:  'G',
	name:    'Gup',
	nameCss: 'gup',
	matrix:   Q.Gate.PAULI_X.matrix
})

We can now test that our new gup gate flips qubit states between 0 and 1.


//  Verify a “Horizontal” qubit has a value of |0⟩
//  and a “Vertical” qubit has a value of |1⟩.

Q.Qubit.HORIZONTAL.toStateVectorText()
"|0⟩"

Q.Qubit.VERTICAL.toStateVectorText()
"|1⟩"


//  Now flip a “Horizontal” |0⟩ to a “Vertical” |1⟩
//  and flip a “Vertical” |1⟩ to a “Horizontal” |0⟩.

gup.applyToQubit( Q.Qubit.HORIZONTAL )
	.toStateVectorText()
"|1⟩"

gup.applyToQubit( Q.Qubit.VERTICAL )
	.toStateVectorText()
"|0⟩"

We can similarly use a qubit’s applyGate method which internally calls a gate’s applyToQubit method:


Q.Qubit.HORIZONTAL      //  Value begins at |0⟩.
	.applyGate( gup )   //  Value is now |1⟩.
	.toStateVectorText()//  Output that as text.
"|1⟩"

Q.Qubit.VERTICAL        //  Value begins at |1⟩.
	.applyGate( gup )   //  Value is now |0⟩.
	.toStateVectorText()//  Output that as text.
"|0⟩"

We can also do this in one go:


Q.Qubit.HORIZONTAL      //  Value begins at |0⟩.
	.applyGate( gup )   //  Value is now |1⟩.
	.applyGate( gup )   //  Value is back to |0⟩.
	.toStateVectorText()//  Output that as text.
"|0⟩"

Static properties

Constants and constant creation


Gates of small consequence
Standard single-qubit gates
Multi-qubit gates
Implicit gates

Q.Circuit supports several multi-qubit gates implictly through composition, rather than explicitly with Gate constants. For example, Q does not explictly define a Controlled-Not (CNOT) gate, Controlled Swap (Fredkin) gate, Toffolli (CCNOT) gate, and so on because they are all easily composed by adding a control matrix to any existing gate matrix.


Prototype properties