Circuits¶
ParityOS provides a framework for representing quantum circuits as ordered sequences of
Operator instances. Circuits serve as the primary container for composing quantum algorithms,
supporting both mutable construction and immutable finalization.
Architecture Hierarchy¶
The following is a coarse overview of the inheritance hierarchy of classes describing circuits:
CircuitLike (Interface for all circuit-like operations)
├── Circuit (Mutable circuit, built up by successively adding operators)
│ └── operator_sequence: list[Operator]
└── FrozenCircuit (Immutable, hashable circuit)
└── operator_sequence: tuple[Operator]
Both Circuit and FrozenCircuit inherit from CircuitLike, implementing the Sequence protocol
to allow indexing and iteration over their operators.
Circuit Properties¶
Certain circuit properties can be checked via methods or by inspecting the aggregated operators.
Sequence and Ordering¶
Circuits are strictly ordered sequences. Two circuits are considered equal only if they contain the exact same operators in the exact same order. Equivalent circuits (e.g. circuits that only differ by permutations of commuting operators) are not considered equal.
from parityos.bits import Qubit
from parityos.operators.circuit import Circuit
from parityos.operators.controlled_operator import CNOT
from parityos.operators.elementary_operator import X
q0, q1 = Qubit(0), Qubit(1)
c1 = Circuit([X(q1), X(q0), CNOT(q0, q1)])
c2 = Circuit([X(q0), X(q1), CNOT(q0, q1)])
assert c1 != c2 # Order matters, even if operators commute
Hermiticity¶
A circuit’s Hermiticity is determined by its constituent operators. You can check if a circuit is
Hermitian by accessing the is_hermitian property or verifying if it is an instance of a Hermitian-compatible
interface (though the primary check is the boolean property).
from parityos.bits import Qubit
from parityos.operators.circuit import Circuit
from parityos.operators.elementary_operator import S, X
qubit = Qubit(0)
# X is Hermitian
c_x = Circuit([X(qubit)])
assert c_x.is_hermitian
# S is not Hermitian
c_s = Circuit([S(qubit)])
assert not c_s.is_hermitian
# Mixed circuit
c_mixed = Circuit([X(qubit), S(qubit)])
assert not c_mixed.is_hermitian
Qubits and Classical Bits¶
Circuits automatically aggregate the qubits and classical bits (cbits) used by their operators and implement the HasFrozenQubits and HasFrozenCBits interfaces:
ordered_qubits: Returns a sorted tuple of the above unique qubit set.cbits: Returns afrozensetof all classical bits (only for operators that support them, e.g., measurements).ordered_cbits: Returns a sorted tuple of the above unique classical bit set.
Circuit Classes¶
Mutable Circuits¶
Circuit is a mutable class designed for building quantum algorithms incrementally. It maintains an
internal list of operators that can be modified after instantiation.
Construction:
from parityos.bits import Qubit
from parityos.operators.circuit import Circuit
from parityos.operators.elementary_operator import H, X
q0, q1 = Qubit(0), Qubit(1)
# Initialize with a list
c = Circuit([X(q0), H(q1)])
Modification: As a mutable sequence, Circuit supports standard list operations:
append: Add an operator to the end.insert: Insert an operator at a specific index.__setitem__: Replace an operator.__delitem__: Remove an operator.
Mutable only methods
measure_all: AppendsMZ(Z-measurement) operators for all qubits in the circuit. It automatically generates new classical bits with unique IDs, skipping any IDs already in use.freeze: Converts the mutableCircuitinto an immutableFrozenCircuit, e.g.
frozen_c = c.freeze()
Immutable Circuits¶
FrozenCircuit is an immutable, hashable representation of a circuit. Once created, its operator
sequence cannot be changed.
Construction: Can be created by using freeze <Circuit.freeze> on a Circuit or instantiated directly. Likewise, a Circuit can be created from a FrozenCircuit using unfreeze
Circuit Addition¶
Appends the operators of one circuit to another using the + operator.
from parityos.bits import Cbit, Qubit
from parityos.operators import Circuit
from parityos.operators.conditional_operator import ConditionalOperator
from parityos.operators.controlled_operator import CX
from parityos.operators.elementary_operator import H, X, Z
from parityos.operators.measurement import MZ
q0, q1, qpsi = Qubit(0), Qubit(1), Qubit("psi")
c0, c1 = Cbit(0), Cbit(1)
# bell state
circuit1 = Circuit([H(q0), CX(q0, q1)])
# teleportation
circuit2 = Circuit([CX(qpsi, q0), H(qpsi), MZ(qpsi, c1), MZ(q0, c0)])
# classical correction
circuit3 = Circuit([ConditionalOperator(c0, X(q1)), ConditionalOperator(c1, Z(q1))])
circuit = circuit1 + circuit2 + circuit3
assert circuit.qubits == {q0, q1, qpsi}
assert circuit.cbits == {c0, c1}
If at least one of the circuits is frozen, the resulting circuit will be a FrozenCircuit, otherwise it will be a Circuit.
Scalar Circuit Multiplication¶
The multiplication operator * facilitates the concatenation of a circuit sequence to itself n times. This is similar in spirit to the scalar multiplication of lists.
from parityos.bits import Qubit
from parityos.operators import Circuit
from parityos.operators.controlled_operator import CX
from parityos.operators.elementary_operator import H
from parityos.operators.rotation_operator import RX
q0, q1 = Qubit(0), Qubit(1)
circuit = Circuit([H(q0), CX(q0, q1), RX(q1)])
repeated_circuit = circuit * 3
assert repeated_circuit == 3 * circuit
Warning
Only multiplication of Circuits with scalars are supported, multiplications between circuits are not.