Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ members = [
resolver = "2"

[workspace.package]
version = "0.1.0-beta.2"
version = "0.1.0-beta.3"
edition = "2024"
rust-version = "1.89"
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion crates/binding-c/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ license.workspace = true
crate-type = ["rlib", "staticlib", "cdylib"]

[dependencies]
cqlib-core = { path = "../cqlib-core", version = "0.1.0-beta.2" }
cqlib-core = { path = "../cqlib-core", version = "0.1.0-beta.3" }
libc = "0.2"
ndarray.workspace = true
num-complex.workspace = true
Expand Down
4 changes: 2 additions & 2 deletions crates/binding-python/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "binding-python"
version = "2.0.0-beta2"
version = "2.0.0-beta3"
edition.workspace = true
rust-version.workspace = true
license-file.workspace = true
Expand All @@ -14,7 +14,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
pyo3 = { version = "0.29", features = ["abi3-py310", "num-complex", "chrono"] }
chrono = "0.4"
cqlib-core = { path = "../cqlib-core", version = '0.1.0-beta.2' }
cqlib-core = { path = "../cqlib-core", version = '0.1.0-beta.3' }
num-complex.workspace = true
numpy.workspace = true
rustworkx-core.workspace = true
Expand Down
2 changes: 2 additions & 0 deletions crates/binding-python/cqlib/circuit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
ClassicalValue = _circuit_module.ClassicalValue
Measurement = _circuit_module.Measurement
ClassicalExpr = _circuit_module.ClassicalExpr
ClassicalDataOp = _circuit_module.ClassicalDataOp
ValueControlBody = _circuit_module.ValueControlBody
ValueSwitchCase = _circuit_module.ValueSwitchCase
ClassicalControlOp = _circuit_module.ClassicalControlOp
Expand All @@ -66,6 +67,7 @@
"CircuitId",
"CircuitError",
"ClassicalControlOp",
"ClassicalDataOp",
"ClassicalExpr",
"ClassicalType",
"ClassicalValue",
Expand Down
3 changes: 3 additions & 0 deletions crates/binding-python/cqlib/circuit/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Submodule Purpose Key types
``.gates`` Gate definitions and factory constants :class:`StandardGate`
``.parameter`` Symbolic/numeric parameter expressions :class:`Parameter`
``.classical`` Runtime classical types and storage handles :class:`ClassicalType`
``.classical_data`` Runtime classical data operations :class:`ClassicalDataOp`
``.classical_expr`` Typed classical expression AST :class:`ClassicalExpr`
``.control_flow`` Classical control-flow operations :class:`ClassicalControlOp`
``.operation`` Instruction and operation types :class:`ValueOperation`
Expand Down Expand Up @@ -84,6 +85,7 @@ from .classical import (
ClassicalVar as ClassicalVar,
Measurement as Measurement,
)
from .classical_data import ClassicalDataOp as ClassicalDataOp
from .classical_expr import ClassicalExpr as ClassicalExpr
from .control_flow import (
ClassicalControlOp as ClassicalControlOp,
Expand Down Expand Up @@ -121,6 +123,7 @@ __all__ = [
"CircuitId",
"CircuitError",
"ClassicalControlOp",
"ClassicalDataOp",
"ClassicalExpr",
"ClassicalType",
"ClassicalValue",
Expand Down
19 changes: 19 additions & 0 deletions crates/binding-python/cqlib/circuit/classical_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This code is part of Cqlib.
#
# (C) Copyright China Telecom Quantum Group 2026
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Runtime exports for classical data operations."""

from .._native import circuit as _circuit_module

ClassicalDataOp = _circuit_module.ClassicalDataOp

__all__ = ["ClassicalDataOp"]
46 changes: 46 additions & 0 deletions crates/binding-python/cqlib/circuit/classical_data.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This code is part of Cqlib.
#
# (C) Copyright China Telecom Quantum Group 2026
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Runtime classical data operations.

:class:`ClassicalDataOp` models side-effecting classical updates in a
circuit schedule: stores into mutable classical variables and measurements
producing immutable classical values. Instances are obtained from
:attr:`Instruction.classical_data` or :attr:`ValueInstruction.classical_data`;
they are not constructed directly.
"""

from .classical import ClassicalValue, ClassicalVar
from .classical_expr import ClassicalExpr

class ClassicalDataOp:
"""Runtime classical data operation (store or measurement)."""
@property
def kind(self) -> str:
"""One of ``"store"``, ``"measure_bit"``, or ``"measure_bits"``."""
...
@property
def target(self) -> ClassicalVar | None:
"""The store target variable if this is a store operation."""
...
@property
def value(self) -> ClassicalExpr | None:
"""The stored expression if this is a store operation."""
...
@property
def result(self) -> ClassicalValue | None:
"""The immutable value receiving the result if this is a measurement."""
...
def __eq__(self, other: object) -> bool: ...
def __copy__(self) -> ClassicalDataOp: ...
def __deepcopy__(self, memo: dict) -> ClassicalDataOp: ...
def __repr__(self) -> str: ...
56 changes: 56 additions & 0 deletions crates/binding-python/cqlib/circuit/operation.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ qubits and parameters to form a complete circuit operation.
import numpy as np
from numpy.typing import NDArray
from .bit import Qubit
from .classical_data import ClassicalDataOp
from .control_flow import ClassicalControlOp
from .gates import CircuitGate, Directive, MCGate, StandardGate, UnitaryGate
from .parameter import Parameter
Expand Down Expand Up @@ -99,6 +100,34 @@ class Instruction:
def directive(self) -> Directive | None:
"""The :class:`Directive` if this is a directive instruction."""
...
@property
def mc_gate(self) -> MCGate | None:
"""The :class:`MCGate` if this is an mc-gate instruction.

The returned gate carries no bound parameters: parameters belong to
the operation (``Operation.params`` / ``ValueOperation.params``), not
to the instruction.
"""
...
@property
def unitary_gate(self) -> UnitaryGate | None:
"""The :class:`UnitaryGate` if this is a unitary instruction.

Parameters of a parametric unitary belong to the operation, not to
the instruction.
"""
...
@property
def circuit_gate(self) -> CircuitGate | None:
"""The :class:`CircuitGate` if this is a circuit-gate instruction.

Parameters belong to the operation, not to the instruction.
"""
...
@property
def classical_data(self) -> ClassicalDataOp | None:
"""The :class:`ClassicalDataOp` if this is a classical-data instruction."""
...
def __str__(self) -> str: ...
def __copy__(self) -> Instruction: ...
def __deepcopy__(self, memo: dict) -> Instruction: ...
Expand Down Expand Up @@ -153,6 +182,33 @@ class ValueInstruction:
"""The :class:`Directive` if this is a directive instruction."""
...
@property
def mc_gate(self) -> MCGate | None:
"""The :class:`MCGate` if this is an mc-gate instruction.

The returned gate carries no bound parameters: parameters belong to
the operation (``ValueOperation.params``), not to the instruction.
"""
...
@property
def unitary_gate(self) -> UnitaryGate | None:
"""The :class:`UnitaryGate` if this is a unitary instruction.

Parameters of a parametric unitary belong to the operation, not to
the instruction.
"""
...
@property
def circuit_gate(self) -> CircuitGate | None:
"""The :class:`CircuitGate` if this is a circuit-gate instruction.

Parameters belong to the operation, not to the instruction.
"""
...
@property
def classical_data(self) -> ClassicalDataOp | None:
"""The :class:`ClassicalDataOp` if this is a classical-data instruction."""
...
@property
def instruction(self) -> Instruction | None:
"""The inner :class:`Instruction` when this is a plain instruction."""
...
Expand Down
85 changes: 85 additions & 0 deletions crates/binding-python/src/circuit/classical_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
// This code is part of Cqlib.
//
// (C) Copyright China Telecom Quantum Group 2026
//
// This code is licensed under the Apache License, Version 2.0. You may
// obtain a copy of this license in the LICENSE.txt file in the root directory
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
//
// Any modifications or derivative works of this code must retain this
// copyright notice, and modified files need to carry a notice indicating
// that they have been altered from the originals.

//! Python wrapper for runtime classical data operations.

use crate::circuit::{PyClassicalExpr, PyClassicalValue, PyClassicalVar};
use cqlib_core::circuit::gate::ClassicalDataOp;
use pyo3::prelude::*;

/// Runtime classical data operation: a store into a mutable classical
/// variable, or a measurement producing an immutable classical value.
///
/// Instances are obtained from `Instruction.classical_data` /
/// `ValueInstruction.classical_data`; they are not constructed directly.
#[pyclass(name = "ClassicalDataOp", module = "cqlib.circuit", from_py_object)]
#[derive(Debug, Clone)]
pub struct PyClassicalDataOp {
pub(crate) inner: ClassicalDataOp,
}

impl From<ClassicalDataOp> for PyClassicalDataOp {
fn from(inner: ClassicalDataOp) -> Self {
Self { inner }
}
}

#[pymethods]
impl PyClassicalDataOp {
/// Returns the operation kind: `'store'`, `'measure_bit'`, or
/// `'measure_bits'`.
#[getter]
pub fn kind(&self) -> &'static str {
self.inner.name()
}

/// Returns the store target variable if this is a store operation,
/// None otherwise.
#[getter]
pub fn target(&self) -> Option<PyClassicalVar> {
self.inner.target().map(PyClassicalVar::from)
}

/// Returns the stored expression if this is a store operation,
/// None otherwise.
#[getter]
pub fn value(&self) -> Option<PyClassicalExpr> {
self.inner.value().cloned().map(PyClassicalExpr::from)
}

/// Returns the immutable value receiving the result if this is a
/// measurement operation, None otherwise.
#[getter]
pub fn result(&self) -> Option<PyClassicalValue> {
self.inner.result().map(PyClassicalValue::from)
}

fn __repr__(&self) -> String {
format!("ClassicalDataOp({})", self.inner.name())
}

fn __eq__(&self, other: &Bound<'_, PyAny>) -> PyResult<bool> {
if !other.is_instance_of::<PyClassicalDataOp>() {
return Ok(false);
}
let other = other.extract::<PyClassicalDataOp>()?;
Ok(self.inner == other.inner)
}

fn __copy__(&self) -> Self {
self.clone()
}

fn __deepcopy__(&self, _memo: &Bound<'_, PyAny>) -> Self {
self.clone()
}
}
Loading
Loading