uniqc.circuit_builder.qcircuit module

Quantum circuit builder with OriginIR and OpenQASM 2.0 output.

This module provides a Circuit class for building quantum circuits programmatically. It supports various quantum gates, controlled operations, dagger (adjoint) blocks, and measurement operations. The circuit can be exported to OriginIR or OpenQASM format.

Key exports:

Circuit: Main quantum circuit builder class. OpcodeType: Type alias for opcode tuples.

class uniqc.circuit_builder.qcircuit.Circuit(qregs=None, param_dict=None)[source]

Bases: object

Quantum circuit builder that generates OriginIR and OpenQASM output.

Variables:
  • used_qubit_list (list[int]) – Qubits referenced in the circuit.

  • circuit_str (str) – Raw string builder used by context managers.

  • max_qubit (int) – Highest qubit index used.

  • qubit_num (int) – Total number of qubits.

  • cbit_num (int) – Total number of classical bits.

  • measure_list (list[int]) – Qubits scheduled for measurement.

  • opcode_list (list[OpCode]) – Internal list of gate opcodes.

  • _qregs (dict[str, QReg]) – Named quantum registers (if created with qregs parameter).

AnyQuantumCircuit — the universal input type

Most public APIs (compile(), Simulator, submit_task()) accept AnyQuantumCircuit, which is a union of:

  • Circuit — this class

  • str — OriginIR or OpenQASM 2.0 (auto-detected from content)

  • qiskit.QuantumCircuit — converted via QASM round-trip

  • pyqpanda3.QProg — converted via OriginIR round-trip

Use to_qiskit_circuit() or to_pyqpanda3_circuit() to convert back to external formats.

add_circuit(other)[source]

Add all gates from another circuit into this circuit.

add_gate(operation, qubits, cbits=None, params=None, dagger=False, control_qubits=None, has_param=False, trainable=True, init_params=None)[source]

Add a gate to the circuit.

Parameters:
  • operation – Gate name (e.g., “H”, “CNOT”, “RX”)

  • qubits – Target qubit(s) - can be int, Qubit, QRegSlice, or list

  • cbits – Classical bit(s) for measurement

  • params – Gate parameters

  • dagger – Whether to apply dagger (adjoint)

  • control_qubits – Control qubit(s)

  • has_param – If True, automatically create an nn.Parameter for this gate’s rotation angle(s). The created parameter is stored in _auto_params and registered in param_map. Requires PyTorch.

  • trainable – Whether the auto-created parameter is trainable (requires_grad). Only used when has_param=True.

  • init_params – Custom initial value(s) for the auto-created parameter. A scalar or list/tuple matching the gate’s num_params. Defaults to Uniform(-π, π) (TorchQuantum convention). Only used when has_param=True.

assign_parameters(values, *, inplace=False)[source]

Bind numeric values to symbolic parameters.

Parameters:
  • values – Either a dict mapping parameter -> value, or a bound Parameters object. Dict keys may be name strings ("theta", "alpha_2"), Parameter objects, sympy Symbol objects, or a Parameters array (paired with a sequence of values).

  • inplace – If True mutate this circuit and return it; otherwise (default) return a new bound circuit, leaving self unchanged.

Partial binding is allowed — parameters absent from values remain symbolic. Fully-substituted parameters collapse to plain floats, so a fully-bound circuit can be simulated or submitted like any concrete circuit.

Returns:

The bound circuit (new instance unless inplace).

barrier(*qubits)[source]

Insert a barrier across the specified qubits.

Parameters:

*qubits – Qubits to include in the barrier.

bind_parameters(values, *, inplace=False)

Alias matching common quantum-SDK naming.

c_and(dest, a, b)[source]

Classical instruction c[dest] = a & b (operands: CREG bit or 0/1).

c_mov(dest, a)[source]

Classical instruction c[dest] = a (operand: CREG bit or 0/1).

c_not(dest, a)[source]

Classical instruction c[dest] = ~a (operand: CREG bit or 0/1).

c_or(dest, a, b)[source]

Classical instruction c[dest] = a | b (operands: CREG bit or 0/1).

c_xor(dest, a, b)[source]

