Skip to content

Commit

Permalink
🔀 Merge pull request #100 from DVLab-NTU/refactor/qcir_flexible_gate_…
Browse files Browse the repository at this point in the history
…type

Refactor/qcir flexible gate type
  • Loading branch information
JoshuaLau0220 authored Mar 17, 2024
2 parents 8d515f3 + 38fbdf5 commit 65f7329
Show file tree
Hide file tree
Showing 43 changed files with 1,020 additions and 549 deletions.
6 changes: 3 additions & 3 deletions docker/test-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#! /usr/bin/env bash

# in /app
cmake -B /app/build -S /app/qsyn -DCOPY_EXECUTABLE=OFF
cmake --build /app/build --parallel "$(nproc)"
cmake -B /app/build -S /app/qsyn -DCOPY_EXECUTABLE=OFF || exit 1
cmake --build /app/build --parallel "$(nproc)" || exit 1

cd /app/qsyn || return # cd to /app/qsyn
cd /app/qsyn || exit 1
/app/qsyn/scripts/RUN_TESTS --qsyn /app/build/qsyn "$@"
5 changes: 2 additions & 3 deletions src/argparse/arg_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
****************************************************************************/
#pragma once

#include <concepts>
#include <functional>
#include <unordered_map>
#include <variant>
Expand Down Expand Up @@ -248,7 +247,7 @@ class ArgumentParser {
bool _all_required_args_are_parsed() const;

template <typename T>
static auto* _get_arg_impl(T&& t, std::string_view name);
static auto* _get_arg_impl(T& t, std::string_view name);
};

