@@ -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