Skip to content

Commit

Permalink
Merge pull request quantumlib#493 from quantumlib/update-fusers
Browse files Browse the repository at this point in the history
Update fusers.
  • Loading branch information
sergeisakov authored Jan 4, 2022
2 parents 7900041 + 6eecca7 commit 931865c
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 63 deletions.
69 changes: 42 additions & 27 deletions lib/fuser_basic.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
* two-qubit gates will get fused. To respect specific time boundaries while
* fusing gates, use the other version of this method below.
* @param param Options for gate fusion.
* @param num_qubits The number of qubits acted on by 'gates'.
* @param max_qubit1 The maximum qubit index (plus one) acted on by 'gates'.
* @param gates The gates (or pointers to the gates) to be fused.
* Gate times of the gates that act on the same qubits should be ordered.
* Gates that are out of time order should not cross the time boundaries
Expand All @@ -66,18 +66,18 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
* acting on a specific pair of qubits which can be applied as a group.
*/
static std::vector<GateFused> FuseGates(const Parameter& param,
unsigned num_qubits,
unsigned max_qubit1,
const std::vector<Gate>& gates,
bool fuse_matrix = true) {
return FuseGates(
param, num_qubits, gates.cbegin(), gates.cend(), {}, fuse_matrix);
param, max_qubit1, gates.cbegin(), gates.cend(), {}, fuse_matrix);
}

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

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

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

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

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

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

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

if (GateIsOutOfOrder(gate.time, gate.qubits, gates_lat)
|| GateIsOutOfOrder(gate.time, gate.controlled_by, gates_lat)) {
IO::errorf("gate is out of time order.\n");
if (!ValidateGate(gate, max_qubit1, gates_lat)) {
gates_fused.resize(0);
return gates_fused;
}
Expand All @@ -193,7 +191,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
auto& mea_gates_at_time = measurement_gates[gate.time];
if (mea_gates_at_time.size() == 0) {
gates_seq.push_back(&gate);
mea_gates_at_time.reserve(num_qubits);
mea_gates_at_time.reserve(max_qubit1);
}

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

std::vector<unsigned> last(num_qubits, 0);
std::vector<unsigned> last(max_qubit1, 0);

const RGate* delayed_measurement_gate = nullptr;

Expand Down Expand Up @@ -281,7 +279,7 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
}
}

for (unsigned q = 0; q < num_qubits; ++q) {
for (unsigned q = 0; q < max_qubit1; ++q) {
auto l = last[q];
if (l == gates_lat[q].size()) continue;

Expand Down Expand Up @@ -360,17 +358,34 @@ class BasicGateFuser final : public Fuser<IO, Gate> {
return k;
}

template <typename GatesLat>
static bool GateIsOutOfOrder(unsigned time,
const std::vector<unsigned>& qubits,
const GatesLat& gates_lat) {
for (unsigned q : qubits) {
if (!gates_lat[q].empty() && time <= gates_lat[q].back()->time) {
return true;
template <typename Gate2, typename GatesLat>
static bool ValidateGate(const Gate2& gate, unsigned max_qubit1,
const GatesLat& gates_lat) {
for (unsigned q : gate.qubits) {
if (q >= max_qubit1) {
IO::errorf("fuser: gate qubit %u is out of range "
"(should be smaller than %u).\n", q, max_qubit1);
return false;
}
if (!gates_lat[q].empty() && gate.time <= gates_lat[q].back()->time) {
IO::errorf("fuser: gate at time %u is out of time order.\n", gate.time);
return false;
}
}

for (unsigned q : gate.controlled_by) {
if (q >= max_qubit1) {
IO::errorf("fuser: gate qubit %u is out of range "
"(should be smaller than %u).\n", q, max_qubit1);
return false;
}
if (!gates_lat[q].empty() && gate.time <= gates_lat[q].back()->time) {
IO::errorf("fuser: gate at time %u is out of time order.\n", gate.time);
return false;
}
}

return false;
return true;
}
};

Expand Down
Loading

0 comments on commit 931865c

Please sign in to comment.