Operator Reference¶
Operators are the building blocks of quantum operations in PySparQ. All operations are implemented as operator objects that take a SparseState and transform it.
What Is an Operator?¶
An operator is a callable object that transforms a SparseState, implementing quantum operations while guaranteeing unitarity.
Basic Usage¶
import pysparq as ps
ps.System.clear()
# Create registers
ps.System.add_register("a", ps.UnsignedInteger, 4)
ps.System.add_register("b", ps.UnsignedInteger, 4)
ps.System.add_register("result", ps.UnsignedInteger, 4)
state = ps.SparseState()
# Initialize the inputs
ps.Init_Unsafe("a", 3)(state)
ps.Init_Unsafe("b", 5)(state)
# Create and apply an operator
add_op = ps.Add_UInt_UInt("a", "b", "result")
add_op(state) # apply the operator
# For a non-self-adjoint operator, use dag() to undo the operation
add_op.dag(state) # undo (restore the original state)
Operator Properties¶
Unitarity¶
All quantum operators must satisfy the unitarity condition:
PySparQ guarantees unitarity through two mechanisms:
Type |
Mechanism |
Example |
|---|---|---|
Out-of-place |
XOR write: |
|
In-place |
Explicit dagger implementation |
|
SelfAdjointOperator vs BaseOperator¶
Base class |
Characteristics |
|
Typical operators |
|---|---|---|---|
|
\(U^\dagger = U\) |
|
|
|
General unitary operator |
Requires an explicit |
|
# SelfAdjointOperator: applying twice restores the original state
op = ps.Add_UInt_UInt("a", "b", "result")
op(state) # apply
op(state) # apply again = undo (because XOR is self-inverse)
# BaseOperator: dag() is required to undo
op = ps.ShiftLeft_InPlace("reg", 2)
op(state) # shift left by 2 bits
op.dag(state) # shift right by 2 bits (undo)
Type Constraints¶
Operators impose strict requirements on register types:
Type |
Description |
Valid range |
|---|---|---|
|
Unsigned integer |
\([0, 2^n-1]\) |
|
Signed integer (two’s complement) |
\([-2^{n-1}, 2^{n-1}-1]\) |
|
Single qubit |
{0, 1} |
|
Fixed-point fraction |
\([0, 1)\) |
|
Raw bit storage |
Arbitrary bit patterns |
# Correct: Boolean for single-qubit gates
ps.System.add_register("qubit", ps.Boolean, 1)
ps.X_Bool("qubit", 0)(state)
# Wrong: type mismatch
# ps.System.add_register("counter", ps.UnsignedInteger, 4)
# ps.X_Bool("counter", 0)(state) # raises an exception!
Bit Constraints¶
Many operators verify:
Register sizes match the expected dimensions
Bit indices are within the register range
Output registers have sufficient capacity
Conditional Operations¶
All operators support conditional execution to implement controlled operations.
Condition Methods¶
Method |
Condition |
Example |
|---|---|---|
|
Register value ≠ 0 |
Controlled by any nonzero state |
|
All bits are 1 |
Multi-qubit control |
|
The specified bit is 1 |
Single-qubit control |
|
The register equals a specific value |
Classical control |
op = ps.Add_UInt_UInt("a", "b", "result")
# Apply when the control register is nonzero
op.conditioned_by_nonzeros("control")(state)
# Apply when bit 0 of flag is 1
op.conditioned_by_bit("flag", 0)(state)
# Apply when mode equals 1
op.conditioned_by_value("mode", 1)(state)
# Multiple conditions
op.conditioned_by_nonzeros(["ctrl1", "ctrl2"])(state)
Clearing Control Conditions¶
op.clear_control_nonzeros()
op.clear_control_by_bit()
op.clear_control_by_value()
op.clear_control_all_ones()
Inspecting Control Variables¶
# Get the current control variables
print(op.condition_variable_nonzeros)
print(op.condition_variable_by_bit) # list[tuple[int, int]]
print(op.condition_variable_by_value) # list[tuple[int, int]]