Commit 9bafef37 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

updates to IR v3 for qcor support


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 68e2a3bf
...@@ -27,7 +27,7 @@ Gate::Gate(std::string name, std::vector<std::size_t> qubts, ...@@ -27,7 +27,7 @@ Gate::Gate(std::string name, std::vector<std::size_t> qubts,
std::vector<InstructionParameter> params) std::vector<InstructionParameter> params)
: gateName(name), qbits(qubts), parameters(params) {} : gateName(name), qbits(qubts), parameters(params) {}
Gate::Gate(const Gate &inst) Gate::Gate(const Gate &inst)
: gateName(inst.gateName), qbits(inst.qbits), parameters(inst.parameters), : gateName(inst.gateName), qbits(inst.qbits), parameters(inst.parameters), arguments(inst.arguments),
enabled(inst.enabled) {} enabled(inst.enabled) {}
const std::string Gate::name() const { return gateName; } const std::string Gate::name() const { return gateName; }
......
...@@ -54,12 +54,11 @@ TEST(GateTester, checkIR3) { ...@@ -54,12 +54,11 @@ TEST(GateTester, checkIR3) {
EXPECT_THROW(circuit->updateRuntimeArguments(2.2), std::runtime_error); EXPECT_THROW(circuit->updateRuntimeArguments(2.2), std::runtime_error);
circuit->updateRuntimeArguments(2.2, 3.3, 4.4); circuit->updateRuntimeArguments(2.2, 3.3, 4.4);
circuit->applyRuntimeArguments();
std::cout << circuit->toString() <<"\n"; std::cout << circuit->toString() <<"\n";
circuit->updateRuntimeArguments(3.2, 4.3, 5.3); circuit->updateRuntimeArguments(3.2, 4.3, 5.3);
circuit->applyRuntimeArguments();
std::cout << circuit->toString() <<"\n"; std::cout << circuit->toString() <<"\n";
} }
......
...@@ -30,7 +30,7 @@ void IRToGraphVisitor::addSingleQubitGate(Gate &inst) { ...@@ -30,7 +30,7 @@ void IRToGraphVisitor::addSingleQubitGate(Gate &inst) {
std::make_pair("bits", inst.bits())}; std::make_pair("bits", inst.bits())};
graph->addVertex(newNode); graph->addVertex(newNode);
graph->addEdge(lastNode.get<int>("id"), newNode.get<int>("id"), 1); graph->addEdge(lastNode.get<std::size_t>("id"), newNode.get<std::size_t>("id"), 1);
qubitToLastNode[bit] = newNode; qubitToLastNode[bit] = newNode;
} }
...@@ -39,8 +39,8 @@ void IRToGraphVisitor::addTwoQubitGate(Gate &inst) { ...@@ -39,8 +39,8 @@ void IRToGraphVisitor::addTwoQubitGate(Gate &inst) {
auto srcbit = inst.bits()[0]; auto srcbit = inst.bits()[0];
auto tgtbit = inst.bits()[1]; auto tgtbit = inst.bits()[1];
auto lastsrcnodeid = qubitToLastNode[srcbit].get<int>("id"); auto lastsrcnodeid = qubitToLastNode[srcbit].get<std::size_t>("id");
auto lasttgtnodeid = qubitToLastNode[tgtbit].get<int>("id"); auto lasttgtnodeid = qubitToLastNode[tgtbit].get<std::size_t>("id");
id++; id++;
CircuitNode newNode{std::make_pair("name", inst.name()), CircuitNode newNode{std::make_pair("name", inst.name()),
...@@ -60,7 +60,7 @@ IRToGraphVisitor::IRToGraphVisitor(const int nQubits) { ...@@ -60,7 +60,7 @@ IRToGraphVisitor::IRToGraphVisitor(const int nQubits) {
std::vector<std::size_t> allQbitIds(nQubits); std::vector<std::size_t> allQbitIds(nQubits);
std::iota(std::begin(allQbitIds), std::end(allQbitIds), 0); std::iota(std::begin(allQbitIds), std::end(allQbitIds), 0);
CircuitNode initNode{std::make_pair("name", std::string("InitialState")), CircuitNode initNode{std::make_pair("name", std::string("InitialState")),
std::make_pair("id", 0), std::make_pair("id", id),
std::make_pair("bits", allQbitIds)}; std::make_pair("bits", allQbitIds)};
for (int i = 0; i < nQubits; i++) { for (int i = 0; i < nQubits; i++) {
qubitToLastNode[i] = initNode; qubitToLastNode[i] = initNode;
...@@ -75,7 +75,7 @@ std::shared_ptr<Graph> IRToGraphVisitor::getGraph() { ...@@ -75,7 +75,7 @@ std::shared_ptr<Graph> IRToGraphVisitor::getGraph() {
graph->addVertex(finalNode); graph->addVertex(finalNode);
for (auto &kv : qubitToLastNode) { for (auto &kv : qubitToLastNode) {
graph->addEdge(kv.second.get<int>("id"), finalNode.get<int>("id"), 1.0); graph->addEdge(kv.second.get<std::size_t>("id"), finalNode.get<std::size_t>("id"), 1.0);
} }
return graph; return graph;
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
namespace xacc { namespace xacc {
namespace quantum { namespace quantum {
using CircuitNode = HeterogeneousMap;//std::map<std::string, InstructionParameter>; using CircuitNode = HeterogeneousMap;
class IRToGraphVisitor : public AllGateVisitor { class IRToGraphVisitor : public AllGateVisitor {
...@@ -29,7 +29,7 @@ protected: ...@@ -29,7 +29,7 @@ protected:
std::map<int, CircuitNode> qubitToLastNode; std::map<int, CircuitNode> qubitToLastNode;
int id = 0; std::size_t id = 0;
void addSingleQubitGate(Gate &inst); void addSingleQubitGate(Gate &inst);
void addTwoQubitGate(Gate &inst); void addTwoQubitGate(Gate &inst);
......
...@@ -38,9 +38,7 @@ PauliOperator::PauliOperator(double c) { ...@@ -38,9 +38,7 @@ PauliOperator::PauliOperator(double c) {
terms.emplace(std::make_pair("I", c)); terms.emplace(std::make_pair("I", c));
} }
PauliOperator::PauliOperator(std::string fromStr) { PauliOperator::PauliOperator(std::string fromStr) { fromString(fromStr); }
fromString(fromStr);
}
PauliOperator::PauliOperator(std::complex<double> c, std::string var) { PauliOperator::PauliOperator(std::complex<double> c, std::string var) {
terms.emplace(std::piecewise_construct, std::forward_as_tuple("I"), terms.emplace(std::piecewise_construct, std::forward_as_tuple("I"),
...@@ -90,10 +88,17 @@ PauliOperator::PauliOperator(std::map<int, std::string> operators, ...@@ -90,10 +88,17 @@ PauliOperator::PauliOperator(std::map<int, std::string> operators,
std::forward_as_tuple(coeff, var, operators)); std::forward_as_tuple(coeff, var, operators));
} }
std::complex<double> PauliOperator::coefficient() {
if (terms.size() > 1) {
xacc::error("Cannot call PauliOperator::coefficient on operator with more "
"than 1 term.");
}
return terms.begin()->second.coeff();
}
std::vector<std::shared_ptr<CompositeInstruction>> std::vector<std::shared_ptr<CompositeInstruction>>
PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) { PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
// Create a new GateQIR to hold the spin based terms // Create a new GateQIR to hold the spin based terms
auto gateRegistry = xacc::getService<IRProvider>("quantum"); auto gateRegistry = xacc::getService<IRProvider>("quantum");
std::vector<std::shared_ptr<CompositeInstruction>> observed; std::vector<std::shared_ptr<CompositeInstruction>> observed;
int counter = 0; int counter = 0;
...@@ -104,8 +109,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) { ...@@ -104,8 +109,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
Term spinInst = inst.second; Term spinInst = inst.second;
auto gateFunction = gateRegistry->createComposite( auto gateFunction =
inst.first, function->getVariables()); gateRegistry->createComposite(inst.first, function->getVariables());
gateFunction->setCoefficient(spinInst.coeff()); gateFunction->setCoefficient(spinInst.coeff());
...@@ -113,6 +118,10 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) { ...@@ -113,6 +118,10 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
gateFunction->addInstruction(function->clone()); gateFunction->addInstruction(function->clone());
} }
for (auto arg : function->getArguments()) {
gateFunction->addArgument(arg, 0);
}
// Loop over all terms in the Spin Instruction // Loop over all terms in the Spin Instruction
// and create instructions to run on the Gate QPU. // and create instructions to run on the Gate QPU.
std::vector<std::shared_ptr<xacc::Instruction>> measurements; std::vector<std::shared_ptr<xacc::Instruction>> measurements;
...@@ -130,8 +139,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) { ...@@ -130,8 +139,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
int t = qbit; int t = qbit;
std::size_t tt = t; std::size_t tt = t;
auto gateName = terms[i].second; auto gateName = terms[i].second;
auto meas = auto meas = gateRegistry->createInstruction("Measure",
gateRegistry->createInstruction("Measure", std::vector<std::size_t>{tt}); std::vector<std::size_t>{tt});
xacc::InstructionParameter classicalIdx(qbit); xacc::InstructionParameter classicalIdx(qbit);
meas->setParameter(0, classicalIdx); meas->setParameter(0, classicalIdx);
measurements.push_back(meas); measurements.push_back(meas);
...@@ -141,7 +150,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) { ...@@ -141,7 +150,8 @@ PauliOperator::observe(std::shared_ptr<CompositeInstruction> function) {
gateRegistry->createInstruction("H", std::vector<std::size_t>{tt}); gateRegistry->createInstruction("H", std::vector<std::size_t>{tt});
gateFunction->addInstruction(hadamard); gateFunction->addInstruction(hadamard);
} else if (gateName == "Y") { } else if (gateName == "Y") {
auto rx = gateRegistry->createInstruction("Rx", std::vector<std::size_t>{tt}); auto rx =
gateRegistry->createInstruction("Rx", std::vector<std::size_t>{tt});
InstructionParameter p(pi / 2.0); InstructionParameter p(pi / 2.0);
rx->setParameter(0, p); rx->setParameter(0, p);
gateFunction->addInstruction(rx); gateFunction->addInstruction(rx);
...@@ -278,8 +288,8 @@ std::vector<std::complex<double>> PauliOperator::toDenseMatrix(const int n) { ...@@ -278,8 +288,8 @@ std::vector<std::complex<double>> PauliOperator::toDenseMatrix(const int n) {
} }
} }
std::vector<std::complex<double>> retv(dim*dim); std::vector<std::complex<double>> retv(dim * dim);
Eigen::MatrixXcd::Map(&retv.data()[0], A.rows(),A.cols()) = A; Eigen::MatrixXcd::Map(&retv.data()[0], A.rows(), A.cols()) = A;
return retv; return retv;
} }
...@@ -360,7 +370,6 @@ void PauliOperator::fromString(const std::string str) { ...@@ -360,7 +370,6 @@ void PauliOperator::fromString(const std::string str) {
clear(); clear();
operator+=(listener.getOperator()); operator+=(listener.getOperator());
} }
bool PauliOperator::contains(PauliOperator &op) { bool PauliOperator::contains(PauliOperator &op) {
...@@ -434,7 +443,8 @@ bool PauliOperator::operator==(const PauliOperator &v) noexcept { ...@@ -434,7 +443,8 @@ bool PauliOperator::operator==(const PauliOperator &v) noexcept {
bool found = false; bool found = false;
for (auto &vkv : v.terms) { for (auto &vkv : v.terms) {
if (kv.second.operator==(vkv.second) | (kv.second.id() == "I" && vkv.second.id() == "I")) { if (kv.second.operator==(vkv.second) |
(kv.second.id() == "I" && vkv.second.id() == "I")) {
found = true; found = true;
break; break;
} }
...@@ -638,10 +648,9 @@ std::shared_ptr<IR> PauliOperator::toXACCIR() { ...@@ -638,10 +648,9 @@ std::shared_ptr<IR> PauliOperator::toXACCIR() {
auto tmp = gateRegistry->createComposite("tmp"); auto tmp = gateRegistry->createComposite("tmp");
auto kernels = observe(tmp); auto kernels = observe(tmp);
auto newIr = gateRegistry->createIR(); auto newIr = gateRegistry->createIR();
for (auto& k : kernels) newIr->addComposite(k); for (auto &k : kernels)
newIr->addComposite(k);
return newIr; return newIr;
} }
int PauliOperator::nQubits() { int PauliOperator::nQubits() {
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
*******************************************************************************/ *******************************************************************************/
#ifndef QUANTUM_UTILS_PAULIOPERATOR_HPP_ #ifndef QUANTUM_UTILS_PAULIOPERATOR_HPP_
#define QUANTUM_UTILS_PAULIOPERATOR_HPP_ #define QUANTUM_UTILS_PAULIOPERATOR_HPP_
#include <ios>
#include <unordered_map> #include <unordered_map>
#include <complex> #include <complex>
#include <map> #include <map>
...@@ -223,7 +222,8 @@ public: ...@@ -223,7 +222,8 @@ public:
}; };
class PauliOperator class PauliOperator
: public xacc::Observable, public xacc::Cloneable<Observable>, : public xacc::Observable,
public xacc::Cloneable<Observable>,
public tao::operators::commutative_ring<PauliOperator>, public tao::operators::commutative_ring<PauliOperator>,
public tao::operators::equality_comparable<PauliOperator>, public tao::operators::equality_comparable<PauliOperator>,
public tao::operators::commutative_multipliable<PauliOperator, double>, public tao::operators::commutative_multipliable<PauliOperator, double>,
...@@ -234,7 +234,7 @@ protected: ...@@ -234,7 +234,7 @@ protected:
public: public:
std::shared_ptr<Observable> clone() override { std::shared_ptr<Observable> clone() override {
return std::make_shared<PauliOperator>(); return std::make_shared<PauliOperator>();
} }
std::unordered_map<std::string, Term>::iterator begin() { std::unordered_map<std::string, Term>::iterator begin() {
...@@ -259,6 +259,39 @@ public: ...@@ -259,6 +259,39 @@ public:
std::vector<std::shared_ptr<CompositeInstruction>> std::vector<std::shared_ptr<CompositeInstruction>>
observe(std::shared_ptr<CompositeInstruction> function) override; observe(std::shared_ptr<CompositeInstruction> function) override;
std::vector<std::shared_ptr<Observable>> getSubTerms() override {
std::vector<std::shared_ptr<Observable>> ret;
for (auto &term : getTerms()) {
ret.emplace_back(
new PauliOperator(term.second.ops(), term.second.coeff()));
}
return ret;
}
virtual std::vector<std::shared_ptr<Observable>> getNonIdentitySubTerms() {
std::vector<std::shared_ptr<Observable>> ret;
for (auto &term : getTerms()) {
if (term.first != "I") {
ret.emplace_back(
new PauliOperator(term.second.ops(), term.second.coeff()));
}
}
return ret;
}
virtual std::shared_ptr<Observable> getIdentitySubTerm() {
for (auto &term : getTerms()) {
if (term.first == "I") {
return std::make_shared<PauliOperator>(term.second.ops(),
term.second.coeff());
}
}
return nullptr;
}
std::complex<double> coefficient() override;
const std::vector<std::pair<std::string, std::complex<double>>> const std::vector<std::pair<std::string, std::complex<double>>>
computeActionOnKet(const std::string &bitString); computeActionOnKet(const std::string &bitString);
const std::vector<std::pair<std::string, std::complex<double>>> const std::vector<std::pair<std::string, std::complex<double>>>
...@@ -302,7 +335,7 @@ public: ...@@ -302,7 +335,7 @@ public:
eval(const std::map<std::string, std::complex<double>> varToValMap); eval(const std::map<std::string, std::complex<double>> varToValMap);
bool isClose(PauliOperator &other); bool isClose(PauliOperator &other);
int nQubits(); int nQubits();
const int nBits() override {return nQubits();} const int nBits() override { return nQubits(); }
PauliOperator &operator+=(const PauliOperator &v) noexcept; PauliOperator &operator+=(const PauliOperator &v) noexcept;
PauliOperator &operator-=(const PauliOperator &v) noexcept; PauliOperator &operator-=(const PauliOperator &v) noexcept;
...@@ -311,18 +344,15 @@ public: ...@@ -311,18 +344,15 @@ public:
PauliOperator &operator*=(const double v) noexcept; PauliOperator &operator*=(const double v) noexcept;
PauliOperator &operator*=(const std::complex<double> v) noexcept; PauliOperator &operator*=(const std::complex<double> v) noexcept;
const std::string name() const override { const std::string name() const override { return "pauli"; }
return "pauli"; const std::string description() const override { return ""; }
} void fromOptions(const HeterogeneousMap &options) override { return; }
const std::string description() const override {
return "";
}
void fromOptions(const HeterogeneousMap& options) override {
return;
}
}; };
} // namespace quantum } // namespace quantum
template const quantum::PauliOperator &
HeterogeneousMap::get<quantum::PauliOperator>(const std::string key) const;
} // namespace xacc } // namespace xacc
#endif #endif
...@@ -13,9 +13,11 @@ ...@@ -13,9 +13,11 @@
#include "exp.hpp" #include "exp.hpp"
#include "FermionOperator.hpp" #include "FermionOperator.hpp"
#include "IRProvider.hpp" #include "IRProvider.hpp"
#include "Instruction.hpp"
#include "ObservableTransform.hpp" #include "ObservableTransform.hpp"
#include "PauliOperator.hpp" #include "PauliOperator.hpp"
#include "Utils.hpp"
#include "xacc.hpp" #include "xacc.hpp"
#include "xacc_service.hpp" #include "xacc_service.hpp"
#include <memory> #include <memory>
...@@ -140,11 +142,11 @@ bool Exp::expand(const HeterogeneousMap &parameters) { ...@@ -140,11 +142,11 @@ bool Exp::expand(const HeterogeneousMap &parameters) {
int name_counter = 1; int name_counter = 1;
std::string name = "exp_tmp"; std::string name = "exp_tmp";
while (xacc::hasCompiled(name)) { while (xacc::hasCompiled(name)) {
name += std::to_string(name_counter); name += std::to_string(name_counter);
} }
xasm_src = "__qpu__ void "+name+"(qbit q, double " + paramLetter + ") {\n" + xasm_src = "__qpu__ void " + name + "(qbit q, double " + paramLetter +
xasm_src + "}"; ") {\n" + xasm_src + "}";
auto xasm = xacc::getCompiler("xasm"); auto xasm = xacc::getCompiler("xasm");
auto tmp = xasm->compile(xasm_src)->getComposites()[0]; auto tmp = xasm->compile(xasm_src)->getComposites()[0];
...@@ -153,7 +155,145 @@ bool Exp::expand(const HeterogeneousMap &parameters) { ...@@ -153,7 +155,145 @@ bool Exp::expand(const HeterogeneousMap &parameters) {
addInstruction(inst); addInstruction(inst);
return true; return true;
} // namespace instructions }
void Exp::applyRuntimeArguments() {
// we expect first argument to be the variable name
// we expect the second argument to be the observable
std::string variable_name = arguments[0]->name;
auto x_val =
arguments[0]->runtimeValue.get<double>(INTERNAL_ARGUMENT_VALUE_KEY);
auto observable = arguments[1]->runtimeValue.getPointerLike<Observable>(
INTERNAL_ARGUMENT_VALUE_KEY);
// Have to make sure this wasn't already expanded
if (nInstructions() == 0) {
std::unordered_map<std::string, xacc::quantum::Term> terms;
if (dynamic_cast<FermionOperator *>(observable)) {
terms = std::dynamic_pointer_cast<PauliOperator>(
xacc::getService<ObservableTransform>("jw")->transform(
xacc::as_shared_ptr(observable)))
->getTerms();
} else {
terms = dynamic_cast<PauliOperator *>(observable)->getTerms();
}
double pi = xacc::constants::pi;
auto gateRegistry = xacc::getService<IRProvider>("quantum");
std::string xasm_src = "";
for (auto inst : terms) {
Term spinInst = inst.second;
// Get the individual pauli terms
auto termsMap = std::get<2>(spinInst);
std::vector<std::pair<int, std::string>> terms;
for (auto &kv : termsMap) {
if (kv.second != "I" && !kv.second.empty()) {
terms.push_back({kv.first, kv.second});
}
}
// The largest qubit index is on the last term
int largestQbitIdx = terms[terms.size() - 1].first;
std::vector<std::size_t> qidxs;
std::stringstream basis_front, basis_back;
for (auto &term : terms) {
auto qid = term.first;
auto pop = term.second;
qidxs.push_back(qid);
if (pop == "X") {
basis_front << "H(q[" << qid << "]);\n";
basis_back << "H(q[" << qid << "]);\n";
} else if (pop == "Y") {
basis_front << "Rx(q[" << qid << "], " << 1.57079362679 << ");\n";
basis_back << "Rx(q[" << qid << "], " << -1.57079362679 << ");\n";
}
}
// std::cout << "QIDS: " << qidxs << "\n";
Eigen::MatrixXi cnot_pairs(2, qidxs.size() - 1);
for (int i = 0; i < qidxs.size() - 1; i++) {
cnot_pairs(0, i) = qidxs[i];
}
for (int i = 0; i < qidxs.size() - 1; i++) {
cnot_pairs(1, i) = qidxs[i + 1];
}
// std::cout << "HOWDY: \n" << cnot_pairs << "\n";
std::stringstream cnot_front, cnot_back;
for (int i = 0; i < qidxs.size() - 1; i++) {
Eigen::VectorXi pairs = cnot_pairs.col(i);
auto c = pairs(0);
auto t = pairs(1);
cnot_front << "CNOT(q[" << c << "], q[" << t << "]);\n";
}
for (int i = qidxs.size() - 2; i >= 0; i--) {
Eigen::VectorXi pairs = cnot_pairs.col(i);
auto c = pairs(0);
auto t = pairs(1);
cnot_back << "CNOT(q[" << c << "], q[" << t << "]);\n";
}
xasm_src = xasm_src + "\n" + basis_front.str() + cnot_front.str();
xasm_src = xasm_src + "Rz(q[" + std::to_string(qidxs[qidxs.size() - 1]) +
"], " + std::to_string(std::real(spinInst.coeff())) + " * " +
variable_name + ");\n";
xasm_src = xasm_src + cnot_back.str() + basis_back.str();
}
int name_counter = 1;
std::string name = "exp_tmp";
while (xacc::hasCompiled(name)) {
name += std::to_string(name_counter);
}
xasm_src = "__qpu__ void " + name + "(qbit q, double " +
arguments[0]->name + ") {\n" + xasm_src + "}";
auto xasm = xacc::getCompiler("xasm");
auto tmp = xasm->compile(xasm_src)->getComposites()[0];
for (auto inst : tmp->getInstructions())
addInstruction(inst);
// store the Rz expressions
for (auto &i : instructions) {
if (i->name() == "Rz") {
rz_expressions.push_back(i->getParameter(0).toString());
}
}
parsingUtil = xacc::getService<ExpressionParsingUtil>("exprtk");
}
int counter = 0;
for (auto &i : instructions) {
if (i->name() == "Rz") {
double x_val_ref = 0.0;