tensorcircuit.symbolcircuit

SymbolCircuit: symbolic parameterized quantum circuit.

Gate parameters are sympy Symbols (or expressions). Amplitude and expectation values are computed via tensor network contraction of numpy object arrays, producing sympy expressions. The class also supports translation to a Qiskit QuantumCircuit with Parameter objects for hardware compilation reuse.

Key design: inherit from Circuit, override gate registration to use symbolic factories from symbolgates.py instead of the standard backend-coupled ones, and override the handful of computation methods that call backend.* on tensor values.

class tensorcircuit.symbolcircuit.SymbolCircuit(nqubits: int, inputs: Any | None = None, mps_inputs: Any | None = None, tensors: Any | None = None, split: Dict[str, Any] | None = None, dim: int | None = None)[source]

Bases: Circuit

Quantum circuit with symbolic (sympy) gate parameters.

Gate parameters are sympy.Symbol objects (or sympy expressions). Amplitude and expectation values return sympy expressions via tensor network contraction. The circuit can be translated to a Qiskit QuantumCircuit with Parameter objects for hardware reuse.

Backend isolationSymbolCircuit is permanently fixed to the numpy backend regardless of any global backend setting. Calling tc.set_backend("jax") (or "tensorflow", "torch", etc.) before or after constructing a SymbolCircuit has no effect on its internal computation. This is by design: the class represents all state vectors and gate matrices as numpy.ndarray with dtype=object, whose entries are sympy expressions. The methods amplitude, wavefunction, and expectation / expectation_before are all overridden to use plain NumPy operations instead of tc.backend.* calls, so they never touch the active backend.

The isolation ends at to_circuit(): the returned Circuit is a standard numerical circuit that does respect the global backend setting at the time it is called.

Example:

import sympy
import tensorcircuit as tc

theta = sympy.Symbol("theta", real=True)

sc = tc.SymbolCircuit(2)
sc.h(0)
sc.rx(1, theta=theta)
sc.cnot(0, 1)

# symbolic expectation — always numpy / sympy, unaffected by set_backend
expr = sc.expectation_ps(z=[0, 1])
print(sympy.simplify(expr))

# bind symbols → standard Circuit that uses the active backend
c = sc.to_circuit({theta: 0.5})

# Qiskit PQC for hardware
qc = sc.to_qiskit()
print(qc.parameters)
ANY(*index: int, **vars: Any) None

Apply ANY gate with parameters on the circuit. See tensorcircuit.gates.any_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CMZ(*index: int, **vars: Any) None

Apply cmz gate on the circuit using hyperedge support for digonal gates. See tensorcircuit.gates.cmz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CNOT(*index: int, **kws: Any) None

Apply CNOT gate on the circuit. See tensorcircuit.gates.cnot_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

CPHASE(*index: int, **vars: Any) None

Apply CPHASE gate with parameters on the circuit. See tensorcircuit.gates.cphase_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CR(*index: int, **vars: Any) None

Apply CR gate with parameters on the circuit. See tensorcircuit.gates.cr_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CRX(*index: int, **vars: Any) None

Apply CRX gate with parameters on the circuit. See tensorcircuit.gates.crx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CRY(*index: int, **vars: Any) None

Apply CRY gate with parameters on the circuit. See tensorcircuit.gates.cry_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CRZ(*index: int, **vars: Any) None

Apply CRZ gate with parameters on the circuit. See tensorcircuit.gates.crz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CU(*index: int, **vars: Any) None

Apply CU gate with parameters on the circuit. See tensorcircuit.gates.cu_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

CY(*index: int, **kws: Any) None

Apply CY gate on the circuit. See tensorcircuit.gates.cy_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.-1.j\\ 0.+0.j & 0.+0.j & 0.+1.j & 0.+0.j \end{bmatrix}\end{split}\]

CZ(*index: int, **kws: Any) None

Apply CZ gate on the circuit. See tensorcircuit.gates.cz_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & -1.+0.j \end{bmatrix}\end{split}\]

DIAGONAL(*index: int, **vars: Any) None

Apply diagonal gate on the circuit using hyperedge support for digonal gates. See tensorcircuit.gates.diagonal_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

EXP(*index: int, **vars: Any) None

Apply EXP gate with parameters on the circuit. See tensorcircuit.gates.exp_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

EXP1(*index: int, **vars: Any) None

Apply EXP1 gate with parameters on the circuit. See tensorcircuit.gates.exp1_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

FREDKIN(*index: int, **kws: Any) None

Apply FREDKIN gate on the circuit. See tensorcircuit.gates.fredkin_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

H(*index: int, **kws: Any) None

Apply H gate on the circuit. See tensorcircuit.gates.h_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.70710677+0.j & 0.70710677+0.j\\ 0.70710677+0.j & -0.70710677+0.j \end{bmatrix}\end{split}\]

I(*index: int, **kws: Any) None

Apply I gate on the circuit. See tensorcircuit.gates.i_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

ISWAP(*index: int, **vars: Any) None

Apply ISWAP gate with parameters on the circuit. See tensorcircuit.gates.iswap_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

MPO(*index: int, **vars: Any) None

Apply mpo gate in MPO format on the circuit. See tensorcircuit.gates.mpo_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

MULTICONTROL(*index: int, **vars: Any) None

Apply multicontrol gate in MPO format on the circuit. See tensorcircuit.gates.multicontrol_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

ORX(*index: int, **vars: Any) None

Apply ORX gate with parameters on the circuit. See tensorcircuit.gates.orx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

ORY(*index: int, **vars: Any) None

Apply ORY gate with parameters on the circuit. See tensorcircuit.gates.ory_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

ORZ(*index: int, **vars: Any) None

Apply ORZ gate with parameters on the circuit. See tensorcircuit.gates.orz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

OX(*index: int, **kws: Any) None

Apply OX gate on the circuit. See tensorcircuit.gates.ox_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

OY(*index: int, **kws: Any) None

Apply OY gate on the circuit. See tensorcircuit.gates.oy_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 0.-1.j & 0.+0.j & 0.+0.j\\ 0.+1.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

OZ(*index: int, **kws: Any) None

Apply OZ gate on the circuit. See tensorcircuit.gates.oz_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & -1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

PHASE(*index: int, **vars: Any) None

Apply PHASE gate with parameters on the circuit. See tensorcircuit.gates.phase_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

R(*index: int, **vars: Any) None

Apply R gate with parameters on the circuit. See tensorcircuit.gates.r_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RX(*index: int, **vars: Any) None

Apply RX gate with parameters on the circuit. See tensorcircuit.gates.rx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RXX(*index: int, **vars: Any) None

Apply RXX gate with parameters on the circuit. See tensorcircuit.gates.rxx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RY(*index: int, **vars: Any) None

Apply RY gate with parameters on the circuit. See tensorcircuit.gates.ry_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RYY(*index: int, **vars: Any) None

Apply RYY gate with parameters on the circuit. See tensorcircuit.gates.ryy_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RZ(*index: int, **vars: Any) None

Apply RZ gate with parameters on the circuit. See tensorcircuit.gates.rz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RZM(*index: int, **vars: Any) None

Apply rzm gate on the circuit using hyperedge support for digonal gates. See tensorcircuit.gates.rzm_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

RZZ(*index: int, **vars: Any) None

Apply RZZ gate with parameters on the circuit. See tensorcircuit.gates.rzz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

S(*index: int, **kws: Any) None

Apply S gate on the circuit. See tensorcircuit.gates.s_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+1.j \end{bmatrix}\end{split}\]

SD(*index: int, **kws: Any) None

Apply SD gate on the circuit. See tensorcircuit.gates.sd_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 0.-1.j \end{bmatrix}\end{split}\]

