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

Qiskit / qiskit / 14412092632

11 Apr 2025 09:10PM UTC coverage: 88.11% (-0.1%) from 88.243%
14412092632

Pull #14176

github

web-flow
Merge baf6b6a53 into 13443f4c9
Pull Request #14176: Oxidize classical expression use in Rust code.

1002 of 1168 new or added lines in 18 files covered. (85.79%)

62 existing lines in 6 files now uncovered.

74088 of 84086 relevant lines covered (88.11%)

433947.98 hits per line

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

54.4
/crates/circuit/src/classical/expr/expr.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 http://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::{Binary, Cast, Index, Stretch, Unary, Value, Var};
14
use crate::classical::types::Type;
15
use pyo3::prelude::*;
16
use pyo3::{intern, IntoPyObjectExt};
17

18
/// A classical expression.
19
///
20
/// Variants that themselves contain [Expr]s are boxed. This is done instead
21
/// of boxing the contained [Expr]s within the specific type to reduce the
22
/// number of boxes we need (e.g. Binary would otherwise contain two boxed
23
/// expressions).
24
#[derive(Clone, Debug, PartialEq)]
25
pub enum Expr {
26
    Unary(Box<Unary>),
27
    Binary(Box<Binary>),
28
    Cast(Box<Cast>),
29
    Value(Value),
30
    Var(Var),
31
    Stretch(Stretch),
32
    Index(Box<Index>),
33
}
34

35
impl Expr {
36
    /// The const-ness of the expression.
37
    pub fn is_const(&self) -> bool {
4,452✔
38
        match self {
4,452✔
39
            Expr::Unary(u) => u.constant,
38✔
40
            Expr::Binary(b) => b.constant,
666✔
41
            Expr::Cast(c) => c.constant,
106✔
42
            Expr::Value(_) => true,
1,780✔
43
            Expr::Var(_) => false,
1,794✔
44
            Expr::Stretch(_) => true,
62✔
45
            Expr::Index(i) => i.constant,
6✔
46
        }
47
    }
4,452✔
48

49
    /// The expression's [Type].
NEW
50
    pub fn ty(&self) -> Type {
×
NEW
51
        match self {
×
NEW
52
            Expr::Unary(u) => u.ty,
×
NEW
53
            Expr::Binary(b) => b.ty,
×
NEW
54
            Expr::Cast(c) => c.ty,
×
NEW
55
            Expr::Value(v) => match v {
×
NEW
56
                Value::Duration(_) => Type::Duration,
×
NEW
57
                Value::Float { ty, .. } => *ty,
×
NEW
58
                Value::Uint { ty, .. } => *ty,
×
59
            },
NEW
60
            Expr::Var(v) => match v {
×
NEW
61
                Var::Standalone { ty, .. } => *ty,
×
NEW
62
                Var::Bit { .. } => Type::Bool,
×
NEW
63
                Var::Register { ty, .. } => *ty,
×
64
            },
NEW
65
            Expr::Stretch(_) => Type::Duration,
×
NEW
66
            Expr::Index(i) => i.ty,
×
67
        }
NEW
68
    }
×
69

70
    /// Returns an iterator over the [Var] nodes in this expression in some
71
    /// deterministic order.
72
    pub fn vars(&self) -> impl Iterator<Item = &Var> {
8,264✔
73
        VarIterator(ExprIterator { stack: vec![self] })
8,264✔
74
    }
8,264✔
75
}
76

77
/// A private iterator over the [Expr] nodes of an expression
78
/// by reference.
79
///
80
/// The first node reference returned is the [Expr] itself.
81
struct ExprIterator<'a> {
82
    stack: Vec<&'a Expr>,
83
}
84

