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

Major updates to AcceleratorBuffer to make it a unified interface for QPU-result data



Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent c577a49c
......@@ -16,15 +16,15 @@ set(CMAKE_STANDARD_REQUIRED ON)
set(CMAKE_CXX_STANDARD 11)
message(STATUS "C++ version ${CXX_STANDARD} configured.")
find_package(Git QUIET)
if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE GIT_SUBMOD_RESULT)
if(NOT GIT_SUBMOD_RESULT EQUAL "0")
message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
endif()
endif()
#find_package(Git QUIET)
#if(GIT_FOUND AND EXISTS "${PROJECT_SOURCE_DIR}/.git")
# execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
# WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
# RESULT_VARIABLE GIT_SUBMOD_RESULT)
# if(NOT GIT_SUBMOD_RESULT EQUAL "0")
# message(FATAL_ERROR "git submodule update --init failed with ${GIT_SUBMOD_RESULT}, please checkout submodules")
# endif()
#endif()
option(XACC_BUILD_TESTS "Build test programs" OFF)
......
......@@ -50,8 +50,16 @@ PyXACCListener::PyXACCListener(bool _useDw) : useDW(_useDw) {
std::shared_ptr<Function> PyXACCListener::getKernel() { return f; }
void PyXACCListener::enterXacckernel(PyXACCIRParser::XacckernelContext *ctx) {
// Note here we expect to have a function with possible nParameters,
// The first parameter must always be the AcceleratorBuffer
if (ctx->param().empty()) {
xacc::error("XACC Python kernels must have at least one argument - the "
"AcceleratorBuffer.");
}
bufferName = ctx->param(0)->getText();
std::vector<InstructionParameter> params;
for (int i = 0; i < ctx->param().size(); i++) {
for (int i = 1; i < ctx->param().size(); i++) {
params.push_back(
InstructionParameter(ctx->param(static_cast<size_t>(i))->getText()));
functionVariableNames.push_back(
......@@ -113,25 +121,26 @@ void PyXACCListener::enterUop(PyXACCIRParser::UopContext *ctx) {
// We may have a IRGenerator that produces d-wave functions,
// if so, we will not have set to correct provider
if (!std::dynamic_pointer_cast<GateFunction>(genF)) {
if (!xacc::hasCompiler("dwave-qmi")) {
xacc::error("Cannot run decorated code for d-wave without d-wave plugins.");
}
f = xacc::getService<IRProvider>("dwave")->createFunction(f->name(), {}, f->getParameters());
auto dwcompiler = xacc::getCompiler("dwave-qmi");
auto acc = xacc::getAccelerator("dwave");
auto buff = acc->getBuffer("q");
auto xaccKernelSrcStr = dwcompiler->translate("", genF);
auto embeddedCode = dwcompiler->compile(xaccKernelSrcStr, acc);
genF = embeddedCode->getKernels()[0];
}
if (!xacc::hasCompiler("dwave-qmi")) {
xacc::error(
"Cannot run decorated code for d-wave without d-wave plugins.");
}
f = xacc::getService<IRProvider>("dwave")->createFunction(
f->name(), {}, f->getParameters());
auto dwcompiler = xacc::getCompiler("dwave-qmi");
auto acc = xacc::getAccelerator("dwave");
auto buff = acc->getBuffer(bufferName);
buff->addExtraInfo("ir-generator", ExtraInfo(generator->name()));
auto xaccKernelSrcStr = dwcompiler->translate("", genF);
auto embeddedCode = dwcompiler->compile(xaccKernelSrcStr, acc);
genF = embeddedCode->getKernels()[0];
}
for (auto i : genF->getInstructions()) {
f->addInstruction(i);
}
// std::cout << "F:\n" << f->toString("q") << "\n";
} else if (gateName == "qmi") {
std::vector<int> qubits;
std::vector<InstructionParameter> params;
......
......@@ -39,6 +39,7 @@ protected:
std::shared_ptr<IRProvider> provider;
std::vector<std::string> functionVariableNames;
bool useDW = false;
std::string bufferName;
public:
std::shared_ptr<Function> getKernel();
......
......@@ -93,7 +93,7 @@ public:
TEST(PyXACCCompilerTester, checkSimple) {
auto compiler = xacc::getService<xacc::Compiler>("xacc-py");
const std::string src = R"src(def f(theta):
const std::string src = R"src(def f(buffer, theta):
X(0)
Rx(theta,0)
CNOT(1,0)
......@@ -113,30 +113,32 @@ TEST(PyXACCCompilerTester, checkSimple) {
}
TEST(PyXACCCompilerTester, checkDW) {
const std::string dwsrc = R"dwsrc(def f():
if (xacc::hasCompiler("dwave-qmi")) {
const std::string dwsrc = R"dwsrc(def f(buffer):
qmi(0,0, 1.0)
qmi(1,1, 2.0)
qmi(0,1, 3.0)
return
)dwsrc";
auto compiler = xacc::getService<xacc::Compiler>("xacc-py");
auto acc = std::make_shared<FakePyAcc>();
auto ir = compiler->compile(dwsrc, acc);
auto f = ir->getKernel("f");
EXPECT_EQ("f", f->name());
EXPECT_EQ(f->nParameters(), 0);
EXPECT_EQ(f->nInstructions(), 3);
auto compiler = xacc::getService<xacc::Compiler>("xacc-py");
auto acc = std::make_shared<FakePyAcc>();
std::cout << "KERNEL:\n" << ir->getKernel("f")->toString("") << "\n";
auto ir = compiler->compile(dwsrc, acc);
auto f = ir->getKernel("f");
EXPECT_EQ("f", f->name());
EXPECT_EQ(f->nParameters(), 0);
EXPECT_EQ(f->nInstructions(), 3);
std::cout << "KERNEL:\n" << ir->getKernel("f")->toString("") << "\n";
}
// CHECK THAT WE THROW AN ERROR WITH MIXED CODE
// CHECK WITH ANNEAL
// CHECK WITH GENERATOR
}
const std::string uccsdSrc = R"uccsdSrc(def foo(theta0,theta1):
const std::string uccsdSrc = R"uccsdSrc(def foo(buffer, theta0,theta1):
Rx(-1.57,0)
)uccsdSrc";
......
......@@ -2,9 +2,12 @@ import xacc
xacc.Initialize()
qpu = xacc.getAccelerator('local-ibm')
qubits = qpu.createBuffer('q',3)
# Create the source code
@xacc.qpu(accelerator='tnqvm')
def teleport():
@xacc.qpu(accelerator=qpu)
def teleport(qubits):
X(0)
H(1)
CNOT(1,2)
......@@ -12,12 +15,11 @@ def teleport():
CNOT(1,2)
CNOT(2,0)
Measure(2, 0)
return
results = teleport()
teleport(qubits)
# Display the results
print(results.getMeasurementStrings())
print(qubits.getMeasurementCounts())
# Finalize the framework
xacc.Finalize()
\ No newline at end of file
......@@ -3,19 +3,21 @@ import numpy as np
xacc.Initialize()
class test(xacc.Accelerator):
def execute(self, buffer, function):
print('executing hello world')
@xacc.qpu() # or ibm, rigetti, etc...
def foo(theta):
qpu = xacc.getAccelerator('local-ibm') # or ibm, rigetti, etc...
buffer = qpu.createBuffer('q',2)
@xacc.qpu(accelerator=qpu)
def foo(buffer, theta):
X(0)
Ry(theta, 1)
CNOT(1, 0)
Measure(0,0)
return
expVals = [foo(t).getExpectationValueZ() for t in np.linspace(-np.pi,np.pi,10)]
print (expVals)
# Execute the code on the QPU
foo(buffer, -3.1415936)
# Check into the results
print(buffer.getExpectationValueZ())
print(buffer.getMeasurementCounts())
xacc.Finalize()
\ No newline at end of file
......@@ -2,13 +2,23 @@ import xacc
import numpy as np
xacc.Initialize()
qpu = xacc.getAccelerator('tnqvm')
qbits = qpu.createBuffer('q',4)
@xacc.qpu(accelerator='tnqvm') # or ibm, rigetti, etc...
def foo(t0, t1):
@xacc.qpu(accelerator=qpu) # or ibm, rigetti, etc...
def foo(buffer, t0, t1):
xacc(uccsd, n_qubits=4, n_electrons=2)
Measure(0,0)
return
print([foo(0,t1).getExpectationValueZ() for t1 in np.linspace(-np.pi,np.pi,20)])
expVals = []
def storeExpVal(qbits,t1):
foo(qbits,0,t1)
expVals.append(qbits.getExpectationValueZ())
val= qbits.getExpectationValueZ()
qbits.resetBuffer()
return val
print([storeExpVal(qbits, t1) for t1 in np.linspace(-np.pi,np.pi,20)])
xacc.Finalize()
\ No newline at end of file
......@@ -14,6 +14,7 @@
#include "IRGenerator.hpp"
#include "IRProvider.hpp"
#include "InstructionIterator.hpp"
#include "AcceleratorBuffer.hpp"
#include <pybind11/complex.h>
#include <pybind11/numpy.h>
......@@ -303,7 +304,37 @@ PYBIND11_MODULE(_pyxacc, m) {
"Compute the probability of a given bit string")
.def("getMeasurementCounts",
&xacc::AcceleratorBuffer::getMeasurementCounts,
"Return the mapping of measure bit strings to their counts.");
"Return the mapping of measure bit strings to their counts.")
.def("getChildren",
(std::vector<std::shared_ptr<AcceleratorBuffer>>(
xacc::AcceleratorBuffer::*)(const std::string)) &
xacc::AcceleratorBuffer::getChildren,
"")
.def("getChildrenNames", &xacc::AcceleratorBuffer::getChildrenNames, "")
.def("listExtraInfoKeys", &xacc::AcceleratorBuffer::listExtraInfoKeys, "")
.def("getInformation",
(std::map<std::string, ExtraInfo>(xacc::AcceleratorBuffer::*)()) &
xacc::AcceleratorBuffer::getInformation,
"")
.def("getInformation",
(ExtraInfo(xacc::AcceleratorBuffer::*)(const std::string)) &
xacc::AcceleratorBuffer::getInformation,
"")
.def("name", &xacc::AcceleratorBuffer::name, "")
.def("getAllUnique", &xacc::AcceleratorBuffer::getAllUnique,
"Return all unique information with the provided string name")
.def("__repr__",
[](const std::shared_ptr<AcceleratorBuffer> b) {
std::stringstream s;
b->print(s);
return s.str();
},
"")
.def("getChildren",
(std::vector<std::shared_ptr<AcceleratorBuffer>>(
xacc::AcceleratorBuffer::*)(const std::string, ExtraInfo)) &
xacc::AcceleratorBuffer::getChildren,
"");
// Expose the Compiler
py::class_<xacc::Compiler, std::shared_ptr<xacc::Compiler>>(
......@@ -420,6 +451,7 @@ PYBIND11_MODULE(_pyxacc, m) {
"Indicate that this is using XACC via the Python API.");
m.def("optimizeFunction", &xacc::optimizeFunction,
"Run an optimizer on the given function.");
m.def("analyzeBuffer", (void(*)(std::shared_ptr<AcceleratorBuffer>)) &xacc::analyzeBuffer, "Analyze the AcceleratorBuffer to produce problem-specific results.");
m.def("Finalize", &xacc::Finalize, "Finalize the framework");
m.def("compileKernel",
......
......@@ -117,7 +117,18 @@ class qpu(object):
# Remove the @qpu line from the source
src = '\n'.join(inspect.getsource(f).split('\n')[1:])
argsList = list(args)
if not isinstance(argsList[0], AcceleratorBuffer):
raise RuntimeError('First argument of an xacc kernel must be the Accelerator Buffer to operate on.')
buffer = argsList[0]
functionBufferName = inspect.getargspec(f)[0][0]
# Replace function arg0 name with buffer.name()
src = src.replace(functionBufferName, buffer.name())
# Get the compiler and compile the code
compiler = getCompiler('xacc-py')
ir = compiler.compile(src, qpu)
......@@ -135,9 +146,8 @@ class qpu(object):
nBits = b
nBits = nBits+1
buf = qpu.createBuffer('q',nBits)
compiledKernel.execute(buf, list(args))
return buf
compiledKernel.execute(argsList[0], argsList[1:])
return
return wrapped_f
def functionToLatex(function):
......
......@@ -4,15 +4,15 @@
namespace xacc {
namespace quantum {
std::shared_ptr<Instruction> DWIRProvider::createInstruction(
const std::string name, std::vector<int> bits,
std::vector<InstructionParameter> parameters) {
std::shared_ptr<Instruction>
DWIRProvider::createInstruction(const std::string name, std::vector<int> bits,
std::vector<InstructionParameter> parameters) {
return std::make_shared<DWQMI>(bits, parameters[0]);
}
std::shared_ptr<Function>
DWIRProvider::createFunction(const std::string name, std::vector<int> bits,
std::vector<InstructionParameter> parameters) {
std::vector<InstructionParameter> parameters) {
return std::make_shared<DWKernel>(name, parameters);
}
......@@ -20,9 +20,7 @@ std::shared_ptr<IR> DWIRProvider::createIR() {
return std::make_shared<DWIR>();
}
std::vector<std::string> DWIRProvider::getInstructions() {
return {"dw-qmi"};
}
std::vector<std::string> DWIRProvider::getInstructions() { return {"dw-qmi"}; }
} // namespace quantum
} // namespace xacc
......@@ -220,8 +220,8 @@ TEST(CircuitOptimizerTester, checkSimple) {
if (xacc::hasCompiler("xacc-py")) {
auto c = xacc::getService<xacc::Compiler>("xacc-py");
auto f =
c->compile("def foo():\n CNOT(0,1)\n CNOT(0,1)\n")->getKernels()[0];
auto f = c->compile("def foo(buffer):\n CNOT(0,1)\n CNOT(0,1)\n")
->getKernels()[0];
auto ir = std::make_shared<GateIR>();
ir->addKernel(f);
......@@ -233,7 +233,8 @@ TEST(CircuitOptimizerTester, checkSimple) {
optF = std::dynamic_pointer_cast<GateFunction>(optF->enabledView());
EXPECT_EQ(0, optF->nInstructions());
f = c->compile("def foo():\n H(0)\n CNOT(0,1)\n CNOT(0,1)\n H(0)\n")
f = c->compile(
"def foo(buffer):\n H(0)\n CNOT(0,1)\n CNOT(0,1)\n H(0)\n")
->getKernels()[0];
ir = std::make_shared<GateIR>();
......@@ -245,7 +246,8 @@ TEST(CircuitOptimizerTester, checkSimple) {
EXPECT_EQ(0, optF->nInstructions());
f = c->compile("def foo():\n CNOT(0,1)\n H(1)\n H(1)\n CNOT(0,1)\n")
f = c->compile(
"def foo(buffer):\n CNOT(0,1)\n H(1)\n H(1)\n CNOT(0,1)\n")
->getKernels()[0];
ir = std::make_shared<GateIR>();
......
......@@ -22,6 +22,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/compiler)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/program)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/accelerator)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/utils)
include_directories(${CMAKE_SOURCE_DIR}/tpls/rapidjson/include)
file (GLOB HEADERS
XACC.hpp
......@@ -35,6 +36,7 @@ file (GLOB HEADERS
file (GLOB SRCS
*.cpp
accelerator/*.cpp
program/*.cpp
utils/*.cpp
accelerator/remote/*.cpp
......
......@@ -13,6 +13,7 @@
#include "XACC.hpp"
#include "InstructionIterator.hpp"
#include "IRProvider.hpp"
#include "IRGenerator.hpp"
#include <signal.h>
#include <cstdlib>
......@@ -322,6 +323,15 @@ const std::string translateWithVisitor(const std::string &originalSource,
return visitor->toString();
}
void analyzeBuffer(std::shared_ptr<AcceleratorBuffer> buffer) {
if (!buffer->hasExtraInfoKey("ir-generator")) {
error("xacc::analyzeBuffer is for use with codes generated with an IRGenerator.");
}
auto gen = getService<IRGenerator>(boost::get<std::string>(buffer->getInformation("ir-generator")));
gen->analyzeResults(buffer);
}
void clearOptions() { RuntimeOptions::instance()->clear(); }
std::shared_ptr<Function> optimizeFunction(const std::string optimizer,
......
......@@ -280,6 +280,8 @@ std::vector<std::shared_ptr<ServiceInterface>> getServices() {
std::shared_ptr<Function> optimizeFunction(const std::string optimizer,
std::shared_ptr<Function> function);
void analyzeBuffer(std::shared_ptr<AcceleratorBuffer> buffer);
std::shared_ptr<IRTransformation> getIRTransformation(const std::string &name);
const std::string translate(std::shared_ptr<Function> function,
......
/*******************************************************************************
* Copyright (c) 2017 UT-Battelle, LLC.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompanies this
* distribution. The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Eclipse Distribution
*License is available at https://eclipse.org/org/documents/edl-v10.php
*
* Contributors:
* Alexander J. McCaskey - initial API and implementation
*******************************************************************************/
#include "AcceleratorBuffer.hpp"
#include "XACC.hpp"
namespace xacc {
bool CheckEqualVisitor::operator()(const int &i) const {
return boost::get<int>(extraInfo) == i;
}
bool CheckEqualVisitor::operator()(const double &i) const {
return boost::get<double>(extraInfo) == i;
}
bool CheckEqualVisitor::operator()(const std::string &i) const {
auto asstr = boost::get<std::string>(extraInfo);
return asstr.compare(i) == 0;
}
bool CheckEqualVisitor::operator()(const std::vector<int> &i) const {
return std::equal(i.begin(), i.end(),
boost::get<std::vector<int>>(extraInfo).begin());
}
bool CheckEqualVisitor::operator()(const std::vector<double> &i) const {
return std::equal(i.begin(), i.end(),
boost::get<std::vector<double>>(extraInfo).begin(),
[](const double &d, const double &f) {
return std::fabs(d - f) < 1e-12;
});
}
bool CheckEqualVisitor::operator()(const std::vector<std::string> &i) const {
return std::equal(i.begin(), i.end(),
boost::get<std::vector<std::string>>(extraInfo).begin());
}
bool CheckEqualVisitor::operator()(const std::map<int, std::vector<int>> &i) const {
return std::equal(i.begin(), i.end(),
boost::get<std::map<int, std::vector<int>>>(extraInfo).begin());
}
void ToJsonVisitor::operator()(const int &i) { writer.Int(i); }
void ToJsonVisitor::operator()(const double &i) { writer.Double(i); }
void ToJsonVisitor::operator()(const std::string &i) { writer.String(i); }
void ToJsonVisitor::operator()(const std::vector<int> &i) {
writer.StartArray();
for (auto &v : i)
writer.Int(v);
writer.EndArray();
}
void ToJsonVisitor::operator()(const std::vector<double> &i) {
writer.StartArray();
for (auto &v : i)
writer.Double(v);
writer.EndArray();
}
void ToJsonVisitor::operator()(const std::vector<std::string> &i) {
writer.StartArray();
for (auto &v : i)
writer.String(v);
writer.EndArray();
}
void ToJsonVisitor::operator()(const std::map<int, std::vector<int>> &i) {
writer.StartArray();
for (auto& kv : i) {
writer.Key(std::to_string(kv.first));
writer.StartArray();
for (auto& v : kv.second) {
writer.Int(v);
}
writer.EndArray();
}
writer.EndArray();
}
AcceleratorBuffer::AcceleratorBuffer(const std::string &str, const int N)
: bufferId(str), nBits(N) {}
AcceleratorBuffer::AcceleratorBuffer(const AcceleratorBuffer &other)
: nBits(other.nBits), bufferId(other.bufferId) {}
bool AcceleratorBuffer::addExtraInfo(const std::string infoName, ExtraInfo i,
AddPredicate predicate) {
if (info.count(infoName) && predicate(info[infoName])) {
if (predicate(info[infoName])) {
info[infoName] = i;
return true;
}
return false;
} else {
info.insert({infoName, i});
return true;
}
}
void AcceleratorBuffer::addExtraInfo(const std::string infoName, ExtraInfo i) {
if (info.count(infoName)) {
// overwrite
info[infoName] = i;
} else {
info.insert({infoName, i});
}
}
std::vector<std::string> AcceleratorBuffer::listExtraInfoKeys() {
std::vector<std::string> sv;
for (auto &kv : info) {
sv.push_back(kv.first);
}
return sv;
}
ExtraInfo AcceleratorBuffer::getInformation(const std::string name) {
if (!info.count(name)) {
xacc::error("Invalid AcceleratorBuffer ExtraInfo key name - " + name + ".");
}
return info[name];
}
std::map<std::string, ExtraInfo> AcceleratorBuffer::getInformation() {
return info;
}
void AcceleratorBuffer::appendChild(const std::string name,
std::shared_ptr<AcceleratorBuffer> buffer) {
children.push_back(std::make_pair(name, buffer));
}
std::vector<std::shared_ptr<AcceleratorBuffer>>
AcceleratorBuffer::getChildren(const std::string name) {
std::vector<std::shared_ptr<AcceleratorBuffer>> childrenWithName;
for (auto &child : children) {
if (child.first == name) {
childrenWithName.push_back(child.second);
}
}
return childrenWithName;
}
std::vector<std::string> AcceleratorBuffer::getChildrenNames() {
std::vector<std::string> names;
for (auto &child : children)
names.push_back(child.first);
return names;
}
bool AcceleratorBuffer::hasExtraInfoKey(const std::string infoName) {
return info.count(infoName);
}