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

zeFresk / ProPauli / 17216228354

25 Aug 2025 05:37PM UTC coverage: 91.333% (-1.7%) from 92.994%
17216228354

Pull #8

github

web-flow
Merge 0e291ecb9 into a58930335
Pull Request #8: Optimize the library

258 of 338 branches covered (76.33%)

Branch coverage included in aggregate %.

371 of 389 new or added lines in 8 files covered. (95.37%)

6 existing lines in 1 file now uncovered.

859 of 885 relevant lines covered (97.06%)

41987.21 hits per line

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

87.13
/include/pauli_container.hpp
1
#ifndef PP_PAULI_CONTAINER_HPP
2
#define PP_PAULI_CONTAINER_HPP
3

4
#include "pauli.hpp"
5
#include "pauli_term.hpp"
6
#include "non_owning_pauli_term.hpp"
7

8
#include <algorithm>
9
#include <iterator>
10
#include <memory>
11
#include <string_view>
12
#include <utility>
13
#include <vector>
14

15
template <typename T>
16
class PauliTermContainer {
17
        std::vector<Pauli> raw_paulis;
18
        std::vector<T> raw_coefficients;
19
        std::size_t qubits;
20

21
    public:
22
        PauliTermContainer(std::size_t nb_qubits) : qubits(nb_qubits) {
91✔
23
                if (nb_qubits == 0) {
91✔
24
                        throw std::invalid_argument("Observable with 0 qubits not allowed.");
3✔
25
                }
3✔
26
                raw_paulis.reserve(64 * nb_qubits);
88✔
27
                raw_coefficients.reserve(64);
88✔
28
        }
88✔
29

30
        PauliTermContainer(std::span<PauliTerm<T>> const& sp) {
10✔
31
                if (sp.size() == 0) {
10!
NEW
32
                        throw std::invalid_argument("Observable with 0 terms not allowed.");
×
NEW
33
                }
×
34
                qubits = sp[0].size();
10✔
35

36
                raw_paulis.reserve(sp.size() * qubits);
10✔
37
                raw_coefficients.reserve(sp.size());
10✔
38
                for (auto const& pt : sp) {
22✔
39
                        raw_coefficients.push_back(pt.coefficient());
22✔
40
                        if (pt.size() != nb_qubits()) {
22!
NEW
41
                                throw std::invalid_argument("All terms in observable must have the same size.");
×
NEW
42
                        }
×
43
                        for (auto const& p : pt) {
70✔
44
                                raw_paulis.push_back(p);
70✔
45
                        }
70✔
46
                }
22✔
47
        }
10✔
48

49
        PauliTermContainer(std::initializer_list<PauliTerm<T>> lst)
50
                : PauliTermContainer(lst.size() > 0 ? lst.begin()->size() : 0) {
42✔
51
                for (auto const& pt : lst) {
74✔
52
                        if (pt.size() != nb_qubits()) {
74✔
53
                                throw std::invalid_argument("All terms should have the same number of qubits.");
1✔
54
                        }
1✔
55
                        auto nopt = create_pauliterm();
73✔
56
                        nopt.copy_paulis(pt.begin(), pt.end());
73✔
57
                        nopt.set_coefficient(pt.coefficient());
73✔
58
                }
73✔
59
        }
42✔
60

61
        PauliTermContainer(std::initializer_list<std::string_view> lst)
62
                : PauliTermContainer(lst.size() > 0 ? lst.begin()->size() : 0) {
46✔
63
                for (auto const& pt : lst) {
54✔
64
                        if (pt.size() != nb_qubits()) {
54!
NEW
65
                                throw std::invalid_argument("All pauli strings should have the same number of qubits.");
×
NEW
66
                        }
×
67
                        auto nopt = create_pauliterm();
54✔
68
                        for (std::size_t i = 0; i < pt.size(); ++i) {
323✔
69
                                nopt[i] = Pauli(pt[i]);
269✔
70
                        }
269✔
71
                        nopt.set_coefficient(1.f);
54✔
72
                }
54✔
73
        }
46✔
74

75
        template <typename It>
76
        PauliTermContainer(It&& begin, It&& end) {
6✔
77
                auto size = std::distance(begin, end);
6✔
78
                if (size == 0) {
6!
79
                        throw std::invalid_argument("Observable with 0 terms not allowed.");
1✔
80
                }
1✔
81

82
                qubits = begin->size();
5✔
83
                auto bcopy = begin;
5✔
84

85
                raw_paulis.reserve(size * qubits);
5✔
86
                raw_coefficients.reserve(size);
5✔
87
                for (; bcopy != end; ++bcopy) {
15✔
88
                        raw_coefficients.push_back(bcopy->coefficient());
10✔
89
                        if (bcopy->size() != nb_qubits()) {
10!
NEW
90
                                throw std::invalid_argument("All pauli terms should have the same number of qubits.");
×
NEW
91
                        }
×
92
                        for (std::size_t j = 0; j < qubits; ++j) {
30✔
93
                                raw_paulis.push_back((*bcopy)[j]);
20✔
94
                        }
20✔
95
                }
10✔
96
        }
5✔
97

98
        std::size_t compute_index(std::size_t term, std::size_t qubit) const { return term * qubits + qubit; }
7,489✔
99
        std::size_t nb_qubits() const { return qubits; }
958✔
100
        std::size_t nb_terms() const { return raw_coefficients.size(); }
8,082✔
101

102
        NonOwningPauliTerm<T> operator[](std::size_t idx) {
2,477✔
103
                assert(idx < nb_terms());
2,477✔
104
                return { raw_paulis.begin() + compute_index(idx, 0), raw_paulis.begin() + compute_index(idx, qubits),
2,477✔
105
                         raw_coefficients[idx] };
2,477✔
106
        }
2,477✔
107

108
        ReadOnlyNonOwningPauliTerm<T> operator[](std::size_t idx) const {
243✔
109
                assert(idx < nb_terms());
243✔
110
                return { raw_paulis.begin() + compute_index(idx, 0), raw_paulis.begin() + compute_index(idx, qubits),
243✔
111
                         raw_coefficients[idx] };
243✔
112
        }
243✔
113

114
        [[nodiscard]] NonOwningPauliTerm<T> create_pauliterm() {
531✔
115
                raw_paulis.resize(raw_paulis.size() + qubits, p_i);
531✔
116
                raw_coefficients.push_back(T{ 0 });
531✔
117
                return { raw_paulis.begin() + compute_index(nb_terms() - 1, 0),
531✔
118
                         raw_paulis.begin() + compute_index(nb_terms() - 1, qubits),
531✔
119
                         raw_coefficients[raw_coefficients.size() - 1] };
531✔
120
        }
531✔
121

122
        void remove_pauliterm(std::size_t idx) {
329✔
123
                assert(idx < nb_terms());
329✔
124
                std::swap(raw_coefficients[idx], raw_coefficients[raw_coefficients.size() - 1]);
329✔
125
                std::swap_ranges(raw_paulis.begin() + compute_index(idx, 0),
329✔
126
                                 raw_paulis.begin() + compute_index(idx, qubits),
329✔
127
                                 raw_paulis.begin() + compute_index(nb_terms() - 1, 0));
329✔
128
                raw_coefficients.pop_back();
329✔
129
                raw_paulis.resize(raw_paulis.size() - qubits, p_i);
329✔
130
        }
329✔
131

132
        class NonOwningIterator {
133
                Pauli* ptr_paulis;
134
                T* ptr_coeffs;
135
                std::size_t qubits;
136

137
            public:
138
                using iterator_category = std::forward_iterator_tag;
139
                using difference_type = std::ptrdiff_t;
140
                using value_type = NonOwningPauliTerm<T>;
141
                using pointer = value_type*;
142
                using reference = value_type&;
143

144
                explicit NonOwningIterator(Pauli* ptr_p, T* ptr_c, std::size_t nb_qubits)
145
                        : ptr_paulis(ptr_p), ptr_coeffs(ptr_c), qubits(nb_qubits) {}
48✔
146

147
                value_type operator*() {
65✔
148
                        return NonOwningPauliTerm<T>{ ptr_paulis + 0, ptr_paulis + qubits, *ptr_coeffs };
65✔
149
                }
65✔
150

151
                value_type operator->() const {
152
                        return NonOwningPauliTerm<T>{ ptr_paulis + 0, ptr_paulis + qubits, *ptr_coeffs };
153
                }
154

155
                NonOwningIterator& operator++() {
52✔
156
                        ptr_paulis += qubits;
52✔
157
                        ptr_coeffs++;
52✔
158
                        return *this;
52✔
159
                }
52✔
160

161
                NonOwningIterator operator++(int) {
162
                        NonOwningIterator ret = *this;
163
                        ++(*this);
164
                        return ret;
165
                }
166

167
                friend bool operator==(NonOwningIterator const& lhs, NonOwningIterator const& rhs) {
76✔
168
                        return lhs.ptr_paulis == rhs.ptr_paulis && lhs.ptr_coeffs == rhs.ptr_coeffs;
76!
169
                }
76✔
170
                friend bool operator!=(NonOwningIterator const& lhs, NonOwningIterator const& rhs) {
76✔
171
                        return !(lhs == rhs);
76✔
172
                }
76✔
173
        };
174

175
        class ReadOnlyNonOwningIterator {
176
                Pauli const* ptr_paulis;
177
                T const* ptr_coeffs;
178
                std::size_t qubits;
179

180
            public:
181
                using iterator_category = std::forward_iterator_tag;
182
                using difference_type = std::ptrdiff_t;
183
                using value_type = ReadOnlyNonOwningPauliTerm<T>;
184
                using pointer = value_type*;
185
                using reference = value_type&;
186

187
                explicit ReadOnlyNonOwningIterator(Pauli const* ptr_p, T const* ptr_c, std::size_t nb_qubits)
188
                        : ptr_paulis(ptr_p), ptr_coeffs(ptr_c), qubits(nb_qubits) {}
25✔
189

190
                value_type operator*() const {
2✔
191
                        return ReadOnlyNonOwningPauliTerm{ ptr_paulis + 0, ptr_paulis + qubits, *ptr_coeffs };
2✔
192
                }
2✔
193

194
                value_type operator->() const {
195
                        return ReadOnlyNonOwningPauliTerm{ ptr_paulis + 0, ptr_paulis + qubits, *ptr_coeffs };
196
                }
197

198
                ReadOnlyNonOwningIterator& operator++() {
285✔
199
                        ptr_paulis += qubits;
285✔
200
                        ptr_coeffs++;
285✔
201
                        return *this;
285✔
202
                }
285✔
203

204
                ReadOnlyNonOwningIterator operator++(int) {
205
                        NonOwningIterator ret = *this;
206
                        ++(*this);
207
                        return ret;
208
                }
209

210
                friend bool operator==(ReadOnlyNonOwningIterator const& lhs, ReadOnlyNonOwningIterator const& rhs) {
298✔
211
                        return lhs.ptr_paulis == rhs.ptr_paulis && lhs.ptr_coeffs == rhs.ptr_coeffs;
298!
212
                }
298✔
213
                friend bool operator!=(ReadOnlyNonOwningIterator const& lhs, ReadOnlyNonOwningIterator const& rhs) {
298✔
214
                        return !(lhs == rhs);
298✔
215
                }
298✔
216
        };
217

218
        NonOwningIterator begin() {
24✔
219
                return NonOwningIterator{ std::to_address(raw_paulis.begin()),
24✔
220
                                          std::to_address(raw_coefficients.begin()), nb_qubits() };
24✔
221
        }
24✔
222
        NonOwningIterator end() {
24✔
223
                return NonOwningIterator{ std::to_address(raw_paulis.end()), std::to_address(raw_coefficients.end()),
24✔
224
                                          nb_qubits() };
24✔
225
        }
24✔
226
        ReadOnlyNonOwningIterator cbegin() const {
12✔
227
                return ReadOnlyNonOwningIterator{ std::to_address(raw_paulis.cbegin()),
12✔
228
                                                  std::to_address(raw_coefficients.cbegin()), nb_qubits() };
12✔
229
        }
12✔
230
        ReadOnlyNonOwningIterator cend() const {
13✔
231
                return ReadOnlyNonOwningIterator{ std::to_address(raw_paulis.cend()),
13✔
232
                                                  std::to_address(raw_coefficients.cend()), nb_qubits() };
13✔
233
        }
13✔
NEW
234
        auto begin() const { return cbegin(); }
×
NEW
235
        auto end() const { return cend(); }
×
236

237
        friend bool operator==(PauliTermContainer const& lhs, PauliTermContainer const& rhs) {
11✔
238
                if (!(lhs.nb_terms() == rhs.nb_terms() && lhs.nb_qubits() == rhs.nb_qubits())) {
11!
NEW
239
                        return false;
×
NEW
240
                }
×
241
                // NOTE: O(n^2) because we don't know if the terms are sorted in the same way.
242
                for (std::size_t i = 0; i < lhs.nb_terms(); ++i) {
22✔
243
                        auto lhs_pt = lhs[i];
11✔
244
                        bool found = false;
11✔
245
                        for (std::size_t j = 0; j < rhs.nb_terms(); ++j) {
11!
246
                                if (lhs_pt == rhs[j]) {
11!
247
                                        found = true;
11✔
248
                                        break;
11✔
249
                                }
11✔
250
                        }
11✔
251
                        if (!found)
11!
NEW
252
                                return false;
×
253
                }
11✔
254
                return true;
11✔
255
        }
11✔
256
        friend bool operator!=(PauliTermContainer const& lhs, PauliTermContainer const& rhs) { return !(lhs == rhs); }
257
};
258

259
namespace std
260
{
261
template <typename T, typename Predicate>
262
size_t erase_if(PauliTermContainer<T>& paulis, Predicate&& predicate) {
97✔
263
        auto deleted = 0;
97✔
264
        for (std::size_t i = 0; i < paulis.nb_terms(); ++i) {
395!
265
                const ReadOnlyNonOwningPauliTerm<T> ronopt = paulis[i];
298✔
266
                if (predicate(ronopt)) {
298!
267
                        paulis.remove_pauliterm(i);
30✔
268
                        --i;
30✔
269
                        ++deleted;
30✔
270
                }
30✔
271
        }
298✔
272
        return deleted;
97✔
273
}
97✔
274
} // namespace std
275

276
#endif
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