Author: Anubhav Vardhan (anubhavvardhan@gmail.com)
User-defined gate added by: Boxi Li (etamin1201@gmail.com)
For more information about QuTiP see http://qutip.org
The circuit image visualization requires LaTeX and ImageMagick for display. The module automatically process the LaTeX code for plotting the circuit, generate the pdf and convert it to the png format.
On Mac and Linux, ImageMagick can be easily installed with the command conda install imagemagick
if you have conda installed.
Otherwise, please follow the installation instructions on the ImageMagick documentation.
On windows, you need to download and install ImageMagick installer. In addition, you also need perl (for pdfcrop) and Ghostscript (additional dependency of ImageMagick for png conversion).
To test if the installation is complete, try the following three commands working correctly in Command Prompt: pdflatex
, pdfcrop
and magick anypdf.pdf antpdf.png
, where anypdf.pdf
is any pdf file you have.
%matplotlib inline
from IPython.display import Image
from numpy import pi
import numpy as np
from qutip import *
from qutip_qip.operations import *
from qutip_qip.circuit import QubitCircuit, Gate
cphase(pi/2)
q = QubitCircuit(2, reverse_states=False)
q.add_gate("CSIGN", controls=[0], targets=[1])
q.png
rx(pi/2)
q = QubitCircuit(1, reverse_states=False)
q.add_gate("RX", targets=[0], arg_value=pi/2, arg_label=r'\frac{\pi}{2}')
q.png
ry(pi/2)
q = QubitCircuit(1, reverse_states=False)
q.add_gate("RY", targets=[0], arg_value=pi/2, arg_label=r'\frac{\pi}{2}')
q.png
rz(pi/2)
q = QubitCircuit(1, reverse_states=False)
q.add_gate("RZ", targets=[0], arg_value=pi/2, arg_label=r'\frac{\pi}{2}')
q.png
cnot()
q = QubitCircuit(2, reverse_states=False)
q.add_gate("CNOT", controls=[0], targets=[1])
q.png
csign()
q = QubitCircuit(2, reverse_states=False)
q.add_gate("CSIGN", controls=[0], targets=[1])
q.png
berkeley()
q = QubitCircuit(2, reverse_states=False)
q.add_gate("BERKELEY", targets=[0, 1])
q.png
swapalpha(pi/2)
fredkin()
toffoli()
swap()
q = QubitCircuit(2, reverse_states=False)
q.add_gate("SWAP", targets=[0, 1])
q.png
iswap()
q = QubitCircuit(2, reverse_states=False)
q.add_gate("ISWAP", targets=[0, 1])
q.png
sqrtiswap()
sqrtswap()
sqrtnot()
snot()
phasegate(pi/2)
globalphase(pi/2)
molmer_sorensen(pi/2)
qrot(pi/2, pi/4)
The example above show how to generate matrice representations of the gates implemented in QuTiP, in their minimal qubit requirements. If the same gates is to be represented in a qubit register of size $N$, the optional keywork argument N
can be specified when calling the gate function. For example, to generate the matrix for the CNOT gate for a $N=3$ bit register:
cnot(N=3)
q = QubitCircuit(3, reverse_states=False)
q.add_gate("CNOT", controls=[1], targets=[2])
q.png
Furthermore, the control and target qubits (when applicable) can also be similarly specified using keyword arguments control
and target
(or in some cases controls
or targets
):
cnot(N=3, control=2, target=0)
q = QubitCircuit(3, reverse_states=False)
q.add_gate("CNOT", controls=[0], targets=[2])
q.png
The gates implemented in QuTiP can be used to build any qubit circuit using the class QubitCircuit. The output can be obtained in the form of a unitary matrix or a latex representation.
In the following example, we take a SWAP gate. It is known that a swap gate is equivalent to three CNOT gates applied in the given format.
N = 2
qc0 = QubitCircuit(N)
qc0.add_gate("ISWAP", [0, 1], None)
qc0.png
U_list0 = qc0.propagators()
U0 = gate_sequence_product(U_list0)
U0
qc1 = QubitCircuit(N)
qc1.add_gate("CNOT", 0, 1)
qc1.add_gate("CNOT", 1, 0)
qc1.add_gate("CNOT", 0, 1)
qc1.png
U_list1 = qc1.propagators()
U1 = gate_sequence_product(U_list1)
U1
In place of manually converting the SWAP gate to CNOTs, it can be automatically converted using an inbuilt function in QubitCircuit
qc2 = qc0.resolve_gates("CNOT")
qc2.png
U_list2 = qc2.propagators()
U2 = gate_sequence_product(U_list2)
U2
From QuTiP 4.4, we can also add gate at arbitrary position in a circuit.
qc1.add_gate("CSIGN", index=[1], targets=[0], controls=[1])
qc1.png
qc3 = QubitCircuit(3)
qc3.add_gate("CNOT", 1, 0)
qc3.add_gate("RX", 0, None, pi/2, r"\pi/2")
qc3.add_gate("RY", 1, None, pi/2, r"\pi/2")
qc3.add_gate("RZ", 2, None, pi/2, r"\pi/2")
qc3.add_gate("ISWAP", [1, 2])
qc3.png
U3 = gate_sequence_product(qc3.propagators())
U3
qc4 = qc3.resolve_gates("CNOT")
qc4.png
U4 = gate_sequence_product(qc4.propagators())
U4
qc5 = qc3.resolve_gates("ISWAP")
qc5.png
U5 = gate_sequence_product(qc5.propagators())
U5
qc6 = qc3.resolve_gates(["ISWAP", "RX", "RY"])
qc6.png
U6 = gate_sequence_product(qc6.propagators())
U6
qc7 = qc3.resolve_gates(["CNOT", "RZ", "RX"])
qc7.png
U7 = gate_sequence_product(qc7.propagators())
U7
Interactions between non-adjacent qubits can be resolved by QubitCircuit to a series of adjacent interactions, which is useful for systems such as spin chain models.
qc8 = QubitCircuit(3)
qc8.add_gate("CNOT", 2, 0)
qc8.png
U8 = gate_sequence_product(qc8.propagators())
U8
qc9 = qc8.adjacent_gates()
qc9.gates
[Gate(SWAP, targets=[0, 1], controls=None, classical controls=None, control_value=None), Gate(CNOT, targets=[2], controls=[1], classical controls=None, control_value=None), Gate(SWAP, targets=[0, 1], controls=None, classical controls=None, control_value=None)]
U9 = gate_sequence_product(qc9.propagators())
U9
qc10 = qc9.resolve_gates("CNOT")
qc10.png
U10 = gate_sequence_product(qc10.propagators())
U10
From QuTiP 4.4 one can add a gate at an arbitrary position of a circuit. All one needs to do is to specify the parameter index. With this, we can also add the same gate at multiple positions at the same time.
qc = QubitCircuit(1)
qc.add_gate("RX", targets=1, arg_value=np.pi/2)
qc.add_gate("RX", targets=1, arg_value=np.pi/2)
qc.add_gate("RY", targets=1, arg_value=np.pi/2, index=[0])
qc.gates
[Gate(RY, targets=[1], controls=None, classical controls=None, control_value=None), Gate(RX, targets=[1], controls=None, classical controls=None, control_value=None), Gate(RX, targets=[1], controls=None, classical controls=None, control_value=None)]
From QuTiP 4.4 on, user defined gates can be defined by a python function that takes at most one parameter and return a Qobj
, the dimension of the Qobj
has to match the qubit system.
def user_gate1(arg_value):
# controlled rotation X
mat = np.zeros((4, 4), dtype=np.complex)
mat[0, 0] = mat[1, 1] = 1.
mat[2:4, 2:4] = rx(arg_value)
return Qobj(mat, dims=[[2, 2], [2, 2]])
def user_gate2():
# S gate
mat = np.array([[1., 0],
[0., 1.j]])
return Qobj(mat, dims=[[2], [2]])
To let the QubitCircuit
process those gates, we need to modify its attribute QubitCircuit.user_gates
, which is a python dictionary in the form {name: gate_function}
.
qc = QubitCircuit(2)
qc.user_gates = {"CTRLRX": user_gate1,
"S" : user_gate2}
When calling the add_gate
method, the target qubits and the argument need to be given.
# qubit 0 controls qubit 1
qc.add_gate("CTRLRX", targets=[0,1], arg_value=pi/2)
# qubit 1 controls qubit 0
qc.add_gate("CTRLRX", targets=[1,0], arg_value=pi/2)
# a gate can also be added using the Gate class
g_T = Gate("S", targets=[1])
qc.add_gate("S", targets=[1])
props = qc.propagators()
<ipython-input-60-0c4e722f5dae>:3: DeprecationWarning: `np.complex` is a deprecated alias for the builtin `complex`. To silence this warning, use `complex` by itself. Doing this will not modify any behavior and is safe. If you specifically wanted the numpy scalar type, use `np.complex128` here. Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations mat = np.zeros((4, 4), dtype=np.complex)
props[0] # qubit 0 controls qubit 1
props[1] # qubit 1 controls qubit 0
props[2] # S gate acts on qubit 1
from qutip.ipynbtools import version_table
version_table()
Software | Version |
---|---|
QuTiP | 4.6.0+c003ff5 |
Numpy | 1.20.1 |
SciPy | 1.5.3 |
matplotlib | 3.3.0 |
Cython | 0.29.21 |
Number of CPUs | 12 |
BLAS Info | Generic |
IPython | 7.16.1 |
Python | 3.8.6 | packaged by conda-forge | (default, Oct 7 2020, 18:22:52) [MSC v.1916 64 bit (AMD64)] |
OS | nt [win32] |
Mon Apr 12 19:47:05 2021 W. Europe Daylight Time |