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

Qiskit / qiskit / 15605118675

12 Jun 2025 08:07AM CUT coverage: 88.008% (+0.007%) from 88.001%
15605118675

Pull #14580

github

web-flow
Merge fd9046fad into 19a1fd1cd
Pull Request #14580: [C-API] Fix conversion from std::complex to QKComplex64 error on MSVC

83159 of 94490 relevant lines covered (88.01%)

517653.0 hits per line

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

2.82
/crates/quantum_info/src/sparse_observable/lookup.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 num_complex::Complex64;
14
// The lookup tables are pretty illegible if we have all the syntactic noise of `BitTerm`.
15
use super::BitTerm::{self, *};
16

17
/// Short-hand alias for [Complex64::new] that retains its ability to be used in `const` contexts.
18
const fn c64(re: f64, im: f64) -> Complex64 {
×
19
    Complex64::new(re, im)
×
20
}
×
21

22
/// The allowable items of `BitTerm`.  This is used by the lookup expansion; we need a const-safe
23
/// way of iterating through all of the variants.
24
static BIT_TERMS: [BitTerm; 9] = [X, Plus, Minus, Y, Right, Left, Z, Zero, One];
25

26
/// Create a full binary lookup table for all valid combinations of `BitTerm`.
27
macro_rules! expand_lookup_binary {
28
    (static $table:ident: [$ty:ty], $generate:ident, $dummy:expr) => {
29
        static $table: [$ty; 256] = {
30
            let mut out = [const { $dummy }; 256];
31
            let mut i = 0;
32
            while i < 9 {
33
                let left = BIT_TERMS[i];
34
                let mut j = 0;
35
                while j < 9 {
36
                    let right = BIT_TERMS[j];
37
                    out[((left as usize) << 4) | (right as usize)] = $generate(left, right);
38
                    j += 1;
39
                }
40
                i += 1;
41
            }
42
            out
43
        };
44
    };
45
}
46

47
expand_lookup_binary!(
48
    static MATMUL: [Option<&'static [(Complex64, BitTerm)]>],
49
    matmul_generate,
50
    None
51
);
52
/// Calculate the matrix multiplication of two [BitTerm]s.
53
///
54
/// This is done by a static lookup table.
55
///
56
/// In the output, `None` means that the result was zero.  Beyond that, the slice should be
57
/// interpreted as a sum of the coefficient multiplied by the [BitTerm] pairs.  An empty slice means
58
/// the identity.
59
#[inline(always)]
60
pub fn matmul(left: BitTerm, right: BitTerm) -> Option<&'static [(Complex64, BitTerm)]> {
294✔
61
    // This can be `const` from Rust 1.83 - before that, `const` functions can't refer to `static`s.
294✔
62
    MATMUL[((left as usize) << 4) | (right as usize)]
294✔
63
}
294✔
64

65
/// The `const` version of [matmul].
66
///
67
/// This is less efficient at runtime than [matmul] (which inlines to a couple of bitwise operations
68
/// and a single offset load), but can be used in `const` contexts.
69
const fn matmul_generate(left: BitTerm, right: BitTerm) -> Option<&'static [(Complex64, BitTerm)]> {
×
70
    // This typically gets compiled to a non-inlinable (because the code size is too big) two
×
71
    // separate sets of operate-and-jump instructions, but we use it in the `const` context to build
×
72
    // a static lookup table which can easily be inlined and is a couple of bitwise operations
×
73
    // followed by an offset load of the result.
×
74
    //
×
75
    // These rules were generated by a brute-force search over increasing-n-tuples of (coeff, term)
×
76
    // pairs, where `coeff` was restricted to magnitudes `(0.25, 0.5, 1.0)` at complex phases
×
77
    // `(1, i, -1, -i)`.  Under those conditions, the rules are minimal in number of sum terms, but
×
78
    // don't have any further logic to "curate" the choice of output factorisation.
×
79
    match (left, right) {
×
80
        (X, X) => Some(const { &[] }),
×
81
        (X, Plus) => Some(const { &[(c64(1., 0.), Plus)] }),
×
82
        (X, Minus) => Some(const { &[(c64(-1., 0.), Minus)] }),
×
83
        (X, Y) => Some(const { &[(c64(0., 1.), Z)] }),
×
84
        (X, Right) => Some(const { &[(c64(0.5, 0.), X), (c64(0., 0.5), Z)] }),
×
85
        (X, Left) => Some(const { &[(c64(0.5, 0.), X), (c64(0., -0.5), Z)] }),
×
86
        (X, Z) => Some(const { &[(c64(0., -1.), Y)] }),
×
87
        (X, Zero) => Some(const { &[(c64(0.5, 0.), X), (c64(0., -0.5), Y)] }),
×
88
        (X, One) => Some(const { &[(c64(0.5, 0.), X), (c64(0., 0.5), Y)] }),
×
89
        (Plus, X) => Some(const { &[(c64(1., 0.), Plus)] }),
×
90
        (Plus, Plus) => Some(const { &[(c64(1., 0.), Plus)] }),
×
91
        (Plus, Minus) => None,
×
92
        (Plus, Y) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., 0.5), Z)] }),
