Commit 078aaa04 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

adding QCS IRTransformation to auto-map logical program to physical qubits


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <Mccaskeyaj@ornl.gov>
parent 7c53b151
Pipeline #58923 passed with stages
in 10 minutes and 42 seconds
......@@ -184,6 +184,7 @@ PYBIND11_MODULE(_pyxacc, m) {
"The XACC Intermediate Representation, "
"serves as a container for XACC Functions.")
.def("getKernels", &xacc::IR::getKernels, "Return the kernels in this IR")
.def("mapBits", &xacc::IR::mapBits, "")
.def("addKernel", &xacc::IR::addKernel, "");
py::class_<xacc::InstructionIterator>(m, "InstructionIterator", "")
......
......@@ -75,7 +75,7 @@ public:
*/
void visit(Hadamard &h) {
std::string qubit = std::to_string(h.bits()[0]);
quilStr += "RZ(pi/2) " + qubit + "\\nRX(pi/2) " + qubit + "\\nRZ(pi/2) " + qubit + "\n";
quilStr += "RZ(pi/2) " + qubit + "\nRX(pi/2) " + qubit + "\nRZ(pi/2) " + qubit + "\n";
}
void visit(Identity &i) {
......@@ -96,7 +96,7 @@ public:
void visit(CNOT &cn) {
std::string q1 = std::to_string(cn.bits()[0]);
std::string q2 = std::to_string(cn.bits()[1]);
quilStr += "RZ(-pi/2) " + q2 + "\\nRX(pi/2) " + q2 + "\\nCZ " + q2 + " " + q1 + "\\nRX(-pi/2) " + q2 + "\\nRZ(pi/2) " + q2 + "\\nRZ(pi) "+ q1 + "\n";
quilStr += "RZ(-pi/2) " + q2 + "\nRX(pi/2) " + q2 + "\nCZ " + q2 + " " + q1 + "\nRX(-pi/2) " + q2 + "\nRZ(pi/2) " + q2 + "\nRZ(pi) "+ q1 + "\n";
}
/**
* Visit X gates
......@@ -111,7 +111,7 @@ public:
*/
void visit(Y &y) {
std::string qubit = std::to_string(y.bits()[0]);
quilStr += "RZ(pi) " + qubit + "\\nRX(pi) " + qubit + "\n"; }
quilStr += "RZ(pi) " + qubit + "\nRX(pi) " + qubit + "\n"; }
/**
* Visit Z gates
......@@ -162,7 +162,7 @@ public:
void visit(Ry &ry) {
auto angleStr = ry.getParameter(0).toString();
std::string qubit = std::to_string(ry.bits()[0]);
quilStr += "RX(pi/2) " + qubit + "\\nRZ(" + angleStr + ") " + qubit + "\\nRX(-pi/2) " + qubit + "\n";
quilStr += "RX(pi/2) " + qubit + "\nRZ(" + angleStr + ") " + qubit + "\nRX(-pi/2) " + qubit + "\n";
}
void visit(Rz &rz) {
......
......@@ -16,7 +16,7 @@ target_include_directories(${LIBRARY_NAME}
${CMAKE_SOURCE_DIR}/tpls/pybind11/include
${PYTHON_INCLUDE_DIR})
target_link_libraries(${LIBRARY_NAME}
PUBLIC xacc xacc-quantum-gate
PUBLIC xacc xacc-quantum-gate xacc-quantum-aqc
CppMicroServices ${PYTHON_LIBRARY})
set(_bundle_name xacc_rigetti_qcs)
......
......@@ -5,6 +5,9 @@
#include "CountGatesOfTypeVisitor.hpp"
#include <pybind11/numpy.h>
#include "xacc_service.hpp"
#include "EmbeddingAlgorithm.hpp"
#include <regex>
#include <chrono>
......@@ -17,6 +20,87 @@ using namespace py::literals;
namespace xacc {
namespace quantum {
std::shared_ptr<IR> MapToPhysical::transform(std::shared_ptr<IR> ir) {
auto embeddingAlgorithm = xacc::getService<EmbeddingAlgorithm>("cmr");
std::map<int, int> physical2Logical, logical2Physical;
int counter = 0;
std::set<int> nUniqueBits;
for (auto &edge : _edges) {
nUniqueBits.insert(edge.first);
nUniqueBits.insert(edge.second);
}
for (auto &i : nUniqueBits) {
physical2Logical.insert({i, counter});
logical2Physical.insert({counter,i});
counter++;
}
int nBits = nUniqueBits.size();
auto hardwareGraph = xacc::getService<Graph>("boost-ugraph");
for (int i = 0; i < nBits; i++) {
std::map<std::string, InstructionParameter> m{{"bias", 1.0}};
hardwareGraph->addVertex(m);
}
for (auto &edge : _edges) {
hardwareGraph->addEdge(physical2Logical[edge.first],
physical2Logical[edge.second]);
}
hardwareGraph->write(std::cout);
for (auto &function : ir->getKernels()) {
auto logicalGraph = function->toGraph();
InstructionIterator it(function);
std::set<int> nUniqueProbBits;
std::vector<std::pair<int, int>> probEdges;
while (it.hasNext()) {
// Get the next node in the tree
auto nextInst = it.next();
if (nextInst->isEnabled() && nextInst->bits().size() == 2) {
probEdges.push_back({nextInst->bits()[0], nextInst->bits()[1]});
nUniqueProbBits.insert(nextInst->bits()[0]);
nUniqueProbBits.insert(nextInst->bits()[1]);
}
}
auto nProbBits = nUniqueProbBits.size();
auto problemGraph = xacc::getService<Graph>("boost-ugraph");
for (int i = 0; i < nProbBits; i++) {
std::map<std::string, InstructionParameter> m{{"bias", 1.0}};
problemGraph->addVertex(m);
}
for (auto &inst : probEdges) {
problemGraph->addEdge(inst.first, inst.second, 1.0);
}
std::cout << "\n";
problemGraph->write(std::cout);
// Compute the minor graph embedding
auto embedding = embeddingAlgorithm->embed(problemGraph, hardwareGraph);
embedding.persist(std::cout);
std::vector<int> physicalMap;
for (auto& kv : embedding) {
if (kv.second.size() > 1) {
xacc::error("Invalid logical to physical qubit mapping.");
}
physicalMap.push_back(logical2Physical[kv.second[0]]);
}
function->mapBits(physicalMap);
}
return ir;
}
std::shared_ptr<AcceleratorBuffer>
QCSAccelerator::createBuffer(const std::string &varId) {
auto buffer = std::make_shared<AcceleratorBuffer>(varId, 30);
......@@ -32,19 +116,20 @@ QCSAccelerator::createBuffer(const std::string &varId, const int size) {
return buffer;
}
bool QCSAccelerator::isValidBufferSize(const int NBits) {
return NBits > 0;
}
bool QCSAccelerator::isValidBufferSize(const int NBits) { return NBits > 0; }
void QCSAccelerator::execute(
std::shared_ptr<AcceleratorBuffer> buffer,
const std::shared_ptr<Function> function) {
void QCSAccelerator::execute(std::shared_ptr<AcceleratorBuffer> buffer,
const std::shared_ptr<Function> function) {
auto visitor = std::make_shared<QuilVisitor>(true);
auto backend = xacc::optionExists("qcs-backend") ? xacc::getOption("qcs-backend") : "9q-generic-qvm";
auto shots = xacc::optionExists("qcs-shots") ? std::stoi(xacc::getOption("qcs-shots")) : 1000;
auto backend = xacc::optionExists("qcs-backend")
? xacc::getOption("qcs-backend")
: "9q-generic-qvm";
auto shots = xacc::optionExists("qcs-shots")
? std::stoi(xacc::getOption("qcs-shots"))
: 1000;
std::map<int,int> bitToQubit;
std::map<int, int> bitToQubit;
std::vector<int> tobesorted;
InstructionIterator it(function);
while (it.hasNext()) {
......@@ -53,34 +138,35 @@ void QCSAccelerator::execute(
if (nextInst->isEnabled()) {
nextInst->accept(visitor);
if (nextInst->name() == "Measure") {
// bitToQubit.insert({boost::get<int>(nextInst->getParameter(0)), nextInst->bits()[0]});
bitToQubit.insert(
{mpark::get<int>(nextInst->getParameter(0)), nextInst->bits()[0]});
tobesorted.push_back(nextInst->bits()[0]);
}
}
}
std::sort(tobesorted.begin(),tobesorted.end());
bitToQubit.clear();
for (int i = 0; i < tobesorted.size(); i++) {
bitToQubit[i] = tobesorted[i];
}
// std::sort(tobesorted.begin(),tobesorted.end());
// bitToQubit.clear();
// for (int i = 0; i < tobesorted.size(); i++) {
// bitToQubit[i] = tobesorted[i];
//}
// Create our usual old Quil string, but
// then hack it to fit the new DECLARE stuff
CountGatesOfTypeVisitor<Measure> count(function);
int nMeasures = count.countGates();
auto quilStr = visitor->getQuilString();
std::cout << "QUIL\n" << quilStr << "\n";
// quilStr = std::regex_replace(quilStr, std::regex("["), "ro[");
// boost::replace_all(quilStr, "[", "ro[");
quilStr = "DECLARE ro BIT[" + std::to_string(buffer->size()) + "]\n" + quilStr;
// quilStr = std::regex_replace(quilStr, std::regex("["), "ro[");
// boost::replace_all(quilStr, "[", "ro[");
quilStr =
"DECLARE ro BIT[" + std::to_string(buffer->size()) + "]\n" + quilStr;
std::shared_ptr<py::scoped_interpreter> guard;
if (!xacc::isPyApi) {
guard = std::make_shared<py::scoped_interpreter>();
guard = std::make_shared<py::scoped_interpreter>();
}
// py::print("quil:\n", quilStr);
// py::print("quil:\n", quilStr);
auto pyquil = py::module::import("pyquil");
py::object get_qc = pyquil.attr("get_qc");
auto program = pyquil.attr("Program")();
......@@ -93,52 +179,55 @@ void QCSAccelerator::execute(
py::array_t<int> results = qc.attr("run")(compiled);
auto shape = results.request().shape;
// py::print(shape[0]);
// py::print(shape[1]);
// py::print(results);
// py::print(shape[0]);
// py::print(shape[1]);
// py::print(results);
// py::print("QUIL\n");
// py::print(quilStr);
// py::print(buffer->size());
std::string zeroString = "";
for (int i = 0; i < buffer->size(); i++) zeroString += "0";
for (int i = 0; i < shots; i++) {
std::string bitString = zeroString;
std::stringstream s;
for (int j = 0; j < buffer->size(); j++) {
// auto qbit = bitToQubit[j];
s << *results.data(i,j);
// bitString[buffer->size()-1-qbit] = s.str()[0];
}
bitString = s.str();
std::reverse(bitString.begin(), bitString.end());
for (int i = 0; i < buffer->size(); i++)
zeroString += "0";
for (int i = 0; i < shots; i++) {
std::string bitString = zeroString;
std::stringstream s;
for (int j = 0; j < buffer->size(); j++) {
// auto qbit = bitToQubit[j];
s << *results.data(i, j);
// bitString[buffer->size()-1-qbit] = s.str()[0];
}
bitString = s.str();
std::reverse(bitString.begin(), bitString.end());
// if (i<4) py::print("adding " + bitString);
buffer->appendMeasurement(bitString);
}
buffer->appendMeasurement(bitString);
}
return;
return;
}
std::vector<std::shared_ptr<AcceleratorBuffer>> QCSAccelerator::execute(
std::shared_ptr<AcceleratorBuffer> buffer,
const std::vector<std::shared_ptr<Function>> functions) {
std::vector<std::shared_ptr<AcceleratorBuffer>> tmpBuffers;
int counter = 1;
for (auto f : functions) {
auto tmpBuffer = createBuffer(f->name(),
buffer->size());
high_resolution_clock::time_point t1 = high_resolution_clock::now();
xacc::info("Execution " + std::to_string(counter) + ": " + f->name());
execute(tmpBuffer, f);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>( t2 - t1 ).count();
tmpBuffer->addExtraInfo("exec-time", ExtraInfo(duration*1e-6));
tmpBuffers.push_back(tmpBuffer);
counter++;
}
std::vector<std::shared_ptr<AcceleratorBuffer>> tmpBuffers;
int counter = 1;
for (auto f : functions) {
auto tmpBuffer = createBuffer(f->name(), buffer->size());
high_resolution_clock::time_point t1 = high_resolution_clock::now();
xacc::info("Execution " + std::to_string(counter) + ": " + f->name());
execute(tmpBuffer, f);
high_resolution_clock::time_point t2 = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(t2 - t1).count();
tmpBuffer->addExtraInfo("exec-time", ExtraInfo(duration * 1e-6));
tmpBuffers.push_back(tmpBuffer);
counter++;
}
return tmpBuffers;
return tmpBuffers;
}
} // namespace quantum
......
......@@ -34,6 +34,7 @@
#include "InstructionIterator.hpp"
#include "QuilVisitor.hpp"
#include "CLIParser.hpp"
#include "RemoteAccelerator.hpp"
#define RAPIDJSON_HAS_STDSTRING 1
......@@ -46,10 +47,26 @@ using namespace xacc;
namespace xacc {
namespace quantum {
class MapToPhysical : public xacc::IRTransformation {
protected:
std::vector<std::pair<int, int>> _edges;
public:
MapToPhysical(std::vector<std::pair<int, int>> &edges) : _edges(edges) {}
std::shared_ptr<IR> transform(std::shared_ptr<IR> ir) override;
bool hardwareDependent() { return true; }
const std::string name() const override { return "qcs-map-qubits"; }
const std::string description() const override { return ""; }
};
/**
*
*/
class QCSAccelerator : virtual public Accelerator {
protected:
std::vector<int> physicalQubits;
std::vector<std::pair<int, int>> latticeEdges;
Document latticeJson;
public:
QCSAccelerator() : Accelerator() {}
......@@ -70,13 +87,41 @@ public:
createBuffer(const std::string &varId);
void execute(std::shared_ptr<AcceleratorBuffer> buffer,
const std::shared_ptr<Function> function) override;
const std::shared_ptr<Function> function) override;
std::vector<std::shared_ptr<AcceleratorBuffer>>
execute(std::shared_ptr<AcceleratorBuffer> buffer,
const std::vector<std::shared_ptr<Function>> functions) override;
virtual void initialize() {}
virtual void initialize() {
if (xacc::optionExists("qcs-backend")) {
auto backend = xacc::getOption("qcs-backend");
Client client;
auto response = client.get("https://forest-server.qcs.rigetti.com",
"/lattices/" + backend);
latticeJson.Parse(response);
const auto &oneq = latticeJson["lattice"]["isa"]["1Q"];
auto &twoq = latticeJson["lattice"]["isa"]["2Q"];
for (auto itr = oneq.MemberBegin(); itr != oneq.MemberEnd(); ++itr) {
physicalQubits.push_back(std::stoi(itr->name.GetString()));
}
for (auto itr = twoq.MemberBegin(); itr != twoq.MemberEnd(); ++itr) {
auto connStr = itr->name.GetString();
std::cout << "CONN : " << connStr << "\n";
auto split = xacc::split(connStr, '-');
latticeEdges.push_back({std::stoi(split[0]), std::stoi(split[1])});
}
}
}
std::vector<std::pair<int, int>> getAcceleratorConnectivity() {
if (!latticeEdges.empty()) {
return latticeEdges;
}
return std::vector<std::pair<int, int>>{};
}
/**
* Return true if this Accelerator can allocated
* NBits number of bits.
......@@ -85,7 +130,6 @@ public:
*/
virtual bool isValidBufferSize(const int NBits);
/**
* This Accelerator models QPU Gate accelerators.
* @return
......@@ -97,9 +141,12 @@ public:
* so return an empty list, for now.
* @return
*/
virtual std::vector<std::shared_ptr<IRTransformation>>
getIRTransformations() {
std::vector<std::shared_ptr<IRTransformation>>
getIRTransformations() override {
std::vector<std::shared_ptr<IRTransformation>> v;
if (!latticeEdges.empty()) {
v.push_back(std::make_shared<MapToPhysical>(latticeEdges));
}
return v;
}
......@@ -109,23 +156,19 @@ public:
* from the command line with these options.
*/
virtual OptionPairs getOptions() {
OptionPairs desc {{"qcs-shots",
"Provide the number of trials to execute."},{
"qcs-backend", ""}};
OptionPairs desc{{"qcs-shots", "Provide the number of trials to execute."},
{"qcs-backend", ""}};
return desc;
}
virtual const std::string name() const { return "qcs"; }
virtual const std::string description() const {
return "";
}
virtual const std::string description() const { return ""; }
/**
* The destructor
*/
virtual ~QCSAccelerator() {}
};
} // namespace quantum
......
......@@ -24,7 +24,6 @@ public:
auto acc = std::make_shared<xacc::quantum::QCSAccelerator>();
context.RegisterService<xacc::Accelerator>(acc);
context.RegisterService<xacc::OptionsProvider>(acc);
}
/**
......
......@@ -36,39 +36,34 @@
using namespace xacc::quantum;
TEST(QCSTester, checkSimple) {
TEST(QCSTester, checkSimpleTransformation) {
int shots = 8192;
int nExecs = 4;
xacc::setOption("qcs-shots", "10000");
xacc::setOption("qcs-backend","Aspen-4-4Q-A");
auto acc = xacc::getAccelerator("qcs");
auto buffer = acc->createBuffer("buffer", 17);
auto buffer = acc->createBuffer("buffer", 4);
auto compiler = xacc::getService<xacc::Compiler>("xacc-py");
const std::string src = R"src(def f(buffer):
Rx(1.57,1)
Rx(1.57,14)
Rx(1.57,15)
Measure(0, 1)
Measure(1, 14)
Measure(2, 15)
CX(0,1)
CX(1,2)
CX(2,3)
Measure(0, 0)
Measure(1, 1)
Measure(2, 2)
)src";
auto ir = compiler->compile(src, acc);
auto f = ir->getKernel("f");
xacc::setOption("qcs-shots", "10000");
xacc::setOption("qcs-backend","Aspen-1-4Q-G");
// acc->execute(buffer, f);
// // int nshots = 0;
// auto counts = buffer->getMeasurementCounts();
// buffer->print();
// std::cout << "\n\n";
// for (auto &kv : counts) {
// std::cout << kv.first << ":" << kv.second << "\n";
// }
// EXPECT_EQ(nshots, nExecs * shots);
auto t = acc->getIRTransformations()[0];
ir = t->transform(ir);
std::cout << "TEST:\n" << ir->getKernels()[0]->toString() << "\n";
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment