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

got python api hooked back up and running



Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 337ab2bb
......@@ -93,7 +93,7 @@ add_subdirectory(tpls)
add_subdirectory(xacc)
add_subdirectory(quantum)
if(PYTHON_INCLUDE_DIR)
#add_subdirectory(python)
add_subdirectory(python)
endif()
#find_package(Clang 9.0.0)
......
include_directories(${CMAKE_SOURCE_DIR}/xacc)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate)
include_directories(${CMAKE_SOURCE_DIR}/quantum/aqc)
include_directories(${CMAKE_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR}/xacc/ir)
include_directories(${CMAKE_SOURCE_DIR}/xacc/service)
include_directories(${CMAKE_SOURCE_DIR}/xacc/compiler)
include_directories(${CMAKE_SOURCE_DIR}/xacc/program)
include_directories(${CMAKE_SOURCE_DIR}/xacc/accelerator)
include_directories(${CMAKE_SOURCE_DIR}/xacc/utils)
include_directories(${CMAKE_SOURCE_DIR}/tpls/rapidjson/include)
include_directories(${CMAKE_SOURCE_DIR}/tpls/exprtk)
include_directories(${CMAKE_SOURCE_DIR}/tpls/spdlog)
include_directories(${CMAKE_SOURCE_DIR}/tpls/eigen)
include_directories(${CMAKE_SOURCE_DIR}/tpls/taocpp)
include_directories(${CMAKE_SOURCE_DIR}/quantum/utils)
include_directories(${CMAKE_SOURCE_DIR}/quantum/aqc/ir)
include_directories(${CMAKE_SOURCE_DIR}/quantum/aqc/compiler)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/ir)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/ir/instructions)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/utils)
include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/observable)
add_subdirectory(compiler)
include_directories(${PYTHON_INCLUDE_DIR})
......@@ -35,10 +9,8 @@ if(APPLE)
endif(APPLE)
add_library(_pyxacc SHARED xacc-py.cpp)
set_target_properties(_pyxacc PROPERTIES PREFIX "")
target_link_libraries(_pyxacc PUBLIC CppMicroServices xacc Boost::graph xacc-pauli xacc-fermion)
target_link_libraries(_pyxacc PUBLIC xacc xacc-pauli xacc-fermion)
if(APPLE)
set_target_properties(_pyxacc PROPERTIES INSTALL_RPATH "@loader_path/lib")
......
......@@ -2,49 +2,37 @@
# Copyright (c) 2018 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 v.10 which accompany 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
# and Eclipse Distribution License v.10 which accompany 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
# Alexander J. McCaskey - initial API and implementation
# *******************************************************************************/
set (PACKAGE_NAME "PYXACC Compiler")
set (PACKAGE_DESCIPTION "PYXACC Compiler Bundle")
set (LIBRARY_NAME xacc-py-compiler)
file (GLOB_RECURSE HEADERS *.hpp generated/*.hpp)
file (GLOB SRC *.cpp generated/*.cpp)
set(LIBRARY_NAME xacc-pyxasm-compiler)
include_directories(${CMAKE_BINARY_DIR}/tpls/cppmicroservices/framework/include)
include_directories(${CMAKE_BINARY_DIR}/tpls/cppmicroservices/include)
include_directories(${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src)
include_directories(${CMAKE_SOURCE_DIR}/tpls/cppmicroservices/framework/include)
set(ANTLR_LIB ${CMAKE_SOURCE_DIR}/dist/libantlr4-runtime.so)
if (APPLE)
set(ANTLR_LIB ${CMAKE_SOURCE_DIR}/dist/libantlr4-runtime.dylib)
endif()
include_directories(generated)
include_directories(${CMAKE_SOURCE_DIR}/tpls/boost-cmake/boost/boost_1_64_0)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
link_directories(${CMAKE_SOURCE_DIR}/dist)
file (GLOB_RECURSE HEADERS *.hpp generated/*.hpp)
file (GLOB SRC *.cpp generated/*.cpp)
# Set up dependencies to resources to track changes
usFunctionGetResourceSource(TARGET ${LIBRARY_NAME} OUT SRC)
# Generate bundle initialization code
usFunctionGenerateBundleInit(TARGET ${LIBRARY_NAME} OUT SRC)
add_library(${LIBRARY_NAME} SHARED ${SRC})
set(_bundle_name xacc_py_compiler)
set(_bundle_name xacc_pyxasm_compiler)
set_target_properties(${LIBRARY_NAME} PROPERTIES
# This is required for every bundle
COMPILE_DEFINITIONS US_BUNDLE_NAME=${_bundle_name}
# This is for convenience, used by other CMake functions
US_BUNDLE_NAME ${_bundle_name}
)
# Embed meta-data from a manifest.json file
usFunctionEmbedResources(TARGET ${LIBRARY_NAME}
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}
......@@ -52,7 +40,9 @@ usFunctionEmbedResources(TARGET ${LIBRARY_NAME}
manifest.json
)
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc xacc-quantum-gate xacc-quantum-aqc antlr4-runtime)
target_include_directories(${LIBRARY_NAME} PRIVATE . generated
${CMAKE_SOURCE_DIR}/tpls/antlr/runtime/src)
target_link_libraries(${LIBRARY_NAME} PUBLIC xacc ${ANTLR_LIB})
if(APPLE)
set_target_properties(${LIBRARY_NAME} PROPERTIES INSTALL_RPATH "@loader_path/../lib")
......@@ -62,7 +52,7 @@ else()
set_target_properties(${LIBRARY_NAME} PROPERTIES LINK_FLAGS "-shared")
endif()
install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins)
install(TARGETS ${LIBRARY_NAME} DESTINATION ${CMAKE_INSTALL_PREFIX}/plugins)
if (${XACC_BUILD_TESTS})
include_directories(${GTEST_INCLUDE_DIRS})
......
/*******************************************************************************
* Copyright (c) 2018 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 "PyXACCCompiler.hpp"
#include "PyXACCListener.hpp"
#include "PyXACCIRLexer.h"
#include "GateIR.hpp"
#include "InstructionIterator.hpp"
#include "PyXACCVisitor.hpp"
using namespace antlr4;
using namespace pyxacc;
namespace xacc {
namespace quantum {
std::shared_ptr<IR> PyXACCCompiler::compile(const std::string &src,
std::shared_ptr<Accelerator> acc) {
auto e1 = new PyXACCErrorListener();
auto e2 = new PyXACCErrorListener();
// Setup the Antlr Parser
ANTLRInputStream input(src);
PyXACCIRLexer lexer(&input);
lexer.removeErrorListeners();
lexer.addErrorListener(e1);
CommonTokenStream tokens(&lexer);
PyXACCIRParser parser(&tokens);
parser.removeErrorListeners();
parser.addErrorListener(e2);
// Walk the Abstract Syntax Tree
tree::ParseTree *tree = parser.xaccsrc();
DWorGateListener l;
tree::ParseTreeWalker::DEFAULT.walk(&l, tree);
PyXACCListener listener(l.isDW, acc);
tree::ParseTreeWalker::DEFAULT.walk(&listener, tree);
// Create and return the IR
auto ir = std::make_shared<GateIR>();
ir->addKernel(listener.getKernel());
delete e1;
delete e2;
return ir;
}
std::shared_ptr<IR> PyXACCCompiler::compile(const std::string &src) {
return compile(src, nullptr);
}
const std::string
PyXACCCompiler::translate(const std::string &bufferVariable,
std::shared_ptr<Function> function) {
auto visitor = std::make_shared<PyXACCVisitor>(function->getParameters());
xacc::InstructionIterator it(function);
while (it.hasNext()) {
// Get the next node in the tree
auto nextInst = it.next();
if (nextInst->isEnabled()) {
nextInst->accept(visitor);
}
}
return visitor->getPyXACCString();
}
} // namespace quantum
} // namespace xacc
/*******************************************************************************
* Copyright (c) 2018 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
*******************************************************************************/
#ifndef PYTHON_PYXACCCOMPILER_HPP_
#define PYTHON_PYXACCCOMPILER_HPP_
#include "XACC.hpp"
#include "antlr4-runtime.h"
namespace xacc {
namespace quantum {
/**
* An Antlr error listener for handling parsing errors.
*/
class PyXACCErrorListener : public antlr4::BaseErrorListener {
public:
void syntaxError(antlr4::Recognizer *recognizer,
antlr4::Token *offendingSymbol, size_t line,
size_t charPositionInLine, const std::string &msg,
std::exception_ptr e) override {
std::ostringstream output;
output << "Invalid PyXACC source: ";
output << "line " << line << ":" << charPositionInLine << " " << msg;
xacc::error(output.str());
}
};
/**
* The PyXACCCompiler is an XACC Compiler that compiles
* python-like gate instruction source code to produce a
* XACC IR.
*/
class PyXACCCompiler : public xacc::Compiler {
public:
/**
* The Compiler.
*/
PyXACCCompiler() {}
/**
* Compile the given kernel code for the
* given Accelerator.
*
* @param src The source code
* @param acc Reference to the D-Wave Accelerator
* @return
*/
virtual std::shared_ptr<xacc::IR> compile(const std::string &src,
std::shared_ptr<Accelerator> acc);
/**
* Compile the given kernel code.
*
* @param src The source code
* @return
*/
virtual std::shared_ptr<xacc::IR> compile(const std::string &src);
/**
* We don't allow translations for the PyXACC Compiler.
* @param bufferVariable
* @param function
* @return
*/
virtual const std::string translate(const std::string &bufferVariable,
std::shared_ptr<Function> function);
virtual const std::string name() const { return "xacc-py"; }
virtual const std::string description() const { return ""; }
/**
* The destructor
*/
virtual ~PyXACCCompiler() {}
};
} // namespace quantum
} // namespace xacc
#endif
/*******************************************************************************
* Copyright (c) 2018 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 <iostream>
#include <IRProvider.hpp>
#include "PyXACCListener.hpp"
#include "XACC.hpp"
#include "GateFunction.hpp"
#include "IRGenerator.hpp"
#include "xacc_service.hpp"
using namespace pyxacc;
namespace xacc {
namespace quantum {
void DWorGateListener::enterGate(PyXACCIRParser::GateContext *ctx) {
// Get the name of the gate
auto gate = ctx->getText();
// 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) {
isDW = true;
}
}
// Once we have seen qmi or anneal, ensure that we
// don't see any gate model instructions
if (isDW && (gate != "qmi" && gate != "anneal"))
xacc::error("Cannot mix gate and dwave instructions.");
}
PyXACCListener::PyXACCListener(std::shared_ptr<Accelerator> acc)
: accelerator(acc) {
provider = xacc::getService<IRProvider>("gate");
}
PyXACCListener::PyXACCListener(bool _useDw, std::shared_ptr<Accelerator> acc)
: useDW(_useDw), accelerator(acc) {
if (_useDw)
provider = xacc::getService<IRProvider>("dwave");
else
provider = xacc::getService<IRProvider>("gate");
}
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 = 1; i < ctx->param().size(); i++) {
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());
}
}
f = provider->createFunction(ctx->kernelname->getText(), {}, params);
}
void PyXACCListener::enterUop(PyXACCIRParser::UopContext *ctx) {
// Note, if the user has specified something like
// H(...) or H(0...2), then we have a different handle
if (ctx->allbitsOp() != nullptr)
return;
auto is_double = [](const std::string &s) -> bool {
try {
std::stod(s);
} catch (std::exception &e) {
return false;
}
return true;
};
auto is_int = [](const std::string &s) -> bool {
try {
std::stoi(s);
} catch (std::exception &e) {
return false;
}
return true;
};
auto gateName = ctx->gatename->getText();
xacc::trim(gateName);
if (gateName == "CX") {
gateName = "CNOT";
} else if (gateName == "MEASURE") {
gateName = "Measure";
}
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();
auto nArgs = ctx->explist()->exp().size();
int nOptions = 0;
// how many options are there?
for (int i = 0; i < nArgs; i++) {
if (ctx->explist()->exp(i)->key() != nullptr) {
nOptions++;
}
}
// Parameters may be optional sometimes
auto nParams = nArgs - nOptions - nBits;
// get all InstructionParameters first
std::vector<InstructionParameter> params;
for (int i = 0; i < nParams; i++) {
auto tmp = ctx->explist()->exp(i);
if (gateName == "Measure") {
InstructionParameter param(std::stoi(tmp->getText()));
params.push_back(param);
} else {
if (tmp->real() != nullptr || tmp->id() != nullptr) {
auto str = tmp->getText();
auto param = is_double(str) ? InstructionParameter(std::stod(str))
: InstructionParameter(str);
params.push_back(param);
} else if (tmp->exp().size() == 1 && tmp->exp(0)->real() != nullptr) {
// this is a neg double
params.push_back(InstructionParameter(std::stod(tmp->getText())));
} else {
params.push_back(InstructionParameter(tmp->getText()));
}
}
}
// Get qubit indices
std::vector<int> qubits;
for (int i = nParams; i < nBits + nParams; i++) {
qubits.push_back(std::stoi(ctx->explist()->exp(i)->INT()->getText()));
}
auto inst = provider->createInstruction(gateName, qubits);
int counter = 0;
for (auto &p : params) {
inst->setParameter(counter, p);
counter++;
}
// See if we have any options
for (int i = nBits + nParams; i < nArgs; i++) {
auto key = ctx->explist()->exp(i)->key()->getText();
auto valStr = ctx->explist()->exp(i)->exp(0)->getText();
if (is_int(valStr)) {
InstructionParameter p(std::stoi(valStr));
inst->setOption(key, p);
} else if (is_double(valStr)) {
InstructionParameter p(std::stod(valStr));
inst->setOption(key, p);
} else {
InstructionParameter p(valStr);
inst->setOption(key, p);
}
// FIXME HANDLE OTHER TYPES ???
}
f->addInstruction(inst);
} 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)) {
params.insert({key, InstructionParameter(std::stoi(valStr))});
} else if (is_double(valStr)) {
params.insert({key, InstructionParameter(std::stod(valStr))});
} else {
params.insert({key, InstructionParameter(valStr)});
}
}
// FIXME HANDLE OTHER TYPES
}
}
// Add the Function's InstructionParameters
for (int i = 0; i < f->nParameters(); i++) {
params.insert({"param_" + std::to_string(i), f->getParameter(i)});
}
if (params.empty()) {
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, 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,
// 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 = accelerator->getBuffer(bufferName);
buff->addExtraInfo("ir-generator", ExtraInfo(generator->name()));
auto xaccKernelSrcStr = dwcompiler->translate("", genF);
auto embeddedCode = dwcompiler->compile(xaccKernelSrcStr, accelerator);
genF = embeddedCode->getKernels()[0];
}
for (auto i : genF->getInstructions()) {
f->addInstruction(i);
}
}
} else if (gateName == "qmi") {
std::vector<int> qubits;
std::vector<InstructionParameter> params;
qubits.push_back(std::stoi(ctx->explist()->exp(0)->INT()->getText()));
qubits.push_back(std::stoi(ctx->explist()->exp(1)->INT()->getText()));
auto str = ctx->explist()->exp(2)->getText();
auto param = is_double(str) ? InstructionParameter(std::stod(str))
: InstructionParameter(str);
params.push_back(param);
auto gate = provider->createInstruction(gateName, qubits, params);
f->addInstruction(gate);
} /*else if (gateName == "xacc") {
// SOON TO BE DEPRECATED IN FAVOR OR IRGENERATOR()
auto generatorName = ctx->explist()->exp(0)->getText();
std::map<std::string, InstructionParameter> params;
for (int i = 1; i < ctx->explist()->exp().size(); i++) {
auto key = ctx->explist()->exp(i)->id()->getText();
auto valStr = ctx->explist()->exp(i)->exp(0)->getText();
if (is_int(valStr)) {
params.insert({key, InstructionParameter(std::stoi(valStr))});
} else if (is_double(valStr)) {
params.insert({key, InstructionParameter(std::stod(valStr))});
} else {
params.insert({key, InstructionParameter(valStr)});
}
}
// Add the Function's InstructionParameters
for (int i = 0; i < f->nParameters(); i++) {
params.insert({"param_" + std::to_string(i), f->getParameter(i)});
}
auto generator = xacc::getService<xacc::IRGenerator>(generatorName);
auto genF = generator->generate(params);