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

Dynamic Extraction #137

Merged
merged 22 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dbf447a
:recycle: Refactor get_num_gadgets
chinyi0523 Mar 7, 2024
fe952c0
:wheelchair: Add print gadgets
chinyi0523 Mar 7, 2024
8798ef4
:sparkles: Random remove gadgets
chinyi0523 Mar 8, 2024
613aabf
Merge
chinyi0523 Mar 15, 2024
533e2be
:sparkles: Allow random extraction and sorted extraction
chinyi0523 Mar 15, 2024
b6754af
🔀 Merge branch 'develop' into feature/random-gadget-removal
chinyi0523 Mar 24, 2024
a2fb315
🔀 Merge branch 'develop' into feature/random-gadget-removal
chinyi0523 Mar 27, 2024
f1a5295
Merge branch 'develop' into feature/random-gadget-removal
chinyi0523 Mar 30, 2024
2ee2387
:construction: Random experiment
chinyi0523 Apr 13, 2024
b08ba49
Merge branch 'develop' into feature/random-gadget-removal
chinyi0523 Apr 14, 2024
5af3f65
:sparkles: Allow random extraction in cmd line
chinyi0523 Apr 14, 2024
0b484bf
Merge branch 'develop' into feature/random-gadget-removal
chinyi0523 May 15, 2024
52bfb26
🧫 Remove frontiers by calculation
chinyi0523 Jun 9, 2024
d064f8c
:fire: Remove redundant codes
chinyi0523 Jun 12, 2024
5071607
:sparkles: Dynamic extraction
chinyi0523 Aug 6, 2024
8a784a7
:wheel_chair: Rename functions
chinyi0523 Aug 16, 2024
ebaab37
🔙 Back to original printing
chinyi0523 Aug 16, 2024
20159dc
Merge branch 'develop' into gflow-extract
chinyi0523 Aug 16, 2024
ce8b075
:bug: no apt update before apt install in test scripts
JoshuaLau0220 Aug 19, 2024
c8a02cb
:bug: fix bad extractor ctor param order leading to wrong initialization
JoshuaLau0220 Aug 19, 2024
a18c3e1
:pencil2: make command usage and comments more helpful
JoshuaLau0220 Aug 19, 2024
d45f83c
:fire: remove dead apis in gflow object
JoshuaLau0220 Aug 20, 2024
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
2 changes: 2 additions & 0 deletions docker/clang-test.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
FROM dvlab/qsyn-env:latest

RUN apt update

RUN apt install -y \
diffutils \
patch \
Expand Down
2 changes: 2 additions & 0 deletions docker/gcc-test.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
FROM dvlab/qsyn-env:latest

RUN apt update

