This notebook gives some examples of how to use Qubiter to write and simulate a quantum circuit that does quantum phase estimation (qPE).
Even though qPE was invented by Kitaev, it can be understood (See IBM Quantum Experience Tutorial for the details) as a quantum computer version of a much earlier model, namely, the von Neumann Pointer-System model for a quantum mechanical measurement.
In the case of quantum computers, the Pointer in von Neumann's model is represented by several "pointer qubits" and the System by several "system qubits". The matrix U whose eigenvalues we wish to find acts on the System qubits.
In Qubiter, we call the "pointer qubits" the "probes", and the qbits that U acts on the "atom qbits". We call U the "atom matrix". $\newcommand{\bra}[1]{\left\langle{#1}\right|}$ $\newcommand{\ket}[1]{\left|{#1}\right\rangle}$
First change your working directory to the qubiter directory in your computer, and add its path to the path environment variable.
import os
import sys
print(os.getcwd())
os.chdir('../../')
print(os.getcwd())
sys.path.insert(0,os.getcwd())
/home/rrtucci/PycharmProjects/qubiter/qubiter/jupyter_notebooks /home/rrtucci/PycharmProjects/qubiter
from qubiter.SEO_writer import *
from qubiter.SEO_simulator import *
from qubiter.StateVec import *
from qubiter.adv_applications.PhaseEstSEO_writer import PhaseEstSEO_writer
from qubiter.adv_applications.PhaseEstSEO_writer import AtomWriter
import numpy as np
loaded OneQubitGate, WITHOUT autograd.numpy
In this example, 2 qbits are used
probe qubits = {0},
atom qubits = {1}
The atom matrix is the X Pauli matrix, $U = \sigma_X$
Eigenvectors of U are
$H\ket{0} = \frac{1}{\sqrt{2}}(\ket{0} + \ket{1})$ for +1
$H\ket{1} = \frac{1}{\sqrt{2}}(\ket{0} - \ket{1})$ for -1
where $H = \frac{1}{\sqrt{2}}\left[ \begin{array}{cc} 1 & 1\\ 1 & -1 \end{array}\right ]$ is the Hadamard matrix
Open a writer, tell it where to write to. We will use zero bit last (ZL) convention.
num_qbits = 2
emb = CktEmbedder(num_qbits, num_qbits)
file_prefix = 'ph_est_nb_a'
wr = SEO_writer(file_prefix, emb)
Next write the whole circuit
wr.write_one_qbit_gate(1, OneQubitGate.had2)
wr.write_one_qbit_gate(0, OneQubitGate.had2)
control_pos = 0
target_pos = 1
trols = Controls.new_single_trol(num_qbits, control_pos, kind=True)
wr.write_controlled_one_qbit_gate(
target_pos, trols, OneQubitGate.sigx)
wr.write_one_qbit_gate(0, OneQubitGate.had2)
Close English and Picture files
wr.close_files()
Look in files
to see the quantum circuit that was generated
Print the Picture file
wr.print_pic_file(jup=True)
1 | H | | 2 | | H | 3 | X---@ | 4 | | H |
Specify initial state vector for simulation.
init_st_vec = StateVec.get_standard_basis_st_vec([0, 0])
Open a simulator. This automatically multiplies quantum circuit in given file.
sim = SEO_simulator(file_prefix, num_qbits, init_st_vec)
Print description of final state vector
StateVec.describe_st_vec_dict(sim.cur_st_vec_dict,
print_st_vec=True, do_pp=True, omit_zero_amps=True, show_pp_probs=True)
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (00)ZL ( 0.707107 + 0.000000j) prob=0.500000 (10)ZL ( 0.707107 + 0.000000j) prob=0.500000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (1.0, 0.0), 1: (0.5, 0.5)}
In this example, num_qbits are used
probe qubits = {0, 1, 2, ..., num_qbits-2}
atom qubits = {num_qbits-1}
The atom matrix is a Z axis rotation, $U = e^{i*rads*\sigma_Z}$, for some Real number $rads$
Eigenvectors of U are same as those for $\sigma_Z$, $\ket{0}$ and $\ket{1}$
An object of the AtomWriter2 class will be called by the writer of the full qPE circuit to write the powers of the atom matrix.
class AtomWriter2(AtomWriter):
def __init__(self, do_write, rads, **kwargs):
self.rads = rads
AtomWriter.__init__(self, do_write, **kwargs)
def write_pow(self, power):
z_axis = 3
self.write_one_qbit_gate(0, OneQubitGate.rot_ax, [power*self.rads, z_axis])
def write_pow_hermitian(self, power):
z_axis = 3
self.write_one_qbit_gate(0, OneQubitGate.rot_ax, [-power*self.rads, z_axis])
for num_qbits in range(2, 9):
print('-----------------Number of bits=', num_qbits)
rads = 2*np.pi/16
atom_wr = AtomWriter2(rads=rads, do_write=False)
file_prefix = 'ph_est_nb_b'
emb = CktEmbedder(num_qbits, num_qbits)
wr = PhaseEstSEO_writer(do_write=True,
num_probe_bits=num_qbits - 1,
atom_writer=atom_wr,
file_prefix=file_prefix,
emb=emb)
wr.close_files()
wr.print_pic_file(jup=True)
init_st_vec = StateVec.get_standard_basis_st_vec([0]*num_qbits)
sim = SEO_simulator(file_prefix, num_qbits, init_st_vec)
StateVec.describe_st_vec_dict(sim.cur_st_vec_dict,
print_st_vec=True, do_pp=True, omit_zero_amps=True, show_pp_probs=True)
print('spike_bit prediction=', num_qbits - 1 + np.log2(rads/(2*np.pi)))
-----------------Number of bits= 2
1 | | H | 2 | Rz--@ | 3 | | H |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (00)ZL ( 0.961940 + 0.191342j) prob=0.961940 (01)ZL ( 0.038060 - 0.191342j) prob=0.038060 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.96194, 0.03806), 1: (1.0, 0.0)} spike_bit prediction= -3.0 -----------------Number of bits= 3
1 | | | H | 2 | | H | | 3 | Rz--+---@ | 4 | Rz--@ | | 5 | | H | | 6 | | @P--@ | 7 | | | H | 8 | | <---> |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (000)ZL ( 0.753417 + 0.503417j) prob=0.821067 (010)ZL ( 0.100136 - 0.149864j) prob=0.032486 (001)ZL (-0.062076 - 0.312076j) prob=0.101245 (011)ZL ( 0.208522 - 0.041478j) prob=0.045202 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.853553, 0.146447), 1: (0.922312, 0.077688), 2: (1.0, 0.0)} spike_bit prediction= -2.0 -----------------Number of bits= 4
1 | | | | H | 2 | | | H | | 3 | | H | | | 4 | Rz--+---+---@ | 5 | Rz--+---@ | | 6 | Rz--@ | | | 7 | | H | | | 8 | | @P--@ | | 9 | | | H | | 10 | | @P--+---@ | 11 | | | @P--@ | 12 | | | | H | 13 | | | <---> | 14 | | <---+---> | 15 | | <---> | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (0000)ZL ( 0.125000 + 0.628417j) prob=0.410533 (0100)ZL ( 0.125000 - 0.024864j) prob=0.016243 (0010)ZL ( 0.125000 - 0.187076j) prob=0.050622 (0110)ZL ( 0.125000 + 0.083522j) prob=0.022601 (0001)ZL ( 0.125000 - 0.628417j) prob=0.410533 (0101)ZL ( 0.125000 + 0.024864j) prob=0.016243 (0011)ZL ( 0.125000 - 0.083522j) prob=0.022601 (0111)ZL ( 0.125000 + 0.187076j) prob=0.050622 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.5, 0.5), 1: (0.853553, 0.146447), 2: (0.89429, 0.10571), 3: (1.0, 0.0)} spike_bit prediction= -1.0 -----------------Number of bits= 5
1 | | | | | H | 2 | | | | H | | 3 | | | H | | | 4 | | H | | | | 5 | Rz--+---+---+---@ | 6 | Rz--+---+---@ | | 7 | Rz--+---@ | | | 8 | Rz--@ | | | | 9 | | H | | | | 10 | | @P--@ | | | 11 | | | H | | | 12 | | @P--+---@ | | 13 | | | @P--@ | | 14 | | | | H | | 15 | | @P--+---+---@ | 16 | | | @P--+---@ | 17 | | | | @P--@ | 18 | | | | | H | 19 | | | | <---> | 20 | | | <---+---> | 21 | | | <---> | | 22 | | <---+---+---> | 23 | | <---+---> | | 24 | | <---> | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (00001)ZL ( 1.000000 - 0.000000j) prob=1.000000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.0, 1.0), 1: (1.0, 0.0), 2: (1.0, 0.0), 3: (1.0, 0.0), 4: (1.0, 0.0)} spike_bit prediction= 0.0 -----------------Number of bits= 6
1 | | | | | | H | 2 | | | | | H | | 3 | | | | H | | | 4 | | | H | | | | 5 | | H | | | | | 6 | Rz--+---+---+---+---@ | 7 | Rz--+---+---+---@ | | 8 | Rz--+---+---@ | | | 9 | Rz--+---@ | | | | 10 | Rz--@ | | | | | 11 | | H | | | | | 12 | | @P--@ | | | | 13 | | | H | | | | 14 | | @P--+---@ | | | 15 | | | @P--@ | | | 16 | | | | H | | | 17 | | @P--+---+---@ | | 18 | | | @P--+---@ | | 19 | | | | @P--@ | | 20 | | | | | H | | 21 | | @P--+---+---+---@ | 22 | | | @P--+---+---@ | 23 | | | | @P--+---@ | 24 | | | | | @P--@ | 25 | | | | | | H | 26 | | | | | <---> | 27 | | | | <---+---> | 28 | | | | <---> | | 29 | | | <---+---+---> | 30 | | | <---+---> | | 31 | | | <---> | | | 32 | | <---+---+---+---> | 33 | | <---+---+---> | | 34 | | <---+---> | | | 35 | | <---> | | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (000010)ZL ( 1.000000 - 0.000000j) prob=1.000000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (1.0, 0.0), 1: (0.0, 1.0), 2: (1.0, 0.0), 3: (1.0, 0.0), 4: (1.0, 0.0), 5: (1.0, 0.0)} spike_bit prediction= 1.0 -----------------Number of bits= 7
1 | | | | | | | H | 2 | | | | | | H | | 3 | | | | | H | | | 4 | | | | H | | | | 5 | | | H | | | | | 6 | | H | | | | | | 7 | Rz--+---+---+---+---+---@ | 8 | Rz--+---+---+---+---@ | | 9 | Rz--+---+---+---@ | | | 10 | Rz--+---+---@ | | | | 11 | Rz--+---@ | | | | | 12 | Rz--@ | | | | | | 13 | | H | | | | | | 14 | | @P--@ | | | | | 15 | | | H | | | | | 16 | | @P--+---@ | | | | 17 | | | @P--@ | | | | 18 | | | | H | | | | 19 | | @P--+---+---@ | | | 20 | | | @P--+---@ | | | 21 | | | | @P--@ | | | 22 | | | | | H | | | 23 | | @P--+---+---+---@ | | 24 | | | @P--+---+---@ | | 25 | | | | @P--+---@ | | 26 | | | | | @P--@ | | 27 | | | | | | H | | 28 | | @P--+---+---+---+---@ | 29 | | | @P--+---+---+---@ | 30 | | | | @P--+---+---@ | 31 | | | | | @P--+---@ | 32 | | | | | | @P--@ | 33 | | | | | | | H | 34 | | | | | | <---> | 35 | | | | | <---+---> | 36 | | | | | <---> | | 37 | | | | <---+---+---> | 38 | | | | <---+---> | | 39 | | | | <---> | | | 40 | | | <---+---+---+---> | 41 | | | <---+---+---> | | 42 | | | <---+---> | | | 43 | | | <---> | | | | 44 | | <---+---+---+---+---> | 45 | | <---+---+---+---> | | 46 | | <---+---+---> | | | 47 | | <---+---> | | | | 48 | | <---> | | | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (0000100)ZL ( 1.000000 - 0.000000j) prob=1.000000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (1.0, 0.0), 1: (1.0, 0.0), 2: (0.0, 1.0), 3: (1.0, 0.0), 4: (1.0, 0.0), 5: (1.0, 0.0), 6: (1.0, 0.0)} spike_bit prediction= 2.0 -----------------Number of bits= 8
1 | | | | | | | | H | 2 | | | | | | | H | | 3 | | | | | | H | | | 4 | | | | | H | | | | 5 | | | | H | | | | | 6 | | | H | | | | | | 7 | | H | | | | | | | 8 | Rz--+---+---+---+---+---+---@ | 9 | Rz--+---+---+---+---+---@ | | 10 | Rz--+---+---+---+---@ | | | 11 | Rz--+---+---+---@ | | | | 12 | Rz--+---+---@ | | | | | 13 | Rz--+---@ | | | | | | 14 | Rz--@ | | | | | | | 15 | | H | | | | | | | 16 | | @P--@ | | | | | | 17 | | | H | | | | | | 18 | | @P--+---@ | | | | | 19 | | | @P--@ | | | | | 20 | | | | H | | | | | 21 | | @P--+---+---@ | | | | 22 | | | @P--+---@ | | | | 23 | | | | @P--@ | | | | 24 | | | | | H | | | | 25 | | @P--+---+---+---@ | | | 26 | | | @P--+---+---@ | | | 27 | | | | @P--+---@ | | | 28 | | | | | @P--@ | | | 29 | | | | | | H | | | 30 | | @P--+---+---+---+---@ | | 31 | | | @P--+---+---+---@ | | 32 | | | | @P--+---+---@ | | 33 | | | | | @P--+---@ | | 34 | | | | | | @P--@ | | 35 | | | | | | | H | | 36 | | @P--+---+---+---+---+---@ | 37 | | | @P--+---+---+---+---@ | 38 | | | | @P--+---+---+---@ | 39 | | | | | @P--+---+---@ | 40 | | | | | | @P--+---@ | 41 | | | | | | | @P--@ | 42 | | | | | | | | H | 43 | | | | | | | <---> | 44 | | | | | | <---+---> | 45 | | | | | | <---> | | 46 | | | | | <---+---+---> | 47 | | | | | <---+---> | | 48 | | | | | <---> | | | 49 | | | | <---+---+---+---> | 50 | | | | <---+---+---> | | 51 | | | | <---+---> | | | 52 | | | | <---> | | | | 53 | | | <---+---+---+---+---> | 54 | | | <---+---+---+---> | | 55 | | | <---+---+---> | | | 56 | | | <---+---> | | | | 57 | | | <---> | | | | | 58 | | <---+---+---+---+---+---> | 59 | | <---+---+---+---+---> | | 60 | | <---+---+---+---> | | | 61 | | <---+---+---> | | | | 62 | | <---+---> | | | | | 63 | | <---> | | | | | |
*********branch= pure state vector: ZL convention (Zero bit Last in state tuple) (00001000)ZL ( 1.000000 - 0.000000j) prob=1.000000 total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (1.0, 0.0), 1: (1.0, 0.0), 2: (1.0, 0.0), 3: (0.0, 1.0), 4: (1.0, 0.0), 5: (1.0, 0.0), 6: (1.0, 0.0), 7: (1.0, 0.0)} spike_bit prediction= 3.0
We have printed the result for a range of $num\_bits$. The very last line for each $num\_bits$ printed tells the bit where we predict the spike (P(1)>>P(0)) will occur. If
$rads = \frac{2 \pi}{2^r}$,
then we predict that
$spike\_bit + r = num\_bits -1 = num\_probes$
If $rads$ cannot be expressed in this form, then the distributions over the first $num\_bits - 1$ bits will have multiple spikes at a bit $spike\_bit$ such that
$rads \approx 2\pi \sum_{spike\_bit} \frac{2^{spike\_bit}}{2^{num\_probes}}= 2\pi \sum_{k=0}^{num\_probes - 1} \frac{2^k}{2^{num\_probes}}n(k)$
for $0 \leq rads \leq 2\pi$, where $n(k)=1$ if $k$ is a spike bit and $n(k)=0$ otherwise.