Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/qcir flexible gate type #83

Merged
merged 5 commits into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/convert/qcir_to_tensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,13 @@ std::optional<QTensor<double>> to_tensor(QCir const &qcir) try {
spdlog::warn("QCir is empty!!");
return std::nullopt;
}
qcir.update_topological_order();
spdlog::debug("Add boundary");

QTensor<double> tensor;

// NOTE: Constucting an identity(_qubit.size()) takes much time and memory.
// To make this process interruptible by SIGINT (ctrl-C), we grow the qubit size one by one
for (size_t i = 0; i < qcir.get_qubits().size(); ++i) {
for (size_t i = 0; i < qcir.get_num_qubits(); ++i) {
if (stop_requested()) {
spdlog::warn("Conversion interrupted.");
return std::nullopt;
Expand All @@ -141,7 +140,7 @@ std::optional<QTensor<double>> to_tensor(QCir const &qcir) try {
spdlog::trace(" - Add Qubit: {} input: {} output: {}", qubit_id, oi_pair.second, oi_pair.first);
}

for (auto const &gate : qcir.get_topologically_ordered_gates()) {
for (auto const &gate : qcir.get_gates()) {
if (stop_requested()) {
spdlog::warn("Conversion interrupted.");
return std::nullopt;
Expand Down
7 changes: 4 additions & 3 deletions src/convert/qcir_to_zxgraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,8 @@ std::optional<ZXGraph> to_zxgraph(QCir const& qcir, size_t decomposition_mode) {
spdlog::error("QCir is empty!!");
return std::nullopt;
}
qcir.update_gate_time();
auto const times = qcir.calculate_gate_times();

ZXGraph graph;
spdlog::debug("Add boundaries");
for (size_t i = 0; i < qcir.get_qubits().size(); i++) {
Expand All @@ -473,7 +474,7 @@ std::optional<ZXGraph> to_zxgraph(QCir const& qcir, size_t decomposition_mode) {
graph.add_edge(input, output, EdgeType::simple);
}

for (auto const& gate : qcir.get_topologically_ordered_gates()) {
for (auto const& gate : qcir.get_gates()) {
if (stop_requested()) {
spdlog::warn("Conversion interrupted.");
return std::nullopt;
Expand All @@ -487,7 +488,7 @@ std::optional<ZXGraph> to_zxgraph(QCir const& qcir, size_t decomposition_mode) {
}

for (auto& v : tmp->get_vertices()) {
v->set_col(v->get_col() + static_cast<float>(gate->get_time()));
v->set_col(v->get_col() + static_cast<float>(times.at(gate->get_id())));
}

graph.concatenate(*tmp);
Expand Down
1 change: 1 addition & 0 deletions src/duostra/duostra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void Duostra::make_dependency() {
}
all_gates.emplace_back(std::move(temp_gate));
}
// REVIEW - is the reordering necessary?
std::unordered_map<size_t, size_t> reordered_map;
for (size_t i = 0; i < all_gates.size(); i++) {
reordered_map[all_gates[i].get_id()] = i;
Expand Down
3 changes: 1 addition & 2 deletions src/duostra/mapping_eqv_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ MappingEquivalenceChecker::MappingEquivalenceChecker(QCir* phy, QCir* log, Devic
init = placer->place_and_assign(_device);
} else
_device.place(init);
_physical->update_topological_order();
for (auto const& qubit : _logical->get_qubits()) {
_dependency[qubit->get_id()] = _reverse ? qubit->get_last() : qubit->get_first();
}
Expand All @@ -45,7 +44,7 @@ MappingEquivalenceChecker::MappingEquivalenceChecker(QCir* phy, QCir* log, Devic
* @return false
*/
bool MappingEquivalenceChecker::check() {
auto execute_order = _physical->get_topologically_ordered_gates();
auto execute_order = _physical->get_gates();
if (_reverse) reverse(execute_order.begin(), execute_order.end()); // NOTE - Now the order starts from back
// NOTE - Traverse all physical gates, should match dependency of logical gate
std::unordered_set<QCirGate*> swaps;
Expand Down
37 changes: 5 additions & 32 deletions src/extractor/extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,12 @@ void Extractor::extract_singles() {
std::vector<std::pair<ZXVertex*, ZXVertex*>> toggle_list;
for (ZXVertex* o : _graph->get_outputs()) {
if (_graph->get_first_neighbor(o).second == EdgeType::hadamard) {
prepend_single_qubit_gate("h", _qubit_map[o->get_qubit()], dvlab::Phase(0));
_logical_circuit->add_gate("h", {_qubit_map[o->get_qubit()]}, dvlab::Phase(0), false);
toggle_list.emplace_back(o, _graph->get_first_neighbor(o).first);
}
auto const ph = _graph->get_first_neighbor(o).first->get_phase();
if (ph != dvlab::Phase(0)) {
prepend_single_qubit_gate("rotate", _qubit_map[o->get_qubit()], ph);
_logical_circuit->add_gate("pz", {_qubit_map[o->get_qubit()]}, ph, false);
_graph->get_first_neighbor(o).first->set_phase(dvlab::Phase(0));
}
}
Expand Down Expand Up @@ -269,7 +269,7 @@ void Extractor::extract_cxs() {
auto ctrl = _qubit_map[front_id2_vertex[c]->get_qubit()];
auto targ = _qubit_map[front_id2_vertex[t]->get_qubit()];
spdlog::debug("Adding CX: {} {}", ctrl, targ);
prepend_double_qubit_gate("cx", {ctrl, targ}, dvlab::Phase(0));
_logical_circuit->add_gate("cx", {ctrl, targ}, dvlab::Phase(0), false);
}
}

Expand Down Expand Up @@ -323,7 +323,7 @@ size_t Extractor::extract_hadamards_from_matrix(bool check) {

for (auto& [f, n] : front_neigh_pairs) {
// NOTE - Add Hadamard according to the v of frontier (row)
prepend_single_qubit_gate("h", _qubit_map[f->get_qubit()], dvlab::Phase(0));
_logical_circuit->add_gate("h", {_qubit_map[f->get_qubit()]}, dvlab::Phase(0), false);
// NOTE - Set #qubit and #col according to the old frontier
n->set_qubit(f->get_qubit());
n->set_col(f->get_col());
Expand Down Expand Up @@ -777,7 +777,7 @@ void Extractor::update_neighbors() {
for (auto& [b, ep] : _graph->get_neighbors(f)) {
if (_graph->get_inputs().contains(b)) {
if (ep == EdgeType::hadamard) {
prepend_single_qubit_gate("h", _qubit_map[f->get_qubit()], dvlab::Phase(0));
_logical_circuit->add_gate("h", {_qubit_map[f->get_qubit()]}, dvlab::Phase(0), false);
}
break;
}
Expand Down Expand Up @@ -838,33 +838,6 @@ void Extractor::update_matrix() {
_biadjacency = get_biadjacency_matrix(*_graph, _frontier, _neighbors);
}

/**
* @brief Prepend single-qubit gate to circuit. If _device is given, directly map to physical device.
*
* @param type
* @param qubit logical
* @param phase
*/
void Extractor::prepend_single_qubit_gate(std::string const& type, QubitIdType qubit, dvlab::Phase phase) {
if (type == "rotate") {
_logical_circuit->add_single_rz(qubit, phase, false);
} else {
_logical_circuit->add_gate(type, {qubit}, phase, false);
}
}

/**
* @brief Prepend double-qubit gate to circuit. If _device is given, directly map to physical device.
*
* @param type
* @param qubits
* @param phase
*/
void Extractor::prepend_double_qubit_gate(std::string const& type, QubitIdList const& qubits, dvlab::Phase phase) {
assert(qubits.size() == 2);
_logical_circuit->add_gate(type, qubits, phase, false);
}

/**
* @brief Prepend series of gates.
*
Expand Down
2 changes: 0 additions & 2 deletions src/extractor/extract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ class Extractor {
void update_graph_by_matrix(qsyn::zx::EdgeType et = qsyn::zx::EdgeType::hadamard);
void update_matrix();

void prepend_single_qubit_gate(std::string const& type, QubitIdType qubit, dvlab::Phase phase);
void prepend_double_qubit_gate(std::string const& type, QubitIdList const& qubits, dvlab::Phase phase);
void prepend_series_gates(std::vector<Operation> const& logical, std::vector<Operation> const& physical = {});
void prepend_swap_gate(QubitIdType q0, QubitIdType q1, qcir::QCir* circuit);
bool frontier_is_cleaned();
Expand Down
85 changes: 16 additions & 69 deletions src/qcir/optimizer/basic_optimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ QCir Optimizer::_parse_once(QCir const& qcir, bool reversed, bool do_minimize_cz
: spdlog::debug("Start parsing forward");

reset(qcir);
qcir.update_topological_order();
std::vector<QCirGate*> gates = qcir.get_topologically_ordered_gates();
std::vector<QCirGate*> gates = qcir.get_gates();
if (reversed) {
std::reverse(gates.begin(), gates.end());
}
Expand All @@ -107,29 +106,16 @@ QCir Optimizer::_parse_once(QCir const& qcir, bool reversed, bool do_minimize_cz
result.add_procedures(qcir.get_procedures());

for (auto& t : _xs) {
auto x_gate = new QCirGate(_gate_count, GateRotationCategory::px, dvlab::Phase(1));
x_gate->add_qubit(t, true);
_gate_count++;
Optimizer::_add_gate_to_circuit(result, x_gate, reversed);
Optimizer::_add_gate_to_circuit(result, _store_x(t), reversed);
}

_swaps = Optimizer::_get_swap_path();

for (auto& [c, t] : _swaps) {
// TODO - Use SWAP gate to replace cnots
auto cnot_1 = new QCirGate(_gate_count, GateRotationCategory::px, dvlab::Phase(1));
cnot_1->add_qubit(c, false);
cnot_1->add_qubit(t, true);
auto cnot_2 = new QCirGate(_gate_count + 1, GateRotationCategory::px, dvlab::Phase(1));
cnot_2->add_qubit(t, false);
cnot_2->add_qubit(c, true);
auto cnot_3 = new QCirGate(_gate_count + 2, GateRotationCategory::px, dvlab::Phase(1));
cnot_3->add_qubit(c, false);
cnot_3->add_qubit(t, true);
_gate_count += 3;
Optimizer::_add_gate_to_circuit(result, cnot_1, reversed);
Optimizer::_add_gate_to_circuit(result, cnot_2, reversed);
Optimizer::_add_gate_to_circuit(result, cnot_3, reversed);
Optimizer::_add_gate_to_circuit(result, _store_cx(c, t), reversed);
Optimizer::_add_gate_to_circuit(result, _store_cx(t, c), reversed);
Optimizer::_add_gate_to_circuit(result, _store_cx(c, t), reversed);
}
std::string statistics_str;
fmt::format_to(std::back_inserter(statistics_str), " ParseForward No.{} iteration done.\n", _iter);
Expand Down Expand Up @@ -266,9 +252,7 @@ QCir Optimizer::_build_from_storage(size_t n_qubits, bool reversed) {
* @param target Index of the target qubit
*/
void Optimizer::_add_hadamard(QubitIdType target, bool erase) {
auto h_gate = new QCirGate(_gate_count, GateRotationCategory::h, dvlab::Phase(1));
h_gate->add_qubit(target, true);
_gate_count++;
auto h_gate = _store_h(target);
_gates[target].emplace_back(h_gate);
if (erase) _hadamards.erase(target);
_available[target].clear();
Expand Down Expand Up @@ -296,10 +280,7 @@ void Optimizer::_add_cx(QubitIdType t1, QubitIdType t2, bool do_swap) {
if (count_if(_available[t2].begin(), _available[t2].end(), [&](QCirGate* g) { return Optimizer::two_qubit_gate_exists(g, GateRotationCategory::px, t2, t1); })) {
_statistics.DO_SWAP++;
spdlog::trace("Apply a do_swap commutation");
auto cnot = new QCirGate(_gate_count, GateRotationCategory::px, dvlab::Phase(1));
cnot->add_qubit(t1, false);
cnot->add_qubit(t2, true);
_gate_count++;
auto cnot = _store_cx(t1, t2);
_gates[t1].erase(--(find_if(_gates[t1].rbegin(), _gates[t1].rend(), [&](QCirGate* g) { return Optimizer::two_qubit_gate_exists(g, GateRotationCategory::px, t2, t1); })).base());
_gates[t2].erase(--(find_if(_gates[t2].rbegin(), _gates[t2].rend(), [&](QCirGate* g) { return Optimizer::two_qubit_gate_exists(g, GateRotationCategory::px, t2, t1); })).base());
_availty[t1] = false;
Expand Down Expand Up @@ -347,10 +328,7 @@ void Optimizer::_add_cx(QubitIdType t1, QubitIdType t2, bool do_swap) {
}
}
if (!found_match) {
auto cnot = new QCirGate(_gate_count, GateRotationCategory::px, dvlab::Phase(1));
cnot->add_qubit(t1, false);
cnot->add_qubit(t2, true);
_gate_count++;
auto cnot = _store_cx(t1, t2);
_gates[t1].emplace_back(cnot);
_gates[t2].emplace_back(cnot);
_available[t1].emplace_back(cnot);
Expand All @@ -369,10 +347,7 @@ bool Optimizer::_replace_cx_and_cz_with_s_and_cx(QubitIdType t1, QubitIdType t2)
targ = !i ? t2 : t1;
for (auto& g : _available[ctrl]) {
if (g->is_cx() && g->get_control()._qubit == ctrl && g->get_targets()._qubit == targ) {
cnot = new QCirGate(_gate_count, GateRotationCategory::px, dvlab::Phase(1));
_gate_count++;
cnot->add_qubit(g->get_control()._qubit, false);
cnot->add_qubit(g->get_targets()._qubit, true);
cnot = _store_cx(g->get_control()._qubit, g->get_targets()._qubit);
if (_availty[targ]) {
if (count_if(_available[targ].begin(), _available[targ].end(), [&](QCirGate* gate_other) { return Optimizer::two_qubit_gate_exists(gate_other, GateRotationCategory::px, ctrl, targ); })) {
found_match = true;
Expand Down Expand Up @@ -410,15 +385,9 @@ bool Optimizer::_replace_cx_and_cz_with_s_and_cx(QubitIdType t1, QubitIdType t2)
_gates[ctrl].erase(--(find_if(_gates[ctrl].rbegin(), _gates[ctrl].rend(), [&](QCirGate* g) { return Optimizer::two_qubit_gate_exists(g, GateRotationCategory::px, ctrl, targ); })).base());
_gates[targ].erase(--(find_if(_gates[targ].rbegin(), _gates[targ].rend(), [&](QCirGate* g) { return Optimizer::two_qubit_gate_exists(g, GateRotationCategory::px, ctrl, targ); })).base());

auto s1 = new QCirGate(_gate_count, GateRotationCategory::pz, dvlab::Phase(-1, 2));
s1->add_qubit(targ, true);
_gate_count++;
auto s2 = new QCirGate(_gate_count, GateRotationCategory::pz, dvlab::Phase(1, 2));
s2->add_qubit(targ, true);
_gate_count++;
auto s3 = new QCirGate(_gate_count, GateRotationCategory::pz, dvlab::Phase(1, 2));
s3->add_qubit(ctrl, true);
_gate_count++;
auto s1 = _store_sdg(targ);
auto s2 = _store_s(targ);
auto s3 = _store_s(ctrl);

if (!_available[targ].empty()) {
_gates[targ].insert(dvlab::iterator::prev(_gates[targ].end(), _available[targ].size()), s1);
Expand Down Expand Up @@ -482,16 +451,7 @@ void Optimizer::_add_cz(QubitIdType t1, QubitIdType t2, bool do_minimize_czs) {
}
// NOTE - No cancel found
if (!found_match) {
auto cz = new QCirGate(_gate_count, GateRotationCategory::pz, dvlab::Phase(1));
if (t1 < t2) {
cz->add_qubit(t1, false);
cz->add_qubit(t2, true);
} else {
cz->add_qubit(t2, false);
cz->add_qubit(t1, true);
}

_gate_count++;
auto cz = (t1 < t2) ? _store_cz(t1, t2) : _store_cz(t2, t1);
_gates[t1].emplace_back(cz);
_gates[t2].emplace_back(cz);
_available[t1].emplace_back(cz);
Expand All @@ -515,23 +475,10 @@ bool Optimizer::two_qubit_gate_exists(QCirGate* g, GateRotationCategory gt, Qubi
* @param type 0: Z-axis, 1: X-axis, 2: Y-axis
*/
void Optimizer::_add_rotation_gate(QubitIdType target, dvlab::Phase ph, GateRotationCategory const& rotation_category) {
auto rotate = std::invoke([&]() {
switch (rotation_category) {
case GateRotationCategory::pz:
return new QCirGate(_gate_count, rotation_category, ph);
case GateRotationCategory::px:
return new QCirGate(_gate_count, rotation_category, ph);
case GateRotationCategory::py:
return new QCirGate(_gate_count, rotation_category, ph);
default:
DVLAB_UNREACHABLE("wrong type!! Type shoud be PZ, PX or PY");
}
});

rotate->add_qubit(target, true);
assert(rotation_category == GateRotationCategory::pz || rotation_category == GateRotationCategory::px || rotation_category == GateRotationCategory::py);
auto rotate = _store_rotation_gate(target, ph, rotation_category);
_gates[target].emplace_back(rotate);
_available[target].emplace_back(rotate);
_gate_count++;
}

/**
Expand All @@ -541,7 +488,7 @@ void Optimizer::_add_rotation_gate(QubitIdType target, dvlab::Phase ph, GateRota
std::vector<size_t> Optimizer::_compute_stats(QCir const& circuit) {
size_t two_qubit = 0, had = 0, non_pauli = 0;
std::vector<size_t> stats;
for (auto const& g : circuit.update_topological_order()) {
for (auto const& g : circuit.get_gates()) {
if (g->is_cx() || g->is_cz()) {
two_qubit++;
} else if (g->is_h()) {
Expand Down
6 changes: 3 additions & 3 deletions src/qcir/optimizer/gate_optimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ void Optimizer::_match_hadamards(QCirGate* gate) {
if (g2->get_phase().denominator() == 2) {
_statistics.HS_EXCHANGE++;
spdlog::trace("Transform H-S-H into Sdg-H-Sdg");
auto zp = new QCirGate(_gate_count, GateRotationCategory::pz, -1 * g2->get_phase());
zp->add_qubit(qubit, true);
_gate_count++;
auto zp = (g2->get_phase() == Phase(1, 2))
? _store_sdg(qubit)
: _store_s(qubit);
g2->set_phase(zp->get_phase()); // NOTE - S to Sdg
_gates[qubit].insert(_gates[qubit].end() - 2, zp);
return;
Expand Down
1 change: 0 additions & 1 deletion src/qcir/optimizer/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ void Optimizer::reset(QCir const& qcir) {
_xs.clear();
_zs.clear();
_swaps.clear();
_gate_count = 0;
_statistics = {};
for (int i = 0; i < gsl::narrow<QubitIdType>(qcir.get_qubits().size()); i++) {
_availty.emplace_back(false);
Expand Down
Loading
Loading