• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 22659992356

04 Mar 2026 07:47AM UTC coverage: 87.711% (-0.3%) from 87.962%
22659992356

Pull #15502

github

web-flow
Merge 0c243f16e into c81aece0f
Pull Request #15502: Transpiler pass that converts a generic circuit to PBC

259 of 271 new or added lines in 5 files covered. (95.57%)

4560 existing lines in 202 files now uncovered.

100719 of 114830 relevant lines covered (87.71%)

1143514.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.47
/crates/circuit/src/classical/expr/binary.rs
1
// This code is part of Qiskit.
2
//
3
// (C) Copyright IBM 2025
4
//
5
// This code is licensed under the Apache License, Version 2.0. You may
6
// obtain a copy of this license in the LICENSE.txt file in the root directory
7
// of this source tree or at https://www.apache.org/licenses/LICENSE-2.0.
8
//
9
// Any modifications or derivative works of this code must retain this
10
// copyright notice, and modified files need to carry a notice indicating
11
// that they have been altered from the originals.
12

13
use crate::classical::expr::{Expr, ExprKind, PyExpr};
14
use crate::classical::types::Type;
15
use crate::imports;
16
use pyo3::prelude::*;
17
use pyo3::types::PyTuple;
18
use pyo3::{IntoPyObjectExt, intern};
19

20
/// A binary expression.
21
#[derive(Clone, Debug, PartialEq)]
22
pub struct Binary {
23
    pub op: BinaryOp,
24
    pub left: Expr,
25
    pub right: Expr,
26
    pub ty: Type,
27
    pub constant: bool,
28
}
29

30
/// The Rust-side enum indicating a [Binary] expression's kind.
31
///
32
/// The values are part of the public Qiskit Python interface, since
33
/// they are public in the sister Python enum `_BinaryOp` in `expr.py`
34
/// and used in our QPY serialization format.
35
///
36
/// WARNING: If you add more, **be sure to update expr.py** as well
37
/// as the implementation of [::bytemuck::CheckedBitPattern]
38
/// below.
39
#[repr(u8)]
40
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
41
pub enum BinaryOp {
42
    BitAnd = 1,
43
    BitOr = 2,
44
    BitXor = 3,
45
    LogicAnd = 4,
46
    LogicOr = 5,
47
    Equal = 6,
48
    NotEqual = 7,
49
    Less = 8,
50
    LessEqual = 9,
51
    Greater = 10,
52
    GreaterEqual = 11,
53
    ShiftLeft = 12,
54
    ShiftRight = 13,
55
    Add = 14,
56
    Sub = 15,
57
    Mul = 16,
58
    Div = 17,
59
}
60

61
unsafe impl ::bytemuck::CheckedBitPattern for BinaryOp {
62
    type Bits = u8;
63

64
    fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
3,020✔
65
        *bits > 0 && *bits < 18
3,020✔
66
    }
3,020✔
67
}
68

69
impl BinaryOp {
70
    pub fn from_u8(value: u8) -> PyResult<BinaryOp> {
298✔
71
        Ok(bytemuck::checked::cast::<u8, BinaryOp>(value))
298✔
72
    }
298✔
73
}
74

75
impl<'py> IntoPyObject<'py> for Binary {
76
    type Target = PyAny;
77
    type Output = Bound<'py, PyAny>;
78
    type Error = PyErr;
79

80
    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
2,228✔
81
        Ok(Bound::new(py, (PyBinary(self), PyExpr(ExprKind::Binary)))?.into_any())
2,228✔
82
    }
2,228✔
83
}
84

85
impl<'a, 'py> FromPyObject<'a, 'py> for Binary {
86
    type Error = <PyBinary as FromPyObject<'a, 'py>>::Error;
87

88
    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
2,560✔
89
        let PyBinary(b) = ob.extract()?;
2,560✔
90
        Ok(b)
2,560✔
91
    }
2,560✔
92
}
93

94
impl<'py> IntoPyObject<'py> for BinaryOp {
95
    type Target = PyAny;
96
    type Output = Bound<'py, Self::Target>;
97
    type Error = PyErr;
98

99
    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
1,316✔
100
        imports::BINARY_OP.get_bound(py).call1((self as usize,))
1,316✔
101
    }
1,316✔
102
}
103

104
impl<'a, 'py> FromPyObject<'a, 'py> for BinaryOp {
105
    type Error = PyErr;
106

107
    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
2,722✔
108
        let value = ob.getattr(intern!(ob.py(), "value"))?;
2,722✔
109
        Ok(bytemuck::checked::cast(value.extract::<u8>()?))
2,722✔
110
    }
2,722✔
111
}
112