SU4(*index: int, **vars: Any) None

Apply SU4 gate with parameters on the circuit. See tensorcircuit.gates.su4_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

SWAP(*index: int, **kws: Any) None

Apply SWAP gate on the circuit. See tensorcircuit.gates.swap_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

T(*index: int, **kws: Any) None

Apply T gate on the circuit. See tensorcircuit.gates.t_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1. & +0.j & 0. & +0.j\\ 0. & +0.j & 0.70710677+0.70710677j \end{bmatrix}\end{split}\]

TD(*index: int, **kws: Any) None

Apply TD gate on the circuit. See tensorcircuit.gates.td_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1. & +0.j & 0. & +0.j\\ 0. & +0.j & 0.70710677-0.70710677j \end{bmatrix}\end{split}\]

TOFFOLI(*index: int, **kws: Any) None

Apply TOFFOLI gate on the circuit. See tensorcircuit.gates.toffoli_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

U(*index: int, **vars: Any) None

Apply U gate with parameters on the circuit. See tensorcircuit.gates.u_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

WROOT(*index: int, **kws: Any) None

Apply WROOT gate on the circuit. See tensorcircuit.gates.wroot_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.70710677+0.j & -0.5 & -0.5j\\ 0.5 & -0.5j & 0.70710677+0.j \end{bmatrix}\end{split}\]

X(*index: int, **kws: Any) None

Apply X gate on the circuit. See tensorcircuit.gates.x_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 1.+0.j\\ 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

Y(*index: int, **kws: Any) None

Apply Y gate on the circuit. See tensorcircuit.gates.y_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 0.-1.j\\ 0.+1.j & 0.+0.j \end{bmatrix}\end{split}\]

Z(*index: int, **kws: Any) None

Apply Z gate on the circuit. See tensorcircuit.gates.z_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & -1.+0.j \end{bmatrix}\end{split}\]

__init__(nqubits: int, inputs: Any | None = None, mps_inputs: Any | None = None, tensors: Any | None = None, split: Dict[str, Any] | None = None, dim: int | None = None) None[source]

Initialize a SymbolCircuit with nqubits qubits.

The initial state is \(|0\rangle^{\otimes n}\) represented as numpy object-dtype tensor network nodes (compatible with sympy).

Parameters:

nqubits (int) – Number of qubits.

static all_zero_nodes(n: int, prefix: str = 'qb-', dim: int = 2) List[Node]
amplitude(l: str | Sequence[int]) Any[source]

Compute \(\langle l \vert \psi \rangle\) symbolically.

Parameters:

l (Union[str, Sequence[int]]) – Bitstring as a string (e.g. "01") or sequence of ints.

Returns:

Sympy expression for the amplitude.

Return type:

sympy expression

amplitude_before(l: str | Any) List[Gate]

Returns the tensornetwor nodes for the amplitude of the circuit given the bitstring l. For state simulator, it computes \(\langle l\vert \psi\rangle\), for density matrix simulator, it computes \(Tr(\rho \vert l\rangle \langle 1\vert)\) Note how these two are different up to a square operation.

Parameters:

l (Union[str, Tensor]) – The bitstring of 0 and 1s.

Returns:

The tensornetwork nodes for the amplitude of the circuit.

Return type:

List[Gate]

amplitudedamping(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply amplitudedamping quantum channel on the circuit. See tensorcircuit.channels.amplitudedampingchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

any(*index: int, **vars: Any) None

Apply ANY gate with parameters on the circuit. See tensorcircuit.gates.any_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

append(c: AbstractCircuit, indices: List[int] | None = None) AbstractCircuit

append circuit c before

Example:

>>> c1 = tc.Circuit(2)
>>> c1.H(0)
>>> c1.H(1)
>>> c2 = tc.Circuit(2)
>>> c2.cnot(0, 1)
>>> c1.append(c2)
<tensorcircuit.circuit.Circuit object at 0x7f8402968970>
>>> c1.draw()
    ┌───┐
q_0:┤ H ├──■──
    ├───┤┌─┴─┐
q_1:┤ H ├┤ X ├
    └───┘└───┘
Parameters:
  • c (BaseCircuit) – The other circuit to be appended

  • indices (Optional[List[int]], optional) – the qubit indices to which c is appended on. Defaults to None, which means plain concatenation.

Returns:

The composed circuit

Return type:

BaseCircuit

append_from_qir(qir: List[Dict[str, Any]], allow_channel: bool = False) None

Apply the ciurict in form of quantum intermediate representation after the current cirucit.

Example:

>>> c = tc.Circuit(3)
>>> c.H(0)
>>> c.to_qir()
[{'gatef': h, 'gate': Gate(...), 'index': (0,), 'name': 'h', 'split': None, 'mpo': False}]
>>> c2 = tc.Circuit(3)
>>> c2.CNOT(0, 1)
>>> c2.to_qir()
[{'gatef': cnot, 'gate': Gate(...), 'index': (0, 1), 'name': 'cnot', 'split': None, 'mpo': False}]
>>> c.append_from_qir(c2.to_qir())
>>> c.to_qir()
[{'gatef': h, 'gate': Gate(...), 'index': (0,), 'name': 'h', 'split': None, 'mpo': False},
 {'gatef': cnot, 'gate': Gate(...), 'index': (0, 1), 'name': 'cnot', 'split': None, 'mpo': False}]
Parameters:
  • qir (List[Dict[str, Any]]) – The quantum intermediate representation.

  • allow_channel (bool, optional) – whether to allow channel in the qir, defaults to False

apply(gate: Gate | QuOperator, *index: int, name: str | None = None, split: Dict[str, Any] | None = None, mpo: bool = False, diagonal: bool = False, ir_dict: Dict[str, Any] | None = None) None

An implementation of this method should also append gate directionary to self._qir

apply_general_gate(gate: Gate | QuOperator, *index: int, name: str | None = None, split: Dict[str, Any] | None = None, mpo: bool = False, diagonal: bool = False, ir_dict: Dict[str, Any] | None = None) None[source]

Override for backend isolation.

static apply_general_gate_delayed(gatef: Callable[[...], Any], name: str | None = None, mpo: bool = False) Callable[[...], None][source]

Override for fixed gates: use symbolic gate factory instead of the backend-coupled gatef() call.

apply_general_kraus(kraus: Sequence[Gate], *index: int, status: float | None = None, with_prob: bool = False, name: str | None = None) Any

Monte Carlo trajectory simulation of general Kraus channel whose Kraus operators cannot be amplified to unitary operators. For unitary operators composed Kraus channel, unitary_kraus() is much faster.

This function is jittable in theory. But only jax+GPU combination is recommended for jit since the graph building time is too long for other backend options; though the running time of the function is very fast for every case.

Parameters:
  • kraus (Sequence[Gate]) – A list of tn.Node for Kraus operators.

  • index (int) – The qubits index that Kraus channel is applied on.

  • status (Optional[float], optional) – Random tensor uniformly between 0 or 1, defaults to be None, when the random number will be generated automatically

static apply_general_kraus_delayed(krausf: Callable[[...], Sequence[Gate]], is_unitary: bool = False) Callable[[...], None]
static apply_general_variable_gate_delayed(gatef: Callable[[...], Any], name: str | None = None, mpo: bool = False, diagonal: bool = False) Callable[[...], None][source]

Override for variable gates: use symbolic gate factory (sympy cos/sin) instead of the backend-coupled gatef(**vars) call.

barrier_instruction(*index: List[int]) None

add a barrier instruction flag, no effect on numerical simulation

Parameters:

index (List[int]) – the corresponding qubits

bind(param_dict: Dict[Symbol, Any]) SymbolCircuit[source]

Return a new SymbolCircuit with some or all parameters substituted (partial or full binding).

Parameters:

param_dict (Dict[sympy.Symbol, Any]) – Mapping from sympy Symbol to value (numeric or another sympy expression).

Returns:

New SymbolCircuit with substituted parameters.

Return type:

SymbolCircuit

ccnot(*index: int, **kws: Any) None

Apply TOFFOLI gate on the circuit. See tensorcircuit.gates.toffoli_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

ccx(*index: int, **kws: Any) None

Apply TOFFOLI gate on the circuit. See tensorcircuit.gates.toffoli_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

circuit_param: Dict[str, Any]
cmz(*index: int, **vars: Any) None

Apply cmz gate on the circuit using hyperedge support for digonal gates. See tensorcircuit.gates.cmz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

cnot(*index: int, **kws: Any) None

Apply CNOT gate on the circuit. See tensorcircuit.gates.cnot_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

static coloring_copied_nodes(nodes: Sequence[Node], nodes0: Sequence[Node], is_dagger: bool = True, flag: str = 'inputs') None

Tag copied nodes while preserving the original node’s identity for lightcone cancellation.

Parameters:
  • nodes (Sequence[tn.Node]) – A sequence of newly copied nodes.

  • nodes0 (Sequence[tn.Node]) – The sequence of original nodes from which nodes were copied.

  • is_dagger (bool, optional) – Whether the copied nodes represent conjugate operations, defaults to True.

  • flag (str, optional) – A label for the node type, defaults to “inputs”.

static coloring_nodes(nodes: Sequence[Node], is_dagger: bool = False, flag: str = 'inputs') None

Tag nodes with metadata used for casual lightcone simplification and tracing.

Parameters:
  • nodes (Sequence[tn.Node]) – A sequence of tensornetwork nodes to tag.

  • is_dagger (bool, optional) – Whether the nodes represent conjugate operations (U^dagger), defaults to False.

  • flag (str, optional) – A label for the node type (e.g., “gate”, “inputs”, “operator”), defaults to “inputs”.

cond_measure(*args: Any, **kwargs: Any) Any

Overridden to provide better error message for symbolic circuits.

cond_measurement(*args: Any, **kwargs: Any) Any[source]

Overridden to provide better error message for symbolic circuits.

conditional_gate(which: Any, kraus: Sequence[Gate], *index: int) None

Apply which-th gate from kraus list, i.e. apply kraus[which]

Parameters:
  • which (Tensor) – Tensor of shape [] and dtype int

  • kraus (Sequence[Gate]) – A list of gate in the form of tc.gate or Tensor

  • index (int) – the qubit lines the gate applied on

copy() AbstractCircuit
static copy_nodes(nodes: Sequence[Node], dangling: Sequence[Edge] | None = None, conj: bool | None = False) Tuple[List[Node], List[Edge]]

copy all nodes and dangling edges correspondingly

Returns:

cphase(*index: int, **vars: Any) None

Apply CPHASE gate with parameters on the circuit. See tensorcircuit.gates.cphase_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

cr(*index: int, **vars: Any) None

Apply CR gate with parameters on the circuit. See tensorcircuit.gates.cr_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

crx(*index: int, **vars: Any) None

Apply CRX gate with parameters on the circuit. See tensorcircuit.gates.crx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

cry(*index: int, **vars: Any) None

Apply CRY gate with parameters on the circuit. See tensorcircuit.gates.cry_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

crz(*index: int, **vars: Any) None

Apply CRZ gate with parameters on the circuit. See tensorcircuit.gates.crz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

cswap(*index: int, **kws: Any) None

Apply FREDKIN gate on the circuit. See tensorcircuit.gates.fredkin_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

cu(*index: int, **vars: Any) None

Apply CU gate with parameters on the circuit. See tensorcircuit.gates.cu_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

cx(*index: int, **kws: Any) None

Apply CNOT gate on the circuit. See tensorcircuit.gates.cnot_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

cy(*index: int, **kws: Any) None

Apply CY gate on the circuit. See tensorcircuit.gates.cy_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.-1.j\\ 0.+0.j & 0.+0.j & 0.+1.j & 0.+0.j \end{bmatrix}\end{split}\]

cz(*index: int, **kws: Any) None

Apply CZ gate on the circuit. See tensorcircuit.gates.cz_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & -1.+0.j \end{bmatrix}\end{split}\]

depolarizing(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply depolarizing quantum channel on the circuit. See tensorcircuit.channels.depolarizingchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

depolarizing2(index: int, *, px: float, py: float, pz: float, status: float | None = None) float

Apply a depolarizing channel to the circuit in a Monte Carlo way. For each call, one of the Pauli gates (X, Y, Z) or an Identity gate is applied to the qubit at the given index based on the probabilities px, py, and pz.

Parameters:
  • index (int) – The index of the qubit to apply the depolarizing channel on.

  • px (float) – The probability of applying an X gate.

  • py (float) – The probability of applying a Y gate.

  • pz (float) – The probability of applying a Z gate.

  • status (Optional[float], optional) – A random number between 0 and 1 to determine which gate to apply. If None, a random number is generated automatically. Defaults to None.

Returns:

Returns 0.0. The function modifies the circuit in place.

Return type:

float

depolarizing2_instruction(q1: int, q2: int, p: float, **kws: Any) None

add a 2-qubit depolarizing instruction flag, no effect on numerical simulation

depolarizing_instruction(q: int, px: float | None = None, py: float | None = None, pz: float | None = None, **kws: Any) None

add a depolarizing instruction flag, no effect on numerical simulation

depolarizing_reference(index: int, *, px: float, py: float, pz: float, status: float | None = None) Any

Apply depolarizing channel in a Monte Carlo way, i.e. for each call of this method, one of gates from X, Y, Z, I are applied on the circuit based on the probability indicated by px, py, pz.

Parameters:
  • index (int) – The qubit that depolarizing channel is on

  • px (float) – probability for X noise

  • py (float) – probability for Y noise

  • pz (float) – probability for Z noise

  • status (Optional[float], optional) – random seed uniformly from 0 to 1, defaults to None (generated implicitly)

Returns:

int Tensor, the element lookup: [0: x, 1: y, 2: z, 3: I]

Return type:

Tensor

detector_instruction(lookback_indices: Sequence[int], coords: Sequence[float] | None = None, **kws: Any) None

add a detector instruction flag, no effect on numerical simulation

Parameters:

lookback_indices (Sequence[int]) – the corresponding measurement record indices

detector_probabilities() Any

Calculate the joint probability distribution of all detectors in the circuit.

Returns:

A tensor representing the joint probability distribution.

Return type:

Tensor

diaggates = ['diagonal', 'rzm', 'cmz']
diagonal(*index: int, **vars: Any) None

Apply diagonal gate on the circuit using hyperedge support for digonal gates. See tensorcircuit.gates.diagonal_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

draw(**kws: Any) Any

Visualise the circuit. This method recevies the keywords as same as qiskit.circuit.QuantumCircuit.draw. More details can be found here: https://qiskit.org/documentation/stubs/qiskit.circuit.QuantumCircuit.draw.html. Interesting kws options include: ``idle_wires``(bool)

Example:

>>> c = tc.Circuit(3)
>>> c.H(1)
>>> c.X(2)
>>> c.CNOT(0, 1)
>>> c.draw(output='text')
q_0: ───────■──
     ┌───┐┌─┴─┐
q_1: ┤ H ├┤ X ├
     ├───┤└───┘
q_2: ┤ X ├─────
     └───┘
exp(*index: int, **vars: Any) None

Apply EXP gate with parameters on the circuit. See tensorcircuit.gates.exp_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

exp1(*index: int, **vars: Any) None

Apply EXP1 gate with parameters on the circuit. See tensorcircuit.gates.exp1_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

expectation(*ops: Tuple[Any, List[int]], reuse: bool = True, enable_lightcone: bool = False, **kws: Any) Any[source]

Compute \(\langle \psi | O | \psi \rangle\) symbolically.

Parameters:
  • ops (Tuple[operator, List[int]]) – Pairs of (operator, qubit_indices). The operator may be a Gate, a tn.Node, or a plain numpy array. Symbolic (object-dtype) operators are supported.

  • reuse (bool) – Cache the contracted state vector for repeated calls, defaults to True.

  • enable_lightcone (bool) – whether enable light cone simplification, defaults to False

Returns:

Sympy expression for the expectation value.

expectation_before(*ops: Tuple[Any, List[int]], reuse: bool = True, **kws: Any) List[Node][source]

Build the tensor network for <psi|O|psi> without contracting.

Operators may be: * A Gate / tn.Node (numerical or symbolic tensor) * A plain np.ndarray

All operator tensors are converted to numpy dtype=object for compatibility with the symbolic state tensor.

expectation_ps(x: Sequence[int] | None = None, y: Sequence[int] | None = None, z: Sequence[int] | None = None, ps: Sequence[int] | None = None, reuse: bool = True, noise_conf: Any | None = None, nmc: int = 1000, status: Any | None = None, **kws: Any) Any

Shortcut for Pauli string expectation. x, y, z list are for X, Y, Z positions

Example:

>>> c = tc.Circuit(2)
>>> c.X(0)
>>> c.H(1)
>>> c.expectation_ps(x=[1], z=[0])
array(-0.99999994+0.j, dtype=complex64)
>>> c = tc.Circuit(2)
>>> c.cnot(0, 1)
>>> c.rx(0, theta=0.4)
>>> c.rx(1, theta=0.8)
>>> c.h(0)
>>> c.h(1)
>>> error1 = tc.channels.generaldepolarizingchannel(0.1, 1)
>>> error2 = tc.channels.generaldepolarizingchannel(0.06, 2)
>>> noise_conf = NoiseConf()
>>> noise_conf.add_noise("rx", error1)
>>> noise_conf.add_noise("cnot", [error2], [[0, 1]])
>>> c.expectation_ps(x=[0], noise_conf=noise_conf, nmc=10000)
(0.46274087-3.764033e-09j)
Parameters:
  • x (Optional[Sequence[int]], optional) – sites to apply X gate, defaults to None

  • y (Optional[Sequence[int]], optional) – sites to apply Y gate, defaults to None

  • z (Optional[Sequence[int]], optional) – sites to apply Z gate, defaults to None

  • ps (Optional[Sequence[int]], optional) – or one can apply a ps structures instead of x, y, z, e.g. [0, 1, 3, 0, 2, 2] for X_1Z_2Y_4Y_5 defaults to None, ps can overwrite x, y and z

  • reuse (bool, optional) – whether to cache and reuse the wavefunction, defaults to True

  • noise_conf (Optional[NoiseConf], optional) – Noise Configuration, defaults to None

  • nmc (int, optional) – repetition time for Monte Carlo sampling for noisfy calculation, defaults to 1000

  • status (Optional[Tensor], optional) – external randomness given by tensor uniformly from [0, 1], defaults to None, used for noisfy circuit sampling

Returns:

Expectation value

Return type:

Tensor

fredkin(*index: int, **kws: Any) None

Apply FREDKIN gate on the circuit. See tensorcircuit.gates.fredkin_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

free_symbols() Set[Symbol][source]

Return the set of all free sympy Symbols used as gate parameters.

Returns:

Set of sympy Symbols.

Return type:

Set[sympy.Symbol]

classmethod from_cirq(qc: Any, n: int | None = None, inputs: List[float] | None = None, circuit_params: Dict[str, Any] | None = None) AbstractCircuit

Import Cirq Circuit object as a tc.Circuit object.

Example:

>>> import cirq
>>> c = cirq.Circuit()
>>> q = cirq.LineQubit.range(3)
>>> c.append(cirq.H(q[0]))
>>> c.append(cirq.CNOT(q[0], q[1]))
>>> tc_c = tc.Circuit.from_cirq(c)
Parameters:
  • qc (cirq.Circuit) – Cirq Circuit object

  • n (int) – The number of qubits for the circuit

  • inputs (Optional[List[float]], optional) – possible input wavefunction for tc.Circuit, defaults to None

  • circuit_params (Optional[Dict[str, Any]]) – kwargs given in Circuit.__init__ construction function, default to None.

Returns:

The same circuit but as tensorcircuit object

Return type:

Circuit

classmethod from_json(jsonstr: str, circuit_params: Dict[str, Any] | None = None) AbstractCircuit

load json str as a Circuit

Parameters:
  • jsonstr (str) – _description_

  • circuit_params (Optional[Dict[str, Any]], optional) – Extra circuit parameters in the format of __init__, defaults to None

Returns:

_description_

Return type:

AbstractCircuit

classmethod from_json_file(file: str, circuit_params: Dict[str, Any] | None = None) AbstractCircuit

load json file and convert it to a circuit

Parameters:
  • file (str) – filename

  • circuit_params (Optional[Dict[str, Any]], optional) – _description_, defaults to None

Returns:

_description_

Return type:

AbstractCircuit

classmethod from_openqasm(qasmstr: str, circuit_params: Dict[str, Any] | None = None, keep_measure_order: bool = False) AbstractCircuit
classmethod from_openqasm_file(file: str, circuit_params: Dict[str, Any] | None = None, keep_measure_order: bool = False) AbstractCircuit
classmethod from_qir(qir: List[Dict[str, Any]], circuit_params: Dict[str, Any] | None = None, allow_channel: bool = False) AbstractCircuit

Restore the circuit from the quantum intermediate representation.

Example:

>>> c = tc.Circuit(3)
>>> c.H(0)
>>> c.rx(1, theta=tc.array_to_tensor(0.7))
>>> c.exp1(0, 1, unitary=tc.gates._zz_matrix, theta=tc.array_to_tensor(-0.2), split=split)
>>> len(c)
7
>>> c.expectation((tc.gates.z(), [1]))
array(0.764842+0.j, dtype=complex64)
>>> qirs = c.to_qir()
>>>
>>> c = tc.Circuit.from_qir(qirs, circuit_params={"nqubits": 3})
>>> len(c._nodes)
7
>>> c.expectation((tc.gates.z(), [1]))
array(0.764842+0.j, dtype=complex64)
Parameters:
  • qir (List[Dict[str, Any]]) – The quantum intermediate representation of a circuit.

  • circuit_params (Optional[Dict[str, Any]]) – Extra circuit parameters.

Returns:

The circuit have same gates in the qir.

Return type:

Circuit

classmethod from_qiskit(qc: Any, n: int | None = None, inputs: List[float] | None = None, circuit_params: Dict[str, Any] | None = None, binding_params: Sequence[float] | Dict[Any, float] | None = None) AbstractCircuit

Import Qiskit QuantumCircuit object as a tc.Circuit object.

Example:

>>> from qiskit import QuantumCircuit
>>> qisc = QuantumCircuit(3)
>>> qisc.h(2)
>>> qisc.cswap(1, 2, 0)
>>> qisc.swap(0, 1)
>>> c = tc.Circuit.from_qiskit(qisc)
Parameters:
  • qc (QuantumCircuit in Qiskit) – Qiskit Circuit object

  • n (int) – The number of qubits for the circuit

  • inputs (Optional[List[float]], optional) – possible input wavefunction for tc.Circuit, defaults to None

  • circuit_params (Optional[Dict[str, Any]]) – kwargs given in Circuit.__init__ construction function, default to None.

  • binding_params (Optional[Union[Sequence[float], Dict[Any, float]]]) – (variational) parameters for the circuit. Could be either a sequence or dictionary depending on the type of parameters in the Qiskit circuit. For ParameterVectorElement use sequence. For Parameter use dictionary

Returns:

The same circuit but as tensorcircuit object

Return type:

Circuit

classmethod from_qsim_file(file: str, circuit_params: Dict[str, Any] | None = None) AbstractCircuit
static front_from_nodes(nodes: List[Node]) List[Edge]
gate_aliases = [['cnot', 'cx'], ['fredkin', 'cswap'], ['toffoli', 'ccnot'], ['toffoli', 'ccx'], ['any', 'unitary'], ['sd', 'sdg'], ['td', 'tdg']]
gate_count(gate_list: str | Sequence[str] | None = None) int

count the gate number of the circuit

Example:

>>> c = tc.Circuit(3)
>>> c.h(0)
>>> c.multicontrol(0, 1, 2, ctrl=[0, 1], unitary=tc.gates._x_matrix)
>>> c.toffolli(1, 2, 0)
>>> c.gate_count()
3
>>> c.gate_count(["multicontrol", "toffoli"])
2
Parameters:

gate_list (Optional[Sequence[str]], optional) – gate name or gate name list to be counted, defaults to None (counting all gates)

Returns:

the total number of all gates or gates in the gate_list

Return type:

int

gate_count_by_condition(cond_func: Callable[[Dict[str, Any]], bool]) int

count the number of gates that satisfy certain condition

Example:

>>> c = tc.Circuit(3)
>>> c.x(0)
>>> c.h(0)
>>> c.multicontrol(0, 1, 2, ctrl=[0, 1], unitary=tc.gates._x_matrix)
>>> c.gate_count_by_condition(lambda qir: qir["index"] == (0, ))
2
>>> c.gate_count_by_condition(lambda qir: qir["mpo"])
1
Parameters:

cond_func (Callable[[Dict[str, Any]], bool]) – the condition for counting the gate

Returns:

the total number of all gates which satisfy the condition

Return type:

int

gate_summary() Dict[str, int]

return the summary dictionary on gate type - gate count pair

Returns:

the gate count dict by gate type

Return type:

Dict[str, int]

general_kraus(kraus: Sequence[Gate], *index: int, status: float | None = None, with_prob: bool = False, name: str | None = None) Any

Monte Carlo trajectory simulation of general Kraus channel whose Kraus operators cannot be amplified to unitary operators. For unitary operators composed Kraus channel, unitary_kraus() is much faster.

This function is jittable in theory. But only jax+GPU combination is recommended for jit since the graph building time is too long for other backend options; though the running time of the function is very fast for every case.

Parameters:
  • kraus (Sequence[Gate]) – A list of tn.Node for Kraus operators.

  • index (int) – The qubits index that Kraus channel is applied on.

  • status (Optional[float], optional) – Random tensor uniformly between 0 or 1, defaults to be None, when the random number will be generated automatically

generaldepolarizing(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply generaldepolarizing quantum channel on the circuit. See tensorcircuit.channels.generaldepolarizingchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

get_circuit_as_quoperator() QuOperator

Get the QuOperator MPO like representation of the circuit unitary without contraction.

Returns:

QuOperator object for the circuit unitary (open indices for the input state)

Return type:

QuOperator

get_positional_logical_mapping() Dict[int, int]

Get positional logical mapping dict based on measure instruction. This function is useful when we only measure part of the qubits in the circuit, to process the count result from partial measurement, we must be aware of the mapping, i.e. for each position in the count bitstring, what is the corresponding qubits (logical) defined on the circuit

Returns:

positional_logical_mapping

Return type:

Dict[int, int]

get_quoperator() QuOperator[source]

Get symbolic QuOperator representation.

get_quvector() QuVector

Get the representation of the output state in the form of QuVector while maintaining the circuit uncomputed

Returns:

QuVector representation of the output state from the circuit

Return type:

QuVector

get_state_as_quvector() QuVector

Get the representation of the output state in the form of QuVector while maintaining the circuit uncomputed

Returns:

QuVector representation of the output state from the circuit

Return type:

QuVector

h(*index: int, **kws: Any) None

Apply H gate on the circuit. See tensorcircuit.gates.h_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.70710677+0.j & 0.70710677+0.j\\ 0.70710677+0.j & -0.70710677+0.j \end{bmatrix}\end{split}\]

i(*index: int, **kws: Any) None

Apply I gate on the circuit. See tensorcircuit.gates.i_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

initial_mapping(logical_physical_mapping: Dict[int, int], n: int | None = None, circuit_params: Dict[str, Any] | None = None) AbstractCircuit

generate a new circuit with the qubit mapping given by logical_physical_mapping

Parameters:
  • logical_physical_mapping (Dict[int, int]) – how to map logical qubits to the physical qubits on the new circuit

  • n (Optional[int], optional) – number of qubit of the new circuit, can be different from the original one, defaults to None

  • circuit_params (Optional[Dict[str, Any]], optional) – _description_, defaults to None

Returns:

_description_

Return type:

AbstractCircuit

inputs: Any
inverse(circuit_params: Dict[str, Any] | None = None) AbstractCircuit

inverse the circuit, return a new inversed circuit

EXAMPLE:

>>> c = tc.Circuit(2)
>>> c.H(0)
>>> c.rzz(1, 2, theta=0.8)
>>> c1 = c.inverse()
Parameters:

circuit_params (Optional[Dict[str, Any]], optional) – keywords dict for initialization the new circuit, defaults to None

Returns:

the inversed circuit

Return type:

Circuit

is_dm: bool = False
is_mps: bool = False
is_valid() bool

[WIP], check whether the circuit is legal.

Returns:

The bool indicating whether the circuit is legal

Return type:

bool

isotropicdepolarizing(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply isotropicdepolarizing quantum channel on the circuit. See tensorcircuit.channels.isotropicdepolarizingchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

iswap(*index: int, **vars: Any) None

Apply ISWAP gate with parameters on the circuit. See tensorcircuit.gates.iswap_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

matrix() ndarray[source]

Compute the symbolic unitary matrix of the circuit.

measure(*args: Any, **kwargs: Any) Any[source]

Overridden to provide better error message for symbolic circuits.

measure_instruction(*index: int) None

add a measurement instruction flag, no effect on numerical simulation

Parameters:

index (int) – the corresponding qubits

measure_jit(*index: int, with_prob: bool = False, status: Any | None = None) Tuple[Any, Any]

Take measurement on the given site indices (computational basis). This method is jittable is and about 100 times faster than unjit version!

Parameters:
  • index (int) – Measure on which site (wire) index.

  • with_prob (bool, optional) – If true, theoretical probability is also returned.

  • status (Optional[Tensor]) – external randomness, with shape [index], defaults to None

Returns:

The sample output and probability (optional) of the quantum line.

Return type:

Tuple[Tensor, Tensor]

measure_reference(*args: Any, **kwargs: Any) Any[source]

Overridden to provide better error message for symbolic circuits.

mid_measure(index: int, keep: int = 0) Any

Middle measurement in z-basis on the circuit, note the wavefunction output is not normalized with mid_measurement involved, one should normalize the state manually if needed. This is a post-selection method as keep is provided as a prior.

Parameters:
  • index (int) – The index of qubit that the Z direction postselection applied on.

  • keep (int, optional) – the post-selected digit in {0, …, d-1}, defaults to be 0.

mid_measurement(index: int, keep: int = 0) Any

Middle measurement in z-basis on the circuit, note the wavefunction output is not normalized with mid_measurement involved, one should normalize the state manually if needed. This is a post-selection method as keep is provided as a prior.

Parameters:
  • index (int) – The index of qubit that the Z direction postselection applied on.

  • keep (int, optional) – the post-selected digit in {0, …, d-1}, defaults to be 0.

mpo(*index: int, **vars: Any) None

Apply mpo gate in MPO format on the circuit. See tensorcircuit.gates.mpo_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

mpogates = ['multicontrol', 'mpo']
mr_instruction(q: int, p: float = 0.0, **kws: Any) None

add a measure-reset instruction flag, no effect on numerical simulation

Parameters:

q (int) – the corresponding qubit

multicontrol(*index: int, **vars: Any) None

Apply multicontrol gate in MPO format on the circuit. See tensorcircuit.gates.multicontrol_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

orx(*index: int, **vars: Any) None

Apply ORX gate with parameters on the circuit. See tensorcircuit.gates.orx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

ory(*index: int, **vars: Any) None

Apply ORY gate with parameters on the circuit. See tensorcircuit.gates.ory_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

orz(*index: int, **vars: Any) None

Apply ORZ gate with parameters on the circuit. See tensorcircuit.gates.orz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

outcome_probability(state: Sequence[int]) Any

Calculate the probability of a specific detector outcome bitstring.

Parameters:

state (Sequence[int]) – The detector outcome bitstring as a sequence of 0s and 1s.

Returns:

The probability of the given outcome.

Return type:

Tensor

ox(*index: int, **kws: Any) None

Apply OX gate on the circuit. See tensorcircuit.gates.ox_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

oy(*index: int, **kws: Any) None

Apply OY gate on the circuit. See tensorcircuit.gates.oy_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 0.-1.j & 0.+0.j & 0.+0.j\\ 0.+1.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

oz(*index: int, **kws: Any) None

Apply OZ gate on the circuit. See tensorcircuit.gates.oz_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & -1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

pauli2_instruction(q1: int, q2: int, **kws: Any) None

add a 2-qubit pauli instruction flag, no effect on numerical simulation

pauli_instruction(q: int, px: float | None = None, py: float | None = None, pz: float | None = None, **kws: Any) None

add a pauli instruction flag, no effect on numerical simulation

perfect_sampling(status: Any | None = None) Tuple[str, float]

Sampling base-d strings (0-9A-Z when d <= 36) from the circuit output based on quantum amplitudes. Reference: arXiv:1201.3974.

Parameters:

status (Optional[Tensor]) – external randomness, with shape [nqubits], defaults to None

Returns:

Sampled base-d string and the corresponding theoretical probability.

Return type:

Tuple[str, float]

phase(*index: int, **vars: Any) None

Apply PHASE gate with parameters on the circuit. See tensorcircuit.gates.phase_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

phasedamping(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply phasedamping quantum channel on the circuit. See tensorcircuit.channels.phasedampingchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

post_select(index: int, keep: int = 0) Any

Middle measurement in z-basis on the circuit, note the wavefunction output is not normalized with mid_measurement involved, one should normalize the state manually if needed. This is a post-selection method as keep is provided as a prior.

Parameters:
  • index (int) – The index of qubit that the Z direction postselection applied on.

  • keep (int, optional) – the post-selected digit in {0, …, d-1}, defaults to be 0.

post_selection(index: int, keep: int = 0) Any

Middle measurement in z-basis on the circuit, note the wavefunction output is not normalized with mid_measurement involved, one should normalize the state manually if needed. This is a post-selection method as keep is provided as a prior.

Parameters:
  • index (int) – The index of qubit that the Z direction postselection applied on.

  • keep (int, optional) – the post-selected digit in {0, …, d-1}, defaults to be 0.

prepend(c: AbstractCircuit) AbstractCircuit

prepend circuit c before

Parameters:

c (BaseCircuit) – The other circuit to be prepended

Returns:

The composed circuit

Return type:

BaseCircuit

probability() ndarray[source]

Compute the symbolic probability distribution.

projected_subsystem(traceout: Any, left: Tuple[int, ...]) Any[source]

Compute symbolic projected subsystem.

quoperator() QuOperator

Get symbolic QuOperator representation.

quvector() QuVector

Get the representation of the output state in the form of QuVector while maintaining the circuit uncomputed

Returns:

QuVector representation of the output state from the circuit

Return type:

QuVector

r(*index: int, **vars: Any) None

Apply R gate with parameters on the circuit. See tensorcircuit.gates.r_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

readouterror_bs(readout_error: Sequence[Any] | None = None, p: Any | None = None) Any

Apply readout error to original probabilities of bit string and return the noisy probabilities.

Example:

>>> readout_error = []
>>> readout_error.append([0.9,0.75])  # readout error for qubit 0, [p0|0,p1|1]
>>> readout_error.append([0.4,0.7])   # readout error for qubit 1, [p0|0,p1|1]
Parameters:
  • readout_error (Optional[Sequence[Any]]. Tensor, List, Tuple) – list of readout error for each qubits.

  • p (Optional[Any]) – probabilities of bit string

Return type:

Tensor

replace_inputs(inputs: Any) None

Replace the input state with the circuit structure unchanged.

Parameters:

inputs (Tensor) – Input wavefunction.

replace_mps_inputs(mps_inputs: QuOperator) None

Replace the input state in MPS representation while keep the circuit structure unchanged.

Example:

>>> c = tc.Circuit(2)
>>> c.X(0)
>>>
>>> c2 = tc.Circuit(2, mps_inputs=c.quvector())
>>> c2.X(0)
>>> c2.wavefunction()
array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)
>>>
>>> c3 = tc.Circuit(2)
>>> c3.X(0)
>>> c3.replace_mps_inputs(c.quvector())
>>> c3.wavefunction()
array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)
Parameters:

mps_inputs (Tuple[Sequence[Gate], Sequence[Edge]]) – (Nodes, dangling Edges) for a MPS like initial wavefunction.

reset(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply reset quantum channel on the circuit. See tensorcircuit.channels.resetchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

reset_instruction(*index: int) None

add a reset instruction flag, no effect on numerical simulation

Parameters:

index (int) – the corresponding qubits

rx(*index: int, **vars: Any) None

Apply RX gate with parameters on the circuit. See tensorcircuit.gates.rx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

rxx(*index: int, **vars: Any) None

Apply RXX gate with parameters on the circuit. See tensorcircuit.gates.rxx_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

ry(*index: int, **vars: Any) None

Apply RY gate with parameters on the circuit. See tensorcircuit.gates.ry_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

ryy(*index: int, **vars: Any) None

Apply RYY gate with parameters on the circuit. See tensorcircuit.gates.ryy_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

rz(*index: int, **vars: Any) None

Apply RZ gate with parameters on the circuit. See tensorcircuit.gates.rz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

rzm(*index: int, **vars: Any) None

Apply rzm gate on the circuit using hyperedge support for digonal gates. See tensorcircuit.gates.rzm_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

rzz(*index: int, **vars: Any) None

Apply RZZ gate with parameters on the circuit. See tensorcircuit.gates.rzz_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

s(*index: int, **kws: Any) None

Apply S gate on the circuit. See tensorcircuit.gates.s_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 0.+1.j \end{bmatrix}\end{split}\]

sample(*args: Any, **kwargs: Any) Any[source]

Overridden to provide better error message for symbolic circuits.

sample_detector(shots: int = 1, batch: int | None = None, allow_state: bool = False, status: Any | None = None, seed: int | None = None, **kws: Any) Any

Sample detector outcomes from instruction-annotated circuits.

Parameters:
  • shots (int, optional) – Number of samples to draw, defaults to 1.

  • batch (int, optional) – Number of samples to process in a single batch, defaults to None (equal to shots).

  • allow_state (bool, optional) – If True, uses the full detector probability distribution for sampling (faster but memory-intensive); if False, uses an autoregressive sampling method based on the tensor network, defaults to False.

  • status (Optional[Tensor], optional) – Random numbers in [0, 1] used for sampling, defaults to None. If allow_state is True, shape should be [shots] or [shots, 1]; if allow_state is False, shape should be [shots, num_detectors].

  • seed (Optional[int], optional) – Random seed for sampling, defaults to None.

Returns:

A boolean tensor containing the sampled detector outcomes with shape [shots, num_detectors].

Return type:

Tensor

sample_expectation_ps(x: Sequence[int] | None = None, y: Sequence[int] | None = None, z: Sequence[int] | None = None, shots: int | None = None, random_generator: Any | None = None, status: Any | None = None, readout_error: Sequence[Any] | None = None, noise_conf: Any | None = None, nmc: int = 1000, statusc: Any | None = None, **kws: Any) Any[source]

Symbolic execution for analytical Pauli string expectation.

Parameters:
  • x (Optional[Sequence[int]]) – List of indices for Pauli X.

  • y (Optional[Sequence[int]]) – List of indices for Pauli Y.

  • z (Optional[Sequence[int]]) – List of indices for Pauli Z.

  • shots (Optional[int]) – Must be None for analytical symbolic result.

Returns:

Sympy expression for the expectation value.

sd(*index: int, **kws: Any) None

Apply SD gate on the circuit. See tensorcircuit.gates.sd_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 0.-1.j \end{bmatrix}\end{split}\]

