Package qucirc
qucirc
A lightweight and extensible quantum circuit representation for Python and Rust.
| crates.io | docs.rs | Github | PyPI | Documentation |
Features
- Support for common quantum gates (H, X, Y, Z, CNOT, etc.) defined in OpenQASM 3.0 Standard Library
- Python API for easy integration
- Extendable circuit visualization using Typst
- DAG Representation of the circuit, easily exported to
petgraph
. - Support for parameterized gates (RX, RY, RZ, U, etc.)
- Classical bit operations and measurements
- SVG visualization support
Installation
Python
pip install qucirc
Rust
cargo add qucirc
Usage
Basic Circuit Creation
from qucirc import Circuit, ops
# Create a new circuit with 2 qubits
circ = Circuit(2)
# Add some gates
circ += ops.H[0] # Hadamard gate on qubit 0
circ += ops.CNOT[0, 1] # CNOT gate with control=0, target=1
# Visualize the circuit
print(circ.to_typst()) # Typst representation
print(circ.to_svg()) # SVG visualization
Working with Gates
The library supports various quantum gates:
- Single-qubit gates: H, X, Y, Z, S, T
- Parameterized gates: RX(θ), RY(θ), RZ(θ), P(φ)
- Two-qubit gates: CNOT, CY, CZ, SWAP
- Controlled gates: CH, CP(φ), CRX(θ), CRY(θ), CRZ(θ), CU(θ,φ,λ)
Example with parameterized gates:
from qucirc import Circuit, ops
import math
circuit = Circuit(2)
circuit += ops.RX(math.pi/2)[0] # Rotation around X axis
circuit += ops.CP(math.pi/4)[0, 1] # Controlled phase gate
circ
Classical Bits and Measurements
from qucirc import Circuit, ops
circuit = Circuit(2)
# Add a classical bit
bit_index = circuit.new_bits(bitwidth=1, name="c0")
# Add measurement
circuit.add_gate(ops.Measure[0, bit_index])
Circuit Visualization
The library provides multiple ways to visualize circuits:
- Typst visualization based on Quill:
# Using Jupyter Notebook
import math
import qucirc
from qucirc import ops
circ = qucirc.Circuit()
[q0, q1] = circ.new_qubits("q_0", "q_1")
circ += ops.H[q0]
circ += ops.H[q1]
circ += ops.CNOT[q0, q1]
circ += ops.P(math.pi / 3)[q0]
c0 = circ.new_bits()
circ += ops.Measure[q0, c0]
circ
- Exporting to Typst (for documentation):
print(circ.to_typst())
- String representation:
print(circ)
DAG-based Symbolic representation
import math
import qucirc
from qucirc import ops
circ1 = qucirc.Circuit()
circ1 += ops.H[0]
circ1 += ops.P(1/3 * math.pi)[1]
circ2 = qucirc.Circuit()
circ2 += ops.P(1/3 * math.pi)[1]
circ2 += ops.H[0]
assert circ1 == circ2
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Sub-modules
qucirc.ops
-
Quantum gate operations: …
Classes
class Bits (...)
-
A structure encapsulating a classical wire characterized by an identifier and a bitwidth. This type represents a classical wire by wrapping a string label with its corresponding number of bits, facilitating its use in contexts where explicit bit specifications and identifier management are required.
Static methods
def new(name, bitwidth)
-
Creates and returns a new classical wire instance with the specified identifier and bitwidth. This function constructs a new wire with the provided name and number of bits, then boxes it for dynamic dispatch over the underlying wire interface.
class Circuit (qubits=0)
-
A structure representing a quantum circuit with its associated components is defined. This type organizes the circuit’s state by maintaining a vector of wires, a directed acyclic graph where nodes correspond to quantum gates and edges represent connections via wire indices, and a vector that tracks the current output node for each input wire.
Instance variables
var wires
-
Returns a vector containing cloned boxed wire trait objects from the circuit's internal collection.
This accessor function retrieves all wires by cloning the internal list, ensuring that the caller receives an independent copy of the wires for inspection or further manipulation.
Methods
def get_wire(self, /, name)
-
Retrieves the index of a wire based on its string representation.
Searches through the internal collection of wires and returns the position of the first wire whose debug format matches the provided name, returning None if no match is found.
def new_bits(self, /, bitwidth=1, name=Ellipsis)
-
Creates and adds a new wire representing bits to the circuit.
Adds a wire with a specified bitwidth and name to the circuit. If the provided name is empty, a default name is generated automatically to ensure uniqueness. The wire is appended to the list of circuit wires, and the corresponding output is initialized to None, returning the index of the newly added wire.
def new_qubit(self, /, name=Ellipsis)
-
Creates and registers a new qubit wire within the circuit.
This function accepts a mutable string for the qubit's name and, if the provided name is empty, automatically generates a unique identifier. It appends a new qubit to the circuit's collection of wires and returns the index corresponding to the newly added wire.
def new_qubits(self, /, *args)
-
Creates several new qubit wires from a vector of names and returns their indices. This method iterates over each provided name, cloning it as necessary, and calls the routine responsible for initializing a new qubit wire for each entry; the resulting indices are then collected and returned as a vector.
def new_qubits_n(self, /, count=1, name=Ellipsis)
-
Creates a set of new qubits and returns their indices as a vector.
This method accepts a count and a name, and for each qubit to be created, it delegates to the single qubit creation function. If the provided name is empty or equals "q", it automatically generates a unique identifier; otherwise, it uses the provided name for every qubit created.
def new_wire(self, /, wire)
-
Adds a new wire to the circuit and returns its index. This method takes ownership of a boxed wire trait object, appends it to the internal collection of wires, and updates the output tracking vector by inserting a corresponding placeholder.
def new_zerostate(self, /)
-
Constructs and appends a new zero state wire to the circuit, returning the index of the added wire.
Adds a zero state wire by inserting it into the circuit’s collection of wires and initializes its corresponding output placeholder, thereby expanding and managing the circuit’s internal state.
def to_gates(self, /)
-
Returns a vector containing all the gates that compose the circuit. This method extracts the gate entries from the underlying circuit structure, clones each one, and collects them into a list for subsequent use.
def to_typst(self, /)
-
Converts the circuit into a typst-formatted string representation.
Transforms the circuit's internal state into a typst document string, enabling further rendering or integration into documentation.
class Gate (...)
-
Encapsulates a quantum gate that couples an operation with its input wire indices. This structure holds a boxed operation implementing the required interface for quantum operations and a list of indices that identify the corresponding input wires, allowing for structured management and manipulation within a quantum circuit.
class Qubit (...)
-
A simple wrapper type encapsulating a quantum bit identifier using a string.
This type primarily serves to distinguish quantum bits from other wire representations by wrapping a string value that acts as its identifier. Its design promotes clear type usage in the context of quantum circuits while supporting the trait object interface defined for wires.
Static methods
def new(name)
-
Creates a new instance representing a quantum bit wire. This function accepts a string parameter to label the quantum element and returns it as a boxed dynamic trait object, enabling it to be used polymorphically wherever the wire abstraction is required.
class ZeroState (...)
-
A unit structure representing a quantum wire initialized to a zero state.
This item embodies a specialized wire used within quantum circuit implementations, ensuring compatibility with interface expectations for quantum wires while serving as a straightforward, marker-like type. It is intended for use in contexts where the initialization of a quantum bit to a zero state is required.
Static methods
def new()
-
Returns a boxed trait object encapsulating a quantum wire in the zero state. This constructor function instantiates the zero state wire, enabling its use within contexts where trait objects conforming to the wire interface are required.