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

Qiskit / qiskit / 15097493208

18 May 2025 03:37PM CUT coverage: 88.293% (-0.4%) from 88.736%
15097493208

Pull #14348

github

web-flow
Merge 91e694599 into a18e15163
Pull Request #14348: Document Primitives types

4 of 4 new or added lines in 1 file covered. (100.0%)

950 existing lines in 27 files now uncovered.

78332 of 88718 relevant lines covered (88.29%)

427990.26 hits per line

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

94.44
/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 classical;
18
pub mod converters;
19
pub mod dag_circuit;
20
pub mod dag_node;
21
mod dot_utils;
22
pub mod duration;
23
pub mod error;
24
pub mod gate_matrix;
25
pub mod imports;
26
pub mod interner;
27
pub mod nlayout;
28
pub mod object_registry;
29
pub mod operations;
30
pub mod packed_instruction;
31
pub mod parameter_expression;
32
pub mod parameter_table;
33
pub mod register_data;
34
pub mod slice;
35
pub mod symbol_expr;
36
pub mod symbol_parser;
37
pub mod util;
38

39
pub mod rustworkx_core_vnext;
40

41
use pyo3::prelude::*;
42
use pyo3::types::{PySequence, PyTuple};
43
use pyo3::PyTypeInfo;
44

45
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, FromPyObject)]
46
pub struct Qubit(pub u32);
47

48
#[derive(Copy, Clone, Debug, Hash, Ord, PartialOrd, Eq, PartialEq, FromPyObject)]
49
pub struct Clbit(pub u32);
50

51
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
52
pub struct Var(u32);
53

54
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
55
pub struct Stretch(u32);
56

57
pub use nlayout::PhysicalQubit;
58
pub use nlayout::VirtualQubit;
59

60
macro_rules! impl_circuit_identifier {
61
    ($type:ident) => {
62
        impl $type {
63
            /// Construct a new identifier from a usize, if you have a u32 you can
64
            /// construct one directly via [$type()]. This will panic if the `usize`
65
            /// index exceeds `u32::MAX`.
66
            #[inline(always)]
67
            pub fn new(index: usize) -> Self {
5,666,130✔
68
                $type(index.try_into().unwrap_or_else(|_| {
5,666,130✔
69
                    panic!(
2✔
70
                        "Index value '{}' exceeds the maximum identifier width!",
2✔
71
                        index
2✔
72
                    )
2✔
73
                }))
5,666,130✔
74
            }
5,666,130✔
75

76
            /// Convert to a usize.
77
            #[inline(always)]
78
            pub fn index(&self) -> usize {
18,590,560✔
79
                self.0 as usize
18,590,560✔
80
            }
18,590,560✔
81
        }
82

83
        impl From<u32> for $type {
84
            fn from(value: u32) -> Self {
11,230,710✔
85
                $type(value)
11,230,710✔
86
            }
11,230,710✔
87
        }
88

89
        impl From<$type> for u32 {
90
            fn from(value: $type) -> Self {
23,674,682✔
91
                value.0
23,674,682✔
92
            }
23,674,682✔
93
        }
94
    };
95
}
96

97
impl_circuit_identifier!(Qubit);
98
impl_circuit_identifier!(Clbit);
99
impl_circuit_identifier!(Var);
100
impl_circuit_identifier!(Stretch);
101

102
pub struct TupleLikeArg<'py> {
103
    value: Bound<'py, PyTuple>,
104
}
105

106
impl<'py> FromPyObject<'py> for TupleLikeArg<'py> {
107
    fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
219,852✔
108
        let value = match ob.downcast::<PySequence>() {
219,852✔
109
            Ok(seq) => seq.to_tuple()?,
219,788✔
110
            Err(_) => PyTuple::new(
111
                ob.py(),
64✔
112
                ob.try_iter()?
64✔
113
                    .map(|o| Ok(o?.unbind()))
64✔
114
                    .collect::<PyResult<Vec<PyObject>>>()?,
64✔
UNCOV
115
            )?,
×
116
        };
117
        Ok(TupleLikeArg { value })
219,852✔
118
    }
219,852✔
119
}
120

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

148
            fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
13,968✔
149
                (*self).into_pyobject(py)
13,968✔
150
            }
13,968✔
151
        }
152
    };
153
}
154

155
pub fn circuit(m: &Bound<PyModule>) -> PyResult<()> {
12✔
156
    m.add_class::<bit::PyBit>()?;
12✔
157
    m.add_class::<bit::PyClbit>()?;
12✔
158
    m.add_class::<bit::PyQubit>()?;
12✔
159
    m.add_class::<bit::PyAncillaQubit>()?;
12✔
160
    m.add_class::<bit::PyRegister>()?;
12✔
161
    m.add_class::<bit::PyClassicalRegister>()?;
12✔
162
    m.add_class::<bit::PyQuantumRegister>()?;
12✔
163
    m.add_class::<bit::PyAncillaRegister>()?;
12✔
164

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

189
    m.add_class::<circuit_data::CircuitData>()?;
12✔
190
    m.add_class::<circuit_instruction::CircuitInstruction>()?;
12✔
191
    m.add_class::<dag_circuit::DAGCircuit>()?;
12✔
192
    m.add_class::<dag_node::DAGNode>()?;
12✔
193
    m.add_class::<dag_node::DAGInNode>()?;
12✔
194
    m.add_class::<dag_node::DAGOutNode>()?;
12✔
195
    m.add_class::<dag_node::DAGOpNode>()?;
12✔
196
    m.add_class::<dag_circuit::PyBitLocations>()?;
12✔
197
    m.add_class::<operations::StandardGate>()?;
12✔
198
    m.add_class::<operations::StandardInstructionType>()?;
12✔
199
    m.add_class::<parameter_expression::ParameterExpression>()?;
12✔
200
    let classical_mod = PyModule::new(m.py(), "classical")?;
12✔
201
    classical::register_python(&classical_mod)?;
12✔
202
    m.add_submodule(&classical_mod)?;
12✔
203
    Ok(())
12✔
204
}
12✔
205

206
#[cfg(test)]
207
mod test {
208
    use super::*;
209

210
    #[test]
211
    fn test_qubit_create() {
1✔
212
        let expected = Qubit(12345);
1✔
213
        let val = 12345_usize;
1✔
214
        let result = Qubit::new(val);
1✔
215
        assert_eq!(result, expected);
1✔
216
    }
1✔
217

218
    #[test]
219
    #[should_panic]
220
    fn test_qubit_index_too_large() {
1✔
221
        let val = u32::MAX as usize + 42;
1✔
222
        Qubit::new(val);
1✔
223
    }
1✔
224

225
    #[test]
226
    fn test_clbit_create() {
1✔
227
        let expected = Clbit(12345);
1✔
228
        let val = 12345_usize;
1✔
229
        let result = Clbit::new(val);
1✔
230
        assert_eq!(result, expected);
1✔
231
    }
1✔
232

233
    #[test]
234
    #[should_panic]
235
    fn test_clbit_index_too_large() {
1✔
236
        let val = u32::MAX as usize + 42;
1✔
237
        Clbit::new(val);
1✔
238
    }
1✔
239

240
    #[test]
241
    fn test_qubit_index() {
1✔
242
        let qubit = Qubit(123456789);
1✔
243
        let expected = 123456789_usize;
1✔
244
        let result = qubit.index();
1✔
245
        assert_eq!(result, expected);
1✔
246
    }
1✔
247

248
    #[test]
249
    fn test_clbit_index() {
1✔
250
        let clbit = Clbit(1234542);
1✔
251
        let expected = 1234542_usize;
1✔
252
        let result = clbit.index();
1✔
253
        assert_eq!(result, expected);
1✔
254
    }
1✔
255
}
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