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 "PauliGraph.hpp" | |||
16 | ||||
17 | #include "Gate/Gate.hpp" | |||
18 | #include "OpType/OpType.hpp" | |||
19 | #include "Utils/GraphHeaders.hpp" | |||
20 | ||||
21 | namespace tket { | |||
22 | ||||
23 | ✗ | bool operator<( | ||
24 | const PauliGadgetProperties &pgp1, const PauliGadgetProperties &pgp2) { | |||
25 | ✗ | return (pgp1.tensor_.string < pgp2.tensor_.string); | ||
26 | } | |||
27 | ||||
28 | ✗ | PauliGraph::PauliGraph(unsigned n) : cliff_(n) {} | ||
29 | ||||
30 | 52 | PauliGraph::PauliGraph(const qubit_vector_t &qbs, const bit_vector_t &bits) | ||
31 |
6/12✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 52 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 52 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 52 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 52 times.
✗ Branch 16 not taken.
✓ Branch 18 taken 52 times.
✗ Branch 19 not taken.
|
52 | : cliff_(qbs), bits_(bits) {} | |
32 | ||||
33 | 2856 | PauliVertSet PauliGraph::get_successors(const PauliVert &vert) const { | ||
34 | 2856 | PauliVertSet succs; | ||
35 |
1/2✓ Branch 1 taken 2856 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 2856 times.
✗ Decision 'false' not taken.
|
7109 | for (auto iter = boost::adjacent_vertices(vert, graph_); |
36 |
3/4✓ Branch 1 taken 7109 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4253 times.
✓ Branch 4 taken 2856 times.
|
7109 | iter.first != iter.second; iter.first++) { | |
37 |
3/6✓ Branch 1 taken 4253 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4253 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4253 times.
✗ Branch 8 not taken.
|
4253 | succs.insert(*iter.first); | |
38 | } | |||
39 | 2856 | return succs; | ||
40 | } | |||
41 | ||||
42 | 1939 | PauliVertSet PauliGraph::get_predecessors(const PauliVert &vert) const { | ||
43 | 1939 | PauliVertSet preds; | ||
44 |
1/2✓ Branch 1 taken 1939 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 1939 times.
✗ Decision 'false' not taken.
|
4659 | for (auto iter = boost::inv_adjacent_vertices(vert, graph_); |
45 |
3/4✓ Branch 1 taken 4659 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2720 times.
✓ Branch 4 taken 1939 times.
|
4659 | iter.first != iter.second; iter.first++) { | |
46 |
3/6✓ Branch 1 taken 2720 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2720 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2720 times.
✗ Branch 8 not taken.
|
2720 | preds.insert(*iter.first); | |
47 | } | |||
48 | 1939 | return preds; | ||
49 | } | |||
50 | ||||
51 | ✗ | PauliEdgeSet PauliGraph::get_in_edges(const PauliVert &vert) const { | ||
52 | ✗ | PauliEdgeSet ins; | ||
53 |
0/1? Decision couldn't be analyzed.
|
✗ | for (auto iter = boost::in_edges(vert, graph_); iter.first != iter.second; | |
54 | ✗ | iter.first++) { | ||
55 | ✗ | ins.insert(*iter.first); | ||
56 | } | |||
57 | ✗ | return ins; | ||
58 | } | |||
59 | ||||
60 | ✗ | PauliEdgeSet PauliGraph::get_out_edges(const PauliVert &vert) const { | ||
61 | ✗ | PauliEdgeSet outs; | ||
62 |
0/1? Decision couldn't be analyzed.
|
✗ | for (auto iter = boost::out_edges(vert, graph_); iter.first != iter.second; | |
63 | ✗ | iter.first++) { | ||
64 | ✗ | outs.insert(*iter.first); | ||
65 | } | |||
66 | ✗ | return outs; | ||
67 | } | |||
68 | ||||
69 | ✗ | PauliVert PauliGraph::source(const PauliEdge &edge) const { | ||
70 | ✗ | return boost::source(edge, graph_); | ||
71 | } | |||
72 | ||||
73 | ✗ | PauliVert PauliGraph::target(const PauliEdge &edge) const { | ||
74 | ✗ | return boost::target(edge, graph_); | ||
75 | } | |||
76 | ||||
77 | 665 | void PauliGraph::apply_gate_at_end( | ||
78 | const Gate &gate, const unit_vector_t &args) { | |||
79 |
2/2✓ Branch 5 taken 868 times.
✓ Branch 6 taken 664 times.
|
2/2✓ Decision 'true' taken 868 times.
✓ Decision 'false' taken 664 times.
|
1532 | for (const UnitID &arg : args) { |
80 |
2/2✓ Branch 1 taken 856 times.
✓ Branch 2 taken 12 times.
|
2/2✓ Decision 'true' taken 856 times.
✓ Decision 'false' taken 12 times.
|
868 | if (arg.type() == UnitType::Qubit) { |
81 |
6/10✓ Branch 1 taken 856 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 856 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 856 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 856 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 855 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 855 times.
|
856 | if (measures_.left.find(Qubit(arg)) != measures_.left.end()) { |
82 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | throw MidCircuitMeasurementNotAllowed( | |
83 | "PauliGraph does not support mid-circuit measurements " | |||
84 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | "- cannot add gate after measure on qubit " + | |
85 |
1/2✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | arg.repr()); | |
86 | } | |||
87 |
5/10✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 12 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 12 times.
|
12 | } else if (measures_.right.find(Bit(arg)) != measures_.right.end()) { |
88 | ✗ | throw MidCircuitMeasurementNotAllowed( | ||
89 | "PauliGraph does not support mid-circuit measurements - " | |||
90 | ✗ | "cannot add gate after measure to bit " + | ||
91 | ✗ | arg.repr()); | ||
92 | } | |||
93 | } | |||
94 | 664 | OpType type = gate.get_type(); | ||
95 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 652 times.
|
2/2✓ Decision 'true' taken 12 times.
✓ Decision 'false' taken 652 times.
|
664 | if (type == OpType::Measure) { |
96 |
6/12✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 12 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
|
12 | measures_.insert({Qubit(args.at(0)), Bit(args.at(1))}); | |
97 | 12 | return; | ||
98 | } | |||
99 |
1/2✓ Branch 4 taken 652 times.
✗ Branch 5 not taken.
|
652 | qubit_vector_t qbs = {args.begin(), args.end()}; | |
100 |
8/11✓ Branch 0 taken 294 times.
✓ Branch 1 taken 131 times.
✓ Branch 2 taken 136 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
652 | switch (type) { | |
101 | 294 | case OpType::Z: | ||
102 | case OpType::X: | |||
103 | case OpType::Y: | |||
104 | case OpType::S: | |||
105 | case OpType::Sdg: | |||
106 | case OpType::V: | |||
107 | case OpType::Vdg: | |||
108 | case OpType::H: | |||
109 | case OpType::CX: | |||
110 | case OpType::CY: | |||
111 | case OpType::CZ: | |||
112 | case OpType::SWAP: | |||
113 | case OpType::noop: | |||
114 | case OpType::Phase: { | |||
115 |
1/2✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
|
294 | cliff_.apply_gate_at_end(type, qbs); | |
116 | 294 | break; | ||
117 | } | |||
118 |
1/1✓ Decision 'true' taken 131 times.
|
131 | case OpType::Rz: { | |
119 |
2/4✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 131 times.
✗ Branch 5 not taken.
|
131 | QubitPauliTensor pauli = cliff_.get_zpauli(qbs.at(0)); | |
120 |
3/6✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 131 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 131 times.
✗ Branch 8 not taken.
|
131 | Expr angle = gate.get_params().at(0); | |
121 |
1/2✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
|
131 | std::optional<unsigned> cliff_angle = equiv_Clifford(angle); | |
122 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 131 times.
|
131 | if (cliff_angle) { |
123 |
0/1? Decision couldn't be analyzed.
|
✗ | for (unsigned i = 0; i < cliff_angle.value(); i++) { | |
124 | ✗ | cliff_.apply_gate_at_end(OpType::S, qbs); | ||
125 | } | |||
126 | } else | |||
127 |
1/2✓ Branch 1 taken 131 times.
✗ Branch 2 not taken.
|
131 | apply_pauli_gadget_at_end(pauli, angle); | |
128 | 131 | break; | ||
129 | 131 | } | ||
130 |
1/1✓ Decision 'true' taken 136 times.
|
136 | case OpType::Rx: { | |
131 |
2/4✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 136 times.
✗ Branch 5 not taken.
|
136 | QubitPauliTensor pauli = cliff_.get_xpauli(qbs.at(0)); | |
132 |
3/6✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 136 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 136 times.
✗ Branch 8 not taken.
|
136 | Expr angle = gate.get_params().at(0); | |
133 |
1/2✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
|
136 | std::optional<unsigned> cliff_angle = equiv_Clifford(angle); | |
134 |
2/2✓ Branch 1 taken 96 times.
✓ Branch 2 taken 40 times.
|
0/1? Decision couldn't be analyzed.
|
136 | if (cliff_angle) { |
135 |
3/4✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 192 times.
✓ Branch 4 taken 96 times.
|
0/1? Decision couldn't be analyzed.
|
288 | for (unsigned i = 0; i < cliff_angle.value(); i++) { |
136 |
1/2✓ Branch 1 taken 192 times.
✗ Branch 2 not taken.
|
192 | cliff_.apply_gate_at_end(OpType::V, qbs); | |
137 | } | |||
138 | } else | |||
139 |
1/2✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
|
40 | apply_pauli_gadget_at_end(pauli, angle); | |
140 | 136 | break; | ||
141 | 136 | } | ||
142 |
1/1✓ Decision 'true' taken 28 times.
|
28 | case OpType::Ry: { | |
143 |
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.
|
28 | Expr angle = gate.get_params().at(0); | |
144 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | std::optional<unsigned> cliff_angle = equiv_Clifford(angle); | |
145 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 28 times.
|
28 | if (cliff_angle) { |
146 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (cliff_angle.value() != 0) { | |
147 | ✗ | cliff_.apply_gate_at_end(OpType::V, qbs); | ||
148 |
0/1? Decision couldn't be analyzed.
|
✗ | for (unsigned i = 0; i < cliff_angle.value(); i++) { | |
149 | ✗ | cliff_.apply_gate_at_end(OpType::S, qbs); | ||
150 | } | |||
151 | ✗ | cliff_.apply_gate_at_end(OpType::Vdg, qbs); | ||
152 | } | |||
153 | } else { | |||
154 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | QubitPauliTensor zpauli = cliff_.get_zpauli(qbs.at(0)); | |
155 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | QubitPauliTensor xpauli = cliff_.get_xpauli(qbs.at(0)); | |
156 |
2/4✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
|
28 | QubitPauliTensor ypauli = i_ * xpauli * zpauli; | |
157 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | apply_pauli_gadget_at_end(ypauli, angle); | |
158 | 28 | } | ||
159 | 28 | break; | ||
160 | 28 | } | ||
161 |
1/1✓ Decision 'true' taken 48 times.
|
48 | case OpType::T: { | |
162 |
2/4✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
|
48 | QubitPauliTensor pauli = cliff_.get_zpauli(qbs.at(0)); | |
163 |
2/4✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
|
48 | apply_pauli_gadget_at_end(pauli, 0.25); | |
164 | 48 | break; | ||
165 | 48 | } | ||
166 |
1/1✓ Decision 'true' taken 9 times.
|
9 | case OpType::Tdg: { | |
167 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | QubitPauliTensor pauli = cliff_.get_zpauli(qbs.at(0)); | |
168 |
2/4✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | apply_pauli_gadget_at_end(pauli, 0.25); | |
169 | 9 | break; | ||
170 | 9 | } | ||
171 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::ZZMax: { | |
172 | ✗ | cliff_.apply_gate_at_end(OpType::H, {qbs.at(1)}); | ||
173 | ✗ | cliff_.apply_gate_at_end(OpType::CX, qbs); | ||
174 | ✗ | cliff_.apply_gate_at_end(OpType::Sdg, {qbs.at(0)}); | ||
175 | ✗ | cliff_.apply_gate_at_end(OpType::S, {qbs.at(1)}); | ||
176 | ✗ | cliff_.apply_gate_at_end(OpType::V, {qbs.at(1)}); | ||
177 | ✗ | break; | ||
178 | } | |||
179 | 5 | case OpType::PhaseGadget: | ||
180 | case OpType::ZZPhase: { | |||
181 |
3/6✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
|
5 | Expr angle = gate.get_params().at(0); | |
182 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | std::optional<unsigned> cliff_angle = equiv_Clifford(angle); | |
183 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 4 times.
|
5 | if (cliff_angle) { |
184 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
0/1? Decision couldn't be analyzed.
|
1 | if (cliff_angle.value() != 0) { |
185 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
|
2 | for (unsigned i = 1; i < qbs.size(); i++) { |
186 |
6/12✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 2 times.
✓ Branch 18 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
3 | cliff_.apply_gate_at_end(OpType::CX, {qbs.at(i - 1), qbs.at(i)}); | |
187 | } | |||
188 |
3/4✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
|
0/1? Decision couldn't be analyzed.
|
2 | for (unsigned i = 0; i < cliff_angle.value(); i++) { |
189 |
4/8✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
2 | cliff_.apply_gate_at_end(OpType::S, {qbs.back()}); | |
190 | } | |||
191 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2/2✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1 times.
|
2 | for (unsigned i = qbs.size() - 1; i > 0; i--) { |
192 |
6/12✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✓ Branch 17 taken 2 times.
✓ Branch 18 taken 1 times.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
3 | cliff_.apply_gate_at_end(OpType::CX, {qbs.at(i - 1), qbs.at(i)}); | |
193 | } | |||
194 | } | |||
195 | } else { | |||
196 | 4 | QubitPauliTensor pauli; | ||
197 |
2/2✓ Branch 4 taken 8 times.
✓ Branch 5 taken 4 times.
|
2/2✓ Decision 'true' taken 8 times.
✓ Decision 'false' taken 4 times.
|
12 | for (const Qubit &qb : qbs) { |
198 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | pauli = pauli * cliff_.get_zpauli(qb); | |
199 | } | |||
200 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | apply_pauli_gadget_at_end(pauli, angle); | |
201 | 4 | } | ||
202 | 5 | break; | ||
203 | 5 | } | ||
204 |
1/1✓ Decision 'true' taken 1 times.
|
1 | case OpType::XXPhase: { | |
205 |
3/6✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
|
1 | Expr angle = gate.get_params().at(0); | |
206 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | std::optional<unsigned> cliff_angle = equiv_Clifford(angle); | |
207 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 1 times.
|
1 | if (cliff_angle) { |
208 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (cliff_angle.value() != 0) { | |
209 | ✗ | cliff_.apply_gate_at_end(OpType::CX, {qbs.at(1), qbs.at(0)}); | ||
210 |
0/1? Decision couldn't be analyzed.
|
✗ | for (unsigned i = 0; i < cliff_angle.value(); i++) { | |
211 | ✗ | cliff_.apply_gate_at_end(OpType::V, {qbs.back()}); | ||
212 | } | |||
213 | ✗ | cliff_.apply_gate_at_end(OpType::CX, {qbs.at(1), qbs.at(0)}); | ||
214 | } | |||
215 | } else { | |||
216 | QubitPauliTensor pauli = | |||
217 |
5/10✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
|
2 | cliff_.get_xpauli(qbs.at(0)) * cliff_.get_xpauli(qbs.at(1)); | |
218 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | apply_pauli_gadget_at_end(pauli, angle); | |
219 | 1 | } | ||
220 | 1 | break; | ||
221 | 1 | } | ||
222 |
0/1✗ Decision 'true' not taken.
|
✗ | case OpType::YYPhase: { | |
223 | ✗ | Expr angle = gate.get_params().at(0); | ||
224 | ✗ | std::optional<unsigned> cliff_angle = equiv_Clifford(angle); | ||
225 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (cliff_angle) { | |
226 |
0/2✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
|
✗ | if (cliff_angle.value() != 0) { | |
227 | ✗ | const Qubit &arg0 = qbs.at(0); | ||
228 | ✗ | const Qubit &arg1 = qbs.at(1); | ||
229 | ✗ | cliff_.apply_gate_at_end(OpType::V, {arg0}); | ||
230 | ✗ | cliff_.apply_gate_at_end(OpType::V, {arg1}); | ||
231 | ✗ | cliff_.apply_gate_at_end(OpType::CX, {arg1, arg0}); | ||
232 |
0/1? Decision couldn't be analyzed.
|
✗ | for (unsigned i = 0; i < cliff_angle.value(); i++) { | |
233 | ✗ | cliff_.apply_gate_at_end(OpType::V, {arg1}); | ||
234 | } | |||
235 | ✗ | cliff_.apply_gate_at_end(OpType::CX, {arg1, arg0}); | ||
236 | ✗ | cliff_.apply_gate_at_end(OpType::Vdg, {arg0}); | ||
237 | ✗ | cliff_.apply_gate_at_end(OpType::Vdg, {arg1}); | ||
238 | } | |||
239 | } else { | |||
240 | QubitPauliTensor pauli = | |||
241 | ✗ | -1. * cliff_.get_xpauli(qbs.at(0)) * cliff_.get_zpauli(qbs.at(0)) * | ||
242 | ✗ | cliff_.get_xpauli(qbs.at(1)) * cliff_.get_zpauli(qbs.at(1)); | ||
243 | ✗ | apply_pauli_gadget_at_end(pauli, angle); | ||
244 | } | |||
245 | ✗ | break; | ||
246 | } | |||
247 |
0/1✗ Decision 'true' not taken.
|
✗ | default: { | |
248 | ✗ | throw BadOpType("Cannot add gate to PauliGraph", type); | ||
249 | } | |||
250 | } | |||
251 | 652 | } | ||
252 | ||||
253 | 373 | void PauliGraph::apply_pauli_gadget_at_end( | ||
254 | const QubitPauliTensor &pauli, const Expr &angle) { | |||
255 |
1/2✓ Branch 1 taken 373 times.
✗ Branch 2 not taken.
|
373 | PauliVertSet to_search = end_line_; | |
256 |
1/2✓ Branch 1 taken 373 times.
✗ Branch 2 not taken.
|
373 | PauliVertSet commuted; | |
257 |
1/2✓ Branch 1 taken 373 times.
✗ Branch 2 not taken.
|
373 | PauliVert new_vert = boost::add_vertex(graph_); | |
258 |
3/6✓ Branch 1 taken 373 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 373 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 373 times.
✗ Branch 8 not taken.
|
373 | graph_[new_vert] = {pauli, angle}; | |
259 |
2/2✓ Branch 1 taken 2592 times.
✓ Branch 2 taken 346 times.
|
2/2✓ Decision 'true' taken 2592 times.
✓ Decision 'false' taken 346 times.
|
2938 | while (!to_search.empty()) { |
260 | // Get next candidate parent | |||
261 |
1/2✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
|
2592 | PauliVert to_compare = *to_search.begin(); | |
262 |
1/2✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
|
2592 | to_search.erase(to_search.begin()); | |
263 | ||||
264 | // Check that we have already commuted past all of its children | |||
265 | 2592 | bool ready = true; | ||
266 |
6/10✓ Branch 1 taken 2592 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 2884 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2024 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4616 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2884 times.
✓ Branch 15 taken 1732 times.
|
0/1? Decision couldn't be analyzed.
|
4616 | for (const PauliVert &child : get_successors(to_compare)) { |
267 |
4/6✓ Branch 4 taken 2884 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2884 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 860 times.
✓ Branch 10 taken 2024 times.
|
2/2✓ Decision 'true' taken 860 times.
✓ Decision 'false' taken 2024 times.
|
2884 | if (commuted.get<TagKey>().find(child) == commuted.get<TagKey>().end()) { |
268 | 860 | ready = false; | ||
269 | 860 | break; | ||
270 | } | |||
271 | 2592 | } | ||
272 |
2/2✓ Branch 0 taken 860 times.
✓ Branch 1 taken 1732 times.
|
2/2✓ Decision 'true' taken 1732 times.
✓ Decision 'false' taken 860 times.
|
2592 | if (!ready) continue; |
273 | ||||
274 | // Check if we can commute past it | |||
275 |
2/4✓ Branch 1 taken 1732 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1732 times.
✗ Branch 5 not taken.
|
1732 | QubitPauliTensor compare_pauli = graph_[to_compare].tensor_; | |
276 |
3/4✓ Branch 1 taken 1732 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1294 times.
✓ Branch 4 taken 438 times.
|
2/2✓ Decision 'true' taken 1294 times.
✓ Decision 'false' taken 438 times.
|
1732 | if (pauli.commutes_with(compare_pauli)) { |
277 |
3/4✓ Branch 1 taken 1294 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 1267 times.
|
2/2✓ Decision 'true' taken 27 times.
✓ Decision 'false' taken 1267 times.
|
1294 | if (pauli.string == compare_pauli.string) { |
278 | // Identical strings - we can merge vertices | |||
279 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
1/2✓ Decision 'true' taken 27 times.
✗ Decision 'false' not taken.
|
27 | if (pauli.coeff == compare_pauli.coeff) { |
280 |
2/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
27 | graph_[to_compare].angle_ += angle; | |
281 | } else { | |||
282 | ✗ | graph_[to_compare].angle_ -= angle; | ||
283 | } | |||
284 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | boost::clear_vertex(new_vert, graph_); | |
285 |
1/2✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
|
27 | boost::remove_vertex(new_vert, graph_); | |
286 | ||||
287 | std::optional<unsigned> cl_ang = | |||
288 |
2/4✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
|
27 | equiv_Clifford(graph_[to_compare].angle_); | |
289 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 6 times.
|
2/2✓ Decision 'true' taken 21 times.
✓ Decision 'false' taken 6 times.
|
27 | if (cl_ang) { |
290 |
2/4✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 21 times.
✗ Branch 6 not taken.
|
21 | cliff_.apply_pauli_at_front(graph_[to_compare].tensor_, *cl_ang); | |
291 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | start_line_.erase(to_compare); | |
292 |
6/10✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 41 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 41 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 62 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 41 times.
✓ Branch 15 taken 21 times.
|
0/1? Decision couldn't be analyzed.
|
62 | for (const PauliVert &v : get_predecessors(to_compare)) { |
293 |
3/4✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 37 times.
|
2/2✓ Decision 'true' taken 4 times.
✓ Decision 'false' taken 37 times.
|
41 | if (boost::out_degree(v, graph_) == 1) { |
294 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | end_line_.insert(v); | |
295 | } | |||
296 | 21 | } | ||
297 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | end_line_.erase(to_compare); | |
298 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | boost::clear_vertex(to_compare, graph_); | |
299 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | boost::remove_vertex(to_compare, graph_); | |
300 | } | |||
301 | 27 | return; | ||
302 | } else { | |||
303 | // Commute and continue searching | |||
304 |
1/2✓ Branch 1 taken 1267 times.
✗ Branch 2 not taken.
|
1267 | PauliVertSet preds = get_predecessors(to_compare); | |
305 |
1/2✓ Branch 3 taken 1267 times.
✗ Branch 4 not taken.
|
1267 | to_search.insert(preds.begin(), preds.end()); | |
306 |
1/2✓ Branch 1 taken 1267 times.
✗ Branch 2 not taken.
|
1267 | commuted.insert(to_compare); | |
307 | 1267 | } | ||
308 | } else { | |||
309 | // Does not commute - add dependency edge | |||
310 |
1/2✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
|
438 | boost::add_edge(to_compare, new_vert, graph_); | |
311 |
1/2✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
|
438 | end_line_.erase(to_compare); | |
312 | } | |||
313 |
2/2✓ Branch 1 taken 1705 times.
✓ Branch 2 taken 27 times.
|
1732 | } | |
314 |
1/2✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
|
346 | end_line_.insert(new_vert); | |
315 |
4/6✓ Branch 1 taken 346 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 145 times.
✓ Branch 6 taken 201 times.
✓ Branch 8 taken 145 times.
✗ Branch 9 not taken.
|
0/1? Decision couldn't be analyzed.
|
346 | if (get_predecessors(new_vert).empty()) start_line_.insert(new_vert); |
316 |
4/4✓ Branch 1 taken 346 times.
✓ Branch 2 taken 27 times.
✓ Branch 4 taken 346 times.
✓ Branch 5 taken 27 times.
|
400 | } | |
317 | ||||
318 | 390 | PauliGraph::TopSortIterator::TopSortIterator() | ||
319 | 390 | : pg_(nullptr), | ||
320 | 390 | current_vert_(boost::graph_traits<PauliDAG>::null_vertex()) {} | ||
321 | ||||
322 | 38 | PauliGraph::TopSortIterator::TopSortIterator(const PauliGraph &pg) { | ||
323 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 38 times.
|
38 | if (pg.start_line_.empty()) { |
324 | ✗ | current_vert_ = boost::graph_traits<PauliDAG>::null_vertex(); | ||
325 | ✗ | return; | ||
326 | } | |||
327 | 38 | pg_ = &pg; | ||
328 |
4/6✓ Branch 3 taken 107 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 145 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 107 times.
✓ Branch 9 taken 38 times.
|
0/1? Decision couldn't be analyzed.
|
145 | for (const PauliVert &vert : pg.start_line_) { |
329 |
4/8✓ Branch 1 taken 107 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 107 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 107 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 107 times.
✗ Branch 12 not taken.
|
107 | search_set_.insert({pg.graph_[vert].tensor_, vert}); | |
330 | } | |||
331 | 38 | current_vert_ = search_set_.begin()->second; | ||
332 |
1/2✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
38 | search_set_.erase(search_set_.begin()); | |
333 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | visited_ = {current_vert_}; | |
334 |
5/8✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 60 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 22 times.
✓ Branch 12 taken 38 times.
|
0/1? Decision couldn't be analyzed.
|
60 | for (const PauliVert &child : pg_->get_successors(current_vert_)) { |
335 |
4/8✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 22 times.
✗ Branch 12 not taken.
|
22 | search_set_.insert({pg.graph_[child].tensor_, child}); | |
336 | 38 | } | ||
337 | } | |||
338 | ||||
339 | 290 | const PauliVert &PauliGraph::TopSortIterator::operator*() const { | ||
340 | 290 | return current_vert_; | ||
341 | } | |||
342 | ||||
343 | ✗ | const PauliVert *PauliGraph::TopSortIterator::operator->() const { | ||
344 | ✗ | return ¤t_vert_; | ||
345 | } | |||
346 | ||||
347 | 352 | bool PauliGraph::TopSortIterator::operator==( | ||
348 | const TopSortIterator &other) const { | |||
349 | 352 | return this->current_vert_ == other.current_vert_; | ||
350 | } | |||
351 | ||||
352 | 318 | bool PauliGraph::TopSortIterator::operator!=( | ||
353 | const TopSortIterator &other) const { | |||
354 | 318 | return !(*this == other); | ||
355 | } | |||
356 | ||||
357 | ✗ | PauliGraph::TopSortIterator PauliGraph::TopSortIterator::operator++(int) { | ||
358 | ✗ | PauliGraph::TopSortIterator it = *this; | ||
359 | ✗ | ++*this; | ||
360 | ✗ | return it; | ||
361 | } | |||
362 | ||||
363 | 264 | PauliGraph::TopSortIterator &PauliGraph::TopSortIterator::operator++() { | ||
364 | 264 | bool found_next = false; | ||
365 |
6/6✓ Branch 0 taken 343 times.
✓ Branch 1 taken 226 times.
✓ Branch 3 taken 305 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 305 times.
✓ Branch 6 taken 264 times.
|
0/1? Decision couldn't be analyzed.
|
569 | while (!found_next && !search_set_.empty()) { |
366 | 305 | current_vert_ = search_set_.begin()->second; | ||
367 | 305 | search_set_.erase(search_set_.begin()); | ||
368 | ||||
369 | // Check that we have visited all parents | |||
370 | 305 | found_next = true; | ||
371 |
6/10✓ Branch 1 taken 305 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 476 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 397 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 702 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 476 times.
✓ Branch 15 taken 226 times.
|
0/1? Decision couldn't be analyzed.
|
702 | for (const PauliVert &parent : pg_->get_predecessors(current_vert_)) { |
372 |
3/4✓ Branch 2 taken 476 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 79 times.
✓ Branch 6 taken 397 times.
|
2/2✓ Decision 'true' taken 79 times.
✓ Decision 'false' taken 397 times.
|
476 | if (visited_.find(parent) == visited_.end()) { |
373 | 79 | found_next = false; | ||
374 | 79 | break; | ||
375 | } | |||
376 | 305 | } | ||
377 | } | |||
378 |
2/2✓ Branch 0 taken 226 times.
✓ Branch 1 taken 38 times.
|
2/2✓ Decision 'true' taken 226 times.
✓ Decision 'false' taken 38 times.
|
264 | if (found_next) { |
379 | 226 | visited_.insert(current_vert_); | ||
380 |
5/8✓ Branch 1 taken 226 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 309 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 535 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 309 times.
✓ Branch 12 taken 226 times.
|
0/1? Decision couldn't be analyzed.
|
535 | for (const PauliVert &child : pg_->get_successors(current_vert_)) { |
381 |
4/8✓ Branch 1 taken 309 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 309 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 309 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 309 times.
✗ Branch 12 not taken.
|
309 | search_set_.insert({pg_->graph_[child].tensor_, child}); | |
382 | 226 | } | ||
383 | } else { | |||
384 | 38 | *this = TopSortIterator(); | ||
385 | } | |||
386 | 264 | return *this; | ||
387 | } | |||
388 | ||||
389 | 38 | PauliGraph::TopSortIterator PauliGraph::begin() const { | ||
390 | 38 | return TopSortIterator(*this); | ||
391 | } | |||
392 | ||||
393 | 352 | PauliGraph::TopSortIterator PauliGraph::end() const { | ||
394 | 352 | return TopSortIterator(); | ||
395 | } | |||
396 | ||||
397 | ✗ | void PauliGraph::to_graphviz_file(const std::string &filename) const { | ||
398 | ✗ | std::ofstream dot_file(filename); | ||
399 | ✗ | to_graphviz(dot_file); | ||
400 | } | |||
401 | ||||
402 | ✗ | void PauliGraph::to_graphviz(std::ostream &out) const { | ||
403 | ✗ | out << "digraph G {\n"; | ||
404 | ||||
405 | ✗ | std::map<PauliVert, unsigned> index_map; | ||
406 | ✗ | unsigned i = 0; | ||
407 | ✗ | BGL_FORALL_VERTICES(v, graph_, PauliDAG) { | ||
408 | ✗ | index_map.insert({v, i}); | ||
409 | ✗ | out << i << " [label = \"" << graph_[v].tensor_.to_str() << ", " | ||
410 | ✗ | << graph_[v].angle_ << "\"];\n"; | ||
411 | ✗ | ++i; | ||
412 | } | |||
413 | ||||
414 | ✗ | BGL_FORALL_EDGES(e, graph_, PauliDAG) { | ||
415 | ✗ | PauliVert v_so = source(e); | ||
416 | ✗ | PauliVert v_ta = target(e); | ||
417 | ✗ | out << index_map.at(v_so) << " -> " << index_map.at(v_ta) << ";\n"; | ||
418 | } | |||
419 | ||||
420 | ✗ | out << "}"; | ||
421 | } | |||
422 | ||||
423 | } // namespace tket | |||
424 |