113
/// A Python descriptor to prevent PyO3 from attempting to import the Python-side
114
/// enum before we're initialized.
115
#[pyclass(module = "qiskit._accelerate.circuit.classical.expr")]
116
struct PyBinaryOp;
117

118
#[pymethods]
119
impl PyBinaryOp {
120
    fn __get__(&self, obj: &Bound<PyAny>, _obj_type: &Bound<PyAny>) -> Py<PyAny> {
3,044✔
121
        imports::BINARY_OP.get_bound(obj.py()).clone().unbind()
3,044✔
122
    }
3,044✔
123
}
124

125
/// A binary expression.
126
///
127
/// Args:
128
///     op: The opcode describing which operation is being done.
129
///     left: The left-hand operand.
130
///     right: The right-hand operand.
131
///     type: The resolved type of the result.
132
#[pyclass(
133
    eq,
134
    extends = PyExpr,
135
    name = "Binary",
136
    module = "qiskit._accelerate.circuit.classical.expr",
UNCOV
137
    from_py_object
×
138
)]
139
#[derive(PartialEq, Clone, Debug)]
140
pub struct PyBinary(Binary);
141

UNCOV
142
#[pymethods]
×
143
impl PyBinary {
144
    // The docstring for 'Op' is defined in Python (expr.py).
145
    #[classattr]
146
    #[allow(non_snake_case)]
147
    fn Op(py: Python) -> PyResult<Py<PyAny>> {
12✔
148
        PyBinaryOp.into_py_any(py)
12✔
149
    }
12✔
150

151
    #[new]
152
    #[pyo3(text_signature = "(op, left, right, type)")]
153
    fn new(py: Python, op: BinaryOp, left: Expr, right: Expr, ty: Type) -> PyResult<Py<Self>> {
2,722✔
154
        let constant = left.is_const() && right.is_const();
2,722✔
155
        Py::new(
2,722✔
156
            py,
2,722✔
157
            (
2,722✔
158
                PyBinary(Binary {
2,722✔
159
                    op,
2,722✔
160
                    left,
2,722✔
161
                    right,
2,722✔
162
                    ty,
2,722✔
163
                    constant,
2,722✔
164
                }),
2,722✔
165
                PyExpr(ExprKind::Binary),
2,722✔
166
            ),
2,722✔
167
        )
168
    }
2,722✔
169

170
    #[getter]
171
    fn get_op(&self, py: Python) -> PyResult<Py<PyAny>> {
1,316✔
172
        self.0.op.into_py_any(py)
1,316✔
173
    }
1,316✔
174

175
    #[getter]
176
    fn get_left(&self, py: Python) -> PyResult<Py<PyAny>> {
3,064✔
177
        self.0.left.clone().into_py_any(py)
3,064✔
178
    }
3,064✔
179

180
    #[getter]
181
    fn get_right(&self, py: Python) -> PyResult<Py<PyAny>> {
2,908✔
182
        self.0.right.clone().into_py_any(py)
2,908✔
183
    }
2,908✔
184

185
    #[getter]
186
    fn get_const(&self) -> bool {
414✔
187
        self.0.constant
414✔
188
    }
414✔
189

190
    #[getter]
191
    fn get_type(&self, py: Python) -> PyResult<Py<PyAny>> {
5,678✔
192
        self.0.ty.into_py_any(py)
5,678✔
193
    }
5,678✔
194

195
    fn accept<'py>(
2,638✔
196
        slf: PyRef<'py, Self>,
2,638✔
197
        visitor: &Bound<'py, PyAny>,
2,638✔
198
    ) -> PyResult<Bound<'py, PyAny>> {
2,638✔
199
        visitor.call_method1(intern!(visitor.py(), "visit_binary"), (slf,))
2,638✔
200
    }
2,638✔
201

202
    fn __reduce__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
308✔
203
        (
204
            py.get_type::<Self>(),
308✔
205
            (
206
                self.get_op(py)?,
308✔
207
                self.get_left(py)?,
308✔
208
                self.get_right(py)?,
308✔
209
                self.get_type(py)?,
308✔
210
            ),
211
        )
212
            .into_pyobject(py)
308✔
213
    }
308✔
214

215
    fn __repr__(&self, py: Python) -> PyResult<String> {
8✔
216
        Ok(format!(
8✔
217
            "Binary({}, {}, {}, {})",
218
            self.get_op(py)?.bind(py).repr()?,
8✔
219
            self.get_left(py)?.bind(py).repr()?,
8✔
220
            self.get_right(py)?.bind(py).repr()?,
8✔
221
            self.get_type(py)?.bind(py).repr()?,
8✔
222
        ))
223
    }
8✔
224
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc