Commit 98b00905 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

turning on xasm compiler and range circuit generator


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent f3bc2eb9
add_subdirectory(gate)
add_subdirectory(ir_provider)
add_subdirectory(observable)
\ No newline at end of file
add_subdirectory(observable)
add_subdirectory(plugins)
\ No newline at end of file
#include "Circuit.hpp"
// #include "exprtk.hpp"
// using symbol_table_t = exprtk::symbol_table<double>;
// using expression_t = exprtk::expression<double>;
// using parser_t = exprtk::parser<double>;
#define RAPIDJSON_HAS_STDSTRING 1
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
using namespace rapidjson;
#include "JsonVisitor.hpp"
#include "IRProvider.hpp"
#include "IRToGraphVisitor.hpp"
namespace xacc {
namespace quantum {
void Circuit::throwIfInvalidInstructionParameter(InstPtr instruction) {
if (!parsingUtil) {
parsingUtil = xacc::getService<ExpressionParsingUtil>("exprtk");
}
if (!instruction->isComposite() && instruction->isParameterized()) {
for (int i = 0; i < instruction->nParameters(); i++) {
auto parameter = instruction->getParameter(i);
......@@ -23,16 +31,6 @@ void Circuit::throwIfInvalidInstructionParameter(InstPtr instruction) {
instruction->setParameter(i, constant);
continue;
}
// symbol_table_t symbol_table;
// symbol_table.add_constants();
// expression_t expr;
// expr.register_symbol_table(symbol_table);
// parser_t parser;
// if (parser.compile(parameter.toString(), expr)) {
// auto value = expr.value();
// instruction->setParameter(i, value);
// continue;
// }
// ok, now we should check that the expression
// contains only our variables
......@@ -40,16 +38,6 @@ void Circuit::throwIfInvalidInstructionParameter(InstPtr instruction) {
if (parsingUtil->validExpression(parameter.toString(), variables)) {
continue;
}
// for (int i = 0; i < variables.size(); i++) {
// symbol_table.add_variable(variables[i], tmp[i]);
// }
// expression_t expr2;
// expr2.register_symbol_table(symbol_table);
// parser_t parser2;
// if (parser2.compile(parameter.toString(), expr2)) {
// // This had only variables we know
// continue;
// }
std::stringstream ermsg;
ermsg << "\nInvalid parameterized instruction:\n" +
......@@ -80,26 +68,6 @@ Circuit::operator()(const std::vector<double> &params) {
exit(0);
}
// std::vector<double> p = params;
// symbol_table_t symbol_table;
// symbol_table.add_constants();
// std::vector<std::string> variableNames;
// std::vector<double> values;
// for (int i = 0; i < variables.size(); i++) {
// auto var = variables[i];
// variableNames.push_back(var);
// symbol_table.add_variable(var, p[i]);
// }
// auto compileExpression = [&](InstructionParameter &p) -> double {
// auto expression = mpark::get<std::string>(p);
// expression_t expr;
// expr.register_symbol_table(symbol_table);
// parser_t parser;
// parser.compile(expression, expr);
// return expr.value();
// };
auto evaluatedCircuit = std::make_shared<Circuit>("evaled_" + name());
// Walk the IR Tree, handle functions and instructions differently
......@@ -131,5 +99,110 @@ Circuit::operator()(const std::vector<double> &params) {
}
return evaluatedCircuit;
}
void Circuit::persist(std::ostream &outStream) {
JsonVisitor<PrettyWriter<StringBuffer>, StringBuffer> visitor(
shared_from_this());
outStream << visitor.write();
}
void Circuit::load(std::istream &inStream) {
// std::vector<std::string> irGeneratorNames;
// auto irgens = xacc::getRegisteredIds<xacc::IRGenerator>();
// for (auto &irg : irgens) {
// irGeneratorNames.push_back(irg);
// }
variables.clear();
instructions.clear();
auto provider = xacc::getService<IRProvider>("quantum");
std::string json(std::istreambuf_iterator<char>(inStream), {});
// std::cout << "JSON: " << json << "\n";
Document doc;
doc.Parse(json);
auto &kernel = doc["circuits"].GetArray()[0];
circuitName = kernel["circuit"].GetString();
auto instructionsArray = kernel["instructions"].GetArray();
for (int i = 0; i < instructionsArray.Size(); i++) {
auto &inst = instructionsArray[i];
auto gname = inst["gate"].GetString();
std::vector<std::size_t> qbits;
auto bitsArray = inst["qubits"].GetArray();
for (int k = 0; k < bitsArray.Size(); k++) {
qbits.push_back(bitsArray[k].GetUint64());
}
std::vector<InstructionParameter> local_parameters;
auto &paramsArray = inst["parameters"];
for (int k = 0; k < paramsArray.Size(); k++) {
auto &value = paramsArray[k];
if (value.IsInt()) {
local_parameters.push_back(InstructionParameter(value.GetInt()));
} else if (value.IsDouble()) {
local_parameters.push_back(InstructionParameter(value.GetDouble()));
} else {
local_parameters.push_back(InstructionParameter(value.GetString()));
}
}
std::shared_ptr<Instruction> instToAdd;
instToAdd = provider->createInstruction(gname, qbits, local_parameters);
auto vars = kernel["variables"].GetArray();
for (int i = 0; i < vars.Size(); i++ ){
addVariable(vars[i].GetString());
}
auto coeff = kernel["coefficient"].GetDouble();
setCoefficient(coeff);
if (!inst["enabled"].GetBool()) {
instToAdd->disable();
}
addInstruction(instToAdd);
}
}
const int Circuit::depth() { return toGraph()->depth() - 2; }
const std::string Circuit::persistGraph() {
std::stringstream s;
toGraph()->write(s);
return s.str();
}
std::shared_ptr<Graph> Circuit::toGraph() {
// Compute number of qubits
int maxBit = 0;
InstructionIterator it(shared_from_this());
while (it.hasNext()) {
auto inst = it.next();
for (auto &b : inst->bits()) {
if (b > maxBit) {
maxBit = b;
}
}
}
auto visitor = std::make_shared<IRToGraphVisitor>(maxBit + 1);
InstructionIterator it2(shared_from_this());
while (it2.hasNext()) {
auto inst = it2.next();
if (inst->isEnabled()) {
inst->accept(visitor);
}
}
return visitor->getGraph();
}
} // namespace quantum
} // namespace xacc
\ No newline at end of file
......@@ -72,14 +72,11 @@ protected:
public:
Circuit(const std::string &name)
: circuitName(name),
parsingUtil(xacc::getService<ExpressionParsingUtil>("exprtk")) {}
Circuit(const std::string &name, std::vector<std::string>& vars)
: circuitName(name), variables(vars),
parsingUtil(xacc::getService<ExpressionParsingUtil>("exprtk")) {}
Circuit(const std::string &name, std::vector<std::string>&& vars)
: circuitName(name), variables(vars),
parsingUtil(xacc::getService<ExpressionParsingUtil>("exprtk")) {}
: circuitName(name) {}
Circuit(const std::string &name, std::vector<std::string> &vars)
: circuitName(name), variables(vars) {}
Circuit(const std::string &name, std::vector<std::string> &&vars)
: circuitName(name), variables(vars) {}
Circuit(const Circuit &other)
: circuitName(other.circuitName), variables(other.variables),
......@@ -149,8 +146,8 @@ public:
return false;
}
void persist(std::ostream &outStream) override {}
void load(std::istream &inStream) override {}
void persist(std::ostream &outStream) override;
void load(std::istream &inStream) override;
const int nInstructions() override { return instructions.size(); }
......@@ -183,6 +180,9 @@ public:
for (auto &i : insts)
addInstruction(i);
}
void addInstructions(const std::vector<InstPtr>& insts) override {
for (auto& i : insts) addInstruction(i);
}
bool hasChildren() const override { return !instructions.empty(); }
bool expand(const HeterogeneousMap &runtimeOptions) override {
......@@ -207,10 +207,14 @@ public:
void addVariables(const std::vector<std::string> &vars) override {
variables.insert(variables.end(), vars.begin(), vars.end());
}
const std::vector<std::string> getVariables() override {
return variables;
}
const int depth() override { return 0; }
const std::string persistGraph() override { return ""; }
std::shared_ptr<Graph> toGraph() override { return nullptr; }
const int depth() override;
const std::string persistGraph() override;
std::shared_ptr<Graph> toGraph() override;
const std::size_t nLogicalBits() override { return 0; }
const std::size_t nPhysicalBits() override { return 0; }
......@@ -226,8 +230,10 @@ public:
return newF;
}
void setCoefficient(const std::complex<double> c) override {coefficient=c;}
const std::complex<double> getCoefficient() override {return coefficient;}
void setCoefficient(const std::complex<double> c) override {
coefficient = c;
}
const std::complex<double> getCoefficient() override { return coefficient; }
std::shared_ptr<CompositeInstruction>
operator()(const std::vector<double> &params) override;
......
......@@ -155,6 +155,91 @@ TEST(GateTester, checkTerminatingNode) {
std::cout << "Circuit2:\n" << circuit->toString() << "\n";
}
TEST(GateFunctionTester, checkPersistLoad) {
auto f = std::make_shared<Circuit>("foo", std::vector<std::string>{"phi"});
auto h = std::make_shared<Hadamard>(1);
auto cn1 = std::make_shared<CNOT>(0, 1);
auto rz = std::make_shared<Rz>(0, 3.1415);
auto rz2 = std::make_shared<Rz>(std::vector<std::size_t>{1});
xacc::InstructionParameter p("phi");
rz2->setParameter(0, p);
f->addInstruction(h);
f->addInstruction(cn1);
f->addInstruction(rz);
f->addInstruction(rz2);
std::stringstream ss;
f->persist(ss);
std::cout << ss.str() << "\n";
std::istringstream iss(ss.str());
auto newF = std::make_shared<Circuit>("new");
newF->load(iss);
std::cout << "HELLO: " << newF->toString() << "\n";
}
TEST(GateTester, checkGenerateGraph) {
auto f = std::make_shared<Circuit>("foo");
auto h = std::make_shared<Hadamard>(1);
auto cn1 = std::make_shared<CNOT>(1, 2);
auto cn2 = std::make_shared<CNOT>(0, 1);
auto h2 = std::make_shared<Hadamard>(0);
auto rz = std::make_shared<Rz>(2, 3.1415);
f->addInstructions({h,cn1,cn2,h2,rz});
auto s = f->persistGraph();
// std::stringstream ss;
// g->write(ss);
std::string expected = R"expected(digraph G {
node [shape=box style=filled]
0 [label="id=0;name=InitialState;bits=[0,1,2]"];
1 [label="id=1;name=H;bits=[1]"];
2 [label="id=2;name=CNOT;bits=[1,2]"];
3 [label="id=3;name=CNOT;bits=[0,1]"];
4 [label="id=4;name=H;bits=[0]"];
5 [label="id=5;name=Rz;bits=[2]"];
6 [label="id=6;name=FinalState;bits=[0,1,2]"];
0->1 ;
0->2 ;
0->3 ;
1->2 ;
2->3 ;
2->5 ;
3->4 ;
3->6 ;
4->6 ;
5->6 ;
}
)expected";
std::cout << s << "\nExpected:\n" << expected << "\n";
EXPECT_TRUE(expected == s);
}
TEST(GateFunctionTester, checkDepth) {
auto f = std::make_shared<Circuit>("foo");
auto x = std::make_shared<X>(0);
auto h = std::make_shared<Hadamard>(1);
auto cn1 = std::make_shared<CNOT>(1, 2);
auto rz = std::make_shared<Rz>(1, 3.1415);
auto z = std::make_shared<Z>(2);
f->addInstructions({x,h,cn1,rz,z});
auto g = f->toGraph();
EXPECT_EQ(3, g->depth());
}
int main(int argc, char **argv) {
xacc::Initialize();
::testing::InitGoogleTest(&argc, argv);
......
......@@ -10,7 +10,7 @@ namespace quantum {
void IRToGraphVisitor::addSingleQubitGate(Gate &inst) {
auto bit = inst.bits()[0];
auto lastNode = qubitToLastNode[bit];
auto lastBit = lastNode.get<std::vector<int>>("bits")[0];
auto lastBit = lastNode.get<std::vector<std::size_t>>("bits")[0];
id++;
......@@ -46,7 +46,7 @@ void IRToGraphVisitor::addTwoQubitGate(Gate &inst) {
IRToGraphVisitor::IRToGraphVisitor(const int nQubits) {
graph = xacc::getService<Graph>(
"boost-digraph"); // std::make_shared<DirectedBoostGraph>(nQubits);
std::vector<int> allQbitIds(nQubits);
std::vector<std::size_t> allQbitIds(nQubits);
std::iota(std::begin(allQbitIds), std::end(allQbitIds), 0);
CircuitNode initNode{std::make_pair("name", std::string("InitialState")),
std::make_pair("id", 0),
......@@ -60,7 +60,7 @@ IRToGraphVisitor::IRToGraphVisitor(const int nQubits) {
std::shared_ptr<Graph> IRToGraphVisitor::getGraph() {
CircuitNode finalNode{std::make_pair("name", std::string("FinalState")),
std::make_pair("id", id+1),
std::make_pair("bits", graph->getVertexProperties(0).get<std::vector<int>>("bits"))};
std::make_pair("bits", graph->getVertexProperties(0).get<std::vector<std::size_t>>("bits"))};
graph->addVertex(finalNode);
for (auto &kv : qubitToLastNode) {
......
......@@ -37,24 +37,15 @@ JsonVisitor<W, B>::JsonVisitor(std::vector<std::shared_ptr<xacc::CompositeInstru
template <class W, class B> std::string JsonVisitor<W, B>::write() {
writer->StartObject();
writer->String("kernels");
writer->String("circuits");
writer->StartArray();
for (auto f : functions) {
// This is a Function, start it as an Object
writer->StartObject();
writer->String("function");
writer->String("circuit");
writer->String(f->name());
// if (f->hasBeenBitMapped()) {
// writer->String("bitmap");
// writer->StartArray();
// for (auto& b : f->getBitMap()) {
// writer->Int(b);
// }
// writer->EndArray();
// }
// All functions have instructions, start
// that array here.
writer->String("instructions");
......@@ -71,26 +62,15 @@ template <class W, class B> std::string JsonVisitor<W, B>::write() {
// End Instructions
writer->EndArray();
// writer->String("options");
// writer->StartObject();
// for (auto& kv : f->getOptions()) {
// writer->Key(kv.first);
// auto p = kv.second;
// switch (p.which()) {
// case 0:
// writer->Int(p.template as<int>());
// break;
// case 1:
// writer->Double(p.template as<double>());
// break;
// case 2:
// writer->String(p.template as<std::string>());
// break;
// default:
// writer->String(p.toString());
// }
// }
// writer->EndObject();
writer->String("variables");
writer->StartArray();
for (auto& v : f->getVariables()) {
writer->String(v);
}
writer->EndArray();
writer->String("coefficient");
writer->Double(std::real(f->getCoefficient()));
// End Function
writer->EndObject();
......
......@@ -11,6 +11,7 @@
#include "CompositeInstruction.hpp"
#include "xacc_service.hpp"
#include "XACC.hpp"
namespace xacc {
namespace quantum {
......@@ -22,8 +23,17 @@ std::shared_ptr<Instruction> QuantumIRProvider::createInstruction(const std::str
std::shared_ptr<Instruction> QuantumIRProvider::createInstruction(
const std::string name, std::vector<std::size_t> bits,
std::vector<InstructionParameter> parameters) {
std::shared_ptr<Instruction> inst;
if (xacc::hasService<Instruction>(name)) {
inst = xacc::getService<Instruction>(name);
} else if (xacc::hasContributedService<Instruction>(name)) {
inst = xacc::getContributedService<Instruction>(name);
} else if (xacc::hasCompiled(name)) {
inst = xacc::getCompiled(name);
} else {
xacc::error("Invalid instruction name - " + name);
}
if (!inst->isComposite()) {
inst->setBits(bits);
......
#include "range.hpp"
#include "XACC.hpp"
#include "xacc_service.hpp"
using namespace xacc;
namespace xacc {
namespace circuits {
const std::vector<std::string> Range::requiredKeys() {
return {"nq", "gate", "start", "end"};
}
bool Range::expand(const xacc::HeterogeneousMap &runtimeOptions) {
if (!runtimeOptions.keyExists<std::string>("gate")) {
return false;
}
std::stringstream sss;
runtimeOptions.print<int, std::string>(sss);
int start = 0, end = -1, nqubits;
if (!runtimeOptions.keyExists<int>("nq")) {
if (!runtimeOptions.keyExists<int>("start") &&
!runtimeOptions.keyExists<int>("end")) {
return false;
} else {
if (runtimeOptions.keyExists<int>("start")) {
start = runtimeOptions.get<int>("start");
}
if (runtimeOptions.keyExists<int>("end")) {
end = runtimeOptions.get<int>("end");
}
}
} else {
end = runtimeOptions.get<int>("nq");
}
if (end == -1) {
std::stringstream ss;
runtimeOptions.print<int, std::string>(ss);
xacc::error("Invalid Range runtimeOptions:\n"+ss.str());
}
auto gate = runtimeOptions.get<std::string>("gate");
auto provider = xacc::getIRProvider("quantum");
for (std::size_t i = start; i < end; i++) {
auto g = provider->createInstruction(gate, std::vector<std::size_t>{i});
addInstruction(g);
}
return true;
} // namespace instructions
} // namespace circuits
} // namespace xacc
\ No newline at end of file
#ifndef XACC_GENERATORS_RANGE_HPP_
#define XACC_GENERATORS_RANGE_HPP_
#include "Circuit.hpp"
namespace xacc {
class AcceleratorBuffer;
class Function;
} // namespace xacc
namespace xacc {
namespace circuits {
class Range : public xacc::quantum::Circuit, public Cloneable<Instruction> {
public:
Range() : Circuit("range") {}
bool expand(const xacc::HeterogeneousMap &runtimeOptions) override;
const std::vector<std::string> requiredKeys() override;
std::shared_ptr<Instruction> clone() override {
return std::make_shared<Range>();
}
};
} // namespace circuits
} // namespace xacc
#endif
\ No newline at end of file
add_xacc_test(Range)
target_link_libraries(RangeTester xacc xacc-quantum-gate)
\ No newline at end of file
#include "XACC.hpp"
#include <gtest/gtest.h>
#include "xacc_service.hpp"
#include "Circuit.hpp"
using namespace xacc;
TEST(RangeTester, checkSimple) {
// NOW Test it somehow...
auto r = std::dynamic_pointer_cast<quantum::Circuit>(
xacc::getService<Instruction>("range"));
EXPECT_TRUE(r->expand(
{std::make_pair("gate", std::string("H")), std::make_pair("nq", 10)}));
std::cout << "F:\n" << r->toString() << "\n";
EXPECT_EQ(10, r->nInstructions());
auto r2 = std::dynamic_pointer_cast<quantum::Circuit>(
xacc::getService<Instruction>("range"));
EXPECT_TRUE(r2->expand({std::make_pair("gate", std::string("H")),
std::make_pair("start", 3), std::make_pair("end", 10)}));
std::cout << "G:\n" << r2->toString() << "\n";
EXPECT_EQ(7, r2->nInstructions());
}
int main(int argc, char **argv) {
xacc::Initialize(argc, argv);
::testing::InitGoogleTest(&argc, argv);
auto ret = RUN_ALL_TESTS();
xacc::Finalize();
return ret;