Commit 346e62f9 authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Adding support for parameterized kernels

parent f39ef0a1
......@@ -41,12 +41,6 @@ using namespace clang;
namespace scaffold {
class KernelParameter {
public:
std::string type;
std::string varName;
};
class ScaffoldASTConsumer: public clang::ASTConsumer,
public clang::RecursiveASTVisitor<ScaffoldASTConsumer> {
......@@ -62,8 +56,6 @@ protected:
std::map<std::string, int> cbitRegToMeasuredQubit;
std::vector<KernelParameter> parameters;
public:
// Override the method that gets called for each parsed top-level
......@@ -140,26 +132,24 @@ public:
// std::cout << "Found " << cbitVarName << "\n";
} else if (boost::contains(varType, "qbit")) {
qbitVarName = varDecl->getDeclName().getAsString();
boost::trim(qbitVarName);
// std::cout << "Found " << qbitVarName << "\n";
}
} else if (isa<FunctionDecl>(d)) {
auto c = cast<FunctionDecl>(d);
function = std::make_shared<xacc::quantum::GateFunction>(
c->getDeclName().getAsString());
clang::LangOptions lo;
clang::PrintingPolicy policy(lo);
std::string arg;
llvm::raw_string_ostream argstream(arg);
// Skip first parameter since its supposed to be the qubit register
std::vector<xacc::InstructionParameter> parameters;
clang::FunctionDecl::param_iterator pBegin = c->param_begin();
clang::FunctionDecl::param_iterator pEnd = c->param_end();
// std::cout << "TRYING FUNC " << c->getDeclName().getAsString() << " params " << c->param_size() << "\n";
for (auto i = pBegin; i != pEnd; ++i) {
KernelParameter p;
p.type = (*i)->getType().getAsString();
p.varName = (*i)->getNameAsString();
// std::cout << "HELLO World: " << (*i)->getType().getAsString() << " : " << (*i)->getNameAsString() << "\n";
for (auto i = pBegin+1; i != pEnd; ++i) {
auto paramName = (*i)->getNameAsString();
boost::trim(paramName);
xacc::InstructionParameter p(paramName);
parameters.push_back(p);
}
function = std::make_shared<xacc::quantum::GateFunction>(
c->getDeclName().getAsString(), parameters);
}
return true;
}
......
......@@ -136,8 +136,16 @@ BOOST_AUTO_TEST_CASE(checkWithParameter) {
auto f = gateqir->getKernel("gateWithParam");
BOOST_VERIFY(f->nInstructions() == 3);
BOOST_VERIFY(f->nParameters() == 1);
gateqir->persist(std::cout);
xacc::InstructionParameter p(3.14);
std::vector<xacc::InstructionParameter> params{p};
f->evaluateVariableParameters(params);
std::cout << "\n\n";
gateqir->persist(std::cout);
}
/*
......
......@@ -34,6 +34,8 @@ include_directories(${CMAKE_SOURCE_DIR}/tpls/fire/tensors/impl)
include_directories(${CMAKE_SOURCE_DIR}/tpls/fire/tpls/eigen)
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}/tpls/rapidjson/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
......
......@@ -51,7 +51,8 @@ class FunctionalGateInstructionVisitor: public BaseInstructionVisitor,
public InstructionVisitor<X>,
public InstructionVisitor<Z>,
public InstructionVisitor<Measure>,
public InstructionVisitor<ConditionalFunction> {
public InstructionVisitor<ConditionalFunction>,
public InstructionVisitor<Rz> {
protected:
std::function<void(Hadamard&)> hAction;
std::function<void(CNOT&)> cnotAction;
......@@ -59,13 +60,14 @@ protected:
std::function<void(Z&)> zAction;
std::function<void(Measure&)> measureAction;
std::function<void(ConditionalFunction&)> condAction;
std::function<void(Rz&)> rzAction;
public:
template<typename HF, typename CNF, typename XF, typename MF, typename ZF,
typename CF>
FunctionalGateInstructionVisitor(HF h, CNF cn, XF x, MF m, ZF z, CF c) :
typename CF, typename RZF>
FunctionalGateInstructionVisitor(HF h, CNF cn, XF x, MF m, ZF z, CF c, RZF rz) :
hAction(h), cnotAction(cn), xAction(x), zAction(z), measureAction(
m), condAction(c) {
m), condAction(c), rzAction(rz) {
}
void visit(Hadamard& h) {
......@@ -86,6 +88,11 @@ public:
void visit(ConditionalFunction& c) {
condAction(c);
}
void visit(Rz& rz) {
rzAction(rz);
}
virtual ~FunctionalGateInstructionVisitor() {}
};
......
......@@ -29,6 +29,7 @@
*
**********************************************************************************/
#include "SimpleAccelerator.hpp"
#include <complex>
namespace xacc {
namespace quantum {
......@@ -220,10 +221,33 @@ void SimpleAccelerator::execute(std::shared_ptr<AcceleratorBuffer> buffer,
std::to_string(bufResultAsInt));
};
auto rz = [&] (Rz& rZGate) {
const std::complex<double> i(0, 1);
double angle = boost::get<double>(rZGate.getParameter(0));
auto matElement = std::exp(i * angle);
ComplexTensor rz(2,2), I(2,2);
I.setValues( { {1, 0}, {0, 1}});
rz.setValues( { {1, 0}, {0, matElement}});
auto actingQubits = rZGate.bits();
ProductList productList;
for (int j = 0; j < qubits->size(); j++) {
productList.push_back(I);
}
// If this is a one qubit gate, just replace
// the currect I in the list with the gate
productList.at(actingQubits[0]) = rz;
// Create a total unitary for this layer of the circuit
ComplexTensor localU = productList.at(0);
for (int j = 1; j < productList.size(); j++) {
localU = localU.kronProd(productList.at(j));
}
qubits->applyUnitary(localU);
};
// Create a Visitor that will execute our lambdas when
// we encounter one
auto visitor = std::make_shared<FunctionalGateInstructionVisitor>(hadamard,
cnot, x, measure, z, cond);
cnot, x, measure, z, cond, rz);
XACCInfo("Execution Simple Accelerator Simulation.");
......
......@@ -156,13 +156,13 @@ public:
stream
<< std::bitset<TotalNumberOfQubits>(i).to_string().substr(
TotalNumberOfQubits - size(), TotalNumberOfQubits) << " -> "
<< std::fabs(bufferState(i)) << "\n";
<< bufferState(i) << "\n";
}
} else {
for (int i = 0; i < bufferState.dimension(0); i++) {
stream << std::bitset<TotalNumberOfQubits>(i).to_string()
<< " -> " << std::fabs(bufferState(i)) << "\n";
<< " -> " << bufferState(i) << "\n";
}
}
}
......@@ -181,7 +181,7 @@ public:
XACCInfo(
std::bitset<TotalNumberOfQubits>(i).to_string() + " -> "
+ std::to_string(std::real(std::fabs(bufferState(i)))));
+ std::to_string(std::fabs(bufferState(i))));
}
}
}
......
......@@ -32,5 +32,9 @@ if (TARGET xacc-scaffold)
add_executable(teleport_scaffold_simpleaccelerator teleport_scaffold_simpleaccelerator.cpp)
target_link_libraries(teleport_scaffold_simpleaccelerator ${Boost_LIBRARIES} dl)
add_executable(single_qubit_rotation single_qubit_rotation.cpp)
target_link_libraries(single_qubit_rotation ${Boost_LIBRARIES} dl)
install(TARGETS single_qubit_rotation DESTINATION examples)
install(TARGETS teleport_scaffold_simpleaccelerator DESTINATION examples)
endif()
......@@ -28,118 +28,53 @@
* Initial API and implementation - Alex McCaskey
*
**********************************************************************************/
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE ProgramTester
#include "XACC.hpp"
#include <boost/test/included/unit_test.hpp>
#include "Program.hpp"
// Quantum Kernel executing teleportation of
// qubit state to another.
const std::string src("__qpu__ rotate (qbit qreg, double phi) {\n"
" X(qreg[0]);\n"
" Rz(qreg[0], phi);\n"
" MeasZ(qreg[0]);\n"
"}\n");
using namespace xacc;
const double pi = 3.1415926;
class FakeIR: public IR {
public:
FakeIR() {
}
virtual std::string toAssemblyString(const std::string& kernelName,
const std::string& accBufferVarName) {
return std::string();}
virtual void persist(std::ostream& stream) {}
virtual void load(std::istream& inStream) {}
virtual void addKernel(std::shared_ptr<Function> kernel) {
int main (int argc, char** argv) {
}
virtual std::shared_ptr<Function> getKernel(const std::string& name) {
// Initialize the XACC Framework
xacc::Initialize(argc, argv);
}
};
// Create a reference to the 10 qubit simulation Accelerator
auto qpu = xacc::getAccelerator("simple");
class FakeAccelerator: virtual public Accelerator {
// Allocate a register of qubits
auto qubitReg = qpu->createBuffer("qreg", 1);
public:
// Create a Program
xacc::Program program(qpu, src);
virtual AcceleratorType getType() {
return qpu_gate;
}
// Request the quantum kernel representing
// the above source code
auto rotate = program.getKernel<double>("rotate");
std::shared_ptr<AcceleratorBuffer> createBuffer(const std::string& varId) {
auto buffer = std::make_shared<AcceleratorBuffer>(varId);
return buffer;
}
std::shared_ptr<AcceleratorBuffer> createBuffer(const std::string& varId,
const int size) {
if (!isValidBufferSize(size)) {
XACCError("Invalid buffer size.");
}
auto buffer = std::make_shared<AcceleratorBuffer>(varId, size);
return buffer;
}
virtual bool isValidBufferSize(const int NBits) {
return NBits <= 10;
}
std::vector<double> angles {pi / 2.0, pi};
virtual std::vector<IRTransformation> getIRTransformations() {
std::vector<IRTransformation> v;
return v;
}
virtual void execute(std::shared_ptr<AcceleratorBuffer> buffer,
const std::shared_ptr<Function> ir) {
}
virtual ~FakeAccelerator() {
}
};
for (auto angle : angles) {
// Execute!
rotate(qubitReg, angle);
class DummyCompiler : public Compiler {
public:
virtual std::shared_ptr<xacc::IR> compile(const std::string& src,
std::shared_ptr<Accelerator> acc) {
return std::make_shared<FakeIR>();
// Look at results
qubitReg->print(std::cout);
}
virtual std::shared_ptr<xacc::IR> compile(const std::string& src) {
return std::make_shared<FakeIR>();
// Finalize the XACC Framework
xacc::Finalize();
}
virtual const std::string getName() {
return "Dummy";
}
return 0;
}
virtual void modifySource() {
}
virtual std::string getBitType() {
return "hello";
}
virtual ~DummyCompiler() {
}
};
// Register the ScaffoldCompiler with the CompilerRegistry.
static xacc::RegisterCompiler<DummyCompiler> X("dummy");
BOOST_AUTO_TEST_CASE(checkBuildRuntimeArguments) {
const std::string src("__qpu__ void teleport() {"
" qbit q[3];"
" H(q[1]);"
" CNot(q[1],q[2]);"
" CNot(q[0], q[1]);"
" H(q[1]);"
" if(q[1].measure()) {"
" X(q[2]);"
" }"
" if(q[1].measure()) {"
" Z(q[2]);"
" }"
"}");
auto acc = std::make_shared<FakeAccelerator>();
acc->createBuffer("qreg");
Program prog(acc, src);
auto k = prog.getKernel("teleport");
// prog.build("--compiler dummy");
}
......@@ -35,6 +35,7 @@
#include <memory>
#include <boost/test/included/unit_test.hpp>
#include "SimpleAccelerator.hpp"
#include "JsonVisitor.hpp"
using namespace xacc::quantum;
......@@ -72,3 +73,68 @@ BOOST_AUTO_TEST_CASE(checkKernelExecution) {
acc.execute(qreg1, f);
}
template<typename ... RuntimeArgs>
std::function<void(RuntimeArgs...)> setParams(
std::shared_ptr<Function> kernel) {
// Create a lambda that executes the kernel on the Accelerator.
return [=](RuntimeArgs... args) {
if (sizeof...(RuntimeArgs) > 0) {
// Store the runtime parameters in a tuple
auto argsTuple = std::make_tuple(args...);
// Loop through the tuple, and add InstructionParameters
// to the parameters vector.
std::vector<InstructionParameter> parameters;
xacc::tuple_for_each(argsTuple, [&](auto value) {
parameters.push_back(InstructionParameter(value));
});
// Evaluate all Variable Parameters
kernel->evaluateVariableParameters(parameters);
}
return;
};
}
BOOST_AUTO_TEST_CASE(checkExecuteKernelWithParameters) {
SimpleAccelerator acc;
auto qreg1 = acc.createBuffer("qreg", 3);
InstructionParameter fParam("phi");
InstructionParameter rzParam("phi");
auto kernel = std::make_shared<GateFunction>("foo",
std::vector<InstructionParameter>{fParam});
auto rz = std::make_shared<Rz>(std::vector<int> { 2 });
rz->setParameter(0, rzParam);
kernel->addInstruction(rz);
JsonVisitor visitor(kernel);
std::cout << visitor.write() << "\n";
BOOST_VERIFY(boost::get<std::string>(kernel->getInstruction(0)->getParameter(0)) == "phi");
auto k = setParams<double>(kernel);
k(3.1415);
JsonVisitor visitor2(kernel);
std::cout << "set new param:\n" << visitor2.write() << "\n";
BOOST_VERIFY(boost::get<double>(kernel->getInstruction(0)->getParameter(0)) == 3.1415);
for (double i = 0.0; i < 4; i+=1.0) {
k(i);
JsonVisitor visitor3(kernel);
std::cout << "set new param " << i << ":\n" << visitor3.write() << "\n";
BOOST_VERIFY(boost::get<double>(kernel->getInstruction(0)->getParameter(0)) == i);
}
}
......@@ -64,7 +64,10 @@ public:
* @param id
* @param name
*/
GateFunction(const std::string& name) : functionName(name) {}
GateFunction(const std::string& name) :
functionName(name), parameters(
std::vector<InstructionParameter> { }) {
}
GateFunction(const std::string& name,
std::vector<InstructionParameter> params) :
functionName(name), parameters(params) {
......@@ -167,45 +170,52 @@ public:
return parameters.size();
}
DEFINE_VISITABLE()
std::map<int,int> cachedVariableInstructions;
virtual void evaluateVariableParameters(std::vector<InstructionParameter> runtimeParameters) {
for (auto inst : instructions) {
if (inst->isComposite()) {
std::dynamic_pointer_cast<Function>(inst)->evaluateVariableParameters(
runtimeParameters);
} else {
if (inst->isParameterized()) {
for (int i = 0; i < inst->nParameters(); i++) {
auto param = inst->getParameter(i);
// See if this is a string parameter
if (param.which() == 3) {
auto variable = boost::get<std::string>(param);
// Get index
auto it = std::find(parameters.begin(),
parameters.end(), param);
if (it == parameters.end()) {
std::cout << "COULD NOT FIND VARIABLE\n";
XACCError("Variable " + variable + " not found in Function parameters.");
} else {
auto index = std::distance(parameters.begin(),
it);
inst->setParameter(index, runtimeParameters[index]);
cachedVariableInstructions.insert(std::make_pair(i, index));
}
} else {
// See if we have a cached instruction
if (cachedVariableInstructions.find(i) != cachedVariableInstructions.end()) {
auto idx = cachedVariableInstructions[i];
inst->setParameter(idx, runtimeParameters[idx]);
}
}
}
}
}
}
}
/**
* This method should simply be implemented to invoke the
* visit() method on the provided QInstructionVisitor.
*
* @param visitor
*/
// virtual void accept(std::shared_ptr<InstructionVisitor> visitor);
// {
// auto v = std::dynamic_pointer_cast<GateInstructionVisitor>(visitor);
// if (v) {
// v->visit(*this);
// } else {
// visitor->visit(*this);
// }
// }
DEFINE_VISITABLE()
};
///**
// */
//template<typename... Ts>
//using GateFunctionRegistry = Registry<GateFunction, Ts...>;
//
///**
// */
//template<typename T, typename... Ts>
//class RegisterGateFunction {
//public:
// RegisterGateFunction(const std::string& name) {
// GateFunctionRegistry<Ts...>::instance()->add(name,
// (std::function<
// std::shared_ptr<xacc::quantum::GateFunction>(
// Ts...)>) ([](Ts... args) {
// return std::make_shared<T>(args...);
// }));
// }
//};
}
}
......
......@@ -36,6 +36,7 @@
#include "GateFunction.hpp"
#include "Hadamard.hpp"
#include "CNOT.hpp"
#include "Rz.hpp"
#include "InstructionIterator.hpp"
using namespace xacc::quantum;
......@@ -112,3 +113,35 @@ BOOST_AUTO_TEST_CASE(checkWalkFunctionTree) {
}
BOOST_AUTO_TEST_CASE(checkEvaluateVariables) {
xacc::InstructionParameter p("phi");
xacc::InstructionParameter fParam("phi");
BOOST_VERIFY(p == fParam);
auto rz = std::make_shared<Rz>(std::vector<int>{0});
rz->setParameter(0, p);
GateFunction f("foo", std::vector<xacc::InstructionParameter>{fParam});
f.addInstruction(rz);
std::cout << f.toString("qreg") << "\n";
xacc::InstructionParameter runtimeValue(3.1415);
f.evaluateVariableParameters(std::vector<xacc::InstructionParameter>{runtimeValue});
BOOST_VERIFY(boost::get<double>(f.getInstruction(0)->getParameter(0)) == 3.1415);
std::cout << "ParamSet:\n" << f.toString("qreg") << "\n";
xacc::InstructionParameter runtimeValue2(6.28);
f.evaluateVariableParameters(std::vector<xacc::InstructionParameter>{runtimeValue2});
std::cout << "ParamSet:\n" << f.toString("qreg") << "\n";
}
......@@ -35,9 +35,9 @@ set (LIBRARY_NAME xacc)
file (GLOB HEADERS program/*.hpp XACC.hpp ir/*.hpp program/*.hpp compiler/*.hpp accelerator/*.hpp utils/*.hpp)
# Get the test files
file(GLOB test_files tests/*Tester.cpp)
#file(GLOB test_files tests/*Tester.cpp)
# Add the tests
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR}" "${Boost_LIBRARIES}")
#add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR}" "${Boost_LIBRARIES}")
install(FILES ${HEADERS} DESTINATION include/xacc)
......@@ -97,6 +97,8 @@ public:
*/
virtual bool isComposite() { return true; }
virtual void evaluateVariableParameters(std::vector<InstructionParameter> parameters) = 0;
/**
* The destructor
*/
......