Skip to Content

Circuit Transformations

copy(), inverse(), dagger(), reverse(), repeat(), decompose(), and control() return a new circuit. append(), prepend(), initialize(), and gate methods mutate the circuit in place.

Distinguish these behaviors before choosing a method: transformations that return a circuit leave the original object unchanged, while composition and initialization methods modify the receiver.

from unitarylab import Circuit qc = Circuit(2) qc.h(0) qc.cx(0, 1) qc_copy = qc.copy() qc_inverse = qc.inverse() qc_dagger = qc.dagger() qc_reversed = qc.reverse() qc_repeated = qc.repeat(3) qc_decomposed = qc.decompose(n=1) qc_controlled = qc.control(num_control_qubits=2, control_state="01")
MethodDescription
copy()Return an independent copy
inverse() / dagger()Reverse gate order and take each gate’s conjugate transpose
reverse()Reverse qubit indices without changing gate order
repeat(times)Repeat the complete circuit
decompose(n, name)Expand block gates to the requested depth
control(num_control_qubits, control_state=None)Wrap the circuit in a controlled circuit
append(other, target, ...)Append a subcircuit in place
prepend(other, target, ...)Prepend a subcircuit in place
initialize(state, target, ...)Prepare a state in place; target qubits must not have been used

inverse() and dagger() are equivalent and produce the circuit adjoint. A circuit containing non-unitary operations such as measurement cannot be inverted. reverse() remaps qubit positions only; it does not reverse the time order of gates.

import numpy as np from unitarylab import Circuit sub = Circuit(2) sub.z(0) appended = qc.copy() appended.append(sub, target=[0, 1]) prepared = Circuit(2) state = np.array([1 / np.sqrt(2), 1 / np.sqrt(2)]) prepared.initialize(state, target=0) prepared.cx(0, 1)

The executor expands block-gate contents before execution. To draw or analyze the internal structure of block gates, call decompose() first.

Composition constraints

  • The length of target in append() and prepend() must match the subcircuit width; target indices must be unique.
  • Optional control qubits cannot overlap with target; the length of control_state must match the number of controls.
  • repeat(times) requires a positive integer times.
  • initialize() requires a state vector of length , where k is the number of target qubits; the state must be normalizable.
  • decompose(n=...) expands only the requested number of levels; repeated calls or larger n can expand nested blocks further.

Verifying transformations

For a small circuit without measurements, compare matrices to verify composition:

import numpy as np identity = qc.copy() identity.append(qc.inverse(), target=[0, 1]) assert np.allclose(identity.get_matrix(), np.eye(4))

Matrix construction requires memory exponential in the qubit count and is suitable only for small-circuit checks.

Last updated on