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

Qiskit / qiskit / 14337982611

08 Apr 2025 03:49PM CUT coverage: 88.218% (+0.06%) from 88.154%
14337982611

Pull #14000

github

web-flow
Merge eec52e5d3 into b0bc6d8cb
Pull Request #14000: Unify identifer handling of `Var` and `Stretch` in `DAGCircuit`

206 of 231 new or added lines in 3 files covered. (89.18%)

5 existing lines in 2 files now uncovered.

73590 of 83418 relevant lines covered (88.22%)

436285.81 hits per line

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

86.11
/crates/circuit/src/lib.rs
1
// This code is part of Qiskit.
2
//
3
// (C) Copyright IBM 2023, 2024
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
pub mod bit;
14
pub mod bit_locator;
15
pub mod circuit_data;
16
pub mod circuit_instruction;
17
pub mod converters;
18
pub mod dag_circuit;
19
pub mod dag_node;
20
mod dot_utils;
21
pub mod duration;
22
pub mod error;
23
pub mod gate_matrix;
24
pub mod imports;
25
pub mod interner;
26
pub mod object_registry;
27
pub mod operations;
28
pub mod packed_instruction;
29
pub mod parameter_table;
30
pub mod register_data;
31
pub mod slice;
32
pub mod util;
33

34
pub mod rustworkx_core_vnext;
35

36
use pyo3::prelude::*;
37
use pyo3::types::{PySequence, PyTuple};
38
use pyo3::PyTypeInfo;
39

40
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, FromPyObject)]
41
pub struct Qubit(pub u32);
42

43
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, FromPyObject)]
44
pub struct Clbit(pub u32);
45

46
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
47
pub struct Var(u32);
48

49
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
50
pub struct Stretch(u32);
51

52
macro_rules! impl_circuit_identifier {
53
    ($type:ident) => {
54
        impl $type {
55
            /// Construct a new identifier from a usize, if you have a u32 you can
56
            /// construct one directly via [$type()]. This will panic if the `usize`
57
            /// index exceeds `u32::MAX`.
58
            #[inline(always)]
59
            pub fn new(index: usize) -> Self {
5,580,402✔
60
                $type(index.try_into().unwrap_or_else(|_| {
5,580,402✔
NEW
61
                    panic!(
×
NEW
62
                        "Index value '{}' exceeds the maximum identifier width!",
×
NEW
63
                        index
×
NEW
64
                    )
×
65
                }))
5,580,402✔
66
            }
5,580,402✔
67

68
            /// Convert to a usize.
69
            #[inline(always)]
70
            pub fn index(&self) -> usize {
10,906,084✔
71
                self.0 as usize
10,906,084✔
72
            }
10,906,084✔
73
        }
74

75
        impl From<u32> for $type {
76
            fn from(value: u32) -> Self {
10,252,150✔
77
                $type(value)
10,252,150✔
78
            }
10,252,150✔
79
        }
80

81
        impl From<$type> for u32 {
82
            fn from(value: $type) -> Self {
23,588,860✔
83
                value.0
23,588,860✔
84
            }
23,588,860✔
85
        }
86
    };
87
}
88

89
impl_circuit_identifier!(Qubit);
90
impl_circuit_identifier!(Clbit);
91
impl_circuit_identifier!(Var);
92
impl_circuit_identifier!(Stretch);
93

94
pub struct TupleLikeArg<'py> {
95
    value: Bound<'py, PyTuple>,
96
}
97

98
impl<'py> FromPyObject<'py> for TupleLikeArg<'py> {
99
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
207,086✔
100
        let value = match ob.downcast::<PySequence>() {
207,086✔
101
            Ok(seq) => seq.to_tuple()?,
207,022✔
102
            Err(_) => PyTuple::new(
103
                ob.py(),
64✔
104
                ob.try_iter()?
64✔
105
                    .map(|o| Ok(o?.unbind()))
64✔
106
                    .collect::<PyResult<Vec<PyObject>>>()?,
64✔
107
            )?,
×
108
        };
109
        Ok(TupleLikeArg { value })
207,086✔
110
    }
207,086✔
111
}
112

113
/// Implement `IntoPyObject` for the reference to a struct or enum declared as `#[pyclass]` that is
114
/// also `Copy`.
115
///
116
/// For example:
117
/// ```
118
/// #[derive(Clone, Copy)]
119
/// #[pyclass(frozen)]
120
/// struct MyStruct(u32);
121
///
122
/// impl_intopyobject_for_copy_pyclass!(MyStruct);
123
/// ```
124
///
125
/// The `pyclass` attribute macro already ensures that `IntoPyObject` is implemented for `MyStruct`,
126
/// but it doesn't implement it for `&MyStruct` - for non-copy structs, the implementation of that
127
/// is not obvious and may be surprising to users if it existed.  If the struct is `Copy`, though,
128
/// it's explicitly "free" to make new copies and convert them, so we can do that and delegate.
129
///
130
/// Usually this doesn't matter much to code authors, but it can help a lot when dealing with
131
/// references nested in ad-hoc structures, like `(&T1, &T2)`.
132
#[macro_export]
133
macro_rules! impl_intopyobject_for_copy_pyclass {
134
    ($ty:ty) => {
135
        impl<'py> ::pyo3::conversion::IntoPyObject<'py> for &$ty {
136
            type Target = <$ty as ::pyo3::conversion::IntoPyObject<'py>>::Target;
137
            type Output = <$ty as ::pyo3::conversion::IntoPyObject<'py>>::Output;
138
            type Error = <$ty as ::pyo3::conversion::IntoPyObject<'py>>::Error;
139

140
            fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
13,968✔
141
                (*self).into_pyobject(py)
13,968✔
142
            }
13,968✔
143
        }
144
    };
145
}
146

147
pub fn circuit(m: &Bound<PyModule>) -> PyResult<()> {
12✔
148
    m.add_class::<bit::PyBit>()?;
12✔
149
    m.add_class::<bit::PyClbit>()?;
12✔
150
    m.add_class::<bit::PyQubit>()?;
12✔
151
    m.add_class::<bit::PyAncillaQubit>()?;
12✔
152
    m.add_class::<bit::PyRegister>()?;
12✔
153
    m.add_class::<bit::PyClassicalRegister>()?;
12✔
154
    m.add_class::<bit::PyQuantumRegister>()?;
12✔
155
    m.add_class::<bit::PyAncillaRegister>()?;
12✔
156

157
    // We need to explicitly add the auto-generated Python subclasses of Duration
158
    // to the module so that pickle can find them during deserialization.
159
    m.add_class::<duration::Duration>()?;
12✔
160
    m.add(
12✔
161
        "Duration_ns",
12✔
162
        duration::Duration::type_object(m.py()).getattr("ns")?,
12✔
163
    )?;
×
164
    m.add(
12✔
165
        "Duration_us",
12✔
166
        duration::Duration::type_object(m.py()).getattr("us")?,
12✔
167
    )?;
×
168
    m.add(
12✔
169
        "Duration_ms",
12✔
170
        duration::Duration::type_object(m.py()).getattr("ms")?,
12✔
171
    )?;
×
172
    m.add(
12✔
173
        "Duration_s",
12✔
174
        duration::Duration::type_object(m.py()).getattr("s")?,
12✔
175
    )?;
×
176
    m.add(
12✔
177
        "Duration_dt",
12✔
178
        duration::Duration::type_object(m.py()).getattr("dt")?,
12✔
179
    )?;
×
180

181
    m.add_class::<circuit_data::CircuitData>()?;
12✔
182
    m.add_class::<circuit_instruction::CircuitInstruction>()?;
12✔
183
    m.add_class::<dag_circuit::DAGCircuit>()?;
12✔
184
    m.add_class::<dag_node::DAGNode>()?;
12✔
185
    m.add_class::<dag_node::DAGInNode>()?;
12✔
186
    m.add_class::<dag_node::DAGOutNode>()?;
12✔
187
    m.add_class::<dag_node::DAGOpNode>()?;
12✔
188
    m.add_class::<dag_circuit::PyBitLocations>()?;
12✔
189
    m.add_class::<operations::StandardGate>()?;
12✔
190
    m.add_class::<operations::StandardInstructionType>()?;
12✔
191
    Ok(())
12✔
192
}
12✔
193

194
#[cfg(test)]
195
mod test {
196
    use super::*;
197

198
    #[test]
199
    fn test_qubit_create() {
200
        let expected = Qubit(12345);
201
        let val = 12345_usize;
202
        let result = Qubit::new(val);
203
        assert_eq!(result, expected);
204
    }
205

206
    #[test]
207
    #[should_panic]
208
    fn test_qubit_index_too_large() {
209
        let val = u32::MAX as usize + 42;
210
        Qubit::new(val);
211
    }
212

213
    #[test]
214
    fn test_clbit_create() {
215
        let expected = Clbit(12345);
216
        let val = 12345_usize;
217
        let result = Clbit::new(val);
218
        assert_eq!(result, expected);
219
    }
220

221
    #[test]
222
    #[should_panic]
223
    fn test_clbit_index_too_large() {
224
        let val = u32::MAX as usize + 42;
225
        Clbit::new(val);
226
    }
227

228
    #[test]
229
    fn test_qubit_index() {
230
        let qubit = Qubit(123456789);
231
        let expected = 123456789_usize;
232
        let result = qubit.index();
233
        assert_eq!(result, expected);
234
    }
235

236
    #[test]
237
    fn test_clbit_index() {
238
        let clbit = Clbit(1234542);
239
        let expected = 1234542_usize;
240
        let result = clbit.index();
241
        assert_eq!(result, expected);
242
    }
243
}
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

© 2025 Coveralls, Inc