Classical instruction c[dest] = a ^ b (operands: CREG bit or 0/1).

cbit_num
check_dynamic_program_closed()[source]

Raise if any QIF/QWHILE block is still open (missing a matching endqif()/endqwhile()).

Serializing or executing a circuit with unclosed blocks would only reflect however much of the branch/loop body has been built so far, silently hiding the incomplete construction — so both _make_originir_circuit() and dynamic-program execution call this first.

Raises:

ValueError – If self._dynamic_block_stack is non-empty.

property circuit

Generate the circuit in OriginIR format.

circuit_str
cnot(controller, target)[source]

Apply CNOT (controlled-X) gate.

Parameters:
  • controller – Control qubit - can be int, Qubit, or QRegSlice

  • target – Target qubit - can be int, Qubit, or QRegSlice

control(*args)[source]

Return a context manager that wraps gates in a CONTROL block.

All gates added inside the with block will be executed only when all specified control qubits are in state |1>.

Parameters:

*args – One or more control qubits - can be int, Qubit, or QRegSlice

Returns:

A CircuitControlContext context manager.

Raises:

ValueError – No control qubits were supplied.

copy()[source]

Return a deep copy of this circuit.

QRAM declarations, classical memory, and any structured dynamic program (mid-circuit MEASURE/RESET/QIF/QWHILE) are preserved. The dynamic program body is recursively cloned so mutating either circuit’s control-flow blocks after copying cannot affect the other.

cp(control, target, lam)[source]

Apply controlled-phase gate (equivalent to CU1).

Parameters:
  • control – Control qubit.

  • target – Target qubit.

  • lam – Phase angle in radians.

creg(size)[source]

Declare the classical-register (CREG) size for this circuit.

CREG bits c[0..size-1] are single bits written by MEASURE / classical instructions and read by QIF / QWHILE conditions. Sets a floor on the CREG size; it also auto-grows to fit the largest classical bit referenced by measure_to() / classical instructions.

Parameters:

size – Number of classical bits (must be non-negative).

crx(control, target, theta)[source]

Apply controlled-RX gate.

Parameters:
  • control – Control qubit.

  • target – Target qubit.

  • theta – Rotation angle in radians.

cry(control, target, theta)[source]

Apply controlled-RY gate.

Parameters:
  • control – Control qubit.

  • target – Target qubit.

  • theta – Rotation angle in radians.

crz(control, target, theta)[source]

Apply controlled-RZ gate.

Parameters:
  • control – Control qubit.

  • target – Target qubit.

  • theta – Rotation angle in radians.

cswap(q1, q2, q3)[source]

Apply CSWAP (Fredkin) gate to three qubits.

Parameters:
  • q1 – Control qubit - can be int, Qubit, or QRegSlice

  • q2 – First target qubit

  • q3 – Second target qubit

cu(control, target, theta, phi, lam)[source]

Apply controlled-U3 gate.

Parameters:
  • control – Control qubit.

  • target – Target qubit.

  • theta – Rotation angle in radians.

  • phi – Phi angle in radians.

  • lam – Lambda angle in radians.

cx(controller, target)[source]

Apply CX gate (alias for CNOT).

Parameters:
  • controller – Control qubit - can be int, Qubit, or QRegSlice

  • target – Target qubit - can be int, Qubit, or QRegSlice

cz(q1, q2)[source]

Apply controlled-Z gate to two qubits.

Parameters:
  • q1 – First qubit - can be int, Qubit, or QRegSlice

  • q2 – Second qubit - can be int, Qubit, or QRegSlice

dagger()[source]

Return a context manager that wraps gates in a DAGGER block.

All gates added inside the with block will be conjugate-transposed (adjoint).

Returns:

A CircuitDagContext context manager.

property depth

Calculate the depth of the quantum circuit.

endqif()[source]

Close the innermost open QIF block.

Raises:

ValueError – If there is no open QIF block.

endqwhile()[source]

Close the innermost open QWHILE block.

Raises:

ValueError – If there is no open QWHILE block.

property free_parameters

Sorted names of the unbound symbolic parameters in this circuit.

classmethod from_originir(originir_str)[source]