RUN apt install -y \
diffutils \
patch \
Expand Down
6 changes: 5 additions & 1 deletion src/convert/conversion_cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ Command convert_from_zx_cmd(zx::ZXGraphMgr& zxgraph_mgr, QCirMgr& qcir_mgr, tens

auto to_tensor = subparsers.add_parser("tensor")
.description("convert from ZXGraph to Tensor");

to_qcir.add_argument<bool>("-r", "--random")
.action(store_true)
.help("Shuffle the neighbors to the extraction frontier, which changes the gadget removal order.");
},
[&](ArgumentParser const& parser) {
if (!dvlab::utils::mgr_has_data(zxgraph_mgr)) return CmdExecResult::error;
Expand All @@ -142,7 +146,7 @@ Command convert_from_zx_cmd(zx::ZXGraphMgr& zxgraph_mgr, QCirMgr& qcir_mgr, tens
return CmdExecResult::error;
}
zx::ZXGraph target = *zxgraph_mgr.get();
extractor::Extractor ext(&target, nullptr /*, std::nullopt*/);
extractor::Extractor ext(&target, nullptr, parser.parsed("--random") /*, std::nullopt*/);
qcir::QCir* result = ext.extract();
if (result != nullptr) {
qcir_mgr.add(qcir_mgr.get_next_id(), std::unique_ptr<qcir::QCir>(result));
Expand Down
135 changes: 116 additions & 19 deletions src/extractor/extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@

#include "./extract.hpp"

#include <fmt/core.h>
#include <fmt/ostream.h>

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <random>
#include <ranges>

#include "duostra/duostra.hpp"
Expand All @@ -19,6 +25,7 @@
#include "util/boolean_matrix.hpp"
#include "util/ordered_hashmap.hpp"
#include "util/util.hpp"
#include "zx/gflow/gflow.hpp"
#include "zx/simplifier/simplify.hpp"
#include "zx/zx_def.hpp"
#include "zx/zxgraph.hpp"
Expand All @@ -35,35 +42,32 @@ bool FILTER_DUPLICATE_CXS = true;
bool REDUCE_CZS = false;
size_t BLOCK_SIZE = 5;
size_t OPTIMIZE_LEVEL = 2;
bool DYNAMIC_ORDER = false;
float PRED_COEFF = 0.7;

/**
* @brief Construct a new Extractor:: Extractor object
*
* @param g
* @param c
* @param d
*/
Extractor::Extractor(ZXGraph* g, QCir* c /*, std::optional<Device> const& d*/) : _graph(g), _logical_circuit{c ? c : new QCir()} /* ,_physical_circuit{to_physical() ? new QCir() : nullptr}, _device(d), _device_backup(d) */ {
initialize(c == nullptr);
Extractor::Extractor(ZXGraph* graph, QCir* qcir, bool random)
: _graph(graph), _logical_circuit{qcir}, _random(random) {
initialize();
}

/**
* @brief Initialize the extractor. Set ZXGraph to QCir qubit map.
*
*/
void Extractor::initialize(bool from_empty_qcir) {
void Extractor::initialize() {
spdlog::debug("Initializing extractor");

QubitIdType cnt = 0;
if (_logical_circuit == nullptr) {
_logical_circuit = new QCir(_graph->get_num_outputs());
}
for (auto& o : _graph->get_outputs()) {
ZXVertex* neighbor_to_output = _graph->get_first_neighbor(o).first;
if (!neighbor_to_output->is_boundary()) {
neighbor_to_output->set_qubit(o->get_qubit());
_frontier.emplace(neighbor_to_output);
}
_qubit_map[o->get_qubit()] = cnt;
if (from_empty_qcir)
_logical_circuit->add_qubits(1);
cnt++;
}

Expand All @@ -78,6 +82,7 @@ void Extractor::initialize(bool from_empty_qcir) {
_axels.emplace(_graph->get_first_neighbor(v).first);
}
}
_max_axel = _axels.size();
print_frontier(spdlog::level::level_enum::trace);
print_neighbors(spdlog::level::level_enum::trace);
_graph->print_vertices_by_rows(spdlog::level::level_enum::trace);
Expand Down Expand Up @@ -111,7 +116,6 @@ QCir* Extractor::extract() {
_logical_circuit->print_circuit_diagram(spdlog::level::level_enum::trace);
_graph->print_vertices_by_rows(spdlog::level::level_enum::trace);
}

return _logical_circuit;
}

Expand All @@ -128,15 +132,17 @@ bool Extractor::extraction_loop(std::optional<size_t> max_iter) {
update_neighbors();

if (_frontier.empty()) break;

if (remove_gadget()) {
spdlog::debug("Gadget(s) are removed.");
print_frontier(spdlog::level::level_enum::trace);
_graph->print_vertices_by_rows(spdlog::level::level_enum::trace);
_logical_circuit->print_circuit_diagram(spdlog::level::level_enum::trace);
continue;
}

if (DYNAMIC_ORDER) {
// Should clean CZs before further extraction
extract_czs();
}
if (contains_single_neighbor()) {
spdlog::debug("Single neighbor found. Construct an easy matrix.");
update_matrix();
Expand Down Expand Up @@ -170,7 +176,9 @@ bool Extractor::extraction_loop(std::optional<size_t> max_iter) {
void Extractor::clean_frontier() {
spdlog::debug("Cleaning frontier");
extract_singles();
extract_czs();
if (!DYNAMIC_ORDER) {
extract_czs();
}
}

/**
Expand Down Expand Up @@ -233,6 +241,10 @@ bool Extractor::extract_czs(bool check) {
}
}
}
_num_cz_rms += remove_list.size();
if (_previous_gadget) {
_num_cz_rms_after_gadget += remove_list.size();
}

_biadjacency = get_biadjacency_matrix(*_graph, _frontier, _frontier);
std::vector<ZXVertex*> idx2vertex;
Expand Down Expand Up @@ -298,7 +310,7 @@ void Extractor::extract_cxs() {
front_id2_vertex[cnt] = f;
cnt++;
}

_num_cx_rms += _cnots.size();
for (auto& [t, c] : _cnots) {
// NOTE - targ and ctrl are opposite here
auto ctrl = _qubit_map[front_id2_vertex[c]->get_qubit()];
Expand Down Expand Up @@ -392,7 +404,6 @@ size_t Extractor::extract_hadamards_from_matrix(bool check) {
*/
bool Extractor::remove_gadget(bool check) {
spdlog::debug("Removing gadget(s)");

if (check) {
if (_frontier.empty()) {
spdlog::error("no vertex left in the frontier!!");
Expand All @@ -408,8 +419,20 @@ bool Extractor::remove_gadget(bool check) {
print_frontier(spdlog::level::level_enum::trace);
print_axels(spdlog::level::level_enum::trace);

std::vector<ZXVertex*> shuffle_neighbors;
for (const auto& v : _neighbors) {
shuffle_neighbors.push_back(v);
}

if (_random) {
static std::random_device rd1;
static std::mt19937 g1(rd1());
std::shuffle(std::begin(shuffle_neighbors), std::end(shuffle_neighbors), g1);
}

bool removed_some_gadgets = false;
for (auto& n : _neighbors) {

for (auto& n : shuffle_neighbors) {
if (!_axels.contains(n)) {
continue;
}
Expand All @@ -426,6 +449,20 @@ bool Extractor::remove_gadget(bool check) {
break;
}
}
if (DYNAMIC_ORDER) {
const std::vector<qcir::QCirGate> gates;
int diff = 0;
int n_cz = 0;
for (auto const& [cz_cand, _] : _graph->get_neighbors(candidate)) {
if (_frontier.contains(cz_cand)) {
diff += _calculate_diff_pivot_edges_if_extracting_cz(candidate, n, cz_cand);
n_cz++;
}
}
if (PRED_COEFF * float(diff) + 1 * float(n_cz) < 0) {
extract_czs();
}
}

PivotBoundaryRule().apply(*_graph, {{candidate, n}});

Expand All @@ -439,13 +476,73 @@ bool Extractor::remove_gadget(bool check) {
}
}
}

_graph->print_vertices(spdlog::level::level_enum::trace);
print_frontier(spdlog::level::level_enum::trace);
print_axels(spdlog::level::level_enum::trace);

return removed_some_gadgets;
}

/**
* @brief Calculate the difference in the number of pivot edges before and after extracting CZ gates
*
* @param frontier
* @param axel
* @param cz_target
* @return int
*/
int Extractor::_calculate_diff_pivot_edges_if_extracting_cz(ZXVertex* frontier, ZXVertex* axel, ZXVertex* cz_target) {
std::vector<ZXVertex*> n_frontier, n_axel, n_both;
const bool cz_target_is_both = _graph->is_neighbor(cz_target, axel);
for (auto const& [n, _] : _graph->get_neighbors(frontier)) {
if (_graph->is_neighbor(n, axel)) {
n_both.emplace_back(n);
} else {
n_frontier.emplace_back(n);
}
}
for (auto const& [n, _] : _graph->get_neighbors(axel)) {
if (!_graph->is_neighbor(n, axel)) {
n_axel.emplace_back(n);
}
}
int edge_cnt = 0;
if (cz_target_is_both) {
// If remove CZ: from n(both) to n(axel)
// Pivot edges from --frontier & --axel to --frontier & --both
// Difference: # --both - # --axel
for (const auto& v : n_both) {
if (_graph->is_neighbor(v, cz_target))
edge_cnt--;
else
edge_cnt++;
}
for (const auto& v : n_axel) {
if (_graph->is_neighbor(v, cz_target))
edge_cnt++;
else
edge_cnt--;
}
} else {
// If remove CZ: from n(frontier) to n(none)
// Pivot edges from --axel & --both to nothing
// Difference: -(# --axel + # --both)
for (const auto& v : n_axel) {
if (_graph->is_neighbor(v, cz_target))
edge_cnt++;
else
edge_cnt--;
}
for (const auto& v : n_both) {
if (_graph->is_neighbor(v, cz_target))
edge_cnt++;
else
edge_cnt--;
}
}
return edge_cnt;
}
/**
* @brief Swap columns (order of neighbors) to put the most of them on the diagonal of the bi-adjacency matrix
*
Expand Down
46 changes: 32 additions & 14 deletions src/extractor/extract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "spdlog/common.h"
#include "util/boolean_matrix.hpp"
#include "zx/zx_def.hpp"
#include "zx/zxgraph.hpp"

namespace qsyn {

Expand All @@ -29,29 +30,37 @@ class ZXGraph;
}

namespace extractor {

extern bool SORT_FRONTIER;
extern bool SORT_NEIGHBORS;
extern bool PERMUTE_QUBITS;
extern bool FILTER_DUPLICATE_CXS;
extern bool REDUCE_CZS;
extern size_t BLOCK_SIZE;
extern size_t OPTIMIZE_LEVEL;
extern bool SORT_FRONTIER; // sort frontier by the qubit IDs
extern bool SORT_NEIGHBORS; // sort neighbors by the vertex IDs
extern bool PERMUTE_QUBITS; // synthesize permutation circuits at
// the end of extraction
extern bool FILTER_DUPLICATE_CXS; // filters duplicate CXs during extraction
extern bool REDUCE_CZS; // tries to reduce the number of CZs by
// feeding them into the biadjacency matrix
extern bool DYNAMIC_ORDER; // dynamically decides the order of gadget
// removal and CZ extraction
extern size_t BLOCK_SIZE; // the block size for block Gaussian
// elimination. Only used in optimization
// level 0
extern size_t OPTIMIZE_LEVEL; // the strategy for biadjacency elimination.
// 0: fixed block size, 1: all block sizes,
// 2: greedy reduction, 3: best of 1 and 2
extern float PRED_COEFF; // hyperparameter for the dynamic extraction
// routine. If
// #CZs > #(edge reduced) * coeff,
// eagerly extract CZs

class Extractor {
public:
using Target = std::unordered_map<size_t, size_t>;
using ConnectInfo = std::vector<std::set<size_t>>;
using Overlap = std::pair<std::pair<size_t, size_t>, std::vector<size_t>>;
// using Device = duostra::Duostra::Device;
// using Operation = duostra::Duostra::Operation;

Extractor(zx::ZXGraph* g, qcir::QCir* c = nullptr /*, std::optional<Device> const& d = std::nullopt */);
Extractor(zx::ZXGraph* graph, qcir::QCir* qcir = nullptr, bool random = false);

// bool to_physical() { return _device.has_value(); }
qcir::QCir* get_logical() { return _logical_circuit; }

void initialize(bool from_empty_qcir = true);
void initialize();
qcir::QCir* extract();
bool extraction_loop(std::optional<size_t> max_iter = std::nullopt);
bool remove_gadget(bool check = false);
Expand Down Expand Up @@ -83,9 +92,14 @@ class Extractor {
std::vector<dvlab::BooleanMatrix::RowOperation> greedy_reduction(dvlab::BooleanMatrix& m);

private:
size_t _num_cx_iterations = 0;
size_t _num_cz_rms = 0;
size_t _num_cz_rms_after_gadget = 0;
size_t _num_cx_rms = 0;
size_t _num_cx_iterations = 0;
zx::ZXGraph* _graph;
qcir::QCir* _logical_circuit;
bool _random;
bool _previous_gadget = false;
zx::ZXVertexList _frontier;
zx::ZXVertexList _neighbors;
zx::ZXVertexList _axels;
Expand All @@ -103,8 +117,12 @@ class Extractor {

Overlap _max_overlap(dvlab::BooleanMatrix& matrix);

int _calculate_diff_pivot_edges_if_extracting_cz(zx::ZXVertex* frontier, zx::ZXVertex* axel, zx::ZXVertex* cz_target);

size_t _num_cx_filtered = 0;
size_t _num_swaps = 0;
size_t _cnt_print = 0;
size_t _max_axel = 0;

std::vector<size_t> _initial_placement;
};
Expand Down
Loading
Loading