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:

 0 1 1 0
Pauli X gate

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

 0 1 1 0
×
 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⟩"```
• symbol
`String` One or two non-numeric characters used as a unique identifier among gates, and as a label in visual representations such as circuit diagrams. Will default to `"?"` if undefined at creation.
• symbolAmazonBraket
`String` Identifier to be used for this gate when exporting circuit data as Amazon Braket code. If not supplied to the constructor, `Gate` will define this value as `this.symbol.toLowerCase()`.
• symbolSvg
`String [optional]` A visual representation of this gate’s symbol in scalable vector graphic format.
• name
`String` The full name of this gate to be used as a title or long label in a visual representations, etc. Will default to `"Unknown"` if undefined at creation.
• nameCss
`String` Identifier to be used in constructing a Cascading Style Sheet class name as defined in `Q-Circuit-Editor.css`. Will default to `"unknown"` if undefined at creation.
• matrix
`Q.Matrix [optional]` The matrix representation of this gate operation’s logic, if one exists. (All true quantum gates will have a matrix representation, but some visualization operations—such as the creation of a Bloch sphere—will not.)
• applyToQubit
`Function` An action to be performed upon an input `Qubit` instance. If not supplied to the `Gate` constructor, `Gate` will create an operation that multiplies the input qubit by the gate instance’s `matrix`. If the gate instance’s `matrix` is undefined, `Gate` will create an operation that simply returns the input qubit untouched. While this is useful for inspection and debugging a single gate’s functionality, or building a visualization of a single qubit’s changing state, it has no practical use for circuit evaluation as it cannot represent the state of a multiple-qubit system, let alone entanglement.
• index
`Number` An auto-incrementing identification number assigned to the instance, used for minding the total number of instances created.

### Static properties

• index
`Number` The number of instances created so far.
• findBy
`Function( key: String, value: * ) ⇒ Q.Gate` Returns the first object within `Q.Gate.constants` to satisfy the constraint `object[ key ] === value`.
• findBySymbol
`Function( symbol: String ) ⇒ Q.Gate` Returns the result of calling the static method `findBy` with `"symbol"` as the `key` argument and `symbol` as the value argument.
• findByName
`Function( name: String ) ⇒ Q.Gate` Returns the result of calling the static method `findBy` with `"name"` as the `key` argument and `name` as the value argument.

#### Constants and constant creation

• constants
`Object` Constants are appended directly to the `Q.Gate` object. For convenience they are also appended to this `Q.Gate`.constants object to make looking up constants in the JavaScript console trivial, and to make iterating across all constants convenient via functions like `Object.entries`, `Object.keys`, `Object.values`, and so on. The intention that a property act as a constant is signaled by its labelling in all-uppercase.
• createConstant
`Function( key: String, value: * )` Appends a property named by `key` with a value of `value` to both the `Gate` object and its `constants` property.
• createConstants
`Function( … )` Expects an even number of arguments. Will use each pair in the sequence of arguments to call `createConstant`.

##### Gates of small consequence
• IDENTITY
`Q.Gate` An Identity gate has no effect on the value of the qubit it operates on; equivalent to multiplying a value by one. (Generally when a circuit is created from text or another source, any included identity gates are ignored. It is included here for completeness.)
``````
new Q.Gate({

symbol:  'I',
name:    'Identity',
nameCss: 'identity',
matrix:   Q.Matrix.IDENTITY_2X2
})
``````
Matrix representation as declared in `Q.Matrix.IDENTITY_2X2`:
 1 0 0 1
• CURSOR
`Q.Gate` Mathematically the “identity cursor” is equivalent to the `IDENTITY` gate, however it is used by the visual circuit editor as a placeholder when a user is building controlled gates or swap gates (which operate on multiple qubits) from individual components. This is a novel Q invention.
``````
new Q.Gate({

symbol:  '*',
name:    'Identity',
nameCss: 'identity',
matrix:   Q.Matrix.IDENTITY_2X2
})
``````
Matrix representation as declared in `Q.Matrix.IDENTITY_2X2`:
 1 0 0 1
