The purpose of this notebook is to illustrate 2 new members in the set of gates that Qubiter recognizes. The 2 gates are
$U2 = \exp(i[ \theta_0 + \theta_1\sigma_X + \theta_2\sigma_Y + \theta_3\sigma_Z])$ for real $\theta_j$, where $\sigma_X, \sigma_Y, \sigma_Z$ are the Pauli matrices. 2. a generalization of SWAP(0, 1) which I call SWAY(0, 1). SWAY includes SWAP, sqrt(SWAP), iSWAP, sqrt(iSWAP) etc. I discuss SWAY more precisely below.
The Qubiter simulator can now handle both of these gates with any number of controls of type T or F
Qubiter previously included ROTN, which is a U2 with $\theta_0=0$, which means ROTN is an element of SU(2), i.e., the Special 2-dim unitaries whose determinant is 1. Quantum mechanics does not care about global phases, so why would we want a U2 with non-zero $\theta_0$? Because when we attach one or more controls to a U2 with non-zero $\theta_0$, the controls place conditions on that $\theta_0$, so the $\theta_0$ now has a physical significance and can no longer be dropped. For example, $$[e^{i\frac{\pi}{2} \sigma_Z(0)}]^{n(1)} = [i\sigma_Z(0)]^{n(1)}= i^{n(1)}\sigma_Z(0)^{n(1)}$$ is physically different from $$[-ie^{i\frac{\pi}{2} \sigma_Z(0)}]^{n(1)}=\sigma_Z(0)^{n(1)}$$
Recall that the swap of two qubits 0, 1, call it SWAP(1, 0), is defined by
$$ SWAP = diag(1, \sigma_X, 1) $$NOTE: SWAP is qbit symmetric, meaning that SWAP(0,1) = SWAP(1,0)
We define SWAY by
$$ SWAY = diag(1, U2, 1) $$where U2 is the most general 2-dim unitary matrix satisfying $$\sigma_X U2 \sigma_X= U2$$ If U2 is parametrized as
$$U2 = \exp(i[ \theta_0 + \theta_1\sigma_X + \theta_2\sigma_Y + \theta_3\sigma_Z])$$for real $\theta_j$, then SWAY is qbit symmetric (SWAY(0,1)=SWAY(1,0)) iff $\sigma_X U2 \sigma_X= U2$ iff $\theta_2=\theta_3=0$.
Just like
SWAP =
X---@
@---X
X---@
one has
SWAY=
X---@
@---U2
X---@
Next, we will test Qubiter's implementation of these two new types of gates.
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 *
loaded OneQubitGate, WITHOUT autograd.numpy
Next we define some constants that we will use later on.
num_qbits = 5
emb = CktEmbedder(num_qbits, num_qbits)
trols = Controls(num_qbits)
trols.bit_pos_to_kind = {3: True, 4: False}
trols.refresh_lists()
file_prefix = 'sway_test'
g = np.pi/180
rads_list1_ = ['#1', 20*g]
rads_list1 = ['#1', 20*g, 0, 0]
rads_list13 = ['#1', 20*g, 0, 40*g]
rads_list123 = ['#1', 20*g, 30*g, 40*g]
Next we create a SEO_writer and write a 5 qubit circuit with it.
wr = SEO_writer(file_prefix, emb)
wr.write_X(3)
In English files, a U2 gate is represented by U_2_
. In Picture files, it is represented
by either U, Ux, Uy, Uz or Ph. U is used if $\theta_1, \theta_2, \theta_3$ are all non-zero.
Ux is used if $\theta_1$ is non-zero but $\theta_2=\theta_3=0$.
Ph is used if $\theta_1=\theta_2=\theta_3=0$.
wr.write_U2(0, rads_list13)
wr.write_U2(1, rads_list1)
wr.write_controlled_one_qbit_gate(0, trols, OneQubitGate.u2, rads_list13)
Without a rads_list, write_controlled_qbit_swap() writes a controlled SWAP. With a rads_list, it writes a controlled SWAY
In English files, a swap gate is represented by SWAP
. In Picture files, a SWAP is represented by two single-chevron arrowheads pointing away from each other,
$\tt <---+---+--->$
wr.write_qbit_swap(0, 1)
wr.write_controlled_qbit_swap(0, 1, trols)
In English files, a sway gate is represented by SWAY
. In Picture files, a SWAY is represented by 2 double-chevron arrowheads pointing away from each other,
$\tt <<--+---+-->>$
wr.write_qbit_swap(0, 1, rads_list1_)
wr.write_controlled_qbit_swap(0, 1, trols, rads_list1_)
wr.close_files()
The above code wrote English and Picture files in the io_folder.
We can ask wr to print them for us
wr.print_eng_file(jup=True)
1 | SIGX AT 3 | 2 | U_2_ #1 20.000000 0.000000 40.000000 AT 0 | 3 | U_2_ #1 20.000000 0.000000 0.000000 AT 1 | 4 | U_2_ #1 20.000000 0.000000 40.000000 AT 0 IF 4F 3T | 5 | SWAP 1 0 | 6 | SWAP 1 0 IF 4F 3T | 7 | SWAY 1 0 BY #1 20.000000 | 8 | SWAY 1 0 BY #1 20.000000 IF 4F 3T |
wr.print_pic_file(jup=True)
1 | | X | | | | 2 | | | | | U | 3 | | | | Ux | | 4 | O---@---+---+---U | 5 | | | | <---> | 6 | O---@---+---<---> | 7 | | | | <<-->> | 8 | O---@---+---<<-->> |
The following shows that class SEO_simulator recognizes the 2 new gates, with and without controls, and can multiply through them
vman = PlaceholderManager(var_num_to_rads={1: np.pi/6})
sim = SEO_simulator(file_prefix, num_qbits, verbose=False,
vars_manager=vman)
StateVec.describe_st_vec_dict(sim.cur_st_vec_dict)
*********branch= pure total probability of state vector (=one if no measurements)= 1.000000 dictionary with key=qubit, value=(Prob(0), Prob(1)) {0: (0.960906, 0.039094), 1: (0.722135, 0.277865), 2: (1.0, -0.0), 3: (0.0, 1.0), 4: (1.0, -0.0)}