sdg(*index: int, **kws: Any) None

Apply SD gate on the circuit. See tensorcircuit.gates.sd_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & 0.-1.j \end{bmatrix}\end{split}\]

select_gate(which: Any, kraus: Sequence[Gate], *index: int) None

Apply which-th gate from kraus list, i.e. apply kraus[which]

Parameters:
  • which (Tensor) – Tensor of shape [] and dtype int

  • kraus (Sequence[Gate]) – A list of gate in the form of tc.gate or Tensor

  • index (int) – the qubit lines the gate applied on

sexpps(x: Sequence[int] | None = None, y: Sequence[int] | None = None, z: Sequence[int] | None = None, shots: int | None = None, random_generator: Any | None = None, status: Any | None = None, readout_error: Sequence[Any] | None = None, noise_conf: Any | None = None, nmc: int = 1000, statusc: Any | None = None, **kws: Any) Any

Compute the expectation with given Pauli string with measurement shots numbers

Example:

>>> c = tc.Circuit(2)
>>> c.H(0)
>>> c.rx(1, theta=np.pi/2)
>>> c.sample_expectation_ps(x=[0], y=[1])
-0.99999976
>>> readout_error = []
>>> readout_error.append([0.9,0.75])
>>> readout_error.append([0.4,0.7])
>>> c.sample_expectation_ps(x=[0], y=[1],readout_error = readout_error)
>>> c = tc.Circuit(2)
>>> c.cnot(0, 1)
>>> c.rx(0, theta=0.4)
>>> c.rx(1, theta=0.8)
>>> c.h(0)
>>> c.h(1)
>>> error1 = tc.channels.generaldepolarizingchannel(0.1, 1)
>>> error2 = tc.channels.generaldepolarizingchannel(0.06, 2)
>>> readout_error = [[0.9, 0.75],[0.4, 0.7]]
>>> noise_conf = NoiseConf()
>>> noise_conf.add_noise("rx", error1)
>>> noise_conf.add_noise("cnot", [error2], [[0, 1]])
>>> noise_conf.add_noise("readout", readout_error)
>>> c.sample_expectation_ps(x=[0], noise_conf=noise_conf, nmc=10000)
0.44766843
Parameters:
  • x (Optional[Sequence[int]], optional) – index for Pauli X, defaults to None

  • y (Optional[Sequence[int]], optional) – index for Pauli Y, defaults to None

  • z (Optional[Sequence[int]], optional) – index for Pauli Z, defaults to None

  • shots (Optional[int], optional) – number of measurement shots, defaults to None, indicating analytical result

  • random_generator (Optional[Any]) – random_generator, defaults to None

  • status (Optional[Tensor]) – external randomness given by tensor uniformly from [0, 1], if set, can overwrite random_generator

  • readout_error (Optional[Sequence[Any]]. Tensor, List, Tuple) – readout_error, defaults to None. Overrided if noise_conf is provided.

  • noise_conf (Optional[NoiseConf], optional) – Noise Configuration, defaults to None

  • nmc (int, optional) – repetition time for Monte Carlo sampling for noisfy calculation, defaults to 1000

  • statusc (Optional[Tensor], optional) – external randomness given by tensor uniformly from [0, 1], defaults to None, used for noisfy circuit sampling

Returns:

[description]

Return type:

Tensor

sgates = ['i', 'x', 'y', 'z', 'h', 't', 's', 'td', 'sd', 'wroot', 'cnot', 'cz', 'swap', 'cy', 'ox', 'oy', 'oz', 'toffoli', 'fredkin']
split: Dict[str, Any] | None
static standardize_gate(name: str) str

standardize the gate name to tc common gate sets

Parameters:

name (str) – non-standard gate name

Returns:

the standard gate name

Return type:

str

state(form: str = 'default') ndarray

Compute the symbolic output state vector.

Returns a numpy object array containing sympy expressions. Only practical for small qubit counts where the full vector is manageable.

Parameters:

form (str, optional) – Shape of output: "default" → 1-D, "ket" → column, "bra" → row. Defaults to "default".

Returns:

Numpy object array of sympy expressions.

Return type:

np.ndarray

su4(*index: int, **vars: Any) None

Apply SU4 gate with parameters on the circuit. See tensorcircuit.gates.su4_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

swap(*index: int, **kws: Any) None

Apply SWAP gate on the circuit. See tensorcircuit.gates.swap_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j \end{bmatrix}\end{split}\]

t(*index: int, **kws: Any) None

Apply T gate on the circuit. See tensorcircuit.gates.t_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1. & +0.j & 0. & +0.j\\ 0. & +0.j & 0.70710677+0.70710677j \end{bmatrix}\end{split}\]

