Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
b775d2c
Removed unused variables and minor corrections
mudit06mah Jan 19, 2026
c312fbb
Merge pull request #311 from mudit06mah/zzcrosstalk
BoxiLi Jan 20, 2026
a8f1e61
Depreciate N in QubitCircuit and use num_qubits instead
niranjannagumalli Jan 11, 2026
a28fd3c
Replace qc.N with qc.num_qubits in the codebase
niranjannagumalli Jan 28, 2026
a0f4e0e
Depreciated N in gatecompiler
niranjannagumalli Jan 28, 2026
fccb49b
Replaced N with num_qubits in texrenderer
niranjannagumalli Jan 28, 2026
7b5a012
Replace N with num_qubits in convertor.py and fix linting
niranjannagumalli Jan 28, 2026
14dd774
Replaced get_compact_qobj with get_qobj
Mayank447 Feb 9, 2026
8ac2358
Added num_params property and validate_params abstract method for Par…
Mayank447 Feb 9, 2026
a678aeb
Made num_qubits, num_ctrl_qubits, num_param a class attribute instead…
Mayank447 Feb 9, 2026
d23204a
Added GateReadOnlyMeta class for certain gate attributes
Mayank447 Feb 9, 2026
fdc56ed
Made arg_value an iterable in Parametric Gate
Mayank447 Feb 9, 2026
95de51d
Skip __init__subclass checks for abstract classes
Mayank447 Feb 9, 2026
be0b0cb
Replace num_qubits argument with positional argument in QubitCircuit …
niranjannagumalli Feb 9, 2026
7cf6a2e
Update qip-qiskit.rst to use num_qubits argument in CircularSpinChain…
niranjannagumalli Feb 9, 2026
c3bbef7
Removed usage of gates.py in codebase and deprecated them
Mayank447 Feb 9, 2026
4fe70fe
Added more checks to _init_subclass__ in Gate
Mayank447 Feb 9, 2026
4c5ac19
Shifted num_ctrl_qubits from Gate class to ControlledGate class
Mayank447 Feb 9, 2026
8a88790
Made num_qubits, num_params property with abstract method
Mayank447 Feb 9, 2026
90d650b
Renamed ParametrizedGat to ParametricGate
Mayank447 Feb 9, 2026
663752e
Added an abstract method target_class to ControlledGate
Mayank447 Feb 9, 2026
4b391d7
Removed target_class from ControlledParam Gate
Mayank447 Feb 9, 2026
435abc1
Added typing.py
Mayank447 Feb 9, 2026
a78f982
Added additional checks for ControlledGate
Mayank447 Feb 9, 2026
5df2b4a
Made validate_params method abstract for ParametricGate
Mayank447 Feb 9, 2026
cbcee00
Replaced string gate input to add_gate to gate class in codebase
Mayank447 Feb 9, 2026
a837d89
Removed __all__ from individual files in algorithms
Mayank447 Feb 9, 2026
de63be8
Added is_controlled_gate and is_parametric_gate methods to the gate c…
Mayank447 Feb 9, 2026
46c02cd
Made the qubit conversion logic for qiskit circuit same as qutip (no …
Mayank447 Feb 9, 2026
aa9a70e
Split std_gates into single_qubit gates
Mayank447 Feb 10, 2026
74f6cee
Split two qubit gates from std_gates.py
Mayank447 Feb 10, 2026
7670b08
Remove unused code from the split
Mayank447 Feb 10, 2026
151b98c
Finalize gate split to std
Mayank447 Feb 10, 2026
0d473e5
Remove unused imports
Mayank447 Feb 10, 2026
2eb5949
Added self-inverse property to Gate class
Mayank447 Feb 10, 2026
fcf1d8b
Added is_clifford propoerty to the Gate class
Mayank447 Feb 10, 2026
191db06
Added deprecation warning for gate input as string in add_gate method
Mayank447 Feb 10, 2026
f03e48b
Added deprecation warning for arg_value, arg_label and control_value …
Mayank447 Feb 10, 2026
7d8fd89
Replaced * imports with std.
Mayank447 Feb 10, 2026
73a679b
Added docstring for Gate class, ControlledGate class
Mayank447 Feb 10, 2026
875c41d
Added docstring for ParametricGate class
Mayank447 Feb 10, 2026
e0c904a
Renamed ControlledParamGate to ControlledParametricGate and added the…
Mayank447 Feb 10, 2026
8c76e79
Deprecated SNOT, CSIGN
Mayank447 Feb 11, 2026
9e49b0f
Deprecated CNOT gate and replaced with CX
Mayank447 Feb 11, 2026
ad6a19f
Removed ControlledParametricGate class, moved that functionality in C…
Mayank447 Feb 11, 2026
2c6630f
Merge pull request #317 Replace n with num qubits
BoxiLi Feb 12, 2026
1feae75
Replaced SQRTNOT with SQRTX
Mayank447 Feb 13, 2026
8f6bd83
Merge branch 'master' into refactor-gate-class
Mayank447 Feb 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/pulse-paper/customize.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def get_control(self, label):
elif label[:2] == "sy":
return 2 * np.pi * sigmay() / 2, [targets]
else:
raise NotImplementError("Unknown control.")
raise ValueError("Unknown control.")


class MyCompiler(GateCompiler):
Expand Down
38 changes: 1 addition & 37 deletions doc/source/apidoc/qutip_qip.operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,20 @@ qutip\_qip.operations
RY
RZ
H
SNOT
SQRTNOT
S
T
QASMU
SWAP
ISWAP
CNOT
CX
SQRTSWAP
SQRTISWAP
BERKELEY
SWAPALPHA
MS
TOFFOLI
FREDKIN
CNOT
CSIGN
CRX
CRY
CRZ
Expand All @@ -53,39 +50,6 @@ qutip\_qip.operations

.. autosummary::

berkeley
cnot
controlled_gate
cphase
cs_gate
csign
ct_gate
cy_gate
cz_gate
expand_operator
fredkin
gate_sequence_product
globalphase
hadamard_transform
iswap
molmer_sorensen
phasegate
qasmu_gate
qrot
qubit_clifford_group
rotation
rx
ry
rz
s_gate
snot
sqrtiswap
sqrtnot
sqrtswap
swap
swapalpha
t_gate
toffoli
x_gate
y_gate
z_gate
58 changes: 28 additions & 30 deletions doc/source/qip-basics.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,16 @@ A circuit with the various gates and registers available is demonstrated below:
.. testcode::

from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Gate, SWAP
from qutip_qip.operations import X, CX, SWAP
from qutip import tensor, basis

qc = QubitCircuit(N=2, num_cbits=1)
qc = QubitCircuit(2, num_cbits=1)

qc.add_gate("SWAP", targets=[0, 1])
qc.add_gate(SWAP, targets=[0, 1])
qc.add_measurement("M0", targets=[1], classical_store=0) # measurement gate
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("X", targets=0, classical_controls=[0]) # classically controlled gate
qc.add_gate("SWAP", targets=[0, 1])
qc.add_gate(CX, controls=0, targets=1)
qc.add_gate(X, targets=0, classical_controls=[0]) # classically controlled gate
qc.add_gate(SWAP, targets=[0, 1])

print(qc.instruction)

Expand All @@ -53,7 +53,7 @@ A circuit with the various gates and registers available is demonstrated below:

[Gate(SWAP, targets=[0, 1], controls=None, classical controls=None, control_value=None, classical_control_value=None),
Measurement(M0, target=[1], classical_store=0),
Gate(CNOT, targets=[1], controls=[0], classical controls=None, control_value=1, classical_control_value=None),
Gate(CX, targets=[1], controls=[0], classical controls=None, control_value=1, classical_control_value=None),
Gate(X, targets=[0], controls=None, classical controls=[0], control_value=None, classical_control_value=1),
Gate(SWAP, targets=[0, 1], controls=None, classical controls=None, control_value=None, classical_control_value=None)]

Expand Down Expand Up @@ -148,20 +148,18 @@ Gate name Description
"Z" Pauli-Z gate
"S" Single-qubit rotation or Z90
"T" Square root of S gate
"SQRTNOT" Square root of NOT gate
"SNOT" Hadamard gate
"SQRTX" Square root of X gate
"H" Hadamard gate
"PHASEGATE" Add a phase one the state 1
"CRX" Controlled rotation around x axis
"CRY" Controlled rotation around y axis
"CRZ" Controlled rotation around z axis
"CX" Controlled X gate
"CX" Controlled X gate (also called CNOT)
"CY" Controlled Y gate
"CZ" Controlled Z gate
"CS" Controlled S gate
"CT" Controlled T gate
"CPHASE" Controlled phase gate
"CNOT" Controlled NOT gate
"CSIGN" Same as CPHASE
"QASMU" U rotation gate used as a primitive in the QASM standard
"BERKELEY" Berkeley gate
"SWAPalpha" SWAPalpha gate
Expand All @@ -175,7 +173,7 @@ Gate name Description
"GLOBALPHASE" Global phase
==================== ========================================

For some of the gates listed above, :class:`.QubitCircuit` also has a primitive :func:`.QubitCircuit.resolve_gates()` method that decomposes them into elementary gate sets such as CNOT or SWAP with single-qubit gates (RX, RY and RZ). However, this method is not fully optimized. It is very likely that the depth of the circuit can be further reduced by merging quantum gates. It is required that the gate resolution be carried out before the measurements to the circuit are added.
For some of the gates listed above, :class:`.QubitCircuit` also has a primitive :func:`.QubitCircuit.resolve_gates()` method that decomposes them into elementary gate sets such as CX or SWAP with single-qubit gates (RX, RY and RZ). However, this method is not fully optimized. It is very likely that the depth of the circuit can be further reduced by merging quantum gates. It is required that the gate resolution be carried out before the measurements to the circuit are added.

**Custom Gates**

Expand Down Expand Up @@ -278,13 +276,13 @@ QuTiP-QIP offers three distinct methods for visualizing quantum circuits. Below
:include-source:

from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Gate
from qutip_qip.operations import H, CX, ISWAP

# create the quantum circuit
qc = QubitCircuit(2, num_cbits=1)
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("SNOT", targets=1)
qc.add_gate("ISWAP", targets=[0,1])
qc.add_gate(CX, controls=0, targets=1)
qc.add_gate(H, targets=1)
qc.add_gate(ISWAP, targets=[0,1])
qc.add_measurement("M0", targets=1, classical_store=0)

qc.draw("matplotlib", dpi=300)
Expand All @@ -295,13 +293,13 @@ QuTiP-QIP offers three distinct methods for visualizing quantum circuits. Below
:include-source:

from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Gate
from qutip_qip.operations import H, CX, ISWAP

# create the quantum circuit
qc = QubitCircuit(2, num_cbits=1)
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("SNOT", targets=1)
qc.add_gate("ISWAP", targets=[0,1])
qc.add_gate(CX, controls=0, targets=1)
qc.add_gate(H, targets=1)
qc.add_gate(ISWAP, targets=[0,1])
qc.add_measurement("M0", targets=1, classical_store=0)

qc.draw("matplotlib", bulge=False, theme='dark', title="Plotting Quantum Circuit", dpi=300)
Expand Down Expand Up @@ -360,13 +358,13 @@ QuTiP-QIP offers three distinct methods for visualizing quantum circuits. Below
.. testcode::

from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Gate
from qutip_qip.operations import H, CX, ISWAP

# create the quantum circuit
qc = QubitCircuit(2, num_cbits=1)
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("SNOT", targets=1)
qc.add_gate("ISWAP", targets=[0,1])
qc.add_gate(CX, controls=0, targets=1)
qc.add_gate(H, targets=1)
qc.add_gate(ISWAP, targets=[0,1])
qc.add_measurement("M0", targets=1, classical_store=0)

qc.draw("text")
Expand All @@ -375,7 +373,7 @@ QuTiP-QIP offers three distinct methods for visualizing quantum circuits. Below
:options: +NORMALIZE_WHITESPACE

┌──────┐ ┌──────┐ ┌───────┐ ┌───┐
q1 :───┤ CNOT ├──┤ SNOT ├──┤ ├──┤ M ├───
q1 :───┤ CX ├──┤ H ├──┤ ├──┤ M ├───
└───┬──┘ └──────┘ │ │ └─╥─┘
│ │ │ ║
q0 :───────█───────────────┤ ISWAP ├────║─────
Expand Down Expand Up @@ -415,13 +413,13 @@ QuTiP-QIP offers three distinct methods for visualizing quantum circuits. Below
.. code-block::

from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Gate
from qutip_qip.operations import H, CX, ISWAP

# create the quantum circuit
qc = QubitCircuit(2, num_cbits=1)
qc.add_gate("CNOT", controls=0, targets=1)
qc.add_gate("SNOT", targets=1)
qc.add_gate("ISWAP", targets=[0,1])
qc.add_gate(CX, controls=0, targets=1)
qc.add_gate(H, targets=1)
qc.add_gate(ISWAP, targets=[0,1])
qc.add_measurement("M0", targets=1, classical_store=0)

qc.draw("latex")
Expand Down
43 changes: 23 additions & 20 deletions doc/source/qip-processor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,21 @@ We will work through this example and explain briefly the workflow and all the m
from qutip import basis
from qutip_qip.circuit import QubitCircuit
from qutip_qip.device import LinearSpinChain
from qutip_qip.operations import H, X, CX

# Define a circuit
qc = QubitCircuit(3)
qc.add_gate("X", targets=2)
qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate("SNOT", targets=2)
qc.add_gate(X, targets=2)
qc.add_gate(H, targets=0)
qc.add_gate(H, targets=1)
qc.add_gate(H, targets=2)

# Oracle function f(x)
qc.add_gate("CNOT", controls=0, targets=2)
qc.add_gate("CNOT", controls=1, targets=2)
qc.add_gate(CX, controls=0, targets=2)
qc.add_gate(CX, controls=1, targets=2)

qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate(H, targets=0)
qc.add_gate(H, targets=1)

# Run gate-level simulation
init_state = basis([2,2,2], [0,0,0])
Expand Down Expand Up @@ -154,18 +155,20 @@ In the following example we plot the compiled Deutsche Jozsa algorithm:

# Deutsch-Jozsa algorithm
from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import X, H, CX

qc = QubitCircuit(3)
qc.add_gate("X", targets=2)
qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate("SNOT", targets=2)
qc.add_gate(X, targets=2)
qc.add_gate(H, targets=0)
qc.add_gate(H, targets=1)
qc.add_gate(H, targets=2)

# Oracle function f(x)
qc.add_gate("CNOT", controls=0, targets=2)
qc.add_gate("CNOT", controls=1, targets=2)
qc.add_gate(CX, controls=0, targets=2)
qc.add_gate(CX, controls=1, targets=2)

qc.add_gate("SNOT", targets=0)
qc.add_gate("SNOT", targets=1)
qc.add_gate(H, targets=0)
qc.add_gate(H, targets=1)

from qutip_qip.device import LinearSpinChain
spinchain_processor = LinearSpinChain(num_qubits=3, t2=30) # T2 = 30
Expand Down Expand Up @@ -221,9 +224,9 @@ To let it find the optimal pulses, we need to give the parameters for :func:`~qu
:context: close-figs

from qutip_qip.device import OptPulseProcessor, SpinChainModel
setting_args = {"SNOT": {"num_tslots": 6, "evo_time": 2},
"X": {"num_tslots": 1, "evo_time": 0.5},
"CNOT": {"num_tslots": 12, "evo_time": 5}}
setting_args = {H: {"num_tslots": 6, "evo_time": 2},
X: {"num_tslots": 1, "evo_time": 0.5},
CX: {"num_tslots": 12, "evo_time": 5}}
opt_processor = OptPulseProcessor(
num_qubits=3, model=SpinChainModel(3, setup="linear"))
opt_processor.load_circuit( # Provide parameters for the algorithm
Expand All @@ -242,7 +245,7 @@ A compiler converts the quantum circuit to the corresponding pulse-level control
In the framework, it is defined as an instance of the :obj:`.GateCompiler` class.
The compilation procedure is achieved through the following steps.

First, each quantum gate is decomposed into the native gates (e.g., rotation over :math:`x`, :math:`y` axes and the CNOT gate), using the existing decomposition scheme in QuTiP.
First, each quantum gate is decomposed into the native gates (e.g., rotation over :math:`x`, :math:`y` axes and the CX gate), using the existing decomposition scheme in QuTiP.
If a gate acts on two qubits that are not physically connected, like in the chain model and superconducting qubit model, SWAP gates are added to match the topology before the decomposition. Currently, only 1-dimensional chain structures are supported.

Next, the compiler maps each quantum gate to a pulse-level control description.
Expand Down
3 changes: 0 additions & 3 deletions doc/source/qip-qiskit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
`qutip-qip` as a Qiskit backend
**********************************

This submodule was implemented by `Shreyas Pradhan <shpradhan12@gmail.com>`_ as part of Google Summer of Code 2022.
And later updated by `Mayank Goel <mayank.goel447@gmail.com>`_ for Qiskit v2.

Overview
===============

Expand Down
34 changes: 15 additions & 19 deletions doc/source/qip-simulator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,15 @@ examples of circuit evolution. We take a circuit from
.. testcode::

from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import (
Gate, controlled_gate, hadamard_transform)
def controlled_hadamard():
# Controlled Hadamard
return controlled_gate(
hadamard_transform(1), controls=0, targets=1, control_value=1)
qc = QubitCircuit(N=3, num_cbits=3)
qc.add_gate("QASMU", targets=[0], arg_value=[1.91063, 0, 0])
qc.add_gate("CH", controls=[0], targets=[1])
qc.add_gate("TOFFOLI", targets=[2], controls=[0, 1])
qc.add_gate("X", targets=[0])
qc.add_gate("X", targets=[1])
qc.add_gate("CNOT", targets=[1], controls=0)
from qutip_qip.operations import X, CX, CH, QASMU, TOFFOLI
)
qc = QubitCircuit(3, num_cbits=3)
qc.add_gate(QASMU, targets=[0], arg_value=[1.91063, 0, 0])
qc.add_gate(CH, controls=[0], targets=[1])
qc.add_gate(TOFFOLI, targets=[2], controls=[0, 1])
qc.add_gate(X, targets=[0])
qc.add_gate(X, targets=[1])
qc.add_gate(CX, targets=[1], controls=0)

It corresponds to the following circuit:

Expand Down Expand Up @@ -210,12 +206,12 @@ just by measurement on the first qubit:
.. testcode::

qc = QubitCircuit(N=3, num_cbits=3)
qc.add_gate("QASMU", targets=[0], arg_value=[1.91063, 0, 0])
qc.add_gate("CH", controls=[0], targets=[1])
qc.add_gate("TOFFOLI", targets=[2], controls=[0, 1])
qc.add_gate("X", targets=[0])
qc.add_gate("X", targets=[1])
qc.add_gate("CNOT", targets=[1], controls=0)
qc.add_gate(QASMU, targets=[0], arg_value=[1.91063, 0, 0])
qc.add_gate(CH, controls=[0], targets=[1])
qc.add_gate(TOFFOLI, targets=[2], controls=[0, 1])
qc.add_gate(X, targets=[0])
qc.add_gate(X, targets=[1])
qc.add_gate(CX, targets=[1], controls=0)
qc.add_measurement("M0", targets=[0], classical_store=0)
qc.add_measurement("M0", targets=[1], classical_store=0)
qc.add_measurement("M0", targets=[2], classical_store=0)
Expand Down
20 changes: 15 additions & 5 deletions src/qutip_qip/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
from .qft import *
from .qpe import *
from .bit_flip import *
from .phase_flip import *
from .shor_code import *
from .qft import qft, qft_steps, qft_gate_sequence
from .qpe import qpe
from .bit_flip import BitFlipCode
from .phase_flip import PhaseFlipCode
from .shor_code import ShorCode

__all__ = [
"qft",
"qft_steps",
"qft_gate_sequence",
"qpe",
"BitFlipCode",
"PhaseFlipCode",
"ShorCode",
]
Loading
Loading