/**
Expand Down Expand Up @@ -369,7 +368,7 @@ ArgType<T>& ArgumentParser::_add_option(std::string_view name, std::convertible_
.metavar(dvlab::str::toupper_string(name.substr(name.find_first_not_of(_pimpl->option_prefixes))));
}
template <typename T>
auto* ArgumentParser::_get_arg_impl(T&& t, std::string_view name) {
auto* ArgumentParser::_get_arg_impl(T& t, std::string_view name) {
if (t._pimpl->subparsers.has_value() && t._pimpl->activated_subparser.has_value()) {
if (t.get_activated_subparser()->_has_arg(name)) {
return t.get_activated_subparser()->_get_arg(name);
Expand Down
156 changes: 127 additions & 29 deletions src/convert/qcir_to_tableau.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#include "./qcir_to_tableau.hpp"

#include <gsl/narrow>
#include <iterator>
#include <ranges>
#include <tl/adjacent.hpp>
#include <tl/to.hpp>
Expand All @@ -17,6 +16,7 @@
#include "qcir/gate_type.hpp"
#include "qcir/qcir_gate.hpp"
#include "qsyn/qsyn_type.hpp"
#include "tableau/tableau.hpp"
#include "util/phase.hpp"
#include "util/util.hpp"

Expand Down Expand Up @@ -104,15 +104,15 @@ std::vector<size_t> get_qubit_idx_vec(QubitIdList const& qubits) {
return ret;
}

void implement_mcrz(Tableau& tableau, qcir::LegacyGateType const& gate, QubitIdList const& qubits, dvlab::Phase const& phase) {
void implement_mcrz(Tableau& tableau, QubitIdList const& qubits, dvlab::Phase const& phase) {
if (std::holds_alternative<StabilizerTableau>(tableau.back())) {
tableau.push_back(std::vector<PauliRotation>{});
}
// guaranteed to be a vector of PauliRotation
auto& last_rotation_group = std::get<std::vector<PauliRotation>>(tableau.back());

auto const targ = gsl::narrow<size_t>(qubits.back());
for (auto const comb_size : std::views::iota(0ul, gate.get_num_qubits())) {
for (auto const comb_size : std::views::iota(0ul, qubits.size())) {
bool const is_neg = comb_size % 2;
auto qubit_idx_vec = get_qubit_idx_vec(qubits);
do { // NOLINT(cppcoreguidelines-avoid-do-while)
Expand All @@ -128,14 +128,14 @@ void implement_mcrz(Tableau& tableau, qcir::LegacyGateType const& gate, QubitIdL
}
}

void implement_mcpz(Tableau& tableau, qcir::LegacyGateType const& gate, QubitIdList const& qubits, dvlab::Phase const& phase) {
void implement_mcpz(Tableau& tableau, QubitIdList const& qubits, dvlab::Phase const& phase) {
if (std::holds_alternative<StabilizerTableau>(tableau.back())) {
tableau.push_back(std::vector<PauliRotation>{});
}
// guaranteed to be a vector of PauliRotation
auto& last_rotation_group = std::get<std::vector<PauliRotation>>(tableau.back());

for (auto const comb_size : std::views::iota(1ul, gate.get_num_qubits() + 1)) {
for (auto const comb_size : std::views::iota(1ul, qubits.size() + 1)) {
bool const is_neg = (comb_size - 1) % 2;
auto qubit_idx_vec = get_qubit_idx_vec(qubits);
do { // NOLINT(cppcoreguidelines-avoid-do-while)
Expand All @@ -150,8 +150,8 @@ void implement_mcpz(Tableau& tableau, qcir::LegacyGateType const& gate, QubitIdL
}
}

void implement_rotation_gate(Tableau& tableau, qcir::LegacyGateType const& gate, QubitIdList const& qubits) {
auto const pauli = to_pauli(gate.get_rotation_category());
void implement_rotation_gate(Tableau& tableau, qcir::GateRotationCategory category, dvlab::Phase const& ph, QubitIdList const& qubits) {
auto const pauli = to_pauli(category);

auto const targ = gsl::narrow<size_t>(qubits.back());
// convert rotation plane first
Expand All @@ -162,13 +162,13 @@ void implement_rotation_gate(Tableau& tableau, qcir::LegacyGateType const& gate,
}

dvlab::Phase const phase =
gate.get_phase() *
dvlab::Rational(1, static_cast<int>(std::pow(2, gsl::narrow<double>(gate.get_num_qubits()) - 1)));
ph *
dvlab::Rational(1, static_cast<int>(std::pow(2, gsl::narrow<double>(qubits.size()) - 1)));
// implement rotation in Z plane
if (is_r_type_rotation(gate.get_rotation_category())) {
implement_mcrz(tableau, gate, qubits, phase);
if (is_r_type_rotation(category)) {
implement_mcrz(tableau, qubits, phase);
} else {
implement_mcpz(tableau, gate, qubits, phase);
implement_mcpz(tableau, qubits, phase);
}

// restore rotation plane
Expand All @@ -184,33 +184,131 @@ void implement_rotation_gate(Tableau& tableau, qcir::LegacyGateType const& gate,
} // namespace experimental

template <>
bool append_to_tableau(qcir::LegacyGateType const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_type() == "h") {
tableau.h(qubits[0]);
} else if (op.get_type() == "s") {
bool append_to_tableau(qcir::IdGate const& /* op*/, experimental::Tableau& /* tableau */, QubitIdList const& /* qubits */) {
return true;
}

template <>
bool append_to_tableau(qcir::HGate const& /* op */, experimental::Tableau& tableau, QubitIdList const& qubits) {
tableau.h(qubits[0]);
return true;
}

template <>
bool append_to_tableau(qcir::SwapGate const& /* op */, experimental::Tableau& tableau, QubitIdList const& qubits) {
tableau.swap(qubits[0], qubits[1]);
return true;
}

template <>
bool append_to_tableau(qcir::ECRGate const& /* op */, experimental::Tableau& tableau, QubitIdList const& qubits) {
tableau.ecr(qubits[0], qubits[1]);
return true;
}

template <>
bool append_to_tableau(qcir::PZGate const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_phase() == dvlab::Phase(1)) {
tableau.z(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(1, 2)) {
tableau.s(qubits[0]);
} else if (op.get_type() == "sdg") {
} else if (op.get_phase() == dvlab::Phase(-1, 2)) {
tableau.sdg(qubits[0]);
} else if (op.get_type() == "v") {
} else {
experimental::implement_rotation_gate(tableau, qcir::GateRotationCategory::pz, op.get_phase(), qubits);
}

return true;
}

