Skip to content

Commit 931865c

Browse files
authored
Merge pull request #493 from quantumlib/update-fusers
Update fusers.
2 parents 7900041 + 6eecca7 commit 931865c

File tree

4 files changed

+165
-63
lines changed

4 files changed

+165
-63
lines changed

lib/fuser_basic.h

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
5656
* two-qubit gates will get fused. To respect specific time boundaries while
5757
* fusing gates, use the other version of this method below.
5858
* @param param Options for gate fusion.
59-
* @param num_qubits The number of qubits acted on by 'gates'.
59+
* @param max_qubit1 The maximum qubit index (plus one) acted on by 'gates'.
6060
* @param gates The gates (or pointers to the gates) to be fused.
6161
* Gate times of the gates that act on the same qubits should be ordered.
6262
* Gates that are out of time order should not cross the time boundaries
@@ -66,18 +66,18 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
6666
* acting on a specific pair of qubits which can be applied as a group.
6767
*/
6868
static std::vector<GateFused> FuseGates(const Parameter& param,
69-
unsigned num_qubits,
69+
unsigned max_qubit1,
7070
const std::vector<Gate>& gates,
7171
bool fuse_matrix = true) {
7272
return FuseGates(
73-
param, num_qubits, gates.cbegin(), gates.cend(), {}, fuse_matrix);
73+
param, max_qubit1, gates.cbegin(), gates.cend(), {}, fuse_matrix);
7474
}
7575

7676
/**
7777
* Stores sets of gates that can be applied together. Only one- and
7878
* two-qubit gates will get fused.
7979
* @param param Options for gate fusion.
80-
* @param num_qubits The number of qubits acted on by 'gates'.
80+
* @param max_qubit1 The maximum qubit index (plus one) acted on by 'gates'.
8181
* @param gates The gates (or pointers to the gates) to be fused.
8282
* Gate times of the gates that act on the same qubits should be ordered.
8383
* Gates that are out of time order should not cross the time boundaries
@@ -91,10 +91,10 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
9191
*/
9292
static std::vector<GateFused> FuseGates(
9393
const Parameter& param,
94-
unsigned num_qubits, const std::vector<Gate>& gates,
94+
unsigned max_qubit1, const std::vector<Gate>& gates,
9595
const std::vector<unsigned>& times_to_split_at,
9696
bool fuse_matrix = true) {
97-
return FuseGates(param, num_qubits, gates.cbegin(), gates.cend(),
97+
return FuseGates(param, max_qubit1, gates.cbegin(), gates.cend(),
9898
times_to_split_at, fuse_matrix);
9999
}
100100

@@ -103,7 +103,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
103103
* two-qubit gates will get fused. To respect specific time boundaries while
104104
* fusing gates, use the other version of this method below.
105105
* @param param Options for gate fusion.
106-
* @param num_qubits The number of qubits acted on by gates.
106+
* @param max_qubit1 The maximum qubit index (plus one) acted on by 'gates'.
107107
* @param gfirst, glast The iterator range [gfirst, glast) to fuse gates
108108
* (or pointers to gates) in. Gate times of the gates that act on the same
109109
* qubits should be ordered. Gates that are out of time order should not
@@ -113,18 +113,18 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
113113
* acting on a specific pair of qubits which can be applied as a group.
114114
*/
115115
static std::vector<GateFused> FuseGates(
116-
const Parameter& param, unsigned num_qubits,
116+
const Parameter& param, unsigned max_qubit1,
117117
typename std::vector<Gate>::const_iterator gfirst,
118118
typename std::vector<Gate>::const_iterator glast,
119119
bool fuse_matrix = true) {
120-
return FuseGates(param, num_qubits, gfirst, glast, {}, fuse_matrix);
120+
return FuseGates(param, max_qubit1, gfirst, glast, {}, fuse_matrix);
121121
}
122122

123123
/**
124124
* Stores sets of gates that can be applied together. Only one- and
125125
* two-qubit gates will get fused.
126126
* @param param Options for gate fusion.
127-
* @param num_qubits The number of qubits acted on by gates.
127+
* @param max_qubit1 The maximum qubit index (plus one) acted on by 'gates'.
128128
* @param gfirst, glast The iterator range [gfirst, glast) to fuse gates
129129
* (or pointers to gates) in. Gate times of the gates that act on the same
130130
* qubits should be ordered. Gates that are out of time order should not
@@ -138,7 +138,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
138138
* acting on a specific pair of qubits which can be applied as a group.
139139
*/
140140
static std::vector<GateFused> FuseGates(
141-
const Parameter& param, unsigned num_qubits,
141+
const Parameter& param, unsigned max_qubit1,
142142
typename std::vector<Gate>::const_iterator gfirst,
143143
typename std::vector<Gate>::const_iterator glast,
144144
const std::vector<unsigned>& times_to_split_at,
@@ -162,7 +162,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
162162
std::vector<const RGate*> gates_seq;
163163

164164
// Lattice of gates: qubits "hyperplane" and time direction.
165-
std::vector<std::vector<const RGate*>> gates_lat(num_qubits);
165+
std::vector<std::vector<const RGate*>> gates_lat(max_qubit1);
166166

167167
// Current unfused gate.
168168
auto gate_it = gfirst;
@@ -171,7 +171,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
171171
gates_seq.resize(0);
172172
gates_seq.reserve(num_gates);
173173

174-
for (unsigned k = 0; k < num_qubits; ++k) {
174+
for (unsigned k = 0; k < max_qubit1; ++k) {
175175
gates_lat[k].resize(0);
176176
gates_lat[k].reserve(128);
177177
}
@@ -182,9 +182,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
182182

183183
if (gate.time > times[l]) break;
184184

185-
if (GateIsOutOfOrder(gate.time, gate.qubits, gates_lat)
186-
|| GateIsOutOfOrder(gate.time, gate.controlled_by, gates_lat)) {
187-
IO::errorf("gate is out of time order.\n");
185+
if (!ValidateGate(gate, max_qubit1, gates_lat)) {
188186
gates_fused.resize(0);
189187
return gates_fused;
190188
}
@@ -193,7 +191,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
193191
auto& mea_gates_at_time = measurement_gates[gate.time];
194192
if (mea_gates_at_time.size() == 0) {
195193
gates_seq.push_back(&gate);
196-
mea_gates_at_time.reserve(num_qubits);
194+
mea_gates_at_time.reserve(max_qubit1);
197195
}
198196

199197
mea_gates_at_time.push_back(&gate);
@@ -217,7 +215,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
217215
}
218216
}
219217

220-
std::vector<unsigned> last(num_qubits, 0);
218+
std::vector<unsigned> last(max_qubit1, 0);
221219

222220
const RGate* delayed_measurement_gate = nullptr;
223221

@@ -281,7 +279,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
281279
}
282280
}
283281