×
93
        (Plus, Right) => Some(
×
94
            const {
×
95
                &[
96
                    (c64(0.25, 0.), X),
97
                    (c64(0.5, 0.), Right),
98
                    (c64(0., 0.25), Z),
99
                ]
100
            },
×
101
        ),
×
102
        (Plus, Left) => Some(
×
103
            const {
×
104
                &[
105
                    (c64(0.25, 0.), X),
106
                    (c64(0.5, 0.), Left),
107
                    (c64(0., -0.25), Z),
108
                ]
109
            },
×
110
        ),
×
111
        (Plus, Z) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., -0.5), Y)] }),
×
112
        (Plus, Zero) => Some(
×
113
            const {
×
114
                &[
115
                    (c64(0.25, 0.), X),
116
                    (c64(0.5, 0.), Zero),
117
                    (c64(0., -0.25), Y),
118
                ]
119
            },
×
120
        ),
×
121
        (Plus, One) => {
122
            Some(const { &[(c64(0.25, 0.), X), (c64(0.5, 0.), One), (c64(0., 0.25), Y)] })
×
123
        }
124
        (Minus, X) => Some(const { &[(c64(-1., 0.), Minus)] }),
×
125
        (Minus, Plus) => None,
×
126
        (Minus, Minus) => Some(const { &[(c64(1., 0.), Minus)] }),
×
127
        (Minus, Y) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., -0.5), Z)] }),
×
128
        (Minus, Right) => Some(
×
129
            const {
×
130
                &[
131
                    (c64(0.25, 0.), Y),
132
                    (c64(0.5, 0.), Minus),
133
                    (c64(0., -0.25), Z),
134
                ]
135
            },
×
136
        ),
×
137
        (Minus, Left) => Some(
×
138
            const {
×
139
                &[
140
                    (c64(-0.25, 0.), X),
141
                    (c64(0.5, 0.), Left),
142
                    (c64(0., 0.25), Z),
143
                ]
144
            },
×
145
        ),
×
146
        (Minus, Z) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., 0.5), Y)] }),
×
147
        (Minus, Zero) => Some(
×
148
            const {
×
149
                &[
150
                    (c64(0.25, 0.), Z),
151
                    (c64(0.5, 0.), Minus),
152
                    (c64(0., 0.25), Y),
153
                ]
154
            },
×
155
        ),
×
156
        (Minus, One) => Some(
×
157
            const {
×
158
                &[
159
                    (c64(-0.25, 0.), X),
160
                    (c64(0.5, 0.), One),
161
                    (c64(0., -0.25), Y),
162
                ]
163
            },
×
164
        ),
×
165
        (Y, X) => Some(const { &[(c64(0., -1.), Z)] }),
×
166
        (Y, Plus) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., -0.5), Z)] }),
×
167
        (Y, Minus) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., 0.5), Z)] }),
×
168
        (Y, Y) => Some(const { &[] }),
×
169
        (Y, Right) => Some(const { &[(c64(1., 0.), Right)] }),
×
170
        (Y, Left) => Some(const { &[(c64(-1., 0.), Left)] }),
×
171
        (Y, Z) => Some(const { &[(c64(0., 1.), X)] }),
×
172
        (Y, Zero) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., 0.5), X)] }),
×
173
        (Y, One) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., -0.5), X)] }),
×
174
        (Right, X) => Some(const { &[(c64(0.5, 0.), X), (c64(0., -0.5), Z)] }),
×
175
        (Right, Plus) => Some(
×
176
            const {
×
177
                &[
178
                    (c64(0.25, 0.), X),
179
                    (c64(0.5, 0.), Right),
180
                    (c64(0., -0.25), Z),
181
                ]
182
            },
×
183
        ),
×
184
        (Right, Minus) => Some(
×
185
            const {
×
186
                &[
187
                    (c64(0.25, 0.), Y),
188
                    (c64(0.5, 0.), Minus),
189
                    (c64(0., 0.25), Z),
190
                ]
191
            },
×
192
        ),
×
193
        (Right, Y) => Some(const { &[(c64(1., 0.), Right)] }),
×
194
        (Right, Right) => Some(const { &[(c64(1., 0.), Right)] }),
×
195
        (Right, Left) => None,
×
196
        (Right, Z) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., 0.5), X)] }),
×
197
        (Right, Zero) => {
198
            Some(const { &[(c64(0.25, 0.), Y), (c64(0.5, 0.), Zero), (c64(0., 0.25), X)] })
×
199
        }
200
        (Right, One) => {
201
            Some(const { &[(c64(0.25, 0.), Y), (c64(0.5, 0.), One), (c64(0., -0.25), X)] })
×
202
        }
