GCC Code Coverage Report


Directory: ./
File: ZX/ZXDManipulation.cpp
Date: 2022-10-15 05:10:18
Warnings: 2 unchecked decisions!
Exec Total Coverage
Lines: 88 106 83.0%
Functions: 14 16 87.5%
Branches: 150 264 56.8%
Decisions: 29 40 72.5%

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 <tkassert/Assert.hpp>
16
17 #include "Utils/GraphHeaders.hpp"
18 #include "ZX/ZXDiagram.hpp"
19
20 namespace tket {
21
22 namespace zx {
23
24 1524 ZXVert ZXDiagram::add_vertex(ZXGen_ptr op) {
25 1524 ZXVertProperties vp{op};
26
1/2
✓ Branch 2 taken 1524 times.
✗ Branch 3 not taken.
3048 return boost::add_vertex(vp, *graph);
27 1524 }
28
29 580 ZXVert ZXDiagram::add_vertex(ZXType type, QuantumType qtype) {
30
1/2
✓ Branch 1 taken 580 times.
✗ Branch 2 not taken.
580 ZXGen_ptr op = ZXGen::create_gen(type, qtype);
31
1/2
✓ Branch 2 taken 580 times.
✗ Branch 3 not taken.
1160 return add_vertex(op);
32 580 }
33
34 328 ZXVert ZXDiagram::add_vertex(
35 ZXType type, const Expr& param, QuantumType qtype) {
36
2/2
✓ Branch 1 taken 327 times.
✓ Branch 2 taken 1 times.
328 ZXGen_ptr op = ZXGen::create_gen(type, param, qtype);
37
1/2
✓ Branch 2 taken 327 times.
✗ Branch 3 not taken.
654 return add_vertex(op);
38 327 }
39
40 1823 Wire ZXDiagram::add_wire(
41 const ZXVert& va, const ZXVert& vb, const WireProperties& prop) {
42
1/2
✓ Branch 2 taken 1823 times.
✗ Branch 3 not taken.
1823 auto [wire, added] = boost::add_edge(va, vb, prop, *graph);
43 // add_edge only returns false if the graph cannot support parallel edges, but
44 // we have set it up to allow this
45 TKET_ASSERT(added);
46 1823 return wire;
47 }
48
49 1112 Wire ZXDiagram::add_wire(
50 const ZXVert& va, const ZXVert& vb, ZXWireType type, QuantumType qtype,
51 std::optional<unsigned> va_port, std::optional<unsigned> vb_port) {
52
1/2
✓ Branch 2 taken 1112 times.
✗ Branch 3 not taken.
1112 return add_wire(va, vb, {type, qtype, va_port, vb_port});
53 }
54
55 204 void ZXDiagram::remove_vertex(const ZXVert& v) {
56 // Remove from boundary if `v` is a boundary vertex
57
2/2
✓ Branch 2 taken 97 times.
✓ Branch 3 taken 107 times.
2/2
✓ Decision 'true' taken 97 times.
✓ Decision 'false' taken 107 times.
204 if (is_boundary_type(get_zxtype(v))) {
58
1/2
✓ Branch 3 taken 97 times.
✗ Branch 4 not taken.
97 ZXVertVec::iterator v_it = std::find(boundary.begin(), boundary.end(), v);
59
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
0/1
? Decision couldn't be analyzed.
97 if (v_it != boundary.end()) boundary.erase(v_it);
60 }
61
62 204 boost::clear_vertex(v, *graph);
63 204 boost::remove_vertex(v, *graph);
64 204 }
65
66 157 void ZXDiagram::remove_wire(const Wire& w) { boost::remove_edge(w, *graph); }
67
68 2 bool ZXDiagram::remove_wire(
69 const ZXVert& va, const ZXVert& vb, const WireProperties& prop,
70 ZXDiagram::WireSearchOption directed) {
71
12/18
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✓ Branch 14 taken 1 times.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✓ Branch 19 taken 1 times.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✓ Branch 24 taken 1 times.
5 BGL_FORALL_OUTEDGES(va, w, *graph, ZXGraph) {
72
9/12
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 1 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 2 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 2 times.
3 if ((target(w) == vb) && (get_wire_info(w) == prop)) {
73
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 remove_wire(w);
74 1 return true;
75 }
76 }
77
78 // Recheck with reverse wire direction (including ports on the two ends)
79
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1/2
✓ Decision 'true' taken 1 times.
✗ Decision 'false' not taken.
1 if (directed == WireSearchOption::UNDIRECTED) {
80 1 WireProperties rev_props = prop;
81 1 rev_props.source_port = prop.target_port;
82 1 rev_props.target_port = prop.source_port;
83
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 return remove_wire(vb, va, rev_props, WireSearchOption::DIRECTED);
84 }
85 return false;
86 }
87
88 void ZXDiagram::symbol_substitution(const symbol_map_t& symbol_map) {
89 SymEngine::map_basic_basic sub_map;
90
0/2
✗ Decision 'true' not taken.
✗ Decision 'false' not taken.
for (const std::pair<const Sym, Expr>& p : symbol_map) {
91 ExprPtr s = p.first;
92 ExprPtr e = p.second;
93 sub_map[s] = e;
94 }
95 symbol_substitution(sub_map);
96 }
97
98 void ZXDiagram::symbol_substitution(
99 const std::map<Sym, double, SymEngine::RCPBasicKeyLess>& symbol_map) {
100 SymEngine::map_basic_basic sub_map;
101
0/1
? Decision couldn't be analyzed.
for (std::pair<Sym, Expr> p : symbol_map) {
102 ExprPtr s = p.first;
103 ExprPtr e = Expr(p.second);
104 sub_map[s] = e;
105 }
106 symbol_substitution(sub_map);
107 }
108
109 4 void ZXDiagram::symbol_substitution(const SymEngine::map_basic_basic& sub_map) {
110 4 scalar = scalar.subs(sub_map);
111
7/8
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 24 times.
✓ Branch 7 taken 4 times.
✓ Branch 9 taken 24 times.
✓ Branch 10 taken 4 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 4 times.
32 BGL_FORALL_VERTICES(v, *graph, ZXGraph) {
112
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
24 ZXGen_ptr new_op = get_vertex_ZXGen_ptr(v)->symbol_substitution(sub_map);
113
3/4
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 14 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
1/2
✓ Decision 'true' taken 24 times.
✗ Decision 'false' not taken.
24 if (new_op) set_vertex_ZXGen_ptr(v, new_op);
114 24 }
115 4 }
116
117 8 SymSet ZXDiagram::free_symbols() const {
118 8 SymSet symbols = expr_free_symbols(get_scalar());
119
7/8
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 8 times.
✓ Branch 9 taken 40 times.
✓ Branch 10 taken 8 times.
✓ Branch 12 taken 8 times.
✓ Branch 13 taken 8 times.
56 BGL_FORALL_VERTICES(v, *graph, ZXGraph) {
120
2/4
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
40 const SymSet s = get_vertex_ZXGen_ptr(v)->free_symbols();
121
1/2
✓ Branch 3 taken 40 times.
✗ Branch 4 not taken.
40 symbols.insert(s.begin(), s.end());
122 40 }
123 8 return symbols;
124 }
125
126 1 bool ZXDiagram::is_symbolic() const { return !free_symbols().empty(); }
127
128 1451 static void check_valid_wire(
129 const std::optional<unsigned>& port, QuantumType qtype,
130 const std::optional<unsigned>& n_ports, std::vector<bool>& ports_found,
131 ZXGen_ptr op) {
132
2/2
✓ Branch 1 taken 114 times.
✓ Branch 2 taken 1337 times.
2/2
✓ Decision 'true' taken 114 times.
✓ Decision 'false' taken 1337 times.
1451 if (port) {
133
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 113 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 113 times.
114 if (!n_ports)
134
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw ZXError("Wire at a named port of an undirected vertex");
135
2/2
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 112 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 112 times.
113 else if (ports_found.at(*port))
136
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw ZXError("Multiple wires on the same port of a vertex");
137 else
138 112 ports_found.at(*port) = true;
139
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1336 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1336 times.
1337 } else if (n_ports)
140
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw ZXError("Wire at an unnamed port of a directed vertex");
141
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1447 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 1447 times.
1448 if (!op->valid_edge(port, qtype))
142
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw ZXError("QuantumType of wire is incompatible with the given port");
143 1447 }
144
145 66 void ZXDiagram::check_validity() const {
146 66 std::set<ZXVert> boundary_lookup;
147
2/2
✓ Branch 5 taken 239 times.
✓ Branch 6 taken 66 times.
2/2
✓ Decision 'true' taken 239 times.
✓ Decision 'false' taken 66 times.
305 for (const ZXVert& b : boundary) {
148
3/6
✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 239 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 239 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 239 times.
239 if (!is_boundary_type(get_zxtype(b)))
149 throw ZXError("Non-boundary vertex type in boundary");
150
2/4
✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 239 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 239 times.
239 if (!boundary_lookup.insert(b).second)
151 throw ZXError("Vertex appears in boundary multiple times");
152 }
153
7/8
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 739 times.
✓ Branch 7 taken 57 times.
✓ Branch 9 taken 739 times.
✓ Branch 10 taken 57 times.
✓ Branch 12 taken 64 times.
✓ Branch 13 taken 59 times.
855 BGL_FORALL_VERTICES(v, *graph, ZXGraph) {
154
1/2
✓ Branch 1 taken 739 times.
✗ Branch 2 not taken.
739 ZXGen_ptr op = get_vertex_ZXGen_ptr(v);
155
1/2
✓ Branch 2 taken 739 times.
✗ Branch 3 not taken.
739 ZXType type = op->get_type();
156
3/4
✓ Branch 1 taken 739 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 238 times.
✓ Branch 4 taken 501 times.
2/2
✓ Decision 'true' taken 238 times.
✓ Decision 'false' taken 501 times.
739 if (is_boundary_type(type)) {
157
3/4
✓ Branch 1 taken 238 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 236 times.
2/2
✓ Decision 'true' taken 2 times.
✓ Decision 'false' taken 236 times.
238 if (degree(v) != 1)
158
2/4
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 throw ZXError("Boundary vertex does not have degree 1");
159
2/4
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 236 times.
1/2
✗ Decision 'true' not taken.
✓ Decision 'false' taken 236 times.
236 if (boundary_lookup.find(v) == boundary_lookup.end())
160 throw ZXError("Vertex of boundary type is not in the boundary");
161 }
162 737 std::optional<unsigned> n_ports = std::nullopt;
163
3/4
✓ Branch 1 taken 737 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 53 times.
✓ Branch 4 taken 684 times.
2/2
✓ Decision 'true' taken 53 times.
✓ Decision 'false' taken 684 times.
737 if (is_directed_type(type)) {
164 53 const ZXDirected& dir = static_cast<const ZXDirected&>(*op);
165
1/2
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
53 n_ports = dir.n_ports();
166 }
167
3/4
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 684 times.
✓ Branch 6 taken 737 times.
✗ Branch 7 not taken.
737 std::vector<bool> ports_found(n_ports ? *n_ports : 0, false);
168
11/16
✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 504 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1228 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 726 times.
✓ Branch 11 taken 502 times.
✓ Branch 13 taken 726 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 726 times.
✓ Branch 16 taken 502 times.
✓ Branch 18 taken 1239 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 504 times.
✓ Branch 21 taken 735 times.
1963 BGL_FORALL_OUTEDGES(v, w, *graph, ZXGraph) {
169
5/8
✓ Branch 2 taken 726 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 726 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 724 times.
✓ Branch 9 taken 2 times.
✓ Branch 12 taken 724 times.
✗ Branch 13 not taken.
728 check_valid_wire(source_port(w), get_qtype(w), n_ports, ports_found, op);
170 }
171
11/16
✓ Branch 2 taken 735 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 499 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1222 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 725 times.
✓ Branch 11 taken 497 times.
✓ Branch 13 taken 725 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 725 times.
✓ Branch 16 taken 497 times.
✓ Branch 18 taken 1232 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 499 times.
✓ Branch 21 taken 733 times.
1955 BGL_FORALL_INEDGES(v, w, *graph, ZXGraph) {
172
5/8
✓ Branch 2 taken 725 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 725 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 723 times.
✓ Branch 9 taken 2 times.
✓ Branch 12 taken 723 times.
✗ Branch 13 not taken.
727 check_valid_wire(target_port(w), get_qtype(w), n_ports, ports_found, op);
173 }
174
7/8
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 683 times.
✓ Branch 5 taken 50 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 49 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 732 times.
2/2
✓ Decision 'true' taken 1 times.
✓ Decision 'false' taken 732 times.
733 if (n_ports && !std::all_of(
175 ports_found.begin(), ports_found.end(),
176 839 [](const bool& b) { return b; }))
177
2/4
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
1 throw ZXError("Not all ports of a directed vertex have wires connected");
178 744 }
179 66 }
180
181 } // namespace zx
182
183 } // namespace tket
184