Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
vsoftco committed Feb 6, 2024
2 parents 48fd207 + fd65df2 commit 4f5df16
Show file tree
Hide file tree
Showing 7 changed files with 397 additions and 34 deletions.
6 changes: 4 additions & 2 deletions include/staq/output/ionq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,10 @@ namespace output {
namespace ast = qasmtools::ast;

/** \brief Equivalent IonQ standard gates for qasm standard gates */
std::unordered_map<std::string, std::string> qasmstd_to_ionq{
{"sdg", "si"}, {"tdg", "ti"}, {"u1", "rz"}};
std::unordered_map<std::string, std::string> qasmstd_to_ionq{{"sdg", "si"},
{"tdg", "ti"}};
// Note: u1 and rz gates are equivalent up to a global phase. This substitution
// has been left out for now; unsure if global phase matters in IonQ.

/**
* \class staq::output::IonQOutputter
Expand Down
151 changes: 151 additions & 0 deletions include/staq/transformations/group_qregs.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* This file is part of staq.
*
* Copyright (c) 2019 - 2023 softwareQ Inc. All rights reserved.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

/**
* \file transformations/group_qregs.hpp
* \brief Group individual qregs into one global register.
*/

/**
* The classes in this file transformations::LayoutTransformer and
* transformations::BasicLayout are slightly modified versions of
* mapping::LayoutTransformer and mapping::BasicLayout, as defined in
* mapping/layout/basic.hpp.
*/

#ifndef TRANSFORMATIONS_GROUP_QREGS_HPP_
#define TRANSFORMATIONS_GROUP_QREGS_HPP_

#include "qasmtools/ast/replacer.hpp"
#include "qasmtools/ast/traversal.hpp"
#include "transformations/substitution.hpp"

namespace staq {
namespace transformations {

namespace ast = qasmtools::ast;
namespace parser = qasmtools::parser;

using layout = std::unordered_map<ast::VarAccess, int>;

/**
* \class staq::transformations::LayoutTransformer
* \brief Applies a hardware layout to a circuit
*
* Accepts a layout -- that is, a mapping from variable
* accesses to addresses of physical qubits -- and rewrites
* the AST so that all variable accesses refer to the
* relevant address of a global register representing
* the physical qubits
*/
class LayoutTransformer final : public ast::Replacer {
public:
/**
* \class staq::mapping::LayoutTransformer::config
* \brief Holds configuration options
*/
struct config {
std::string register_name = "q";
};

LayoutTransformer() = default;
LayoutTransformer(const config& params) : Replacer(), config_(params) {}
~LayoutTransformer() = default;

/** \brief Main transformation method */
void run(ast::Program& prog, const layout& l) {
// Visit entire program, removing register declarations, then
// add the physical register & apply substitutions
prog.accept(*this);

// Physical register declaration
prog.body().emplace_front(
std::make_unique<ast::RegisterDecl>(ast::RegisterDecl(
prog.pos(), config_.register_name, true, l.size())));

// Substitution
std::unordered_map<ast::VarAccess, ast::VarAccess> subst;
for (auto const& [access, idx] : l) {
subst.insert({access, ast::VarAccess(parser::Position(),
config_.register_name, idx)});
}
transformations::subst_ap_ap(subst, prog);
}

std::optional<std::list<ast::ptr<ast::Stmt>>>
replace(ast::RegisterDecl& decl) override {
if (decl.is_quantum())
return std::list<ast::ptr<ast::Stmt>>();
else
return std::nullopt;
}

private:
config config_;
};

/**
* \class staq::transformations::BasicLayout
* \brief A simple layout generation algorithm
*
* Allocates physical qubits on a first-come, first-serve basis
*/
class BasicLayout final : public ast::Traverse {
public:
BasicLayout() : Traverse() {}
~BasicLayout() = default;

/** \brief Main generation method */
layout generate(ast::Program& prog) {
current_ = layout();
prog.accept(*this);
return current_;
}

void visit(ast::RegisterDecl& decl) override {
if (decl.is_quantum()) {
for (auto i = 0; i < decl.size(); i++) {
current_[ast::VarAccess(parser::Position(), decl.id(), i)] =
static_cast<int>(current_.size());
}
}
}

private:
layout current_;
};

inline void group_qregs(ast::Program& prog) {
BasicLayout gen;
layout l = gen.generate(prog);
LayoutTransformer alg;
alg.run(prog, l);
}

} // namespace transformations
} /* namespace staq */

#endif /* TRANSFORMATIONS_GROUP_QREGS_HPP_ */
2 changes: 1 addition & 1 deletion include/staq/transformations/qasm_synth.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class QASMSynthImpl final : public ast::Replacer {
std::optional<real_t> expr_val = theta_arg.constant_eval_gmp();
if (!expr_val) {
std::cerr << gate.pos() << ": VarExpr found in classical arg0, "
<< "please inline the code.\n";
<< "please inline the code first.\n";
throw qasmtools::parser::ParseError();
}
real_t angle = expr_val.value();
Expand Down
49 changes: 25 additions & 24 deletions include/staq/transformations/replace_ugate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
*/

/**
* \file transformations/replace_ugate.hpp
* \file transformations/replace_ugates.hpp
* \brief Replacing common U gates with QE standard gates
*/

#ifndef TRANSFORMATIONS_REPLACE_UGATE_HPP_
#define TRANSFORMATIONS_REPLACE_UGATE_HPP_
#ifndef TRANSFORMATIONS_REPLACE_UGATES_HPP_
#define TRANSFORMATIONS_REPLACE_UGATES_HPP_

#include <list>
#include <unordered_map>
Expand All @@ -44,7 +44,7 @@ namespace transformations {
namespace ast = qasmtools::ast;

/**
* \brief Replacing UGates
* \brief Replace UGates
*
* Visits an AST and replaces common U gates with QE standard
* gates if possible. Assumes qelib1.inc is included.
Expand All @@ -60,6 +60,9 @@ struct UArgs {
double lambda;
};

/**
* List of replacements to make, e.g. replace U(pi,0,pi) with x.
*/
// clang-format off
static const std::vector<std::pair<UArgs,std::string>> standard_gates{
{{pi, 0, pi}, "x"},
Expand All @@ -74,10 +77,10 @@ static const std::vector<std::pair<UArgs,std::string>> standard_gates{
// clang-format on

/* Implementation */
class ReplaceUGateImpl final : public ast::Replacer {
class ReplaceUGatesImpl final : public ast::Replacer {
public:
ReplaceUGateImpl() = default;
~ReplaceUGateImpl() = default;
ReplaceUGatesImpl() = default;
~ReplaceUGatesImpl() = default;

void run(ast::ASTNode& node) { node.accept(*this); }

Expand All @@ -101,11 +104,10 @@ class ReplaceUGateImpl final : public ast::Replacer {
theta = gate.theta().constant_eval().value();
phi = gate.phi().constant_eval().value();
lambda = gate.lambda().constant_eval().value();
} catch (...) {
std::cerr << "found VarExpr in UGate args"
} catch (const std::bad_optional_access& e) {
std::cerr << "error: VarExpr found in UGate args, please inline "
"the code first."
<< "\n";
// this should never happen; if this is reached then the Replacer
// is recurring too far down the AST
throw;
}

Expand All @@ -127,20 +129,19 @@ class ReplaceUGateImpl final : public ast::Replacer {
// Remaining cases: rz ry rx
if (name == "") {
if (std::abs(theta) < EPS && std::abs(phi) < EPS) {
name = "rz";
// TODO: Directly copy the exprs from the U gate
// to avoid precision loss
c_args.emplace_back(
std::make_unique<ast::RealExpr>(gate.pos(), lambda));
name = "rz"; // U(0,0,lambda) = rz(lambda)
// assumes rz == u1; ignores the global phase
c_args.emplace_back(std::unique_ptr<ast::Expr>(
ast::object::clone(gate.lambda())));
} else if (std::abs(phi) < EPS && std::abs(lambda) < EPS) {
name = "ry";
c_args.emplace_back(
std::make_unique<ast::RealExpr>(gate.pos(), theta));
name = "ry"; // U(theta,0,0) = ry(theta)
c_args.emplace_back(std::unique_ptr<ast::Expr>(
ast::object::clone(gate.theta())));
} else if (std::abs(phi + pi / 2) < EPS &&
std::abs(lambda - pi / 2) < EPS) {
name = "rx";
c_args.emplace_back(
std::make_unique<ast::RealExpr>(gate.pos(), theta));
name = "rx"; // U(theta,-pi/2,pi/2) = rx(theta)
c_args.emplace_back(std::unique_ptr<ast::Expr>(
ast::object::clone(gate.theta())));
}
}

Expand All @@ -161,11 +162,11 @@ class ReplaceUGateImpl final : public ast::Replacer {
};

void replace_ugates(ast::ASTNode& node) {
ReplaceUGateImpl alg;
ReplaceUGatesImpl alg;
alg.run(node);
}

} /* namespace transformations */
} /* namespace staq */

#endif /* TRANSFORMATIONS_REPLACE_UGATE_HPP_ */
#endif /* TRANSFORMATIONS_REPLACE_UGATES_HPP_ */
Loading

0 comments on commit 4f5df16

Please sign in to comment.