template <>
bool append_to_tableau(qcir::PXGate const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_phase() == dvlab::Phase(1)) {
tableau.x(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(1, 2)) {
tableau.v(qubits[0]);
} else if (op.get_type() == "vdg") {
} else if (op.get_phase() == dvlab::Phase(-1, 2)) {
tableau.vdg(qubits[0]);
} else if (op.get_type() == "x") {
tableau.x(qubits[0]);
} else if (op.get_type() == "y") {
} else {
experimental::implement_rotation_gate(tableau, qcir::GateRotationCategory::px, op.get_phase(), qubits);
}

return true;
}

template <>
bool append_to_tableau(qcir::PYGate const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_phase() == dvlab::Phase(1)) {
tableau.y(qubits[0]);
} else if (op.get_type() == "z") {
} else if (op.get_phase() == dvlab::Phase(1, 2)) {
tableau.sdg(qubits[0]);
tableau.v(qubits[0]);
tableau.s(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(-1, 2)) {
tableau.sdg(qubits[0]);
tableau.vdg(qubits[0]);
tableau.s(qubits[0]);
} else {
experimental::implement_rotation_gate(tableau, qcir::GateRotationCategory::py, op.get_phase(), qubits);
}

return true;
}

template <>
bool append_to_tableau(qcir::RZGate const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_phase() == dvlab::Phase(1)) {
tableau.z(qubits[0]);
} else if (op.get_type() == "cx") {
} else if (op.get_phase() == dvlab::Phase(1, 2)) {
tableau.s(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(-1, 2)) {
tableau.sdg(qubits[0]);
} else {
experimental::implement_rotation_gate(tableau, qcir::GateRotationCategory::rz, op.get_phase(), qubits);
}
return true;
}