##### Standard single-qubit gates
`Q.Gate` Applies a Hadamard transform to a single qubit. For the basis qubit states of 0 and 1 this has the effect of putting a qubit into superposition. It represents a rotation on the Bloch sphere around the Z-axis by π radians, followed by a rotation around the Y-axis by π÷2 radians.
``````
new Q.Gate({

symbol:  'H',
matrix:   Q.Matrix(

[ Math.SQRT1_2,  Math.SQRT1_2 ],
[ Math.SQRT1_2, -Math.SQRT1_2 ]
)
})
``````
Matrix representation:
 1 1 1 -1
×  1 √ 2
• PAULI_X
`Q.Gate` The Pauli X gate represents a rotation on the Bloch sphere around the X-axis by π radians. It is the quantum equivalent of the classical NOT gate in that it maps 0 to 1 and 1 to 0.
``````
new Q.Gate({

symbol:  'X',
name:    'Pauli X',
nameCss: 'pauli-x',
matrix:   Q.Matrix(

[ 0, 1 ],
[ 1, 0 ]
)
})
``````
Matrix representation:
 0 1 1 0
• PAULI_Y
`Q.Gate` The Pauli Y gate represents a rotation on the Bloch sphere around the Y-axis by π radians. It maps 0 to i1 and 1 to -i0.
``````
new Q.Gate({

symbol:  'Y',
name:    'Pauli Y',
nameCss: 'pauli-y',
matrix:   Q.Matrix(

[ 0, new Q.ComplexNumber( 0, -1 )],
[ new Q.ComplexNumber( 0, 1 ), 0 ]
)
})
``````
Matrix representation:
 0 -i i 0
• PAULI_Z
`Q.Gate` The Pauli Z gate represents a rotation on the Bloch sphere around the Z-axis by π radians. It is a special case of a Phase shift gate where ϕ = π, and is therefore sometimes referred to as a “phase-flip” gate. It leaves the basis state 0 unchanged and maps 1 to -1.
``````
new Q.Gate({

symbol:  'Z',
name:    'Pauli Z',
nameCss: 'pauli-z',
matrix:   Q.Matrix(

[ 1,  0 ],
[ 0, -1 ]
)
})
``````
Matrix representation:
 1 0 0 -1
• PHASE
`Q.Gate` Phase gates are a family of quantum gates that employ the variable ϕ (phi) to represent tracing a horizontal arc (a line of latitude) of ϕ radians around the Bloch sphere. They leave the basis state 0 unchanged and map 1 to eiϕ 1. The probability of measuring a 0 or 1 is unchanged after applying a phase shift, however it modifies the phase of the quantum state. This particular form used for our `PHASE` constant represents a rotation on the Bloch sphere around the Z-axis of π ÷ 2 radians.
``````
new Q.Gate({

symbol:  'P',
name:    'Phase',
nameCss: 'phase',
updateMatrix\$: function( phi ){

if( Q.isUsefulNumber( phi ) === true ) this.phi = phi
this.matrix = new Q.Matrix(
[ 1, 0 ],
[ 0, Q.ComplexNumber.E.power( new Q.ComplexNumber( 0, this.phi ))]
return this
},
applyToQubit: function( qubit, phi ){

if( Q.isUsefulNumber( phi ) !== true ) phi = this.phi
const matrix = new Q.Matrix(

[ 1, 0 ],
[ 0, Q.ComplexNumber.E.power( new Q.ComplexNumber( 0, phi ))]
)
return new Q.Qubit( matrix.multiply( qubit ))
}
})
``````
Note that there is no explicitly defined `matrix` property. It will be created upon instantiation when the constructor calls the argument object’s `updateMatrix\$` function. Matrix representation (when ϕ = 1):
 1 0 0 ei

Using varying values for ϕ is easy. We can clone this PHASE constant, provide it a new `symbol` (so it has a unique identifier), and a new value for ϕ. In this example we create a gate called `fox` with a ϕ value of π.
``````
var fox = Q.Gate.PHASE.clone({ symbol: 'F', phi: Math.PI })
``````
Our value of ϕ is now set equal to π and we can apply this gate to any qubit.
``````
fox.applyToQubit( Q.Qubit.DIAGONAL ).toTsv()```
"
0.707
-0.707"
```
But we can also send a temporary value for ϕ that will be used only during this function execution; it will not change `fox`’s set value of ϕ. Let’s try temporarily setting ϕ to π ÷ 4.
``````
fox.applyToQubit( Q.Qubit.DIAGONAL, Math.PI / 4 ).toTsv()```
"
0.707
0.5 + 0.5i"
```
Rather than begin our expression with a gate, we can instead begin with a qubit, and then apply our `fox` gate to it.
``````
Q.Qubit.DIAGONAL
.applyGate( fox )
.toTsv()```
"
0.707
-0.707"
```
But what’s more clever is that additional arguments will be passed directly to the gate’s `applyToQubit` method, so we can still use temporary values for ϕ.
``````
Q.Qubit.DIAGONAL
.applyGate( fox, Math.PI / 4 )
.toTsv()```
"
0.707
0.5 + 0.5i"
```
• PI_8
`Q.Gate` The π ÷ 8 gate is a special case of a Phase shift gate where the ϕ (phi) variable is set to π ÷ 4. (But why is it called “π ÷ 8” when it actually divides π by 4?) Like all phase shift gates, it represents a rotation on the Bloch sphere around the Z-axis.
``````
new Q.Gate({

symbol:  'T',
name:    'π ÷ 8',
nameCss: 't',
matrix:   Q.Matrix(

[ 1, 0 ],
[ 0, Q.ComplexNumber.E.power( new Q.ComplexNumber( 0, Math.PI / 4 )) ]
)
})
``````
Matrix representation:
 1 0 0 eiπ ÷ 4
##### Multi-qubit gates
• SWAP
`Q.Gate` The Swap gate swaps the value of two qubits. It is defined here with respect to the bases 00, 01, 10, and 11.
``````
new Q.Gate({

symbol:  'S',
name:    'Swap',
nameCss: 'swap',
matrix:   Q.Matrix(

[ 1, 0, 0, 0 ],
[ 0, 0, 1, 0 ],
[ 0, 1, 0, 0 ],
[ 0, 0, 0, 1 ])
)
})
``````
Matrix representation:
 1 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1
