{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Say \"Hello World\" With Qubiter\n",
"The purpose of this notebook is to illustrate how to use Qubiter to simulate ( i.e., \n",
"predict the outcome of) a simple quantum circuit with a few basic gates\n",
"\n",
"> Below, we won't always give the precise definition of each gate. You can find the\n",
"precise analytical/numerical definition of all gates implemented by Qubiter in the document entitled `qubiter_rosetta_stone.pdf` included with the Qubiter distribution."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\newcommand{\\bra}[1]{\\left\\langle{#1}\\right|}$\n",
"$\\newcommand{\\ket}[1]{\\left|{#1}\\right\\rangle}$\n",
"test: $\\bra{\\psi}M\\ket{\\phi}$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First change your working directory to the Qubiter directory in your computer, and add its path to the path environment variable."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/rrtucci/PycharmProjects/qubiter/qubiter/jupyter_notebooks\n",
"/home/rrtucci/PycharmProjects/qubiter\n"
]
}
],
"source": [
"import os\n",
"import sys\n",
"print(os.getcwd())\n",
"os.chdir('../../')\n",
"print(os.getcwd())\n",
"sys.path.insert(0,os.getcwd())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Suppose you are anywhere in your home ~ directory, and qubiter has been installed somewhere accessible via the path environmental variable. You can find where qubiter is installed like this, in case you want to cd there."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/home/rrtucci/PycharmProjects/qubiter/qubiter/utilities_gen.py\n"
]
}
],
"source": [
"from qubiter.utilities_gen import find_path_to_qubiter\n",
"# this method returns the absolute path to the py file where the method is defined\n",
"path = find_path_to_qubiter()\n",
"print(path)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"loaded OneQubitGate, WITHOUT autograd.numpy\n"
]
}
],
"source": [
"from qubiter.SEO_writer import *\n",
"from qubiter.SEO_simulator import *\n",
"from qubiter.StateVec import *\n",
"from qubiter.SEO_MatrixProduct import *\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" Sometimes, we use the word \"bit\" to denote both qbits (qubits, quantum bits) or cbits (classical bits).\n",
" \n",
" Number of qubits is 4."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"num_qbits = 4"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Use a trivial circuit embedder that embeds 4 qubits into same 4 qubits."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"emb = CktEmbedder(num_qbits, num_qbits)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Open a writer, tell it where to write to.\n",
"We will use zero bit last (ZL) convention, which is the default for SEO_writer."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"file_prefix = 'hello_world_test'\n",
"wr = SEO_writer(file_prefix, emb)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write Pauli matrices $\\sigma_X, \\sigma_Y,\\sigma_Z$ at position 2."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"wr.write_X(2)\n",
"wr.write_Y(2)\n",
"wr.write_Z(2)\n",
"\n",
"# old way of doing it, still works\n",
"# wr.write_one_qbit_gate(2, OneQubitGate.sigx)\n",
"# wr.write_one_qbit_gate(2, OneQubitGate.sigy)\n",
"# wr.write_one_qbit_gate(2, OneQubitGate.sigz)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write 1 qubit Hadamard matrix at position 3."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"wr.write_H(3)\n",
"\n",
"# old way of doing it, still works\n",
"# wr.write_one_qbit_gate(3, OneQubitGate.had2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Rotate qubit 2 by $\\pi$ along directions x, y, z successively.\n",
"\n",
"> Note: We define $Ra(\\theta) = exp(i\\theta\\sigma_a)$ for $a=X,Y,Z$. Others use \n",
"$Ra(\\theta) = exp(-i\\frac{\\theta}{2}\\sigma_a)$ instead.\n",
"\n",
"> Note: $\\theta$ in $Ra(\\theta)$ is inserted in radians, but shows \n",
"up in the English File in degrees."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"wr.write_Rx(2, np.pi)\n",
"wr.write_Ry(2, np.pi)\n",
"wr.write_Rz(2, np.pi)\n",
"\n",
"# old way of doing it, still works dir=1,2,3\n",
"# wr.write_one_qbit_gate(2, OneQubitGate.rot_ax,[np.pi, dir])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Rotate qubit 1 along a non-axis direction $\\hat{n}$ characterized by a list of 3 angles.\n",
"$R(\\theta_1, \\theta_2, \\theta_3) = \\exp(i[\\theta_1 \\sigma_X +\\theta_2\\sigma_Y+\\theta_3\\sigma_Z])$"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"wr.write_Rn(1, [np.pi, np.pi/2, np.pi/3])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Definitions of S and T\n",
"\n",
"$S = diag[1, i] = diag[1, e^{i\\frac{\\pi}{2}}]$\n",
"\n",
"$T = \\sqrt{S}= diag[1, e^{i\\frac{\\pi}{4}}]$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write $S, S^\\dagger, T, T^\\dagger$ at position=2.\n",
"\n",
"> These operations show up in the English File as `P1PH` and in the \n",
"Picture File as `@P`. That is because $P_1 = n =\\ket{1}\\bra{1} = diag(0, 1)$ and the operation \n",
"`P1PH` (i.e. $P_1$ Phase) by a phase angle $\\theta$ equals the diagonal matrix $diag(1, e^{i\\theta})$ "
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"wr.write_S(2)\n",
"wr.write_S(2, herm=True)\n",
"wr.write_T(2)\n",
"wr.write_T(2, herm=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write $CNOT = sigx(target\\_pos)^{n(control\\_pos)}$ with control_pos=3 and target_pos=1"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"wr.write_cnot(3, 1)\n",
"\n",
"# old way of doing it, still works\n",
"# control_pos = 3\n",
"# target_pos = 1\n",
"# trols = Controls.new_single_trol(num_qbits, control_pos, kind=True)\n",
"# wr.write_controlled_one_qbit_gate(\n",
"# target_pos, trols, OneQubitGate.sigx)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"At any point in the circuit, you can use a PRINT statement. This will print\n",
"on the console, immediately after you create\n",
"an object of the class SEO_simulator, a description of the state vector at that point in the circuit.\n",
"Various styles of description are pre-canned for your convenience, or\n",
"you can write your own. See use_PRINT() method of SEO_simulator class.\n",
"Let's use a PRINT statement now in the pre-canned style \"ALL\"."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"wr.write_PRINT(\"ALL\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Swap qubits 1 and 3"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"wr.write_qbit_swap(1, 3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" Recall that\n",
"$P_1 = n = \\ket{1}\\bra{1}=diag(0, 1)$ and a P1 phase (P1PH) by $\\theta$ is $diag(1, e^{i\\theta})$. Write a singly controlled P1PH with control=c=3, target=t=1 and rads = pi/3.\n",
"This gate equals $e^{i*rads*n(t) n(c)}$. "
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"wr.write_c_P1PH(3, 1, rads=np.pi/3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If rads=pi, c_P1PH equals $(-1)^{n(t)n(c)} = \\sigma_Z(t)^{n(c)}$,\n",
"which is commonly called a controlled Z and denoted by Cz. Write a Cz with c=3 and t=1."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"wr.write_c_P1PH(3, 1) # rads=np.pi is default"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Write a controlled rotation at qubit 0 in the Y direction, with a True (@) control at qubit 1, and a False (0) control at qubits 2 and 3."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"target_pos = 0\n",
"rads = 30*np.pi/180\n",
"ax = 2 # y axis\n",
"trols = Controls(num_qbits, {1:True, 2:False, 3:False})\n",
"wr.write_controlled_one_qbit_gate(\n",
" target_pos, trols, OneQubitGate.rot_ax, [rads, ax])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Close English and Picture files."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"wr.close_files()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Look in files\n",
"\n",
"* ../io_folder/hello_world_test_4_eng.txt\n",
"* ../io_folder/hello_world_test_4_ZLpic.txt\n",
"\n",
"to see the quantum circuit that was generated."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once the English and Picture files are generated, you can ask the writer object wr to print them for you on screen"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"