Commit c56c10fd authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

committing work on contributed service interface, with extension to the python api



Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent a71dc6a6
Pipeline #65963 passed with stage
in 6 minutes and 28 seconds
......@@ -38,7 +38,7 @@ add_library(_pyxacc SHARED xacc-py.cpp)
set_target_properties(_pyxacc PROPERTIES PREFIX "")
target_link_libraries(_pyxacc PUBLIC CppMicroServices xacc Boost::graph xacc-pauli)
target_link_libraries(_pyxacc PUBLIC CppMicroServices xacc Boost::graph xacc-pauli xacc-fermion)
if(APPLE)
set_target_properties(_pyxacc PROPERTIES INSTALL_RPATH "@loader_path/lib")
......
......@@ -30,7 +30,8 @@ void DWorGateListener::enterGate(PyXACCIRParser::GateContext *ctx) {
// Until we see a qmi or anneal instruction, keep checking
// the incoming gate name
if (!isDW) {
if (gate.find("qmi") != std::string::npos || gate.find("anneal") != std::string::npos) {
if (gate.find("qmi") != std::string::npos ||
gate.find("anneal") != std::string::npos) {
isDW = true;
}
}
......@@ -67,7 +68,7 @@ void PyXACCListener::enterXacckernel(PyXACCIRParser::XacckernelContext *ctx) {
std::vector<InstructionParameter> params;
for (int i = 1; i < ctx->param().size(); i++) {
if(ctx->param(i)->getText().find("*") == std::string::npos) {
if (ctx->param(i)->getText().find("*") == std::string::npos) {
// if (!boost::contains(ctx->param(i)->getText(), "*")) {
params.push_back(InstructionParameter(ctx->param(i)->getText()));
functionVariableNames.push_back(ctx->param(i)->getText());
......@@ -109,7 +110,6 @@ void PyXACCListener::enterUop(PyXACCIRParser::UopContext *ctx) {
}
if (xacc::hasService<GateInstruction>(gateName)) {
// We have to accept GATE(params..., qbits..., opt=val,...)
auto tmpInst = provider->createInstruction(gateName, std::vector<int>{});
auto nBits = tmpInst->nRequiredBits();
......@@ -181,11 +181,17 @@ void PyXACCListener::enterUop(PyXACCIRParser::UopContext *ctx) {
}
f->addInstruction(inst);
} else if (xacc::hasService<IRGenerator>(gateName)) {
} else if (xacc::hasService<IRGenerator>(gateName) ||
xacc::hasContributedService<IRGenerator>(gateName)) {
// HERE we have something like uccsd(n_qubits=4, n_electrons=2)
// std::cout << "HERE WEE HAVBE " << gateName << ", " <<
// ctx->explist()->getText() << "\n";
auto generatorName = gateName;
std::map<std::string, InstructionParameter> params;
if (ctx->explist() != nullptr) {
for (int i = 0; i < ctx->explist()->exp().size(); i++) {
if (ctx->explist()->exp(i) != nullptr &&
ctx->explist()->exp(i)->exp(0) != nullptr) {
auto key = ctx->explist()->exp(i)->key()->getText();
auto valStr = ctx->explist()->exp(i)->exp(0)->getText();
if (is_int(valStr)) {
......@@ -195,9 +201,10 @@ void PyXACCListener::enterUop(PyXACCIRParser::UopContext *ctx) {
} else {
params.insert({key, InstructionParameter(valStr)});
}
}
// FIXME HANDLE OTHER TYPES
}
}
// Add the Function's InstructionParameters
for (int i = 0; i < f->nParameters(); i++) {
......@@ -205,10 +212,25 @@ void PyXACCListener::enterUop(PyXACCIRParser::UopContext *ctx) {
}
if (params.empty()) {
auto generator = xacc::getService<xacc::IRGenerator>(generatorName);
f->addInstruction(generator);
auto generator =
xacc::getService<xacc::IRGenerator>(generatorName, false);
if (!generator) {
generator = xacc::getContributedService<IRGenerator>(generatorName);
if (!generator) {
xacc::error("Cannot create IRGenerator with name " + generatorName);
}
}
auto genF = generator->generate(params);
f->addInstruction(genF);
} else {
auto generator = xacc::getService<xacc::IRGenerator>(generatorName);
auto generator =
xacc::getService<xacc::IRGenerator>(generatorName, false);
if (!generator) {
generator = xacc::getContributedService<IRGenerator>(generatorName);
if (!generator) {
xacc::error("Cannot create IRGenerator with name " + generatorName);
}
}
auto genF = generator->generate(params);
// We may have a IRGenerator that produces d-wave functions,
......
import xacc
class bell(xacc.IRGenerator):
def __init__(self):
xacc.IRGenerator.__init__(self)
def name(self):
return 'bell'
def generate(self, params):
xacc.qasm('''.compiler quil
.function bell
H 0
CNOT 0 1
MEASURE 0 [0]
MEASURE 1 [1]
''')
return xacc.getCompiled('bell')
irg = bell()
xacc.contributeService('bell', irg)
qpu = xacc.getAccelerator('local-ibm') #my_acc()
buffer = xacc.qalloc(2)
irg2 = xacc.getIRGenerator('bell')
@xacc.qpu( accelerator=qpu)
def function(buffer):
bell()
function(buffer)
print(buffer)
\ No newline at end of file
import xacc,sys, numpy as np
# Get access to the desired QPU and
# allocate some qubits to run on
qpu = xacc.getAccelerator('tnqvm')
buffer = qpu.createBuffer('q', 2)
# Construct the Hamiltonian as an XACC-VQE PauliOperator
ham = xacc.getObservable('pauli', '5.907 - 2.1433 X0X1 - 2.1433 Y0Y1 + .21829 Z0 - 6.125 Z1')
# Define the ansatz and decorate it to indicate
# you'd like to run VQE
@xacc.qpu(algo='vqe',accelerator=qpu, observable=ham)
def ansatz(buffer, t0):
X(0)
Ry(t0, 1)
CNOT(1, 0)
ansatz(buffer)
print('Energy = ', buffer.getInformation('opt-val'))
print('Opt Angles = ', buffer.getInformation('opt-params'))
# Now lets just do a param sweep
ansatz.modifyAlgorithm('energy')
# Execute, starting at .5
def compute_energy_at_angles(angles):
ansatz(buffer, *angles)
return buffer.getInformation('opt-val')
energy = lambda angles : compute_energy_at_angles(angles)
print([energy([a]) for a in np.linspace(-np.pi,np.pi,50)])
......@@ -21,6 +21,7 @@
#include "InstructionParameter.hpp"
#include "EmbeddingAlgorithm.hpp"
#include "PauliOperator.hpp"
#include "FermionOperator.hpp"
#include <pybind11/complex.h>
#include <pybind11/numpy.h>
......@@ -97,7 +98,7 @@ public:
std::vector<std::shared_ptr<AcceleratorBuffer>>
execute(std::shared_ptr<AcceleratorBuffer> buffer,
const std::vector<std::shared_ptr<Function>> functions) override {
return {};
PYBIND11_OVERLOAD_PURE(std::vector<std::shared_ptr<AcceleratorBuffer>>, xacc::Accelerator, execute, buffer, functions);
}
std::shared_ptr<AcceleratorBuffer>
......@@ -111,6 +112,27 @@ public:
}
};
class PyIRGenerator : public xacc::IRGenerator {
public:
/* Inherit the constructors */
using IRGenerator::IRGenerator;
const std::string name() const override {
PYBIND11_OVERLOAD_PURE(const std::string, xacc::IRGenerator, name);
}
const std::string description() const override { return ""; }
std::shared_ptr<Function>
generate(std::map<std::string, InstructionParameter>& parameters) {
PYBIND11_OVERLOAD_PURE(std::shared_ptr<Function>, xacc::IRGenerator, generate, parameters);
}
std::shared_ptr<Function>
generate(std::shared_ptr<AcceleratorBuffer> buffer,
std::vector<InstructionParameter> parameters =
std::vector<InstructionParameter>{}) override { return nullptr;}
};
PYBIND11_MODULE(_pyxacc, m) {
m.doc() =
"Python bindings for XACC. XACC provides a plugin infrastructure for "
......@@ -127,6 +149,11 @@ PYBIND11_MODULE(_pyxacc, m) {
.def(py::init<std::string>(), "Construct as a string.")
.def(py::init<std::complex<double>>(), "Construct as a complex double.");
py::class_<xacc::ContributableService>(
m, "ContributableService",
"")
.def(py::init<std::shared_ptr<IRGenerator>>(), "");
py::class_<xacc::Instruction, std::shared_ptr<xacc::Instruction>>(
m, "Instruction", "")
.def("nParameters", &xacc::Instruction::nParameters, "")
......@@ -143,7 +170,10 @@ PYBIND11_MODULE(_pyxacc, m) {
.def("bits", &xacc::Instruction::bits, "")
.def("getParameter", &xacc::Instruction::getParameter, "")
.def("getParameters", &xacc::Instruction::getParameters, "")
.def("setParameter", ( void ( xacc::Instruction::*)(const int, InstructionParameter &) ) &xacc::Instruction::setParameter, "")
.def("setParameter",
(void (xacc::Instruction::*)(const int, InstructionParameter &)) &
xacc::Instruction::setParameter,
"")
.def("mapBits", &xacc::Instruction::mapBits, "")
.def("name", &xacc::Instruction::name, "")
.def("description", &xacc::Instruction::description, "");
......@@ -173,7 +203,10 @@ PYBIND11_MODULE(_pyxacc, m) {
.def("enable", &xacc::Function::enable, "")
.def("getParameter", &xacc::Function::getParameter, "")
.def("getParameters", &xacc::Function::getParameters, "")
.def("setParameter", ( void ( xacc::Instruction::*)(const int, InstructionParameter &) )&xacc::Function::setParameter, "")
.def("setParameter",
(void (xacc::Instruction::*)(const int, InstructionParameter &)) &
xacc::Function::setParameter,
"")
.def("depth", &xacc::Function::depth, "")
.def("persistGraph", &xacc::Function::persistGraph, "")
.def("mapBits", &xacc::Function::mapBits, "");
......@@ -196,18 +229,17 @@ PYBIND11_MODULE(_pyxacc, m) {
m, "IRTransformation", "")
.def("transform", &xacc::IRTransformation::transform, "");
py::class_<xacc::IRGenerator, std::shared_ptr<xacc::IRGenerator>>(
py::class_<xacc::IRGenerator, std::shared_ptr<xacc::IRGenerator>, PyIRGenerator>(
m, "IRGenerator", "")
.def(py::init<>(),"")
.def("generate",
(std::shared_ptr<xacc::Function>(xacc::IRGenerator::*)(
std::vector<xacc::InstructionParameter>)) &
xacc::IRGenerator::generate,
py::return_value_policy::reference, "")
xacc::IRGenerator::generate, "")
.def("generate",
(std::shared_ptr<xacc::Function>(xacc::IRGenerator::*)(
std::map<std::string, xacc::InstructionParameter> &)) &
xacc::IRGenerator::generate,
py::return_value_policy::reference, "")
xacc::IRGenerator::generate, "")
.def("analyzeResults", &xacc::IRGenerator::analyzeResults, "");
// Expose the Accelerator
......@@ -470,11 +502,33 @@ PYBIND11_MODULE(_pyxacc, m) {
m.def("PyInitialize", &xacc::PyInitialize,
"Initialize the framework from Python.");
// m.def("help", )
m.def("getAccelerator",
(std::shared_ptr<xacc::Accelerator>(*)(const std::string &, AcceleratorParameters)) &
xacc::getAccelerator,
m.def(
"getAccelerator",
[](const std::string &name, AcceleratorParameters p = {}) {
return xacc::getAccelerator(name, p);
},
py::arg("name"), py::arg("params") = AcceleratorParameters{},
py::return_value_policy::reference,
"Return the accelerator with given name.");
m.def("getObservable",
[](const std::string &type, const std::string representation) ->std::shared_ptr<Observable> {
if (type == "pauli") {
return representation.empty()
? std::make_shared<PauliOperator>()
: std::make_shared<PauliOperator>(representation);
} else if (type == "fermion") {
return representation.empty()
? std::make_shared<FermionOperator>()
: std::make_shared<FermionOperator>(representation);
} else if (xacc::hasService<Observable>(type)) {
auto obs = xacc::getService<Observable>(type);
obs->fromString(representation);
return obs;
} else {
xacc::error("Invalid observable type");
return std::make_shared<PauliOperator>();
}
});
m.def("getCompiler",
(std::shared_ptr<xacc::Compiler>(*)(const std::string &)) &
xacc::getCompiler,
......@@ -487,7 +541,7 @@ PYBIND11_MODULE(_pyxacc, m) {
"Return the IRTransformation of given name.");
m.def("getIRGenerator",
(std::shared_ptr<xacc::IRGenerator>(*)(const std::string &)) &
xacc::getService<IRGenerator>,
xacc::getIRGenerator,
py::return_value_policy::reference,
"Return the IRGenerator of given name.");
m.def("getConnectivity",
......@@ -581,6 +635,10 @@ PYBIND11_MODULE(_pyxacc, m) {
xacc::getOptimizer,
"");
m.def("contributeService", [](const std::string name, ContributableService& service) {
xacc::contributeService(name, service);
}, "");
m.def(
"compileKernel",
[](std::shared_ptr<Accelerator> acc, const std::string &src,
......
......@@ -208,6 +208,10 @@ class DecoratorFunction(ABC):
def getFunction(self):
return self.compiledKernel
def modifyAlgorithm(self, algorithm):
newAlgo = serviceRegistry.get_service('decorator_algorithm_service', algorithm)
self.__class__ = newAlgo.__class__
@abstractmethod
def __call__(self, *args, **kwargs):
pass
......@@ -249,7 +253,6 @@ class qpu(object):
wf.initialize(f,*self.args, **self.kwargs)
return wf
def compute_readout_error_probabilities(qubits, buffer, qpu, shots=8192, persist=True):
p10Functions = []
p01Functions = []
......@@ -524,5 +527,11 @@ def main(argv=None):
initialize()
def _finalize():
Finalize()
import atexit
atexit.register(_finalize)
if __name__ == "__main__":
sys.exit(main())
......@@ -234,17 +234,25 @@ std::shared_ptr<Accelerator> getAccelerator(const std::string &name, Accelerator
"xacc::Initialize() before using API.");
}
auto name_backend = split(name, ':');
auto acc = xacc::getService<Accelerator>(name_backend[0]);
auto acc = xacc::getService<Accelerator>(name_backend[0], false);
if (name_backend.size() > 1) {
setOption(name_backend[0] + "-backend", name_backend[1]);
}
if (acc) {
acc->initialize(params);
} else {
if (xacc::hasContributedService<Accelerator>(name)) {
acc = xacc::getContributedService<Accelerator>(name);
if (acc) acc->initialize(params);
} else {
error("Invalid Accelerator. Could not find " + name +
" in Accelerator Registry.");
}
}
return acc;
}
......@@ -319,9 +327,28 @@ std::shared_ptr<IRProvider> getIRProvider(const std::string &name) {
auto irp = xacc::getService<IRProvider>(name);
if (!irp) {
error("Invalid IRProvider. Could not find " + name +
" in Service Registry.");
}
return irp;
}
std::shared_ptr<IRGenerator> getIRGenerator(const std::string &name) {
if (!xacc::xaccFrameworkInitialized) {
error("XACC not initialized before use. Please execute "
"xacc::Initialize() before using API.");
}
auto irp = xacc::getService<IRGenerator>(name, false);
if (!irp) {
if(xacc::hasContributedService<IRGenerator>(name)) {
irp = xacc::getContributedService<IRGenerator>(name);
} else {
error("Invalid IRProvicer. Could not find " + name +
" in Service Registry.");
}
}
return irp;
}
......@@ -594,6 +621,7 @@ void qasm(const std::string &qasmString) {
auto lines = split(qasmString, '\n');
std::string currentFunctionName = "";
for (auto &l : lines) {
xacc::trim(l);
if (l.find(".compiler") == std::string::npos &&
l.find(".function") == std::string::npos && !l.empty()) {
function2code[currentFunctionName] += l + "\n";
......
......@@ -16,6 +16,8 @@
#include "Compiler.hpp"
#include "RemoteAccelerator.hpp"
#include "IRProvider.hpp"
#include "IRGenerator.hpp"
#include "Algorithm.hpp"
#include "Optimizer.hpp"
......@@ -192,6 +194,7 @@ void setOption(const std::string &optionKey, const std::string &value);
void unsetOption(const std::string &optionKey);
std::shared_ptr<IRProvider> getIRProvider(const std::string &name);
std::shared_ptr<IRGenerator> getIRGenerator(const std::string &name);
/**
* Set the Compiler to use.
......
......@@ -19,6 +19,12 @@
#include "Identifiable.hpp"
#include "OptionsProvider.hpp"
#include "Cloneable.hpp"
#include "InstructionParameter.hpp"
#include "IRGenerator.hpp"
#include "Compiler.hpp"
// #include "Algorithm.hpp"
// #include "Optimizer.hpp"
// #include "IRProvider.hpp"
#include <cppmicroservices/FrameworkFactory.h>
#include <cppmicroservices/Framework.h>
......@@ -33,6 +39,10 @@ using namespace cppmicroservices;
namespace xacc {
using ContributableService =
Variant<std::shared_ptr<IRGenerator>, std::shared_ptr<Accelerator>>;//,
// std::shared_ptr<Compiler>, std::shared_ptr<Algorithm>,
// std::shared_ptr<Optimizer>, std::shared_ptr<IRProvider>>;
/**
* The ServiceRegistry provides the plugin infrastructure for XACC.
* It delegates to the CppMicroServices Framework and BundleContexts,
......@@ -56,6 +66,8 @@ protected:
std::string rootPathStr = "";
std::map<std::string, ContributableService> runtimeContributed;
public:
ServiceRegistry() : framework(FrameworkFactory().NewFramework()) {}
const std::string getRootPathString() { return rootPathStr; }
......@@ -69,6 +81,15 @@ public:
}
}
}
void contributeService(const std::string name,
ContributableService &service) {
if (runtimeContributed.count(name)) {
XACCLogger::instance()->error("Service already contributed.");
}
runtimeContributed.insert({name, service});
}
template <typename ServiceInterface> bool hasService(const std::string name) {
auto allServiceRefs = context.GetServiceReferences<ServiceInterface>();
for (auto s : allServiceRefs) {
......@@ -79,6 +100,7 @@ public:
return true;
}
}
return false;
}
......@@ -102,15 +124,39 @@ public:
}
}
if (!ret) {
XACCLogger::instance()->error("Could not find service with name " + name +
". "
"Perhaps the service is not Identifiable.");
return ret;
}
template <typename ServiceInterface>
std::shared_ptr<ServiceInterface>
getContributedService(const std::string name) {
std::shared_ptr<ServiceInterface> ret;
if (runtimeContributed.count(name)) {
ret = runtimeContributed[name].as<std::shared_ptr<ServiceInterface>>();
auto checkCloneable =
std::dynamic_pointer_cast<xacc::Cloneable<ServiceInterface>>(ret);
if (checkCloneable) {
ret = checkCloneable->clone();
}
}
return ret;
}
template<typename Service>
bool hasContributedService(const std::string name) {
if (runtimeContributed.count(name)) {
try {
auto tmp = runtimeContributed[name].as_no_error<std::shared_ptr<Service>>();
} catch (std::exception& e) {
return false;
}
return true;
}
return false;
}
template <typename ServiceInterface>
std::vector<std::shared_ptr<ServiceInterface>> getServices() {
std::vector<std::shared_ptr<ServiceInterface>> services;
......
......@@ -59,6 +59,10 @@ void ServiceAPI_Finalize() {
}
}
void contributeService(const std::string name, ContributableService& service) {
serviceRegistry->contributeService(name, service);
}
std::vector<OptionPairs> getRegisteredOptions() {
return serviceRegistry->getRegisteredOptions();
}
......
......@@ -24,15 +24,17 @@ extern bool serviceAPIInitialized;
void ServiceAPI_Initialize(int argc, char **argv);
void ServiceAPI_Finalize();
void contributeService(const std::string name, ContributableService& service);
template <class Service>
std::shared_ptr<Service> getService(const std::string &serviceName) {
std::shared_ptr<Service> getService(const std::string &serviceName, bool failIfNotFound = true) {
if (!xacc::serviceAPIInitialized) {
XACCLogger::instance()->error(
"XACC not initialized before use. Please execute "
"xacc::Initialize() before using API.");
}
auto service = serviceRegistry->getService<Service>(serviceName);
if (!service) {
if (!service && failIfNotFound) {
XACCLogger::instance()->error("Invalid XACC Service. Could not find " +
serviceName + " in Service Registry.");
}
......@@ -48,6 +50,32 @@ template <typename Service> bool hasService(const std::string &serviceName) {
return serviceRegistry->hasService<Service>(serviceName);
}
template <class Service>
std::shared_ptr<Service> getContributedService(const std::string &serviceName, bool failIfNotFound = true) {
if (!xacc::serviceAPIInitialized) {
XACCLogger::instance()->error(
"XACC not initialized before use. Please execute "
"xacc::Initialize() before using API.");
}
auto service = serviceRegistry->getContributedService<Service>(serviceName);
if (!service && failIfNotFound) {
XACCLogger::instance()->error("Invalid XACC Service. Could not find " +
serviceName + " in Service Registry.");
}
return service;
}
template<typename Service>
bool hasContributedService(const std::string &serviceName) {
if (!xacc::serviceAPIInitialized) {
XACCLogger::instance()->error(
"XACC not initialized before use. Please execute "
"xacc::Initialize() before using API.");
}
return serviceRegistry->hasContributedService<Service>(serviceName);
}
template <typename ServiceInterface>
std::vector<std::string> getRegisteredIds() {
return serviceRegistry->getRegisteredIds<ServiceInterface>();
......
Supports Markdown
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