• SWAP1_2
`Q.Gate` The √Swap gate performs half of a swap between two qubits. It is not maximally entangling. More than one application of it is required to produce a Bell state from its product states. It is defined here with respect to the bases 00, 01, 10, and 11.
``````
new Q.Gate({

symbol:  '√',
name:    '√Swap',
nameCss: 'swap1-2',
matrix:   Q.Matrix(

[ 1, 0, 0, 0 ],
[ 0, new Q.ComplexNumber( 0.5,  0.5 ), new Q.ComplexNumber( 0.5, -0.5 ), 0 ],
[ 0, new Q.ComplexNumber( 0.5, -0.5 ), new Q.ComplexNumber( 0.5,  0.5 ), 0 ],
[ 0, 0, 0, 1 ])
)
})
``````
Matrix representation:
1 0 0 0
0  1 2
× (1 + i)
 1 2
× (1 - i)
0
0  1 2
× (1 - i)
 1 2
× (1 + i)
0
0001
##### 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

• clone
`Function ⇒ Q.Gate` Returns a new `Gate` instance with properties cloned from this instance.
• applyToQubits
`Function( Q.Qubit, … ) ⇒ Array` Calls the instance method `applyToQubit` for each supplied `Q.Qubit` argument and returns an Array of results. For example:
``````
Q.Gate.PAULI_X.applyToQubits(

Q.Qubit.HORIZONTAL,
Q.Qubit.VERTICAL,
…
)``````
The above will return:
```
[
Q.Qubit.VERTICAL,
Q.Qubit.HORIZONTAL,
…
]```
Or for even more fun with Arrays of qubits:
``````
Q.Gate.IDENTITY
.applyToQubits(

...Object.values( Q.Qubit.constants )
)
.map( Q.Qubit.toText )```
[
" 1↵0",          //  Horizontal
" 0↵1",          //  Vertical
" 0.707↵ 0.707", //  Diagonal
" 0.707↵-0.707", //  Anti-Diagonal
" 0.707↵-0.707i",//  Right-hand Circular Polarized
" 0.707↵ 0.707i" //  Left-hand Circular Polarized
]```
While this is useful for inspection and debugging a single gate’s functionality, or building a visualization of a single qubit’s changing state, it has no practical use for circuit evaluation as it cannot represent the state of a multiple-qubit system, let alone entanglement. Will not return a `Q.Gate` instance, and therefore halts “Fluent interface” method chaining along this prototype.
• set\$
`Function( key: String, value: * ) ⇒ Q.Gate` Sets a property on this instance with a key of `key` and a value of `value`, then returns the instance.