quairkit.circuit

The source file of the Circuit class.

class quairkit.circuit.Circuit(num_systems=None, system_dim=2, physical_idx=None)

Class for quantum circuit.

Parameters:
num_systems : int | None

Number of systems in the circuit. Defaults to None. Alias of num_qubits.

system_dim : List[int] | int | None

Dimension of systems of this circuit. Can be a list of system dimensions or an int representing the dimension of all systems. Defaults to be qubit case.

physical_idx : List[int] | None

Physical indices of systems. Defaults to be the same as the logical indices.

Note

When the number of system is unknown and system_dim is an int, the circuit is a dynamic quantum circuit.

Examples

from quairkit import Circuit

# Create a simple circuit with 2 qubits
qc = Circuit(2)
qc.h(0)  # Apply Hadamard gate on qubit 0
qc.cnot([0, 1])  # Apply CNOT gate
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{H} & \ctrl[]{1} & {} \\
\lstick{} & {} & \targ{} & {}
to_latex(style='standard', decimal=2)

The LaTeX representation of the circuit, written in Quantikz format.

Parameters:
style : str

the style of the plot, can be ‘standard’, ‘compact’ or ‘detailed’. Defaults to standard.

decimal : int

number of decimal places to display. Defaults to 2.

Examples

qc = Circuit(2)
qc.h()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{H} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{H} & {} & {}
plot(style='standard', decimal=2, dpi=300, print_code=False, show_plot=True, include_empty=False, **kwargs)

Display the circuit using Quantikz if latex is True, otherwise using matplotlib.

Parameters:
style : str

the style of the plot, can be ‘standard’, ‘compact’ or ‘detailed’. Defaults to standard.

decimal : int

number of decimal places to display. Defaults to 2.

dpi : int

dots per inches of plot image. Defaults to 300.

print_code : bool

whether print the LaTeX code of the circuit, default to False.

show_plot : bool

whether show the plotted circuit, default to True.

include_empty : bool

whether include empty lines, default to False.

**kwargs

additional parameters for matplotlib plot.

Examples

qc = Circuit(2)
qc.h()
qc.plot()
(Displays the plotted circuit using Quantikz or matplotlib)
property qasm : str | list[str]

String representation of the circuit in qasm-like format.

Returns:

string representation of the operator list

property qasm2 : str | list[str]

Transpile the circuit in OpenQASM 2.0 format.

Returns:

Transpilation of the circuit

unitary_matrix()

Get the unitary matrix form of the circuit.

Returns:

Unitary matrix form of the circuit.

Return type:

Tensor

h(qubits_idx='full')

Add single-qubit Hadamard gates.

The matrix form of such a gate is:

\[\begin{split}H = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & 1 \\ 1 & -1 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.h()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{H} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{H} & {} & {}
s(qubits_idx='full')

Add single-qubit S gates.

The matrix form of such a gate is:

\[\begin{split}S = \begin{bmatrix} 1 & 0 \\ 0 & i \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.s()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{S} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{S} & {} & {}
sdg(qubits_idx='full')

Add single-qubit S dagger (S inverse) gates.

The matrix form of such a gate is:

\[\begin{split}S^\dagger = \begin{bmatrix} 1 & 0 \\ 0 & -i \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to 'full'.

Examples

qc = Circuit(2)
qc.sdg()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{S^\dagger} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{S^\dagger} & {} & {}
t(qubits_idx='full')

Add single-qubit T gates.

The matrix form of such a gate is:

\[\begin{split}T = \begin{bmatrix} 1 & 0 \\ 0 & e^{i\pi/4} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.t()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{T} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{T} & {} & {}
tdg(qubits_idx='full')

Add single-qubit T dagger (T inverse) gates.

The matrix form of such a gate is:

\[\begin{split}T^\dagger = \begin{bmatrix} 1 & 0 \\ 0 & e^{-i\pi/4} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to 'full'.

Examples

qc = Circuit(2)
qc.tdg()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{T^\dagger} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{T^\dagger} & {} & {}
x(qubits_idx='full')

Add single-qubit X gates.

The matrix form of such a gate is:

\[\begin{split}X = \begin{bmatrix} 0 & 1 \\ 1 & 0 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.x()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{X} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{X} & {} & {}
y(qubits_idx='full')

Add single-qubit Y gates.

The matrix form of such a gate is:

\[\begin{split}Y = \begin{bmatrix} 0 & -i \\ i & 0 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.y()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{Y} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{Y} & {} & {}
z(qubits_idx='full')

Add single-qubit Z gates.

The matrix form of such a gate is:

\[\begin{split}Z = \begin{bmatrix} 1 & 0 \\ 0 & -1 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.z()
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{Z} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{Z} & {} & {}
p(qubits_idx='full', param=None, param_sharing=False)

Add single-qubit P gates.

The matrix form of such a gate is:

\[\begin{split}P(\theta) = \begin{bmatrix} 1 & 0 \\ 0 & e^{i\theta} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

param : Tensor | float

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.p([0], torch.pi/2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{P(1.57)} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
rx(qubits_idx='full', param=None, param_sharing=False)

Add single-qubit rotation gates about the x-axis.

The matrix form of such a gate is:

\[\begin{split}R_X(\theta) = \begin{bmatrix} \cos\frac{\theta}{2} & -i\sin\frac{\theta}{2} \\ -i\sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

param : Tensor | float

Parameters of the gates. Can be a single float or a tensor for batch operations. For batch operations, the shape should be (batch_size,) or (batch_size, num_gates). Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Note

This method supports batch operations. When param is a tensor with batch dimension, the circuit will process multiple parameter sets simultaneously.

Examples

import torch
from quairkit import Circuit

# Single parameter example
qc = Circuit(2)
qc.rx([0], torch.pi/2)
print(f'Single parameter circuit:\n{qc.to_latex()}')
Single parameter circuit:
\lstick{} & \gate[1]{R_{x}(1.57)} & {} \\
\lstick{} & {} & {}
# Batch parameter example
qc = Circuit(2)
batch_params = torch.tensor([0.0, torch.pi/4, torch.pi/2, torch.pi])
qc.rx([0], batch_params)  # Apply different rotations in batch
state = qc()  # Execute circuit with batched parameters
print(f'Batch size: {state.batch_dim}')
Batch size: [4]
ry(qubits_idx='full', param=None, param_sharing=False)

Add single-qubit rotation gates about the y-axis.

The matrix form of such a gate is:

\[\begin{split}R_Y(\theta) = \begin{bmatrix} \cos\frac{\theta}{2} & -\sin\frac{\theta}{2} \\ \sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

param : Tensor | float

Parameters of the gates. Can be a single float or a tensor for batch operations. For batch operations, the shape should be (batch_size,) or (batch_size, num_gates). Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Note

This method supports batch operations. When param is a tensor with batch dimension, the circuit will process multiple parameter sets simultaneously.

Examples

import torch
from quairkit import Circuit

# Single parameter example
qc = Circuit(2)
qc.ry([0], torch.pi/2)
print(f'Single parameter circuit:\n{qc.to_latex()}')
Single parameter circuit:
\lstick{} & \gate[1]{R_{y}(1.57)} & {} \\
\lstick{} & {} & {}
# Batch parameter example
qc = Circuit(2)
batch_params = torch.tensor([0.0, torch.pi/4, torch.pi/2])
qc.ry([0], batch_params)  # Apply different rotations in batch
state = qc()  # Execute circuit with batched parameters
print(f'Batch size: {state.batch_dim}')
Batch size: [3]
rz(qubits_idx='full', param=None, param_sharing=False)

Add single-qubit rotation gates about the z-axis.

The matrix form of such a gate is:

\[\begin{split}R_Z(\theta) = \begin{bmatrix} e^{-i\theta/2} & 0 \\ 0 & e^{i\theta/2} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

param : Tensor | float

Parameters of the gates. Can be a single float or a tensor for batch operations. For batch operations, the shape should be (batch_size,) or (batch_size, num_gates). Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Note

This method supports batch operations. When param is a tensor with batch dimension, the circuit will process multiple parameter sets simultaneously.

Examples

import torch
from quairkit import Circuit

# Single parameter example
qc = Circuit(2)
qc.rz([0], torch.pi/2)
print(f'Single parameter circuit:\n{qc.to_latex()}')
Single parameter circuit:
\lstick{} & \gate[1]{R_{z}(1.57)} & {} \\
\lstick{} & {} & {}
# Batch parameter example
qc = Circuit(2)
batch_params = torch.tensor([0.0, torch.pi/4, torch.pi/2])
qc.rz([0], batch_params)  # Apply different rotations in batch
state = qc()  # Execute circuit with batched parameters
print(f'Batch size: {state.batch_dim}')
Batch size: [3]
u3(qubits_idx='full', param=None, param_sharing=False)

Add single-qubit rotation gates.

The matrix form of such a gate is:

\[\begin{split}U_3(\theta, \phi, \lambda) = \begin{bmatrix} \cos\frac\theta2 & -e^{i\lambda}\sin\frac\theta2 \\ e^{i\phi}\sin\frac\theta2 & e^{i(\phi+\lambda)}\cos\frac\theta2 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | int | str

Indices of the qubits on which the gates are applied. Defaults to ‘full’.

param : Tensor | Iterable[float]

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.u3([0], torch.pi/2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{U(1.57, 1.57, 1.57)} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
cnot(qubits_idx='cycle')

Add CNOT gates.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\mathit{CNOT} = |0\rangle \langle 0|\otimes I + |1\rangle \langle 1|\otimes X\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

Examples

qc = Circuit(2)
qc.cnot([0, 1])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \targ{} & {} & {}
cy(qubits_idx='cycle')

Add controlled Y gates.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\mathit{CY} = |0\rangle \langle 0|\otimes I + |1\rangle \langle 1|\otimes Y\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

Examples

qc = Circuit(2)
qc.cy([0, 1])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{Y} & {} & {}
cz(qubits_idx='linear')

Add controlled Z gates.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\mathit{CZ} = |0\rangle \langle 0|\otimes I + |1\rangle \langle 1|\otimes Z\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘linear’.

Examples

qc = Circuit(2)
qc.cz([0, 1])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{Z} & {} & {}
swap(qubits_idx='linear')

Add SWAP gates.

The matrix form is:

\[\begin{split}\mathit{SWAP} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘linear’.

Examples

qc = Circuit(2)
qc.swap([0, 1])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2,style={draw=none}]{\permute{2,1}} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
cp(qubits_idx='cycle', param=None, param_sharing=False)

Add controlled P gates.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\begin{split}\mathit{CP}(\theta) = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & e^{i\theta} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

param : Tensor | float

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.cp([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{P(1.57)} & {} & {}
crx(qubits_idx='cycle', param=None, param_sharing=False)

Add controlled rotation gates about the x-axis.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\mathit{CR_X} = |0\rangle \langle 0|\otimes I + |1\rangle \langle 1|\otimes R_X\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

param : Tensor | float

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.crx([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{R_{x}(1.57)} & {} & {}
cry(qubits_idx='cycle', param=None, param_sharing=False)

Add controlled rotation gates about the y-axis.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\mathit{CR_Y} = |0\rangle \langle 0|\otimes I + |1\rangle \langle 1|\otimes R_Y\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

param : Tensor | float

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.cry([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{R_{y}(1.57)} & {} & {}
crz(qubits_idx='cycle', param=None, param_sharing=False)

Add controlled rotation gates about the z-axis.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is:

\[\mathit{CR_Z} = |0\rangle \langle 0|\otimes I + |1\rangle \langle 1|\otimes R_Z\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

param : Tensor | float

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.crz([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{R_{z}(1.57)} & {} & {}
cu(qubits_idx='cycle', param=None, param_sharing=False)

Add controlled single-qubit rotation gates.

For a 2-qubit circuit, when qubits_idx is [0, 1], the matrix form is given by a controlled-U gate.

Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

param : Tensor | float

Parameters of the gate. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.cu([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{U(1.57, ...)} & {} & {}
rxx(qubits_idx='linear', param=None, param_sharing=False)

Add RXX gates.

The matrix form is:

\[\begin{split}R_{XX}(\theta) = \begin{bmatrix} \cos\frac{\theta}{2} & 0 & 0 & -i\sin\frac{\theta}{2} \\ 0 & \cos\frac{\theta}{2} & -i\sin\frac{\theta}{2} & 0 \\ 0 & -i\sin\frac{\theta}{2} & \cos\frac{\theta}{2} & 0 \\ -i\sin\frac{\theta}{2} & 0 & 0 & \cos\frac{\theta}{2} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘linear’.

param : Tensor | float

Parameters of the gate. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.rxx([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2]{R_{xx}(1.57)} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
ryy(qubits_idx='linear', param=None, param_sharing=False)

Add RYY gates.

The matrix form is:

\[\begin{split}R_{YY}(\theta) = \begin{bmatrix} \cos\frac{\theta}{2} & 0 & 0 & i\sin\frac{\theta}{2} \\ 0 & \cos\frac{\theta}{2} & -i\sin\frac{\theta}{2} & 0 \\ 0 & -i\sin\frac{\theta}{2} & \cos\frac{\theta}{2} & 0 \\ i\sin\frac{\theta}{2} & 0 & 0 & \cos\frac{\theta}{2} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘linear’.

param : Tensor | float

Parameters of the gate. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.ryy([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2]{R_{yy}(1.57)} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
rzz(qubits_idx='linear', param=None, param_sharing=False)

Add RZZ gates.

The matrix form is:

\[\begin{split}R_{ZZ}(\theta) = \begin{bmatrix} e^{-i\theta/2} & 0 & 0 & 0 \\ 0 & e^{i\theta/2} & 0 & 0 \\ 0 & 0 & e^{i\theta/2} & 0 \\ 0 & 0 & 0 & e^{-i\theta/2} \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘linear’.

param : Tensor | float

Parameters of the gate. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

Examples

qc = Circuit(2)
qc.rzz([0, 1], torch.pi / 2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2]{R_{zz}(1.57)} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
ms(qubits_idx='linear')

Add Mølmer-Sørensen (MS) gates.

The matrix form is:

\[\begin{split}\mathit{MS} = R_{XX}(-\pi/2) = \frac{1}{\sqrt{2}} \begin{bmatrix} 1 & 0 & 0 & i \\ 0 & 1 & i & 0 \\ 0 & i & 1 & 0 \\ i & 0 & 0 & 1 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

Examples

qc = Circuit(2)
qc.ms([0, 1])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2]{\text{MS}} & \meter[2]{} & {} \\
\lstick{} & {} & {} & {}
cswap(qubits_idx='cycle')

Add CSWAP (Fredkin) gates.

The matrix form is:

\[\begin{split}\mathit{CSWAP} = \begin{bmatrix} 1 & 0 & \cdots & 0 \\ 0 & 1 & & 0 \\ \vdots & & \ddots & \vdots \\ 0 & 0 & \cdots & 1 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

Examples

qc = Circuit(3)
qc.cswap([0, 1, 2])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{1} & \meter[3]{} & {} \\
\lstick{} & \gate[2,style={draw=gray, dashed}]{\permute{2,1}} & {} & {} \\
\lstick{} & {} & {} & {}
ccx(qubits_idx='cycle')

Add CCX (Toffoli) gates.

The matrix form is:

\[\begin{split}\mathit{CCX} = \begin{bmatrix} 1 & 0 & \cdots & 0 \\ 0 & 1 & & 0 \\ \vdots & & \ddots & \vdots \\ 0 & 0 & \cdots & 1 \end{bmatrix}\end{split}\]
Parameters:
qubits_idx : Iterable[int] | str

Indices of the qubits on which the gates are applied. Defaults to ‘cycle’.

Examples

qc = Circuit(3)
qc.ccx([0, 1, 2])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \ctrl[]{2} & \meter[3]{} & {} \\
\lstick{} & \control{} & {} & {} \\
\lstick{} & \targ{} & {} & {}
universal_two_qubits(qubits_idx=None, param=None)

Add universal two-qubit gates. One such gate requires 15 parameters.

Parameters:
qubits_idx : List[int] | str

Indices of the qubits on which the gates are applied.

param : Tensor | float

Parameters of the gates. Batched input should have shape [batch_size, 15]. Single-sample input with numel == 15 is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(2)
qc.universal_two_qubits([0, 1])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a universal 2-qubit layer.)
universal_three_qubits(qubits_idx=None, param=None)

Add universal three-qubit gates. One such gate requires 81 parameters.

Parameters:
qubits_idx : List[int] | None

Indices of the qubits on which the gates are applied.

param : Tensor | float

Parameters of the gates. Batched input should have shape [batch_size, 81]. Single-sample input with numel == 81 is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(3)
qc.universal_three_qubits([0, 1, 2])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a universal 3-qubit layer.)
universal_qudits(system_idx, param=None, param_sharing=False, manifold=False, identity_init=False)

Add universal qudit gates. One such gate requires \(d^2 - 1\) parameters, where \(d\) is the gate dimension.

Parameters:
system_idx : List[int]

Indices of the systems on which the gates are applied.

param : Tensor | float

Parameters of the gates. Defaults to None.

param_sharing : bool

Whether gates in the same layer share a parameter. Defaults to False.

manifold : bool

If True, use ManifoldUniversalQudits which optimizes on the unitary manifold via Riemannian gradient descent. Defaults to False.

identity_init : bool

If True, initialize to identity matrix. Defaults to False.

Examples

qc = Circuit(1, 3)
qc.universal_qudits([0])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\operatorname{UNI}_{3}} & \meter[1]{} & {}
permute(perm, system_idx, control_idx=None)

Add a permutation gate.

Parameters:
perm : List[int]

A list representing the permutation of subsystems.

system_idx : List[int]

Indices of the systems on which the gates are applied.

control_idx : int | None

the index that controls the permutation. Defaults to None.

Examples

qc = Circuit(3)
qc.permute([1, 0, 2], [0, 1, 2])
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[3,style={draw=none}]{\permute{2,1,3}} & \meter[3]{} & {} \\
\lstick{} & {} & {} & {} \\
\lstick{} & {} & {} & {}
qft(system_idx, is_dagger=False)

Add a quantum Fourier transform (QFT) gate.

Parameters:
system_idx : List[int | List[int]] | int

Indices of the systems on which the gate is applied.

is_dagger : bool

Whether to apply the inverse QFT. Defaults to False.

oracle(oracle, system_idx, control_idx=None, gate_name=None, latex_name=None)

Add an oracle gate.

Parameters:
oracle : Tensor

Unitary oracle.

system_idx : List[int | List[int]] | int

Indices of the systems on which the gate is applied.

control_idx : int | None

the index that controls the oracle. Defaults to None.

gate_name : str | None

name of the oracle.

latex_name : str | None

LaTeX name of the gate. Defaults to gate_name.

Examples

qc = Circuit(2)
qc.oracle(oracle=eye(2), system_idx=[0], latex_name=r'$Identity$')
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{$Identity$}
control_oracle(oracle, system_idx, control_idx=-1, gate_name='coracle', latex_name=None)

Add a controlled oracle gate.

Parameters:
oracle : Tensor

Unitary oracle.

system_idx : List[int | List[int]] | int

Indices of the systems on which the gate is applied.

control_idx : int

the index that controls the oracle. Defaults to -1.

gate_name : str

name of the oracle.

latex_name : str | None

LaTeX name of the gate.

Examples

qc = Circuit(2)
qc.control_oracle(oracle=eye(2), system_idx=[0, 1], control_idx=0, latex_name=r'$Identity$')
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \octrl[]{1} & \meter[2]{} & {} \\
\lstick{} & \gate[1]{$Identity$} & {} & {}
param_oracle(generator, num_acted_param, system_idx, control_idx=None, param=None, gate_name=None, latex_name=None, support_batch=True)

Add a parameterized oracle gate.

Parameters:
generator : Callable[[Tensor], Tensor]

Function to generate the oracle.

num_acted_param : int

Number of parameters required for a single application.

system_idx : List[int | List[int]] | int

Indices of the systems on which the gate acts.

control_idx : int | None

The index that controls the oracle. Defaults to None.

param : Tensor | float

Input parameters for the gate. Defaults to None.

gate_name : str | None

Name of the oracle.

latex_name : str | None

LaTeX name of the gate.

support_batch : bool

Whether generator supports batched input.

Note

If the generator does not support batched input, you need to set support_batch to False.

Examples

def rotation_generator(params: torch.Tensor) -> torch.Tensor:
    theta = params[..., 0]
    cos_theta = torch.cos(theta / 2).unsqueeze(-1)
    sin_theta = torch.sin(theta / 2).unsqueeze(-1)
    matrix = torch.cat([
        torch.cat([cos_theta, -1j * sin_theta], dim=-1),
        torch.cat([-1j * sin_theta, cos_theta], dim=-1)
    ], dim=-2)
    return matrix

qc = Circuit(2)
qc.param_oracle(
    generator=rotation_generator,
    num_acted_param=1,
    system_idx=[0, 1],
    control_idx=0,
    param=None,
    gate_name="ControlledRotation",
    support_batch=True
)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \octrl[]{1} \\
\lstick{} & \gate[1]{ControlledRotation(0.36)}
measure(system_idx=None, post_selection=None, if_print=False, measure_basis=None)

Perform a measurement on the specified systems.

Parameters:
system_idx : Iterable[int] | int | str

Systems to measure. Defaults to all.

post_selection : int | str

The post-selection result. Defaults to None.

if_print : bool

Whether to print collapse info. Defaults to False.

measure_basis : Tensor | None

Measurement basis.

Examples

qc = Circuit(2)
qc.measure()
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \meter[2]{} & {} \\
\lstick{} & {} & {}
locc(local_unitary, system_idx, label='M', latex_name='O')

Add a one-way LOCC protocol comprised of unitary operations.

Parameters:
local_unitary : Tensor

The local unitary operation.

system_idx : List[int | List[int]] | int

Systems on which the protocol is applied. The first element indicates the measure system.

label : str

Label for measurement. Defaults to ‘M’.

latex_name : str

LaTeX name for the applied operator. Defaults to ‘O’.

Examples

qc = Circuit(2)
qc.locc(local_unitary=x(), system_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \meter{} & \push{M} \wireoverride{c} & \ctrl[vertical wire=c]{1}\wireoverride{c}  \\
\lstick{} & {} & {} & \gate[1]{O^{(M)}}
param_locc(generator, num_acted_param, system_idx, param=None, label='M', latex_name='U', support_batch=True)

Add a one-way LOCC protocol comprised of unitary operations, where the applied unitary is parameterized.

Parameters:
generator : Callable[[Tensor], Tensor]

Function to generate the oracle.

num_acted_param : int

Number of parameters required for a single application.

system_idx : List[int | List[int]] | int

Systems on which the protocol is applied. The first element indicates the measure system.

param : Tensor | float

Input parameters for the gate. Defaults to None.

label : str

Label for measurement. Defaults to ‘M’.

latex_name : str

LaTeX name for the applied operator. Defaults to ‘U’.

support_batch : bool

Whether generator supports batched input.

Note

If the generator does not support batched input, you need to set support_batch to False.

quasi(list_unitary, probability, system_idx, latex_name='\\mathcal{E}')

Add a quasi-probability operation, now only supports unitary operations.

Parameters:
list_unitary : Tensor

list of unitary operations, each of which corresponds to a probability outcome.

probability : Iterable[float]

(quasi-)probability distribution for applying unitary operations.

system_idx : List[int] | int

Systems on which the operation is applied.

latex_name : str

LaTeX name for the applied operation. Defaults to ‘mathcal{E}’.

param_quasi(generator, num_acted_param, probability, system_idx, probability_param=False, param=None, latex_name='\\mathcal{E}', support_batch=True)

Add a quasi-probability operation, where the applied unitary is parameterized.

Parameters:
generator : Callable[[Tensor], Tensor]

Function to generate the oracle.

num_acted_param : int

Number of parameters required for a single application.

probability : Iterable[float]

(quasi-)probability distribution for applying unitary operations.

probability_param : bool

Whether the probability is parameterized. Defaults to False.

system_idx : List[int] | int

Systems on which the operation is applied.

param : Tensor | float

Input parameters for the gate. Defaults to None.

latex_name : str

LaTeX name for the applied operation. Defaults to ‘mathcal{E}’.

support_batch : bool

Whether generator supports batched input.

reset(system_idx, replace_state=None, state_label=None)

Reset the state of the specified systems to a given state.

Parameters:
system_idx : List[int] | int

list of systems to be reset.

replace_state : Tensor | StateSimulator | None

the state to replace the quantum state. Defaults to zero state.

state_label : str | None

LaTeX label of the reset state, used for printing. Defaults to r’rho’ or r’ket{0}’.

linear_entangled_layer(qubits_idx=None, depth=1, param=None)

Add linear entangled layers consisting of Ry gates, Rz gates, and CNOT gates.

Parameters:
qubits_idx : List[int] | None

Systems to apply the layer on. Defaults to all.

depth : int

Number of layers. Defaults to 1.

param : Tensor | float

Parameters for the layer. Batched input should have shape [batch_size, 2 * depth * len(qubits_idx)]. Single-sample input with matching numel is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(2)
qc.linear_entangled_layer([0, 1], depth=4)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a linear entangled layer.)
real_entangled_layer(qubits_idx=None, depth=1, param=None)

Add strongly entangled layers consisting of Ry gates and CNOT gates.

Parameters:
qubits_idx : List[int] | None

Systems to apply the layer on. Defaults to all.

depth : int

Number of layers. Defaults to 1.

param : Tensor | float

Layer parameters. Batched input should have shape [batch_size, depth * len(qubits_idx)]. Single-sample input with matching numel is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(2)
qc.real_entangled_layer([0, 1], depth=4)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a real entangled layer.)
complex_entangled_layer(qubits_idx=None, depth=1, param=None)

Add strongly entangled layers consisting of single-qubit rotation gates and CNOT gates.

Parameters:
qubits_idx : List[int] | None

Systems to apply the layer on. Defaults to all.

depth : int

Number of layers. Defaults to 1.

param : Tensor | float

Layer parameters. Batched input should have shape [batch_size, 3 * depth * len(qubits_idx)]. Single-sample input with matching numel is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(2)
qc.complex_entangled_layer([0, 1], depth=4)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a complex entangled layer.)
real_block_layer(qubits_idx=None, depth=1, param=None)

Add weakly entangled layers consisting of Ry gates and CNOT gates.

Parameters:
qubits_idx : List[int] | None

Systems to apply the layer on. Defaults to all.

depth : int

Number of layers. Defaults to 1.

param : Tensor | float

Layer parameters. Batched input should have shape [batch_size, 2 * depth * (len(qubits_idx) - 1) + len(qubits_idx)]. Single-sample input with matching numel is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(2)
qc.real_block_layer([0, 1], depth=4)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a real block layer.)
complex_block_layer(qubits_idx=None, depth=1, param=None)

Add weakly entangled layers consisting of single-qubit rotation gates and CNOT gates.

Parameters:
qubits_idx : List[int] | None

Systems to apply the layer on. Defaults to all.

depth : int

Number of layers. Defaults to 1.

param : Tensor | float

Layer parameters. Batched input should have shape [batch_size, (2 * depth * (len(qubits_idx) - 1) + len(qubits_idx)) * 3]. Single-sample input with matching numel is also accepted. Legacy class-specific batched layouts are not accepted.

Examples

qc = Circuit(2)
qc.complex_block_layer([0, 1], depth=4)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
(The output latex code shows a complex block layer.)
basis_encoding(number, qubits_idx=None)

Prepares a basis encoding layer that performs \(|0\rangle^{\otimes n} \to |x\rangle\)

Parameters:
number : int | List[int] | Tensor

Integer to be encoded (must be in [0, 2**n_qubits - 1]). If batched, must be List[int], torch.Tensor.

qubits_idx : List[int] | None

Indices of the qubits on which the layer is applied. Defaults to None.

Examples

qc = Circuit(2)
qc.basis_encoding(3, [0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{X}\gategroup[2,steps=1,style={inner sep=4pt,dashed,label={above:{Basis Encoding}}}]{} \\
\lstick{} & \gate[1]{X}
amplitude_encoding(vector, qubits_idx=None)

Prepares an amplitude encoding layer that performs \(|0\rangle^{\otimes n} \to \sum_{i=0}^{d-1} x_i |i\rangle\)

Parameters:
vector : Tensor

Input normalized vector to be encoded. If batched, size must be 2^n_qubits * batch_size

qubits_idx : List[int] | None

Indices of the qubits on which the encoding is applied. Defaults to None.

Examples

qc = Circuit(2)
vec = torch.tensor([1.0, 0.0, 0.0, 0.0])
qc.amplitude_encoding(vec, [0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2]{\text{Amplitude Encoding}}\gategroup[2,steps=1,style={inner sep=4pt,dashed,label={above:{Amplitude Encoding}}}]{} \\
\lstick{} & {}
angle_encoding(angles, qubits_idx=None, rotation='RY')

Prepares an angle encoding layer that encode angles via rotation gates.

Parameters:
angles : Tensor

Input vector of angles. If batched, size must be num_qubits * batch_size

qubits_idx : List[int] | None

Indices of the qubits on which the encoding is applied. Defaults to None.

rotation : str

Type of rotation gate (‘RY’, ‘RZ’, or ‘RX’).

Examples

qc = Circuit(2)
angles = torch.tensor([0.5, 1.0])
qc.angle_encoding(angles, [0, 1], rotation='RY')
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{R_{y}(0.50)}\gategroup[2,steps=1,style={inner sep=4pt,dashed,label={above:{Angle Encoding}}}]{} \\
\lstick{} & \gate[1]{R_{y}(1.00)}
iqp_encoding(features, set_entanglement, qubits_idx=None, depth=1)

Prepares an instantaneous quantum polynomial (IQP) layer that encode angles via a type of rotation gates.

Parameters:
features : Tensor

Input vector for encoding. If batched, size must be num_qubits * batch_size

set_entanglement : List[List[int]]

the set containing all pairs of qubits to be entangled using RZZ gates

qubits_idx : List[int] | None

Indices of the qubits on which the encoding is applied. Defaults to None.

depth : int

Number of depth. Defaults to 1.

Examples

qc = Circuit(3)
features = torch.tensor([0.1, 0.2, 0.3])
entanglement = [[0, 1], [1, 2]]
qc.iqp_encoding(features, entanglement, [0, 1, 2], depth=1)
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{H}\gategroup[3,steps=8,style={inner sep=4pt,dashed,label={above:{IQP Encoding}}}]{} & \gate[1]{R_{z}(0.10)} & \ctrl[]{1} & {} & \ctrl[]{1} & {} & {} & {} \\
\lstick{} & \gate[1]{H} & \gate[1]{R_{z}(0.20)} & \targ{} & \gate[1]{R_{z}(0.02)} & \targ{} & \ctrl[]{1} & {} & \ctrl[]{1} \\
\lstick{} & \gate[1]{H} & \gate[1]{R_{z}(0.30)} & {} & {} & {} & \targ{} & \gate[1]{R_{z}(0.06)} & \targ{}
trotter(hamiltonian, time, qubits_idx=None, num_steps=1, order=1, name='H')

Add Trotter decompositions of a Hamiltonian evolution operator.

Parameters:
hamiltonian : Hamiltonian

Hamiltonian of the system whose time evolution is to be simulated.

time : float

Total evolution time.

qubits_idx : List[int] | None

Indices of the qubits on which the layer is applied. Defaults to None.

num_steps : int

Number of trotter blocks. Defaults to 1.

order : int

Order of the Trotter-Suzuki decomposition. Defaults to 1.

name : str

Name of the Hamiltonian. Defaults to ‘H’.

bit_flip(prob, qubits_idx='full')

Add bit flip channels.

Parameters:
prob : Tensor | float

Probability of a bit flip.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.bit_flip(prob=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{E}_{p = 0.5}^{\textrm{\tiny{(BF)}}}} \\
\lstick{} & \gate[1]{\mathcal{E}_{p = 0.5}^{\textrm{\tiny{(BF)}}}}
phase_flip(prob, qubits_idx='full')

Add phase flip channels.

Parameters:
prob : Tensor | float

Probability of a phase flip.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.phase_flip(prob=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{E}_{p = 0.5}^{\textrm{\tiny{(PF)}}}} \\
\lstick{} & \gate[1]{\mathcal{E}_{p = 0.5}^{\textrm{\tiny{(PF)}}}}
bit_phase_flip(prob, qubits_idx='full')

Add bit phase flip channels.

Parameters:
prob : Tensor | float

Probability of a bit phase flip.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.bit_phase_flip(prob=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{E}_{p = 0.5}^{\textrm{\tiny{(BPF)}}}} \\
\lstick{} & \gate[1]{\mathcal{E}_{p = 0.5}^{\textrm{\tiny{(BPF)}}}}
amplitude_damping(gamma, qubits_idx='full')

Add amplitude damping channels.

Parameters:
gamma : Tensor | float

Damping probability.

qubits_idx : Iterable[int] | int | str

Systems to apply the damping on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.amplitude_damping(gamma=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{E}_{\gamma = 0.5}^{\textrm{\tiny{(AD)}}}} \\
\lstick{} & \gate[1]{\mathcal{E}_{\gamma = 0.5}^{\textrm{\tiny{(AD)}}}}
generalized_amplitude_damping(gamma, prob, qubits_idx='full')

Add generalized amplitude damping channels.

Parameters:
gamma : Tensor | float

Damping probability.

prob : Tensor | float

Excitation probability.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.generalized_amplitude_damping(gamma=0.5, prob=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{E}_{\gamma = 0.5, p = 0.5}^{\textrm{\tiny{(GAD)}}}} \\
\lstick{} & \gate[1]{\mathcal{E}_{\gamma = 0.5, p = 0.5}^{\textrm{\tiny{(GAD)}}}}
phase_damping(gamma, qubits_idx='full')

Add phase damping channels.

Parameters:
gamma : Tensor | float

Phase damping parameter.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.phase_damping(gamma=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{E}_{\gamma = 0.5}^{\textrm{\tiny{(PD)}}}} \\
\lstick{} & \gate[1]{\mathcal{E}_{\gamma = 0.5}^{\textrm{\tiny{(PD)}}}}
depolarizing(prob, qubits_idx='full')

Add depolarizing channels.

Parameters:
prob : Tensor | float

Depolarizing probability.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.depolarizing(prob=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{D}_{p = 0.5}} \\
\lstick{} & \gate[1]{\mathcal{D}_{p = 0.5}}
generalized_depolarizing(prob, qubits_idx)

Add a general depolarizing channel.

Parameters:
prob : Tensor | float

Probabilities for the Pauli basis.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on.

Examples

qc = Circuit(2)
qc.generalized_depolarizing(prob=0.5, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[2]{\mathcal{D}_{p = 0.5}} \\
\lstick{} & {}
pauli_channel(prob, qubits_idx='full')

Add Pauli channels.

Parameters:
prob : Tensor | float

Probabilities for the Pauli X, Y, and Z operators.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.pauli_channel(prob=[0.1, 0.3, 0.5])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{N}} \\
\lstick{} & \gate[1]{\mathcal{N}}
reset_channel(prob, qubits_idx='full')

Add reset channels.

Parameters:
prob : Tensor | float

Probabilities for resetting to the basis states.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.reset_channel(prob=[0.5, 0.4], qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{N}} \\
\lstick{} & \gate[1]{\mathcal{N}}
thermal_relaxation(const_t, exec_time, qubits_idx='full')

Add thermal relaxation channels.

Parameters:
const_t : Tensor | Iterable[float]

The T1 and T2 relaxation times.

exec_time : Tensor | float

Gate execution time.

qubits_idx : Iterable[int] | int | str

Systems to apply the channel on. Defaults to ‘full’.

Examples

qc = Circuit(2)
qc.thermal_relaxation(const_t=[600, 300], exec_time=500, qubits_idx=[0, 1])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{N}} \\
\lstick{} & \gate[1]{\mathcal{N}}
choi_channel(choi_repr, system_idx, check_legality=True)

Add custom channels in the Choi representation.

Parameters:
choi_repr : Iterable[Tensor]

Choi representation.

system_idx : Iterable[Iterable[int]] | Iterable[int] | int

Systems to apply the channel on.

check_legality : bool

whether to check the legality of the input Choi operator. Defaults to True.

Examples

qc = Circuit(2)
X = torch.tensor(x(), dtype=torch.complex64)
choi = X.kron(X) / 2
qc.choi_channel(choi_repr=choi, system_idx=[0])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{N}}
kraus_channel(kraus_repr, system_idx, check_legality=True)

Add custom channels in the Kraus representation.

Parameters:
kraus_repr : Iterable[Tensor]

Kraus operators.

system_idx : Iterable[Iterable[int]] | Iterable[int] | int

Systems to apply the channel on.

check_legality : bool

whether to check the legality of the input representation. Defaults to True.

Examples

qc = Circuit(2)
qc.kraus_channel(kraus_repr=eye(2), system_idx=[0])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{N}}
stinespring_channel(stinespring_repr, system_idx, check_legality=True)

Add custom channels in the Stinespring representation.

Parameters:
stinespring_repr : Iterable[Tensor]

Stinespring representation.

system_idx : Iterable[Iterable[int]] | Iterable[int] | int

Systems to apply the channel on.

check_legality : bool

whether to check the legality of the input representation. Defaults to True.

Examples

qc = Circuit(2)
qc.stinespring_channel(stinespring_repr=eye(2), system_idx=[0])
print(f'The latex code of this circuit is:\n{qc.to_latex()}')
The latex code of this circuit is:
\lstick{} & \gate[1]{\mathcal{N}}
classmethod from_operators(list_operators)

Reconstruct a Circuit from a saved operator_history (same format as OperatorList.operator_history). Do not support daggered list_operators.

Parameters:
list_operators : List[OperatorInfoType]

operator_history list (or nested lists).

Returns:

a Circuit instance with the same sequence of operations.

Return type:

Circuit

Note

This function assumes all systems are qubits.

classmethod from_qasm2(qasm)

Reconstruct a Circuit from a QASM2 string.

Parameters:
qasm : str

A complete OpenQASM 2.0 string representing a circuit.

Returns:

a Circuit instance with the same sequence of operations.

Raises:
  • ValueError – if the program header is missing or does not include “qelib1.inc”, or malformed ops.

  • NotImplementedError – if the program contains gate/opaque definitions or classically conditioned “if”.

Return type:

Circuit

Note

commands such as “barrier”, “creg” are ignored. Multiple quantum registers are merged by order of definition. The circuit is assumed to be composed of qubits only.