Create a Circuit from an OriginIR(-ext) string.

Text using the classical / control-flow extension (mid-circuit MEASURE/RESET, AND/OR/XOR/MOV/NOT instructions, or QIF/QWHILE blocks) is parsed via the structured program parser; ordinary flat circuits (including QRAM/CONTROL/DAGGER) go through the original flat parser unchanged.

Parameters:

originir_str – OriginIR formatted circuit string.

Returns:

A new Circuit instance.

classmethod from_originir_ext(originir_ext_str)[source]

Create a Circuit from an OriginIR-ext string.

Equivalent to from_originir() — both parse the same superset syntax. This alias makes the intent explicit when working with OriginIR-ext source.

classmethod from_qasm(qasm_str)[source]

Create a Circuit from an OpenQASM 2.0 string.

Parameters:

qasm_str – OpenQASM 2.0 formatted circuit string.

Returns:

A new Circuit instance.

get_matrix()[source]

Return the full unitary matrix of this circuit as np.ndarray.

Qubit 0 is treated as the least-significant bit of the statevector index. The returned matrix uses the convention state_out = U @ state_in and gates are applied in the same order as opcode_list.

Raises:

NotMatrixableError – If the circuit contains MEASURE / CONTROL / DAGGER scope opcodes that have no unitary representation.

get_param(opcode_idx)[source]

Get the tensor parameter registered for opcode_idx.

Raises:

KeyError – If no tensor is registered for this opcode.

get_params_by_gate(gate_name)[source]

Return auto-created parameters for gates named gate_name.

Example:

>>> c = Circuit(2)
>>> c.ry(0, has_param=True)
>>> c.ry(1, has_param=True)
>>> c.rz(0, has_param=True)
>>> len(c.get_params_by_gate("RY"))
2
get_qreg(name)[source]

Get a named quantum register by name.

Parameters:

name – Register name

Returns:

QReg object

Raises:

KeyError – If register name not found

h(qn)[source]

Apply single-qubit Hadamard gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

property has_param

TorchQuantum-aligned alias for has_tensor_params().

Returns True only when at least one parameter is a tensor (i.e., actually trainable). Pure Python-float parameters return False.

This is a no-argument property, distinct from the has_param keyword argument on add_gate() / convenience gate methods (which opts-in to auto-creating an nn.Parameter for that gate).

has_tensor_params()[source]

Check whether this circuit has any registered tensor parameters.

identity(qn)[source]

Apply the identity (no-op) gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

property is_parametric

True if the circuit still contains unbound symbolic parameters.

Such circuits serialize to OriginIR-ext (with a PARAM header) but cannot be simulated, exported to QASM/official OriginIR, or submitted to cloud backends until bound via assign_parameters().

iswap(q1, q2)[source]

Apply iSWAP gate to two qubits.

Parameters:
  • q1 – First qubit - can be int, Qubit, or QRegSlice

  • q2 – Second qubit - can be int, Qubit, or QRegSlice

max_qubit
measure(*qubits)[source]

Schedule qubits for measurement.

Each qubit may be measured at most once per circuit. Calling measure(0) and then measure(0) again — or passing the same qubit twice in a single call (measure(0, 0)) — raises ValueError. This guards against the common mistake of using measure(0, 1) to measure two qubits when cbit is meant to be implicit; use one measure(q) call per qubit instead, or pass distinct qubit indices.

Parameters:

*qubits – One or more qubits to measure — can be int, Qubit, or QRegSlice.

Raises:

ValueError – Called inside an active CONTROL or DAGGER context block, or any qubit would be measured more than once.

measure_list
measure_to(qubit, cbit)[source]

Mid-circuit measurement of qubit into CREG bit cbit.

The qubit’s outcome is written to c[cbit] for use in later QIF / QWHILE conditions or classical instructions. Unlike the terminal measure(), the qubit stays live for further gates and this may be called inside QIF / QWHILE blocks.

Parameters:
  • qubit – The qubit to measure — int, Qubit, or QRegSlice (one qubit).

  • cbit – Destination CREG bit index.

Raises:

ValueError – If qubit resolves to more than one qubit.

opcode_list
property originir

Generate the circuit in OriginIR format.

property originir_official

Generate the circuit in strict official OriginIR format.

p(qn, lam)[source]

Apply phase gate P(λ), equivalent to U1.

Parameters:
  • qn – Target qubit - can be int, Qubit, or QRegSlice

  • lam – Phase angle in radians.

property param_dict

The named parameter dictionary, if provided at construction.

property params

All auto-created nn.Parameter tensors (flat list for optimizers).

phase2q(q1, q2, theta1, theta2, thetazz)[source]

Apply two-qubit phase gate with local and ZZ terms.

Parameters:
  • q1 – First qubit - can be int, Qubit, or QRegSlice

  • q2 – Second qubit - can be int, Qubit, or QRegSlice

  • theta1 – Local phase angle for q1 in radians.

  • theta2 – Local phase angle for q2 in radians.

  • thetazz – ZZ interaction angle in radians.

property qasm

Generate the circuit in OpenQASM format.

qelse()[source]

Open the QELSE branch of the innermost open QIF block.

Raises:

ValueError – If there is no open QIF block awaiting QELSE.

qif(cond)[source]

Open a QIF <cond> ... [QELSE ...] ENDQIF block.

Parameters:

cond – A condition string (see uniqc.circuit_builder.classical_program.parse_cond()) or a Cond instance. Nonzero evaluates as true.

qram_call(name, *qubits, control_qubits=None)[source]

Add a QRAM call to the circuit.

QRAM XOR-loads are self-inverse; when control_qubits is given, the load is applied only when every control qubit is |1> (identity otherwise). Control qubits must be disjoint from the QRAM’s own address/data qubits.

Parameters:
  • name – Name of a previously declared QRAM.

  • *qubits – Qubit list (addr bits followed by data bits).

  • control_qubits – Optional control qubit(s) — can be int, Qubit, QRegSlice, or a list thereof. Merged with any enclosing control() context block, same as ordinary gates.

qram_declare(name, addr_size, data_size)[source]

Declare a QRAM with the given address and data sizes.

Parameters:
  • name – Unique name for this QRAM.

  • addr_size – Number of address qubits.

  • data_size – Number of data qubits.

property qregs

Return the named quantum registers.

qubit_num
qwhile(cond, max_iterations=None)[source]

Open a QWHILE <cond> ... ENDQWHILE block.

Parameters:
  • cond – A condition string or Cond instance. Nonzero evaluates as true; re-evaluated before every iteration.

  • max_iterations – Optional override of the internal iteration watchdog (defaults to uniqc.circuit_builder.classical_program.DEFAULT_MAX_WHILE_ITERATIONS). This is a simulator safety cap, not part of the OriginIR-ext surface syntax.

Raises:

ValueError – If max_iterations is not a positive integer.

record_qubit(qubits)[source]

Record the qubits used in the circuit.

remapping(mapping)[source]

Create a new circuit with qubits remapped according to mapping.

reset(qubit)[source]

Mid-circuit reset of qubit to |0>.

Parameters:

qubit – The qubit to reset — int, Qubit, or QRegSlice (one qubit).

Raises:

ValueError – If qubit resolves to more than one qubit.