85
impl<'a> Iterator for ExprIterator<'a> {
86
    type Item = &'a Expr;
87

88
    fn next(&mut self) -> Option<Self::Item> {
25,710✔
89
        let expr = self.stack.pop()?;
25,710✔
90
        match expr {
17,446✔
91
            Expr::Unary(u) => {
300✔
92
                self.stack.push(&u.operand);
300✔
93
            }
300✔
94
            Expr::Binary(b) => {
4,384✔
95
                self.stack.push(&b.left);
4,384✔
96
                self.stack.push(&b.right);
4,384✔
97
            }
4,384✔
98
            Expr::Cast(c) => self.stack.push(&c.operand),
82✔
99
            Expr::Value(_) => {}
6,230✔
100
            Expr::Var(_) => {}
6,434✔
NEW
101
            Expr::Stretch(_) => {}
×
102
            Expr::Index(i) => {
16✔
103
                self.stack.push(&i.index);
16✔
104
                self.stack.push(&i.target);
16✔
105
            }
16✔
106
        }
107
        Some(expr)
17,446✔
108
    }
25,710✔
109
}
110

111
/// A private iterator over the [Var] nodes contained within an [Expr].
112
struct VarIterator<'a>(ExprIterator<'a>);
113

114
impl<'a> Iterator for VarIterator<'a> {
115
    type Item = &'a Var;
116

117
    fn next(&mut self) -> Option<Self::Item> {
14,698✔
118
        for expr in self.0.by_ref() {
17,446✔
119
            if let Expr::Var(v) = expr {
17,446✔
120
                return Some(v);
6,434✔
121
            }
11,012✔
122
        }
123
        None
8,264✔
124
    }
14,698✔
125
}
126

127
impl From<Unary> for Expr {
NEW
128
    fn from(value: Unary) -> Self {
×
NEW
129
        Expr::Unary(Box::new(value))
×
NEW
130
    }
×
131
}
132

133
impl From<Box<Unary>> for Expr {
NEW
134
    fn from(value: Box<Unary>) -> Self {
×
NEW
135
        Expr::Unary(value)
×
NEW
136
    }
×
137
}
138

139
impl From<Binary> for Expr {
NEW
140
    fn from(value: Binary) -> Self {
×
NEW
141
        Expr::Binary(Box::new(value))
×
NEW
142
    }
×
143
}
144

145
impl From<Box<Binary>> for Expr {
NEW
146
    fn from(value: Box<Binary>) -> Self {
×
NEW
147
        Expr::Binary(value)
×
NEW
148
    }
×
149
}
150

151
impl From<Cast> for Expr {
NEW
152
    fn from(value: Cast) -> Self {
×
NEW
153
        Expr::Cast(Box::new(value))
×
NEW
154
    }
×
155
}
156

157
impl From<Box<Cast>> for Expr {
NEW
158
    fn from(value: Box<Cast>) -> Self {
×
NEW
159
        Expr::Cast(value)
×
NEW
160
    }
×
161
}
162

163
impl From<Value> for Expr {
NEW
164
    fn from(value: Value) -> Self {
×
NEW
165
        Expr::Value(value)
×
NEW
166
    }
×
167
}
168

169
impl From<Var> for Expr {
NEW
170
    fn from(value: Var) -> Self {
×
NEW
171
        Expr::Var(value)
×
NEW
172
    }
×
173
}
174

175
impl From<Stretch> for Expr {
NEW
176
    fn from(value: Stretch) -> Self {
×
NEW
177
        Expr::Stretch(value)
×
NEW
178
    }
×
179
}
180

181
impl From<Index> for Expr {
NEW
182
    fn from(value: Index) -> Self {
×
NEW
183
        Expr::Index(Box::new(value))
×
NEW
184
    }
×
185
}
186

187
impl From<Box<Index>> for Expr {
NEW
188
    fn from(value: Box<Index>) -> Self {
×
NEW
189
        Expr::Index(value)
×
NEW
190
    }
×
191
}
192

193
/// Root base class of all nodes in the expression tree.  The base case should never be
194
/// instantiated directly.
195
///
196
/// This must not be subclassed by users; subclasses form the internal data of the representation of
197
/// expressions, and it does not make sense to add more outside of Qiskit library code.
198
///
199
/// All subclasses are responsible for setting their ``type`` attribute in their ``__init__``, and
200
/// should not call the parent initializer."""
201
#[pyclass(
12✔
202
    eq,