203
        (Left, X) => Some(const { &[(c64(0.5, 0.), X), (c64(0., 0.5), Z)] }),
×
204
        (Left, Plus) => {
205
            Some(const { &[(c64(0.25, 0.), X), (c64(0.5, 0.), Left), (c64(0., 0.25), Z)] })
×
206
        }
207
        (Left, Minus) => Some(
×
208
            const {
×
209
                &[
210
                    (c64(-0.25, 0.), X),
211
                    (c64(0.5, 0.), Left),
212
                    (c64(0., -0.25), Z),
213
                ]
214
            },
×
215
        ),
×
216
        (Left, Y) => Some(const { &[(c64(-1., 0.), Left)] }),
×
217
        (Left, Right) => None,
×
218
        (Left, Left) => Some(const { &[(c64(1., 0.), Left)] }),
×
219
        (Left, Z) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., -0.5), X)] }),
×
220
        (Left, Zero) => Some(
×
221
            const {
×
222
                &[
223
                    (c64(0.25, 0.), Z),
224
                    (c64(0.5, 0.), Left),
225
                    (c64(0., -0.25), X),
226
                ]
227
            },
×
228
        ),
×
229
        (Left, One) => {
230
            Some(const { &[(c64(-0.25, 0.), Y), (c64(0.5, 0.), One), (c64(0., 0.25), X)] })
×
231
        }
232
        (Z, X) => Some(const { &[(c64(0., 1.), Y)] }),
×
233
        (Z, Plus) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., 0.5), Y)] }),
×
234
        (Z, Minus) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., -0.5), Y)] }),
×
235
        (Z, Y) => Some(const { &[(c64(0., -1.), X)] }),
×
236
        (Z, Right) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., -0.5), X)] }),
×
237
        (Z, Left) => Some(const { &[(c64(0.5, 0.), Z), (c64(0., 0.5), X)] }),
×
238
        (Z, Z) => Some(const { &[] }),
×
239
        (Z, Zero) => Some(const { &[(c64(1., 0.), Zero)] }),
×
240
        (Z, One) => Some(const { &[(c64(-1., 0.), One)] }),
×
241
        (Zero, X) => Some(const { &[(c64(0.5, 0.), X), (c64(0., 0.5), Y)] }),
×
242
        (Zero, Plus) => {
243
            Some(const { &[(c64(0.25, 0.), X), (c64(0.5, 0.), Zero), (c64(0., 0.25), Y)] })
×
244
        }
245
        (Zero, Minus) => Some(
×
246
            const {
×
247
                &[
248
                    (c64(0.25, 0.), Z),
249
                    (c64(0.5, 0.), Minus),
250
                    (c64(0., -0.25), Y),
251
                ]
252
            },
×
253
        ),
×
254
        (Zero, Y) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., -0.5), X)] }),
×
255
        (Zero, Right) => Some(
×
256
            const {
×
257
                &[
258
                    (c64(0.25, 0.), Y),
259
                    (c64(0.5, 0.), Zero),
260
                    (c64(0., -0.25), X),
261
                ]
262
            },
×
263
        ),
×
264
        (Zero, Left) => {
265
            Some(const { &[(c64(0.25, 0.), Z), (c64(0.5, 0.), Left), (c64(0., 0.25), X)] })
×
266
        }
267
        (Zero, Z) => Some(const { &[(c64(1., 0.), Zero)] }),
×
268
        (Zero, Zero) => Some(const { &[(c64(1., 0.), Zero)] }),
×
269
        (Zero, One) => None,
×
270
        (One, X) => Some(const { &[(c64(0.5, 0.), X), (c64(0., -0.5), Y)] }),
×
271
        (One, Plus) => {
272
            Some(const { &[(c64(0.25, 0.), X), (c64(0.5, 0.), One), (c64(0., -0.25), Y)] })
×
273
        }
274
        (One, Minus) => {
275
            Some(const { &[(c64(-0.25, 0.), X), (c64(0.5, 0.), One), (c64(0., 0.25), Y)] })
×
276
        }
277
        (One, Y) => Some(const { &[(c64(0.5, 0.), Y), (c64(0., 0.5), X)] }),
×
278
        (One, Right) => {
279
            Some(const { &[(c64(0.25, 0.), Y), (c64(0.5, 0.), One), (c64(0., 0.25), X)] })
×
280
        }
281
        (One, Left) => Some(
×
282
            const {
×
283
                &[
284
                    (c64(-0.25, 0.), Y),
285
                    (c64(0.5, 0.), One),
286
                    (c64(0., -0.25), X),
287
                ]
288
            },
×
289
        ),
×
290
        (One, Z) => Some(const { &[(c64(-1., 0.), One)] }),
×
291
        (One, Zero) => None,
×
292
        (One, One) => Some(const { &[(c64(1., 0.), One)] }),
×
293
    }
294
}
×
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