Function list:
jsqubits is a JavaScript library for quantum computation simulation. Try the online jsqubits runner. Alternatively, you can download and use the JavaScript jsqubits.js library from the jsqubits github repository. It is fully self contained: no third party libraries are required. You can use it to implement quantum algorithms using JavaScript like this:
jsqubits('|01>')
.hadamard(jsqubits.ALL)
.cnot(1, 0)
.hadamard(jsqubits.ALL)
.measure(1)
.result
If you are new to quantum programming, then it is highly recommended that you try reading John Watrous' Quantum Information and Computation Lecture Notes. You may also wish to try reading the partially finished Introduction to Quantum Programming using jsqubits.
QState is used to encapsulate the state of a quantum computer.
You create one by either calling its constructor or using the convenient jsqubits(bitString)
function.
The jsqubits function takes a string zeros and ones representing the state of its qubits. The string may optionally be a "ket" in the Dirac or "bra-ket" notation.
jsqubits("0101") | creates a 4 qubit QState in the simple basis state of | |0101> |
jsqubits("|0101>") | also creates a 4 qubit QState of | |0101> |
If you want your initial state to be in a super-position of states,
then you can use use a number of convenience methods.
QState.add()
can be used to add one quantum state to another in a super-position,
QState.normalize()
can be used to normalize the amplitudes to ensure that the square of their magnitudes sums to 1,
and QState.multiply()
can be used to multiply all a state's amplitudes by any complex number.
For example,
jsqubits('|00>')
.multiply(jsqubits.complex(1,1))
.add(jsqubits('|01>'))
.subtract(jsqubits('|10>'))
.normalize()
creates the QState (0.5+0.5i)|00> + (0.5)|01> + (-0.5)|10>
Another way to create an initial super-position of states is to use the QState constructor directly, passing it the number of qubits, and a (sparse) array of complex number amplitudes. For example
var a = []; a[0] = a[1] = a[4] = a[5] = jsqubits.complex(0.5, 0);
new jsqubits.QState(4, a)
creates the following 4 qubit QState:
(0.5)|0000> + (0.5)|0001> + (0.5)|0100> + (0.5)|0101>
WARNINGS:
A number of operators operate on a single qubit.
For these, you must specify the index of the bit to be operated on, with the right most bit being bit 0,
and the left most bit being bit n-1 for an n bit state.
As a convenience, you can also specify a range of bits using an object with "from" and "to" properties,
and the operator will be applied to each of the bits in that range (inclusive).
The constant jsqubits.ALL
can be used to apply the operator to all the bits.
For most operators (except where indicated), you may also use an array of bit indexes.
Here are some examples using the Pauli X operator.
jsqubits("|0000>").x(0) | gives | |0001> |
jsqubits("|0000>").x({from: 0, to: 2}) | gives | |0111> |
jsqubits("|0000>").x(jsqubits.ALL) | gives | |1111> |
jsqubits("|0000>").x([0,2]) | gives | |0101> |
All qubit manipulations return a new QState and leave the original one untouched. Consider the following code:
var state1 = jsqubits('|00>');
var state2 = state1.x(1);
"state2 is " + state2 + " but state1 is still " + state1
This results in "state2 is |10> but state1 is still |00>"
There are single bit operators for the Pauli operators X, Y, and Z. These can be invoked as x(), y(), z(), or as X(), Y(), or Z(). There is also a hadamard() function. There is a "not" function, which is just an alias for X.
jsqubits("|00>").x(0) | gives | |01> |
jsqubits("|01>").x(0) | gives | |00> |
jsqubits("|00>").y(0) | gives | (i)|01> |
jsqubits("|01>").y(0) | gives | (-i)|00> |
jsqubits("|00>").z(0) | gives | |00> |
jsqubits("|01>").z(0) | gives | (-1)|01> |
jsqubits("|00>").not(0) | gives | |01> |
jsqubits("|01>").not(0) | gives | |00> |
jsqubits("|00>").hadamard(0) | gives | (0.7071)|00> + (0.7071)|01> |
jsqubits("|01>").hadamard(0) | gives | (0.7071)|00> + (-0.7071)|01> |
The R operator is also known as the "phase shift" operator. It leaves the |0> state unchanged, but modifies the amplitude of the |1> state by eiθ, There are also the S and T operators (also known as the phase gate and π/8 gate respectively), which are equivalent to r(π/2) and r(π/4) respectively.
jsqubits("|00>").r(0, Math.PI/3) | gives | |00> |
jsqubits("|01>").r(0, Math.PI/3) | gives | (0.5+0.866i)|01> |
jsqubits("|00>").s(0) | gives | |00> |
jsqubits("|01>").s(0) | gives | (i)|01> |
jsqubits("|00>").t(0) | gives | |00> |
jsqubits("|01>").t(0) | gives | (0.7071+0.7071i)|01> |
Other single qubit operators are those that rotate around the X, Y, and Z axis of the Bloch sphere. These take an angle and apply the operation e-iθX/2, e-iθY/2 or e-iθZ/2.
jsqubits("|00>").rotateX(0, Math.PI/2) | gives | (0.7071)|00> + (-0.7071i)|01> |
jsqubits("|01>").rotateX(0, Math.PI/2) | gives | (-0.7071i)|00> + (0.7071)|01> |
jsqubits("|00>").rotateY(0, Math.PI/2) | gives | (0.7071)|00> + (0.7071)|01> |
jsqubits("|01>").rotateY(0, Math.PI/2) | gives | (-0.7071)|00> + (0.7071)|01> |
jsqubits("|00>").rotateZ(0, Math.PI/2) | gives | (0.7071-0.7071i)|00> |
jsqubits("|01>").rotateZ(0, Math.PI/2) | gives | (0.7071+0.7071i)|01> |
There are controlled versions of all the single qubit operators. For these you must specify control bits as well as target bits. As with the target bits, the control bits may be a single bit index, a range of bits using an object with "from" and "to" properties, or an array of bit indexes. The operation is only performed when all of the control bits are ones. Note that the control and target bits must not have any bits in common.
Here are some examples using the Pauli X operator.
jsqubits("|0000>").controlledX(2, 0) | leaves the state unchanged: | |0000> |
jsqubits("|0100>").controlledX(2, 0) | flips bit zero to give: | |0101> |
jsqubits("|0010>").controlledX([1,3], 0) | leaves the state unchanged: | |0010> |
jsqubits("|1010>").controlledX([1,3], 0) | flips bit zero to give: | |1011> |
jsqubits("|1010>").controlledX({from:1, to: 3}, 0) | leaves the state unchanged: | |1010> |
jsqubits("|1110>").controlledX({from:1, to: 3}, 0) | flips bit zero to give: | |1111> |
jsqubits("|1010>").controlledX([2,3], [0,1]) | leaves the state unchanged: | |1010> |
jsqubits("|1110>").controlledX([2,3], [0,1]) | flips bit zero and one give: | |1101> |
In addition to controlledX(), there are controlledY(), controlledZ(), controlledR(), controlledS(), controlledT(), and controlledHadamard() functions. The function cnot() is an alias for controlledX(). There are also controlledXRotation(), controlledYRotation(), and controlledZRotation() functions.
jsqubits("|010>").controlledXRotation(1, 0, Math.PI/2) | gives | (0.7071)|010> + (-0.7071i)|011> |
The swap and controlledSwap operators allow you to swap two qubits:
jsqubits("|1110>").swap(1, 0) | gives | |1101> |
jsqubits("|1110>").controlledSwap([2,3], 0, 1) | gives | |1101> |
The measurement operator is intended to simulate the act of measuring one or more of the qubits.
As usual, you may specify a single bit index,
a range of bits using an object with "from" and "to" properties,
an array of bit indexes,
or the constant jsqubits.ALL
.
As with all QState functions, the meaurement() function does not actually modify the object,
but instead returns a Measurement object with
a "newState" field containing the new quantum state (as a new QState object),
and a "result" field containing the integer value of the resulting measurement
(ie., the integer consisting of only the measured bits).
jsqubits("|0110>").measure(2) | gives | {result: 1, newState: |0110>} |
jsqubits("|0110>").measure({from:1, to: 3}) | gives | {result: 3, newState: |0110>} |
jsqubits("|0110>").measure(jsqubits.ALL) | gives | {result: 6, newState: |0110>} |
jsqubits("|00>").hadamard(0).measure(1) | gives | {result: 0, newState: (0.7071)|00> + (0.7071)|01>} |
jsqubits("|0110>").measure([1,3]) | gives | {result: 1, newState: |0110>} |
Measurement objects have a convenient asBitString()
method that returns the state of the measured qubits as a string of 0's and 1's.
So, for example, jsqubits("|0110>").measure({from:1, to: 3}).asBitString() will result in
the string 011.
The random number generator used during measurement is exposed as a function called "random" on instances of QState and hence may be over-ridden by replacing the prototype function or replacing it on individual objects. Here is how you can get measurements to always choose the first basis state with a non-zero amplitude:
jsqubits.QState.prototype.random = function() {return 0;};
jsqubits("|100>").hadamard([0,1]).measure(0)
always results in {result: 0, newState: (0.7071)|100> + (0.7071)|110>}
Given that the controlledX() operator can take multiple control bits, a separate Toffoli operator is redundant, but has been added for the sake of convenience. It takes one or more control bit indexes as separate arguments, followed by a target bit index (which actually can instead be a bit range or array).
jsqubits("|0001>").toffoli(0, 2, 3) | leaves the state unchanged: | |0001> |
jsqubits("|0101>").toffoli(0, 2, 3) | flips bit three to give: | |1101> |
The qft
method is a convenience method for computing the quantum fourier transform of a set of qubits.
It is implemented on top of other more primitive operators, such as the Hadarmard and phase shift.
jsqubits("|100>").qft([1,2]) will result in (0.5)|000> + (-0.5)|010> + (0.5)|100> + (-0.5)|110>.
The applyFunction
method takes
an input bit specification,
an output bit specification,
and a function to apply.
The input and output bit specifications must either be single bit indexes
or bit ranges using "from" and "to" properties.
Note that currently they cannot be arrays.
The value of the bits specified by the input bit index (or range)
is fed to the function, and the result is
applied to the output bit (or range).
For example,
jsqubits("|10110>")
.applyFunction(
{from:3, to:4},
{from:0, to:2},
function(x){return x+1;})
In the example, the function is passed the top two bits (ie, the value 2) and so it returns 3. This is to be applied to bits 0 to 2 and so the function's return value is treated as the bit string "011" and xor'ed with the bottom three bits to give: |10101>
The tensorProduct
method of QState returns the Kronecker (or tensor) product.
The kron
method is an alias of tensorProduct
.
For example, jsqubits("|0110>").tensorProduct(jsqubits("|01>")) will result in |011001>.
The amplitude
method can return the value of a specific amplitude.
Note that, while the QState values are displayed to four decimal places, they are maintained to
the maximum precision provided by the JavaScript implementation of floating point numbers,
with the exception that numbers very close to zero are rounded off to zero.
The value used for determining this rounding to zero is the variable jsqubits.roundToZero
.
Given that the amplitudes of a quantum state are complex numbers,
jsqubits has a Complex class. The easiest way to create a complex number is using
the method: jsqubits.complex(real, imaginary)
.
If the number has no imaginary component, then the jsqubits.real(value)
method is a convenient abbreviation of jsqubits.complex(value, 0)
.
jsqubits.complex(3, 4) | = | 3+4i |
jsqubits.real(3) | = | 3 |
jsqubits.complex(3, 4).add(jsqubits.complex(10, 20)) | = | 13+24i |
jsqubits.complex(3, 4).add(7) | = | 10+4i |
jsqubits.complex(3, 4).subtract(jsqubits.complex(10, 20)) | = | -7-16i |
jsqubits.complex(3, 4).subtract(7) | = | -4+4i |
jsqubits.complex(3, 4).multiply(jsqubits.complex(10, 20)) | = | -50+100i |
jsqubits.complex(3, 4).multiply(10) | = | 30+40i |
jsqubits.complex(3, 4).negate() | = | -3-4i |
jsqubits.complex(3, 4).magnitude() | = | 5 |
jsqubits.complex(1, 1).phase() | = | Math.PI/4 |
jsqubits.complex(1, -1).phase() | = | -Math.PI/4 |
jsqubits.complex(3, 4).conjugate() | = | 3-4i |
jsqubits.complex(-1.235959, 3.423523).format({decimalPlaces: 3}) | = | -1.236+3.424i |
jsqubits.ZERO | = | 0 |
jsqubits.ONE | = | 1 |
jsqubits User Manual by David Kemp is licensed under a Creative Commons Attribution 3.0 Unported License.