284-
for (unsigned q = 0; q < num_qubits; ++q) {
282+
for (unsigned q = 0; q < max_qubit1; ++q) {
285283
auto l = last[q];
286284
if (l == gates_lat[q].size()) continue;
287285

@@ -360,17 +358,34 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
360358
return k;
361359
}
362360

363-
template <typename GatesLat>
364-
static bool GateIsOutOfOrder(unsigned time,
365-
const std::vector<unsigned>& qubits,
366-
const GatesLat& gates_lat) {
367-
for (unsigned q : qubits) {
368-
if (!gates_lat[q].empty() && time <= gates_lat[q].back()->time) {
369-
return true;
361+
template <typename Gate2, typename GatesLat>
362+
static bool ValidateGate(const Gate2& gate, unsigned max_qubit1,
363+
const GatesLat& gates_lat) {
364+
for (unsigned q : gate.qubits) {
365+
if (q >= max_qubit1) {
366+
IO::errorf("fuser: gate qubit %u is out of range "
367+
"(should be smaller than %u).\n", q, max_qubit1);
368+
return false;
369+
}
370+
if (!gates_lat[q].empty() && gate.time <= gates_lat[q].back()->time) {
371+
IO::errorf("fuser: gate at time %u is out of time order.\n", gate.time);
372+
return false;
373+
}
374+
}
375+
376+
for (unsigned q : gate.controlled_by) {
377+
if (q >= max_qubit1) {
378+
IO::errorf("fuser: gate qubit %u is out of range "
379+
"(should be smaller than %u).\n", q, max_qubit1);
380+
return false;
381+
}
382+
if (!gates_lat[q].empty() && gate.time <= gates_lat[q].back()->time) {
383+
IO::errorf("fuser: gate at time %u is out of time order.\n", gate.time);
384+
return false;
370385
}
371386
}
372387

373-
return false;
388+
return true;
374389
}
375390
};
376391

0 commit comments

Comments
 (0)