rphi(qn, theta=None, phi=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply RPhi rotation gate.

rx(qn, theta=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply RX rotation gate.

Parameters:
  • qn – Target qubit - can be int, Qubit, or QRegSlice

  • theta – Rotation angle in radians. Omit when has_param=True.

  • has_param – Auto-create an nn.Parameter for this gate.

  • trainable – Whether the parameter is trainable (only with has_param).

  • init_params – Custom initial value. Default: Uniform(-π, π).

ry(qn, theta=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply RY rotation gate.

rz(qn, theta=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply RZ rotation gate.

s(qn)[source]

Apply S (phase) gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

sdg(qn)[source]

Apply S-dagger (inverse phase) gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

set_control(*args)[source]

Manually open a CONTROL block (low-level API; prefer control()).

Parameters:

*args – Control qubits - can be int, Qubit, or QRegSlice

set_dagger()[source]

Manually open a DAGGER block (low-level API; prefer dagger()).

set_param(opcode_idx, tensor)[source]

Register a differentiable tensor for the parametric gate at opcode_idx.

Parameters:
  • opcode_idx – Index into opcode_list.

  • tensor – A torch.Tensor (typically with requires_grad=True).

Raises:

IndexError – If opcode_idx is out of range.

set_param_last(tensor)[source]

Register a tensor for the most recently added gate.

Convenience wrapper around set_param() for the common pattern of registering a parameter immediately after adding a gate.

Returns:

The opcode index that was registered.

Raises:

IndexError – If the circuit has no gates.

swap(q1, q2)[source]

Apply SWAP gate to two qubits.

Parameters:
  • q1 – First qubit - can be int, Qubit, or QRegSlice

  • q2 – Second qubit - can be int, Qubit, or QRegSlice

sx(qn)[source]

Apply square-root-of-X (SX) gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

sxdg(qn)[source]

Apply conjugate-transpose of SX gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

t(qn)[source]

Apply T gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

tdg(qn)[source]

Apply T-dagger (inverse T) gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

property tensor_params

Return all registered tensor parameters (for passing to an optimizer).

to_extended_originir()[source]

Export the circuit in extended OriginIR format (full form with QINIT/CREG/MEASURE).

to_originir()[source]

Export the circuit as an OriginIR string.

to_originir_official()[source]

Export the circuit as strict official OriginIR.

Extended gates are decomposed to the official gate set, and inline dagger / controlled_by syntax is replaced with block-level DAGGER / CONTROL delimiters. The output is suitable for submission to OriginQ cloud.

to_pyqpanda3_circuit()[source]

Convert to a pyqpanda3 QProg.

Returns:

pyqpanda3 QProg equivalent of this circuit.

Raises:

ImportError – If pyqpanda3 is not installed.

to_qasm()[source]

Export the circuit as an OpenQASM 2.0 string.

to_qiskit_circuit()[source]

Convert to a qiskit.QuantumCircuit.

Returns:

qiskit.QuantumCircuit equivalent of this circuit.

Raises:

ImportError – If qiskit is not installed.

toffoli(q1, q2, q3)[source]

Apply Toffoli (CCNOT) gate to three qubits.

Parameters:
  • q1 – First control qubit

  • q2 – Second control qubit

  • q3 – Target qubit

u1(qn, lam=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply U1 single-parameter unitary gate.

u2(qn, phi=None, lam=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply U2 two-parameter unitary gate.

u3(qn, theta=None, phi=None, lam=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply U3 three-parameter unitary gate.

unset_control()[source]

Manually close a CONTROL block (low-level API; prefer control()).

unset_dagger()[source]

Manually close a DAGGER block (low-level API; prefer dagger()).

used_qubit_list
uu15(q1, q2, params)[source]

Apply general two-qubit UU15 gate with 15 parameters.

Parameters:
  • q1 – First qubit - can be int, Qubit, or QRegSlice

  • q2 – Second qubit - can be int, Qubit, or QRegSlice

  • params – List of 15 rotation parameters in radians.

x(qn)[source]

Apply Pauli-X (NOT) gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

xx(q1, q2, theta=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply XX Ising interaction gate.

xy(q1, q2, theta)[source]

Apply XY Ising interaction gate.

Parameters:
  • q1 – First qubit - can be int, Qubit, or QRegSlice

  • q2 – Second qubit - can be int, Qubit, or QRegSlice

  • theta – Interaction angle in radians.

y(qn)[source]

Apply Pauli-Y gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

yy(q1, q2, theta=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply YY Ising interaction gate.

z(qn)[source]

Apply Pauli-Z gate to qubit.

Parameters:

qn – Target qubit - can be int, Qubit, or QRegSlice

zz(q1, q2, theta=None, *, has_param=False, trainable=True, init_params=None)[source]

Apply ZZ Ising interaction gate.

class uniqc.circuit_builder.qcircuit.CircuitControlContext(c, control_list)[source]

Bases: object

Context manager for controlled gate blocks.

c
control_list
class uniqc.circuit_builder.qcircuit.CircuitDagContext(c)[source]

Bases: object

Context manager for dagger (adjoint) gate blocks.

c