GCC Code Coverage Report


Directory: ./
File: Characterisation/FrameRandomisation.cpp
Date: 2022-10-15 05:10:18
Exec Total Coverage
Lines: 284 332 85.5%
Functions: 16 18 88.9%
Branches: 276 555 49.7%
Decisions: 101 118 85.6%

Line Branch Decision Exec Source
1 // Copyright 2019-2022 Cambridge Quantum Computing
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "Characterisation/FrameRandomisation.hpp"
16
17 #include <random>
18
19 #include "Ops/MetaOp.hpp"
20 #include "PauliGraph/ConjugatePauliFunctions.hpp"
21 #include "Utils/PauliStrings.hpp"
22
23 namespace tket {
24
25 class FrameRandomisationError : public std::logic_error {
26 public:
27 explicit FrameRandomisationError(const std::string& message)
28 : std::logic_error(message) {}
29 };
30
31 std::string FrameRandomisation::to_string() const {
32 std::string str = "<tket::FrameRandomisation, Cycle OpTypeSet: ";
33
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (const OpType& ot : cycle_types_) {
34 OpDesc od(ot);
35 str.append(od.name() + " ");
36 }
37 str.append(", Frame OpTypeSet: ");
38
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (const OpType& ot : frame_types_) {
39 OpDesc od(ot);
40 str.append(od.name() + " ");
41 }
42 str.append(">");
43 return str;
44 }
45
46 // Wires Identity gates into each cycle edge. Identity gates then relabelled
47 // with Ops from OpTypeSet to create instances of Frame Randomisation
48 15 void add_noop_frames(std::vector<Cycle>& cycles, Circuit& circ) {
49 15 std::map<Edge, Edge> replacement_rewiring_edges;
50
2/2
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 15 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 15 times.
33 for (Cycle& full_cycle : cycles) {
51
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 std::vector<edge_pair_t> cycle = full_cycle.boundary_edges_;
52 // wire "noop" vertices into each cycle edge
53 // these are later relabelled with frame gates
54 // also wire "barrier" vertices between "noop" vertices and cycle gates
55 // i.e. something like this:
56 // ---C---
57 // |
58 // ---X---
59 // to
60 // -noop--B--C--B--noop-
61 // A | A
62 // -noop--R--X--R--noop-
63 // R R
64 // I I
65 // E E
66 // R R
67
68 18 EdgeVec barrier_ins;
69 18 EdgeVec barrier_outs;
70
2/2
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 18 times.
2/2
✓ Decision 'true' taken 44 times.
✓ Decision 'false' taken 18 times.
62 for (const std::pair<Edge, Edge>& boundary : cycle) {
71
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 Vertex input_noop_vert = circ.add_vertex(OpType::noop);
72
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 Vertex output_noop_vert = circ.add_vertex(OpType::noop);
73 44 Edge in_edge = boundary.first;
74 // boundary out edges can be equal to other boundary in edges
75 // rewiring a vertex into these out edges replace the edge
76 // first see if its been rewired and use new edge if necessary
77 std::map<Edge, Edge>::iterator it =
78
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 replacement_rewiring_edges.find(in_edge);
79
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 43 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 43 times.
44 if (it != replacement_rewiring_edges.end()) {
80 1 in_edge = (*it).second;
81 }
82
83
3/6
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 44 times.
✗ Branch 10 not taken.
44 circ.rewire(input_noop_vert, {in_edge}, {EdgeType::Quantum});
84
3/6
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 44 times.
✗ Branch 10 not taken.
44 circ.rewire(output_noop_vert, {boundary.second}, {EdgeType::Quantum});
85
86 // Can guarantee both have one output edge only as just rewired
87 Edge input_noop_out_edge =
88
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 circ.get_out_edges_of_type(input_noop_vert, EdgeType::Quantum)[0];
89 Edge output_noop_in_edge =
90
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 circ.get_in_edges_of_type(output_noop_vert, EdgeType::Quantum)[0];
91
92
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 barrier_ins.push_back(input_noop_out_edge);
93
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 barrier_outs.push_back(output_noop_in_edge);
94
95
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 replacement_rewiring_edges[boundary.second] =
96
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
88 circ.get_out_edges_of_type(output_noop_vert, EdgeType::Quantum)[0];
97
1/2
✓ Branch 2 taken 44 times.
✗ Branch 3 not taken.
44 full_cycle.add_vertex_pair({input_noop_vert, output_noop_vert});
98 }
99
1/2
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
18 std::vector<EdgeType> sig(barrier_ins.size(), EdgeType::Quantum);
100
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 Op_ptr o_ptr = std::make_shared<MetaOp>(OpType::Barrier, sig);
101
1/2
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
18 Vertex input_barrier_vert = circ.add_vertex(o_ptr);
102
1/2
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
18 Vertex output_barrier_vert = circ.add_vertex(o_ptr);
103
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 circ.rewire(input_barrier_vert, barrier_ins, sig);
104
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 circ.rewire(output_barrier_vert, barrier_outs, sig);
105 18 }
106 15 }
107
108 6 std::vector<std::vector<OpTypeVector>> get_all_frame_permutations(
109 const unsigned& max_frame_size, const OpTypeSet& frame_types) {
110
1/2
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 OpTypeVector base_otv(frame_types.begin(), frame_types.end());
111
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 std::sort(base_otv.begin(), base_otv.end());
112 6 std::vector<OpTypeVector> base_frame;
113
2/2
✓ Branch 4 taken 20 times.
✓ Branch 5 taken 6 times.
2/2
✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 6 times.
26 for (const OpType& ot : base_otv) {
114
2/4
✓ Branch 2 taken 20 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 20 times.
✗ Branch 6 not taken.
20 base_frame.push_back({ot});
115 }
116
1/2
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 std::sort(base_frame.begin(), base_frame.end());
117
2/4
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
18 std::vector<std::vector<OpTypeVector>> out({base_frame});
118
119
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
2/2
✓ Decision 'true' taken 6 times.
✓ Decision 'false' taken 6 times.
12 for (unsigned i = 1; i < max_frame_size; i++) {
120 6 std::vector<OpTypeVector> new_ops;
121
2/2
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 6 times.
2/2
✓ Decision 'true' taken 20 times.
✓ Decision 'false' taken 6 times.
26 for (const OpTypeVector& base_ops : out[0]) {
122
2/2
✓ Branch 6 taken 72 times.
✓ Branch 7 taken 20 times.
2/2
✓ Decision 'true' taken 72 times.
✓ Decision 'false' taken 20 times.
92 for (const OpTypeVector& merge_ops : out[i - 1]) {
123
1/2
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
72 OpTypeVector new_base(base_ops);
124
2/4
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 72 times.
✗ Branch 7 not taken.
72 std::copy(
125 merge_ops.begin(), merge_ops.end(), std::back_inserter(new_base));
126
1/2
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
72 new_ops.push_back(new_base);
127 72 }
128 }
129
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 out.push_back(new_ops);
130 6 }
131 12 return out;
132 6 }
133
134 3 std::vector<std::vector<OpTypeVector>> combine_vectors(
135 const std::vector<std::vector<OpTypeVector>>& vec_0,
136 const std::vector<OpTypeVector>& vec_1) {
137 3 std::vector<std::vector<OpTypeVector>> new_vec;
138
139
2/2
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 3 times.
2/2
✓ Decision 'true' taken 36 times.
✓ Decision 'false' taken 3 times.
39 for (const std::vector<OpTypeVector>& base_frame : vec_0) {
140
2/2
✓ Branch 5 taken 336 times.
✓ Branch 6 taken 36 times.
2/2
✓ Decision 'true' taken 336 times.
✓ Decision 'false' taken 36 times.
372 for (const OpTypeVector& new_frame : vec_1) {
141
1/2
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
336 std::vector<OpTypeVector> copy = base_frame;
142
1/2
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
336 copy.push_back(new_frame);
143
1/2
✓ Branch 1 taken 336 times.
✗ Branch 2 not taken.
336 new_vec.push_back(copy);
144 336 }
145 }
146 3 return new_vec;
147 }
148
149 6 std::vector<std::vector<OpTypeVector>> get_all_permutation_combinations(
150 const std::vector<unsigned>& frame_sizes,
151 const std::vector<std::vector<OpTypeVector>>& frame_permutations) {
152 6 std::vector<std::vector<OpTypeVector>> all_combinations;
153
154
2/2
✓ Branch 6 taken 72 times.
✓ Branch 7 taken 6 times.
2/2
✓ Decision 'true' taken 72 times.
✓ Decision 'false' taken 6 times.
78 for (const OpTypeVector& frame : frame_permutations[frame_sizes[0] - 1]) {
155
5/10
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 72 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 72 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 72 times.
✓ Branch 13 taken 72 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
144 all_combinations.push_back({frame});
156 }
157
158
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 6 times.
2/2
✓ Decision 'true' taken 3 times.
✓ Decision 'false' taken 6 times.
9 for (unsigned i = 1; i < frame_sizes.size(); i++) {
159
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 all_combinations = combine_vectors(
160 6 all_combinations, frame_permutations[frame_sizes[i] - 1]);
161 }
162 6 return all_combinations;
163 }
164
165 200 std::pair<OpTypeVector, std::vector<Vertex>> FrameRandomisation::get_out_frame(
166 const OpTypeVector& in_frame, const Cycle& cycle) {
167
1/2
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
200 OpTypeVector out_frame = in_frame;
168
2/2
✓ Branch 5 taken 600 times.
✓ Branch 6 taken 200 times.
2/2
✓ Decision 'true' taken 600 times.
✓ Decision 'false' taken 200 times.
800 for (const CycleCom& cycle_op : cycle.coms_) {
169 600 OpTypeVector current_frame;
170
2/2
✓ Branch 5 taken 656 times.
✓ Branch 6 taken 600 times.
2/2
✓ Decision 'true' taken 656 times.
✓ Decision 'false' taken 600 times.
1256 for (const unsigned& u : cycle_op.indices)
171
1/2
✓ Branch 2 taken 656 times.
✗ Branch 3 not taken.
656 current_frame.push_back(out_frame[u]);
172
3/4
✓ Branch 1 taken 600 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 456 times.
✓ Branch 4 taken 144 times.
2/2
✓ Decision 'true' taken 456 times.
✓ Decision 'false' taken 144 times.
600 if (!is_initial_q_type(cycle_op.type)) {
173 current_frame =
174
3/6
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 456 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 456 times.
✗ Branch 8 not taken.
456 (frame_cycle_conjugates_.at(cycle_op.type)).at(current_frame);
175 }
176
2/2
✓ Branch 1 taken 656 times.
✓ Branch 2 taken 600 times.
2/2
✓ Decision 'true' taken 656 times.
✓ Decision 'false' taken 600 times.
1256 for (unsigned i = 0; i < current_frame.size(); i++) {
177 656 out_frame[cycle_op.indices[i]] = current_frame[i];
178 }
179 600 }
180
1/2
✓ Branch 2 taken 200 times.
✗ Branch 3 not taken.
400 return {out_frame, {}};
181 200 }
182
183 std::pair<OpTypeVector, std::vector<Vertex>>
184 36 PauliFrameRandomisation::get_out_frame(
185 const OpTypeVector& in_frame, const Cycle& cycle) {
186 36 QubitPauliMap qpm;
187
2/2
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 36 times.
2/2
✓ Decision 'true' taken 92 times.
✓ Decision 'false' taken 36 times.
128 for (unsigned i = 0; i < in_frame.size(); i++) {
188
4/5
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
92 switch (in_frame[i]) {
189
1/1
✓ Decision 'true' taken 27 times.
27 case OpType::noop:
190
3/6
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
27 qpm[Qubit("frame", i)] = Pauli::I;
191 27 break;
192
1/1
✓ Decision 'true' taken 21 times.
21 case OpType::X:
193
3/6
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
21 qpm[Qubit("frame", i)] = Pauli::X;
194 21 break;
195
1/1
✓ Decision 'true' taken 19 times.
19 case OpType::Y:
196
3/6
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 19 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 19 times.
✗ Branch 9 not taken.
19 qpm[Qubit("frame", i)] = Pauli::Y;
197 19 break;
198
1/1
✓ Decision 'true' taken 25 times.
25 case OpType::Z:
199
3/6
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 25 times.
✗ Branch 9 not taken.
25 qpm[Qubit("frame", i)] = Pauli::Z;
200 25 break;
201
0/1
✗ Decision 'true' not taken.
default: {
202 throw FrameRandomisationError(std::string(
203 "Frame OpType " + OpDesc(in_frame[i]).name() +
204 " not a Pauli OpType."));
205 }
206 }
207 }
208
209
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
72 QubitPauliTensor qpt(qpm);
210
211
2/2
✓ Branch 5 taken 198 times.
✓ Branch 6 taken 36 times.
2/2
✓ Decision 'true' taken 198 times.
✓ Decision 'false' taken 36 times.
234 for (const CycleCom& cycle_op : cycle.coms_) {
212
3/5
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
✗ Branch 4 not taken.
198 switch (cycle_op.type) {
213 92 case OpType::noop:
214 case OpType::Input:
215 case OpType::Create:
216 case OpType::Output:
217 case OpType::Discard:
218 92 break;
219 40 case OpType::H:
220 case OpType::S:
221 case OpType::X:
222 case OpType::V:
223 case OpType::Z:
224 case OpType::Y:
225 40 conjugate_PauliTensor(
226
3/6
✓ Branch 3 taken 40 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 40 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 40 times.
✗ Branch 10 not taken.
40 qpt, cycle_op.type, Qubit("frame", cycle_op.indices[0]), false);
227 40 break;
228 case OpType::Vdg:
229 case OpType::Sdg:
230 conjugate_PauliTensor(
231 qpt, cycle_op.type, Qubit("frame", cycle_op.indices[0]), true);
232 break;
233
1/1
✓ Decision 'true' taken 66 times.
66 case OpType::CX:
234 66 conjugate_PauliTensor(
235
3/6
✓ Branch 3 taken 66 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 66 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 66 times.
✗ Branch 10 not taken.
66 qpt, cycle_op.type, Qubit("frame", cycle_op.indices[0]),
236
2/4
✓ Branch 3 taken 66 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 66 times.
✗ Branch 7 not taken.
132 Qubit("frame", cycle_op.indices[1]));
237 66 break;
238
0/1
✗ Decision 'true' not taken.
default: {
239 throw FrameRandomisationError(std::string(
240 "Cycle OpType " + OpDesc(cycle_op.type).name() +
241 " not supported for PauliFrameRandomisation."));
242 }
243 }
244 }
245
246
1/2
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
36 OpTypeVector out_frame(in_frame.size());
247
2/2
✓ Branch 5 taken 92 times.
✓ Branch 6 taken 36 times.
2/2
✓ Decision 'true' taken 92 times.
✓ Decision 'false' taken 36 times.
128 for (const auto& entry : qpt.string.map) {
248
4/5
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
92 switch (entry.second) {
249
1/1
✓ Decision 'true' taken 26 times.
26 case Pauli::I:
250
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 out_frame[entry.first.index()[0]] = OpType::noop;
251 26 break;
252
1/1
✓ Decision 'true' taken 20 times.
20 case Pauli::X:
253
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 out_frame[entry.first.index()[0]] = OpType::X;
254 20 break;
255
1/1
✓ Decision 'true' taken 20 times.
20 case Pauli::Y:
256
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 out_frame[entry.first.index()[0]] = OpType::Y;
257 20 break;
258
1/1
✓ Decision 'true' taken 26 times.
26 case Pauli::Z:
259
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 out_frame[entry.first.index()[0]] = OpType::Z;
260 26 break;
261 }
262 }
263
1/2
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
72 return {out_frame, {}};
264 36 }
265
266 std::pair<OpTypeVector, std::vector<Vertex>>
267 544 UniversalFrameRandomisation::get_out_frame(
268 const OpTypeVector& in_frame, const Cycle& cycle) {
269 544 QubitPauliMap qpm;
270 544 std::vector<Vertex> to_dagger;
271
2/2
✓ Branch 1 taken 1088 times.
✓ Branch 2 taken 544 times.
2/2
✓ Decision 'true' taken 1088 times.
✓ Decision 'false' taken 544 times.
1632 for (unsigned i = 0; i < in_frame.size(); i++) {
272
4/5
✓ Branch 1 taken 272 times.
✓ Branch 2 taken 272 times.
✓ Branch 3 taken 272 times.
✓ Branch 4 taken 272 times.
✗ Branch 5 not taken.
1088 switch (in_frame[i]) {
273
1/1
✓ Decision 'true' taken 272 times.
272 case OpType::noop:
274
3/6
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 272 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 272 times.
✗ Branch 9 not taken.
272 qpm[Qubit("frame", i)] = Pauli::I;
275 272 break;
276
1/1
✓ Decision 'true' taken 272 times.
272 case OpType::X:
277
3/6
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 272 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 272 times.
✗ Branch 9 not taken.
272 qpm[Qubit("frame", i)] = Pauli::X;
278 272 break;
279
1/1
✓ Decision 'true' taken 272 times.
272 case OpType::Y:
280
3/6
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 272 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 272 times.
✗ Branch 9 not taken.
272 qpm[Qubit("frame", i)] = Pauli::Y;
281 272 break;
282
1/1
✓ Decision 'true' taken 272 times.
272 case OpType::Z:
283
3/6
✓ Branch 2 taken 272 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 272 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 272 times.
✗ Branch 9 not taken.
272 qpm[Qubit("frame", i)] = Pauli::Z;
284 272 break;
285
0/1
✗ Decision 'true' not taken.
default: {
286 throw FrameRandomisationError(std::string(
287 "Frame OpType " + OpDesc(in_frame[i]).name() +
288 " not a Pauli OpType."));
289 }
290 }
291 }
292
293
1/2
✓ Branch 1 taken 544 times.
✗ Branch 2 not taken.
1088 QubitPauliTensor qpt(qpm);
294
295
2/2
✓ Branch 5 taken 1232 times.
✓ Branch 6 taken 544 times.
2/2
✓ Decision 'true' taken 1232 times.
✓ Decision 'false' taken 544 times.
1776 for (const CycleCom& cycle_op : cycle.coms_) {
296
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1168 times.
2/2
✓ Decision 'true' taken 64 times.
✓ Decision 'false' taken 1168 times.
1232 if (cycle_op.type == OpType::Rz) {
297
3/6
✓ Branch 3 taken 64 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 64 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 64 times.
✗ Branch 10 not taken.
64 Pauli frame_type = qpt.string.map[Qubit("frame", cycle_op.indices[0])];
298
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 32 times.
2/2
✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 32 times.
64 if (frame_type == Pauli::X || frame_type == Pauli::Y) {
299
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 to_dagger.push_back(cycle_op.address);
300 }
301 // don't conjugate Pauli Tensor as no frame changes for Rz
302 }
303
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 1200 times.
2/2
✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 1200 times.
1232 if (cycle_op.type == OpType::H) {
304 32 conjugate_PauliTensor(
305
3/6
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 32 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 32 times.
✗ Branch 10 not taken.
32 qpt, cycle_op.type, Qubit("frame", cycle_op.indices[0]), false);
306 }
307
2/2
✓ Branch 0 taken 560 times.
✓ Branch 1 taken 672 times.
2/2
✓ Decision 'true' taken 560 times.
✓ Decision 'false' taken 672 times.
1232 if (cycle_op.type == OpType::CX) {
308 560 conjugate_PauliTensor(
309
3/6
✓ Branch 3 taken 560 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 560 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 560 times.
✗ Branch 10 not taken.
560 qpt, cycle_op.type, Qubit("frame", cycle_op.indices[0]),
310
2/4
✓ Branch 3 taken 560 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 560 times.
✗ Branch 7 not taken.
1120 Qubit("frame", cycle_op.indices[1]));
311 }
312 }
313
314
1/2
✓ Branch 3 taken 544 times.
✗ Branch 4 not taken.
1088 OpTypeVector out_frame(in_frame.size());
315
2/2
✓ Branch 5 taken 1088 times.
✓ Branch 6 taken 544 times.
2/2
✓ Decision 'true' taken 1088 times.
✓ Decision 'false' taken 544 times.
1632 for (const auto& entry : qpt.string.map) {
316
4/5
✓ Branch 0 taken 272 times.
✓ Branch 1 taken 272 times.
✓ Branch 2 taken 272 times.
✓ Branch 3 taken 272 times.
✗ Branch 4 not taken.
1088 switch (entry.second) {
317
1/1
✓ Decision 'true' taken 272 times.
272 case Pauli::I:
318
1/2
✓ Branch 1 taken 272 times.
✗ Branch 2 not taken.
272 out_frame[entry.first.index()[0]] = OpType::noop;
319 272 break;
320
1/1
✓ Decision 'true' taken 272 times.
272 case Pauli::X:
321
1/2
✓ Branch 1 taken 272 times.
✗ Branch 2 not taken.
272 out_frame[entry.first.index()[0]] = OpType::X;
322 272 break;
323
1/1
✓ Decision 'true' taken 272 times.
272 case Pauli::Y:
324
1/2
✓ Branch 1 taken 272 times.
✗ Branch 2 not taken.
272 out_frame[entry.first.index()[0]] = OpType::Y;
325 272 break;
326
1/1
✓ Decision 'true' taken 272 times.
272 case Pauli::Z:
327
1/2
✓ Branch 1 taken 272 times.
✗ Branch 2 not taken.
272 out_frame[entry.first.index()[0]] = OpType::Z;
328 272 break;
329 }
330 }
331
1/2
✓ Branch 1 taken 544 times.
✗ Branch 2 not taken.
1088 return {out_frame, to_dagger};
332 544 }
333
334 7 std::vector<Circuit> FrameRandomisation::label_frames(
335 const std::vector<std::vector<OpTypeVector>>& all_frame_ops,
336 const std::vector<Cycle>& cycles) {
337 7 std::vector<Circuit> output_circuit_list;
338 // make instances of all circuits using
339
2/2
✓ Branch 5 taken 374 times.
✓ Branch 6 taken 7 times.
2/2
✓ Decision 'true' taken 374 times.
✓ Decision 'false' taken 7 times.
381 for (const std::vector<OpTypeVector>& cycle_frames : all_frame_ops) {
340 374 std::vector<Vertex> dagger_vertices;
341
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 374 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 374 times.
374 if (cycle_frames.size() != cycles.size()) {
342 throw FrameRandomisationError(
343 std::string("Length of combination of Frame Permutations does not "
344 "equal number of Cycles."));
345 }
346
2/2
✓ Branch 1 taken 758 times.
✓ Branch 2 taken 374 times.
2/2
✓ Decision 'true' taken 758 times.
✓ Decision 'false' taken 374 times.
1132 for (unsigned i = 0; i < cycle_frames.size(); i++) {
347
2/4
✓ Branch 4 taken 758 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 758 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 758 times.
758 if (cycle_frames[i].size() != cycles[i].size()) {
348 throw FrameRandomisationError(
349 std::string("Size of frame does not match the number "
350 "of qubits in Cycles."));
351 }
352
1/2
✓ Branch 2 taken 758 times.
✗ Branch 3 not taken.
758 OpTypeVector in_frame = cycle_frames[i];
353 std::pair<OpTypeVector, std::vector<Vertex>> frame_and_vertices =
354
1/2
✓ Branch 2 taken 758 times.
✗ Branch 3 not taken.
758 get_out_frame(in_frame, cycles[i]);
355
1/2
✓ Branch 4 taken 758 times.
✗ Branch 5 not taken.
1516 dagger_vertices.insert(
356 758 dagger_vertices.end(), frame_and_vertices.second.begin(),
357 frame_and_vertices.second.end());
358
1/2
✓ Branch 1 taken 758 times.
✗ Branch 2 not taken.
758 assign_vertices(
359
1/2
✓ Branch 2 taken 758 times.
✗ Branch 3 not taken.
1516 in_frame, frame_and_vertices.first, cycles[i].get_frame());
360 758 }
361
362
2/2
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 374 times.
2/2
✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 374 times.
406 for (const Vertex& v : dagger_vertices) {
363
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 circuit_.set_vertex_Op_ptr(
364
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
64 v, circuit_.get_Op_ptr_from_Vertex(v)->dagger());
365 }
366
2/4
✓ Branch 1 taken 374 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 374 times.
✗ Branch 5 not taken.
374 output_circuit_list.push_back(Circuit(circuit_));
367
368
2/2
✓ Branch 4 taken 32 times.
✓ Branch 5 taken 374 times.
2/2
✓ Decision 'true' taken 32 times.
✓ Decision 'false' taken 374 times.
406 for (const Vertex& v : dagger_vertices) {
369
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 circuit_.set_vertex_Op_ptr(
370
2/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 32 times.
✗ Branch 6 not taken.
64 v, circuit_.get_Op_ptr_from_Vertex(v)->dagger());
371 }
372 374 }
373 7 return output_circuit_list;
374 }
375
376 15 std::pair<std::vector<unsigned>, unsigned> get_frame_sizes(
377 const std::vector<Cycle>& cycles) {
378 15 unsigned max_frame_size = 0;
379 15 std::vector<unsigned> frame_sizes;
380
2/2
✓ Branch 5 taken 18 times.
✓ Branch 6 taken 15 times.
2/2
✓ Decision 'true' taken 18 times.
✓ Decision 'false' taken 15 times.
33 for (const Cycle& cycle : cycles) {
381
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 unsigned frame_size = cycle.size();
382
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 frame_sizes.push_back(frame_size);
383
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
2/2
✓ Decision 'true' taken 15 times.
✓ Decision 'false' taken 3 times.
18 if (frame_size > max_frame_size) {
384 15 max_frame_size = frame_size;
385 }
386 }
387
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
30 return {frame_sizes, max_frame_size};
388 15 }
389
390 6 std::vector<Circuit> FrameRandomisation::get_all_circuits(const Circuit& circ) {
391 // Get all cycle boundaries
392 // Get all sizes
393 // Get all possible frames for all possible cycles
394 // Apply every permutation of frames to cycles
395 // Return as vector
396 // get all cycles in circuit, wire noop vertices for relabelling into
397 // boundaries
398
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 this->circuit_ = circ;
399
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::vector<Cycle> all_cycles = get_cycles(circuit_);
400
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 6 times.
6 if (all_cycles.size() == 0) {
401 throw FrameRandomisationError(
402 std::string("Circuit has no gates with OpType in Cycle OpTypes."));
403 }
404
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 add_noop_frames(all_cycles, circuit_);
405 std::pair<std::vector<unsigned>, unsigned> frame_sizes =
406
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 get_frame_sizes(all_cycles);
407
408 // work out all possible permutations of given ops for all frame sizes
409 std::vector<std::vector<OpTypeVector>> all_frame_perms =
410
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 get_all_frame_permutations(frame_sizes.second, frame_types_);
411 // combine all these permutations
412 std::vector<std::vector<OpTypeVector>> all_permutation_combinations =
413
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 get_all_permutation_combinations(frame_sizes.first, all_frame_perms);
414 std::vector<Circuit> output_circuit_list =
415
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 label_frames(all_permutation_combinations, all_cycles);
416 12 return output_circuit_list;
417 6 }
418 10 OpTypeVector FrameRandomisation::sample_frame(const unsigned& size) const {
419 10 OpTypeVector frame;
420
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 10 times.
2/2
✓ Decision 'true' taken 28 times.
✓ Decision 'false' taken 10 times.
38 for (unsigned i = 0; i < size; i++)
421
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
28 std::sample(
422 frame_types_.begin(), frame_types_.end(), std::back_inserter(frame), 1,
423
3/6
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 28 times.
✗ Branch 8 not taken.
56 std::mt19937{std::random_device{}()});
424 10 return frame;
425 }
426
427 9 std::vector<std::vector<OpTypeVector>> FrameRandomisation::get_all_samples(
428 const unsigned& samples, const std::vector<unsigned>& frame_sizes) const {
429 9 std::vector<std::vector<OpTypeVector>> output_frames;
430
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 9 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 9 times.
19 for (unsigned i = 0; i < samples; i++) {
431 10 std::vector<OpTypeVector> single_sample;
432
2/2
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 10 times.
2/2
✓ Decision 'true' taken 10 times.
✓ Decision 'false' taken 10 times.
20 for (const unsigned& size : frame_sizes)
433
2/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
10 single_sample.push_back(sample_frame(size));
434
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 output_frames.push_back(single_sample);
435 10 }
436 9 return output_frames;
437 }
438
439 778 void FrameRandomisation::assign_vertices(
440 const OpTypeVector& in_frame, const OpTypeVector& out_frame,
441 const std::vector<std::pair<Vertex, Vertex>>& frame_vertices) {
442
3/6
✓ Branch 2 taken 778 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 778 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 778 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1556 times.
1556 if (in_frame.size() != out_frame.size() ||
443 778 in_frame.size() != frame_vertices.size()) {
444 throw FrameRandomisationError(
445 std::string("Number of gates in sampled frame doesn't match "
446 "number of qubits in frame"));
447 }
448
2/2
✓ Branch 1 taken 1576 times.
✓ Branch 2 taken 778 times.
2/2
✓ Decision 'true' taken 1576 times.
✓ Decision 'false' taken 778 times.
2354 for (unsigned i = 0; i < frame_vertices.size(); i++) {
449 3152 circuit_.set_vertex_Op_ptr(
450
2/4
✓ Branch 3 taken 1576 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1576 times.
✗ Branch 8 not taken.
1576 frame_vertices[i].first, get_op_ptr(in_frame[i]));
451 3152 circuit_.set_vertex_Op_ptr(
452
2/4
✓ Branch 3 taken 1576 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1576 times.
✗ Branch 8 not taken.
1576 frame_vertices[i].second, get_op_ptr(out_frame[i]));
453 }
454 778 }
455
456 1 std::vector<Circuit> FrameRandomisation::sample_randomisation_circuits(
457 const Circuit& circ, unsigned samples) {
458 // get all cycles in circuit, wire noop vertices for relabelling into
459 // boundaries
460
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 this->circuit_ = circ;
461
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::vector<Cycle> all_cycles = get_cycles(circuit_);
462
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
1 if (all_cycles.size() == 0) {
463 throw FrameRandomisationError(
464 std::string("Circuit has no gates with OpType in Cycle OpTypes."));
465 }
466
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 add_noop_frames(all_cycles, circuit_);
467
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 std::vector<unsigned> frame_sizes = get_frame_sizes(all_cycles).first;
468 std::vector<std::vector<OpTypeVector>> all_samples =
469
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 get_all_samples(samples, frame_sizes);
470 std::vector<Circuit> output_circuit_list =
471
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 label_frames(all_samples, all_cycles);
472 2 return output_circuit_list;
473 1 }
474
475 19 std::vector<Cycle> FrameRandomisation::get_cycles(const Circuit& circ) const {
476
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 CycleFinder cf(circ, this->cycle_types_);
477
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
38 return cf.get_cycles();
478 19 }
479
480 8 std::vector<Circuit> PowerCycle::sample_cycles(
481 const Circuit& circ, unsigned total_cycles, unsigned samples) {
482
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 this->circuit_ = circ;
483 8 std::vector<Circuit> out;
484
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::vector<Cycle> all_cycles = get_cycles(circuit_);
485
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
8 if (all_cycles.size() == 0) {
486 throw FrameRandomisationError(
487 std::string("Circuit has no gates with OpType in Clifford gates."));
488 }
489
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
8 if (all_cycles.size() > 1) {
490 throw FrameRandomisationError(
491 std::string("Circuit has non-Clifford gates."));
492 }
493
494
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 add_noop_frames(all_cycles, circuit_);
495
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::vector<unsigned> frame_sizes = get_frame_sizes(all_cycles).first;
496 std::vector<std::vector<OpTypeVector>> all_samples =
497
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 get_all_samples(samples, frame_sizes);
498
2/2
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 8 times.
2/2
✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 8 times.
16 for (const std::vector<OpTypeVector>& sample : all_samples) {
499
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 8 times.
8 if (sample.size() > 1) {
500 throw FrameRandomisationError(
501
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
std::string("Frames have been sampled for more than one cycle."));
502 }
503
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 OpTypeVector in_frame = sample[0];
504 8 OpTypeVector noop_frame;
505
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 8 times.
2/2
✓ Decision 'true' taken 24 times.
✓ Decision 'false' taken 8 times.
32 for (unsigned i = 0; i < in_frame.size(); i++) {
506
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 noop_frame.push_back(OpType::noop);
507 }
508 std::pair<OpTypeVector, std::vector<Vertex>> frame_and_vertices =
509
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 get_out_frame(in_frame, all_cycles[0]);
510
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 assign_vertices(
511
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 in_frame, frame_and_vertices.first, all_cycles[0].get_frame());
512
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 Circuit full_circ = circuit_;
513
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
2/2
✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 8 times.
20 for (unsigned i = 0; i < total_cycles - 1; i++) {
514 frame_and_vertices =
515
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 get_out_frame(frame_and_vertices.first, all_cycles[0]);
516
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 assign_vertices(
517
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 noop_frame, frame_and_vertices.first, all_cycles[0].get_frame());
518
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 full_circ.append(circuit_);
519 }
520
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 out.push_back(full_circ);
521 8 }
522 16 return out;
523 8 }
524
525 } // namespace tket
526