td(*index: int, **kws: Any) None

Apply TD gate on the circuit. See tensorcircuit.gates.td_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1. & +0.j & 0. & +0.j\\ 0. & +0.j & 0.70710677-0.70710677j \end{bmatrix}\end{split}\]

tdg(*index: int, **kws: Any) None

Apply TD gate on the circuit. See tensorcircuit.gates.td_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1. & +0.j & 0. & +0.j\\ 0. & +0.j & 0.70710677-0.70710677j \end{bmatrix}\end{split}\]

tex(**kws: Any) str

Generate latex string based on quantikz latex package

Returns:

Latex string that can be directly compiled via, e.g. latexit

Return type:

str

thermalrelaxation(*index: int, status: float | None = None, name: str | None = None, **vars: float) None

Apply thermalrelaxation quantum channel on the circuit. See tensorcircuit.channels.thermalrelaxationchannel()

Parameters:
  • index (int.) – Site index that the gate applies on.

  • status (Tensor) – uniform external random number between 0 and 1

  • vars (float.) – Parameters for the channel.

to_circuit(param_dict: Dict[Symbol, Any] | None = None) Circuit[source]

Convert to a numerical Circuit by binding symbolic parameters.

Parameters:

param_dict (Optional[Dict[sympy.Symbol, Any]]) – Mapping from sympy Symbol to numerical value. Pass None (or {}) only if the circuit has no free symbols.

