A very silly simple quantum computing circuit simulator.
(the implementation could be wrong though)
By Yiyi Wang
const {QuantumComputing} = require('qubit.js')const qc = new QuantumComputing()qc.boot(3) // simulate 3 qubits.x(0) // apply Pauli X Gate (Not Gate) to qubit[0].measure() // measure allconsole.log(qc.toQASM()) // convert to QASM codeconsole.log(qc.getResult()) // print probabilities

8 possible quantum states
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
8 possible quantum states
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
qc.boot(3)// =>amplitudes = [1, 0, 0, 0, 0, 0, 0, 0]
It is a $unary\ quantum\ gate$
matrix:
$$X = \begin{bmatrix} 0 & 1 \\ 1 & 0\end{bmatrix}$$
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
qc.boot(2).x(0)amplitudes = [1, 0, 0, 0, 0, 0, 0, 0]// =>// what should the amplitudes be ?
We are applying the matrix to a single qubit q[0]...
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
So we found all possible pairs.
$\alpha|0\rangle + \beta|1\rangle$
$|00\color{red}{0}\rangle$ and $|00\color{red}{1}\rangle$
$|01\color{red}{0}\rangle$ and $|01\color{red}{1}\rangle$
$|10\color{red}{0}\rangle$ and $|10\color{red}{1}\rangle$
$|11\color{red}{0}\rangle$ and $|11\color{red}{1}\rangle$
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
For the pair:
$|00\color{red}{0}\rangle$ and $|00\color{red}{1}\rangle$
We have amplitudes $\alpha = 1$ and $\beta = 0$
Therefore
$$\begin{bmatrix}\alpha' \\ \beta' \end{bmatrix}= X\begin{bmatrix}\alpha \\\beta\end{bmatrix}= \begin{bmatrix}0 & 1 \\1 & 0\end{bmatrix}\begin{bmatrix} 1 \\ 0 \end{bmatrix} =\begin{bmatrix} 0 \\ 1 \end{bmatrix}$$
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
qc.boot(2).x(0)amplitudes = [1, 0, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 1, 0, 0, 0, 0, 0, 0]
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
qc.boot(2).x(0).measure() // one qubit register to one classic registeramplitudes = [1, 0, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 1, 0, 0, 0, 0, 0, 0]
$\because probability\ =\ amplitude ^ 2$
$\therefore p(|001\rangle) = 1^2 = 1$

qc.boot(3) // simulate 3 qubits.x(0) // apply Pauli X Gate (Not Gate) to qubit[0].cnot(0, 1) // apply Controlled Not (CNot Gate)// q[0] is control, q[1] is target..measure()

| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
qc.boot(2).x(0).cnot(0, 1) // q[0] is control, q[1] is targetamplitudes = [1, 0, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 1, 0, 0, 0, 0, 0, 0]// =>// what should the amplitudes be ?
it is a Binary Quantum Gate that operates on two qubits
$$CNOT = \begin{bmatrix}1 & 0 & 0 & 0 \\0 & 1 & 0 & 0 \\0 & 0 & 0 & 1 \\0 & 0 & 1 & 0\end{bmatrix}$$
transforms the quantum state: ($|control, target \rangle$)
$a|00\rangle + b|01\rangle + c|10\rangle + d|11\rangle$
into:
$a|00\rangle + b|01\rangle + c|11\rangle + d|10\rangle$
We are applying the matrix to a two qubits (control) q[0] and (target) q[1]...
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
$|control, target \rangle$
$a|00\rangle + b|01\rangle + c|10\rangle + d|11\rangle$
So we found all possible pairs
$|0\color{red}{00}\rangle$ and $|0\color{red}{01}\rangle$ and $|0\color{red}{10}\rangle$ and $|0\color{red}{11}\rangle$
$|1\color{red}{00}\rangle$ and $|1\color{red}{01}\rangle$ and $|1\color{red}{10}\rangle$ and $|1\color{red}{11}\rangle$
For the pair:
$|0\color{red}{00}\rangle$ and $|0\color{red}{01}\rangle$ and $|0\color{red}{10}\rangle$ and $|0\color{red}{11}\rangle$
$\because |control, target \rangle$ and $q[0]$ is control, $q[1]$ is target.
$\therefore a|0\color{red}{00}\rangle + b|0\color{red}{10}\rangle + c|0\color{red}{01}\rangle + d|0\color{red}{11}\rangle$
We have $a = 0$, $b = 0$, $c = 1$, $d = 0$ $$\therefore\begin{bmatrix}a' \\ b' \\ c' \\ d'\end{bmatrix} = CNOT \begin{bmatrix} a \\ b \\ c \\ d \end{bmatrix} =\begin{bmatrix}1 & 0 & 0 & 0 \\0 & 1 & 0 & 0 \\0 & 0 & 0 & 1 \\0 & 0 & 1 & 0\end{bmatrix}\begin{bmatrix}0\\0\\1\\0\end{bmatrix} =\begin{bmatrix} 0 \\ 0 \\ 0 \\ 1 \end{bmatrix}$$
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
qc.boot(2).x(0).cnot(0, 1) // q[0] is control, q[1] is targetamplitudes = [1, 0, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 1, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 0, 0, 1, 0, 0, 0, 0]
| q[2]q[1]q[0] | 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 |
|---|---|---|---|---|---|---|---|---|
| amplitude | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
qc.boot(2).x(0).measure() // one qubit register to one classic registeramplitudes = [1, 0, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 1, 0, 0, 0, 0, 0, 0]// =>amplitudes = [0, 0, 0, 1, 0, 0, 0, 0]
$\because probability\ =\ amplitude ^ 2$
$\therefore p(|011\rangle) = 1^2 = 1$

I implemented two helper functions for applying matrix.
applySingleBitMatrix(offset, matrix)
apply unary quantum gate
applyTwoBitsMatrix(control, target, matrix)
apply binary quantum gate
For example, Hadamard Gate:
$$H = \begin{bmatrix} 1/\sqrt{2} & 1/\sqrt{2} \\ 1/\sqrt{2} & -1/\sqrt{2} \end{bmatrix}$$
qc.h(0)// is the same asconst t = 1 / Math.sqrt(2)qc.applySingleBitMatrix(0, [[t, t], [t, -t]])
For more information about this project, check the qubit.js github repo:
https://github.com/shd101wyy/qubit.js