template <>
bool append_to_tableau(qcir::RXGate const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_phase() == dvlab::Phase(1)) {
tableau.x(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(1, 2)) {
tableau.v(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(-1, 2)) {
tableau.vdg(qubits[0]);
} else {
experimental::implement_rotation_gate(tableau, qcir::GateRotationCategory::rx, op.get_phase(), qubits);
}
return true;
}

template <>
bool append_to_tableau(qcir::RYGate const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_phase() == dvlab::Phase(1)) {
tableau.y(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(1, 2)) {
tableau.sdg(qubits[0]);
tableau.v(qubits[0]);
tableau.s(qubits[0]);
} else if (op.get_phase() == dvlab::Phase(-1, 2)) {
tableau.sdg(qubits[0]);
tableau.vdg(qubits[0]);
tableau.s(qubits[0]);
} else {
experimental::implement_rotation_gate(tableau, qcir::GateRotationCategory::ry, op.get_phase(), qubits);
}
return true;
}

template <>
bool append_to_tableau(qcir::LegacyGateType const& op, experimental::Tableau& tableau, QubitIdList const& qubits) {
if (op.get_type() == "cx") {
tableau.cx(qubits[0], qubits[1]);
} else if (op.get_type() == "cz") {
tableau.cz(qubits[0], qubits[1]);
} else if (op.get_type() == "swap") {
tableau.swap(qubits[0], qubits[1]);
} else if (op.get_type() == "ecr") {
tableau.ecr(qubits[0], qubits[1]);
} else {
experimental::implement_rotation_gate(tableau, op, qubits);
experimental::implement_rotation_gate(tableau, op.get_rotation_category(), op.get_phase(), qubits);
}
return true;
}
Expand Down
85 changes: 61 additions & 24 deletions src/convert/qcir_to_tensor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@

#include <cstddef>
#include <gsl/narrow>
#include <stdexcept>
#include <thread>

#include "fmt/core.h"
#include "qcir/gate_type.hpp"
#include "qcir/qcir.hpp"
#include "qcir/qcir_qubit.hpp"
Expand All @@ -29,28 +26,68 @@ using Qubit2TensorPinMap = std::unordered_map<QubitIdType, std::pair<size_t, siz

using qsyn::tensor::QTensor;

template <>
std::optional<QTensor<double>> to_tensor(HGate const& /* op */) {
return QTensor<double>::hbox(2);
}

template <>
std::optional<QTensor<double>> to_tensor(IdGate const& /* op */) {
return QTensor<double>::identity(1);
}

template <>
std::optional<QTensor<double>> to_tensor(SwapGate const& /* op */) {
auto tensor = QTensor<double>{{1.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0},
{0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 1.0}};
return tensor.to_qtensor();
}

template <>
std::optional<QTensor<double>> to_tensor(ECRGate const& /* op */) {
using namespace std::complex_literals;
auto tensor = QTensor<double>{{0.0, 0.0, 1.0 / std::sqrt(2), 1.i / std::sqrt(2)},
{0.0, 0.0, 1.i / std::sqrt(2), 1.0 / std::sqrt(2)},
{1.0 / std::sqrt(2), -1.i / std::sqrt(2), 0.0, 0.0},
{-1.i / std::sqrt(2), 1.0 / std::sqrt(2), 0.0, 0.0}};
return tensor.to_qtensor();
}

template <>
std::optional<QTensor<double>> to_tensor(PZGate const& op) {
return QTensor<double>::pzgate(op.get_phase());
}

template <>
std::optional<QTensor<double>> to_tensor(PXGate const& op) {
return QTensor<double>::pxgate(op.get_phase());
}

template <>
std::optional<QTensor<double>> to_tensor(PYGate const& op) {
return QTensor<double>::pygate(op.get_phase());
}

template <>
std::optional<QTensor<double>> to_tensor(RZGate const& op) {
return QTensor<double>::rzgate(op.get_phase());
}

template <>
std::optional<QTensor<double>> to_tensor(RXGate const& op) {
return QTensor<double>::rxgate(op.get_phase());
}

template <>
std::optional<QTensor<double>> to_tensor(RYGate const& op) {
return QTensor<double>::rygate(op.get_phase());
}

template <>
std::optional<QTensor<double>> to_tensor(LegacyGateType const& op) {
switch (op.get_rotation_category()) {
case GateRotationCategory::id:
return QTensor<double>::identity(1);
case GateRotationCategory::h:
return QTensor<double>::hbox(2);
case GateRotationCategory::swap: {
auto tensor = QTensor<double>{{1.0, 0.0, 0.0, 0.0},
{0.0, 0.0, 1.0, 0.0},
{0.0, 1.0, 0.0, 0.0},
{0.0, 0.0, 0.0, 1.0}};
return tensor.to_qtensor();
}
case GateRotationCategory::ecr: {
using namespace std::complex_literals;
auto tensor = QTensor<double>{{0.0, 0.0, 1.0 / std::sqrt(2), 1.i / std::sqrt(2)},
{0.0, 0.0, 1.i / std::sqrt(2), 1.0 / std::sqrt(2)},
{1.0 / std::sqrt(2), -1.i / std::sqrt(2), 0.0, 0.0},
{-1.i / std::sqrt(2), 1.0 / std::sqrt(2), 0.0, 0.0}};
return tensor.to_qtensor();
}
case GateRotationCategory::pz:
return QTensor<double>::control(QTensor<double>::pzgate(op.get_phase()), op.get_num_qubits() - 1);
case GateRotationCategory::rz:
Expand Down Expand Up @@ -150,10 +187,10 @@ std::optional<QTensor<double>> to_tensor(QCir const& qcir) try {
spdlog::warn("Conversion interrupted.");
return std::nullopt;
}
spdlog::debug("Gate {} ({})", gate->get_id(), gate->get_type_str());
spdlog::debug("Gate {} ({})", gate->get_id(), gate->get_operation().get_repr());
auto const gate_tensor = to_tensor(*gate);
if (!gate_tensor.has_value()) {
spdlog::error("Conversion of Gate {} ({}) to Tensor is not supported yet!!", gate->get_id(), gate->get_type_str());
spdlog::error("Conversion of Gate {} ({}) to Tensor is not supported yet!!", gate->get_id(), gate->get_operation().get_repr());
return std::nullopt;
}
std::vector<size_t> main_tensor_output_pins;
Expand Down
Loading

0 comments on commit 65f7329

Please sign in to comment.