Returns:

A fully numerical Circuit.

Return type:

Circuit

to_cirq(enable_instruction: bool = False) Any

Translate tc.Circuit to a cirq circuit object.

Parameters:

enable_instruction (bool, defaults to False) – whether also export measurement and reset instructions

Returns:

A cirq circuit of this circuit.

to_graphviz(graph: Graph = None, include_all_names: bool = False, engine: str = 'neato') Graph

Not an ideal visualization for quantum circuit, but reserve here as a general approach to show the tensornetwork [Deprecated, use Circuit.vis_tex or Circuit.draw instead]

to_json(file: str | None = None, simplified: bool = False) Any

circuit dumps to json

Parameters:
  • file (Optional[str], optional) – file str to dump the json to, defaults to None, return the json str

  • simplified (bool) – If False, keep all info for each gate, defaults to be False. If True, suitable for IO since less information is required

Returns:

None if dumps to file otherwise the json str

Return type:

Any

to_openqasm(**kws: Any) str

transform circuit to openqasm via qiskit circuit, see https://qiskit.org/documentation/stubs/qiskit.circuit.QuantumCircuit.qasm.html for usage on possible options for kws

Returns:

circuit representation in openqasm format

Return type:

str

to_openqasm_file(file: str, **kws: Any) None

save the circuit to openqasm file