12✔
203
    hash,
12✔
204
    subclass,
12✔
205
    frozen,
12✔
206
    name = "Expr",
12✔
207
    module = "qiskit._accelerate.circuit.classical.expr"
12✔
208
)]
12✔
209
#[derive(PartialEq, Clone, Copy, Debug, Hash)]
210
pub struct PyExpr(pub ExprKind); // ExprKind is used for fast extraction from Python
211

NEW
212
#[pymethods]
×
213
impl PyExpr {
214
    /// Call the relevant ``visit_*`` method on the given :class:`ExprVisitor`.  The usual entry
215
    /// point for a simple visitor is to construct it, and then call :meth:`accept` on the root
216
    /// object to be visited.  For example::
217
    ///
218
    ///     expr = ...
219
    ///     visitor = MyVisitor()
220
    ///     visitor.accept(expr)
221
    ///
222
    /// Subclasses of :class:`Expr` should override this to call the correct virtual method on the
223
    /// visitor.  This implements double dispatch with the visitor."""
224
    /// return visitor.visit_generic(self)
NEW
225
    fn accept<'py>(
×
NEW
226
        slf: PyRef<'py, Self>,
×
NEW
227
        visitor: &Bound<'py, PyAny>,
×
NEW
228
    ) -> PyResult<Bound<'py, PyAny>> {
×
NEW
229
        visitor.call_method1(intern!(visitor.py(), "visit_generic"), (slf,))
×
NEW
230
    }
×
231
}
232

233
/// The expression's kind, used internally during Python instance extraction to avoid
234
/// `isinstance` checks.
235
#[repr(u8)]
236
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
237
pub enum ExprKind {
238
    Unary,
239
    Binary,
240
    Value,
241
    Var,
242
    Cast,
243
    Stretch,
244
    Index,
245
}
246

247
impl<'py> IntoPyObject<'py> for Expr {
248
    type Target = PyAny;
249
    type Output = Bound<'py, PyAny>;
250
    type Error = PyErr;
251

252
    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
7,070✔
253
        match self {
7,070✔
254
            Expr::Unary(u) => u.into_bound_py_any(py),
142✔
255
            Expr::Binary(b) => b.into_bound_py_any(py),
1,766✔
256
            Expr::Cast(c) => c.into_bound_py_any(py),
48✔
257
            Expr::Value(v) => v.into_bound_py_any(py),
2,546✔
258
            Expr::Var(v) => v.into_bound_py_any(py),
2,450✔
259
            Expr::Stretch(s) => s.into_bound_py_any(py),
98✔
260
            Expr::Index(i) => i.into_bound_py_any(py),
20✔
261
        }
262
    }
7,070✔
263
}
264

265
impl<'py> FromPyObject<'py> for Expr {
266
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
31,442✔
267
        let expr: PyRef<'_, PyExpr> = ob.downcast()?.borrow();
31,442✔
268
        match expr.0 {
14,210✔
269
            ExprKind::Unary => Ok(Expr::Unary(Box::new(ob.extract()?))),
322✔
270
            ExprKind::Binary => Ok(Expr::Binary(Box::new(ob.extract()?))),
2,724✔
271
            ExprKind::Value => Ok(Expr::Value(ob.extract()?)),
4,584✔
272
            ExprKind::Var => Ok(Expr::Var(ob.extract()?)),
6,344✔
273
            ExprKind::Cast => Ok(Expr::Cast(Box::new(ob.extract()?))),
154✔
274
            ExprKind::Stretch => Ok(Expr::Stretch(ob.extract()?)),
62✔
275
            ExprKind::Index => Ok(Expr::Index(Box::new(ob.extract()?))),
20✔
276
        }
277
    }
31,442✔
278
}
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