Parameters:

file (str) – the file path to save the circuit

to_qir() List[Dict[str, Any]]

Return the quantum intermediate representation of the circuit.

Example:

>>> c = tc.Circuit(2)
>>> c.CNOT(0, 1)
>>> c.to_qir()
[{'gatef': cnot, 'gate': Gate(
    name: 'cnot',
    tensor:
        array([[[[1.+0.j, 0.+0.j],
                [0.+0.j, 0.+0.j]],

                [[0.+0.j, 1.+0.j],
                [0.+0.j, 0.+0.j]]],


            [[[0.+0.j, 0.+0.j],
                [0.+0.j, 1.+0.j]],

                [[0.+0.j, 0.+0.j],
                [1.+0.j, 0.+0.j]]]], dtype=complex64),
    edges: [
        Edge(Dangling Edge)[0],
        Edge(Dangling Edge)[1],
        Edge('cnot'[2] -> 'qb-1'[0] ),
        Edge('cnot'[3] -> 'qb-2'[0] )
    ]), 'index': (0, 1), 'name': 'cnot', 'split': None, 'mpo': False}]
Returns:

The quantum intermediate representation of the circuit.

Return type:

List[Dict[str, Any]]

to_qiskit(enable_instruction: bool = False, enable_inputs: bool = False) Any[source]

Translate to a Qiskit QuantumCircuit with Parameter objects.

Each sympy.Symbol used as a gate parameter is mapped to a Qiskit Parameter with the same name. The resulting circuit can be bound with qiskit.QuantumCircuit.assign_parameters() and executed on hardware or simulators.

Simple arithmetic expressions involving symbols are translated when possible (+, -, *, /). Complex expressions (sin, cos, etc.) that appear directly as gate-level parameters will raise a NotImplementedError — but note that rotation angles are passed at the gate level (e.g. rx(theta)), not as matrix entries, so this is rarely an issue for standard circuit translation.

Returns:

Qiskit QuantumCircuit with symbolic Parameters.

Return type:

qiskit.circuit.QuantumCircuit

toffoli(*index: int, **kws: Any) None

Apply TOFFOLI gate on the circuit. See tensorcircuit.gates.toffoli_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j & 0.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j\\ 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 0.+0.j & 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

u(*index: int, **vars: Any) None

Apply U gate with parameters on the circuit. See tensorcircuit.gates.u_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

unitary(*index: int, **vars: Any) None

Apply ANY gate with parameters on the circuit. See tensorcircuit.gates.any_gate().

Parameters:
  • index (int.) – Qubit number that the gate applies on.

  • vars (float.) – Parameters for the gate.

unitary_kraus(kraus: Sequence[Gate], *index: int, prob: Sequence[float] | None = None, status: float | None = None, name: str | None = None) Any

Apply unitary gates in kraus randomly based on corresponding prob. If prob is None, this is reduced to kraus channel language.

Parameters:
  • kraus (Sequence[Gate]) – List of tc.gates.Gate or just Tensors

  • prob (Optional[Sequence[float]], optional) – prob list with the same size as kraus, defaults to None

  • status (Optional[float], optional) – random seed between 0 to 1, defaults to None

Returns:

shape [] int dtype tensor indicates which kraus gate is actually applied

Return type:

Tensor

unitary_kraus2(kraus: Sequence[Gate], *index: int, prob: Sequence[float] | None = None, status: float | None = None, name: str | None = None) Any

Apply a unitary Kraus channel to the circuit using a Monte Carlo approach. This method is functionally similar to unitary_kraus but uses backend.switch for selecting the Kraus operator, which can have different performance characteristics on some backends.

A random Kraus operator from the provided list is applied to the circuit based on the given probabilities. This method is jittable and suitable for simulating noisy quantum circuits where the noise is represented by unitary Kraus operators.

Warning

This method may have issues with vmap due to potential concurrent access locks, potentially related with backend.switch. unitary_kraus is generally recommended.

Parameters:
  • kraus (Sequence[Gate]) – A sequence of Gate objects representing the unitary Kraus operators.

  • index (int) – The qubit indices on which to apply the Kraus channel.

  • prob (Optional[Sequence[float]], optional) – A sequence of probabilities corresponding to each Kraus operator. If None, probabilities are derived from the operators themselves. Defaults to None.

  • status (Optional[float], optional) – A random number between 0 and 1 to determine which Kraus operator to apply. If None, a random number is generated automatically. Defaults to None.

  • name (Optional[str], optional) – An optional name for the operation. Defaults to None.

Returns:

A tensor indicating which Kraus operator was applied.

Return type:

Tensor

vgates = ['r', 'cr', 'u', 'cu', 'rx', 'ry', 'rz', 'phase', 'rxx', 'ryy', 'rzz', 'cphase', 'crx', 'cry', 'crz', 'orx', 'ory', 'orz', 'iswap', 'any', 'exp', 'exp1', 'su4']
vis_tex(**kws: Any) str

Generate latex string based on quantikz latex package

Returns:

Latex string that can be directly compiled via, e.g. latexit

Return type:

str

wavefunction(form: str = 'default') ndarray[source]

Compute the symbolic output state vector.

Returns a numpy object array containing sympy expressions. Only practical for small qubit counts where the full vector is manageable.

Parameters:

form (str, optional) – Shape of output: "default" → 1-D, "ket" → column, "bra" → row. Defaults to "default".

Returns:

Numpy object array of sympy expressions.

Return type:

np.ndarray

wroot(*index: int, **kws: Any) None

Apply WROOT gate on the circuit. See tensorcircuit.gates.wroot_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.70710677+0.j & -0.5 & -0.5j\\ 0.5 & -0.5j & 0.70710677+0.j \end{bmatrix}\end{split}\]

x(*index: int, **kws: Any) None

Apply X gate on the circuit. See tensorcircuit.gates.x_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 1.+0.j\\ 1.+0.j & 0.+0.j \end{bmatrix}\end{split}\]

y(*index: int, **kws: Any) None

Apply Y gate on the circuit. See tensorcircuit.gates.y_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 0.+0.j & 0.-1.j\\ 0.+1.j & 0.+0.j \end{bmatrix}\end{split}\]

z(*index: int, **kws: Any) None

Apply Z gate on the circuit. See tensorcircuit.gates.z_gate().

Parameters:

index (int.) –

Qubit number that the gate applies on. The matrix for the gate is

\[\begin{split}\begin{bmatrix} 1.+0.j & 0.+0.j\\ 0.+0.j & -1.+0.j \end{bmatrix}\end{split}\]