Commit 057edcae authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Cleaning up Accelerator infrastructure. Simplifying API, updated teleport example

parent c4d7f7db
......@@ -50,36 +50,29 @@ const std::string src("__qpu__ teleport (qbit qreg) {\n"
int main (int argc, char** argv) {
// Initialize the XACC Framework
xacc::Initialize();
// Create a convenient alias for our simulator...
using CircuitSimulator = xacc::quantum::FireTensorAccelerator<6>;
// Create a reference to the 10 qubit simulation Accelerator
auto qpu = xacc::getAccelerator("firetensor");
// Create a reference to the 6 qubit simulation Accelerator
auto qpu = std::make_shared<CircuitSimulator>();
// Allocate 3 qubits, give them a unique identifier...
// Allocate a register of qubits
auto qubitReg = qpu->createBuffer("qreg", 3);
using QubitRegisterType = decltype(qubitReg);
// Construct a new XACC Program
xacc::Program quantumProgram(qpu, src);
// Build the program using Scaffold comipler
// and output the Graph Intermediate Representation
quantumProgram.build("--compiler scaffold "
"--writeIR teleport.xir");
// Create a Program
xacc::Program program(qpu, src);
// Retrieve the created kernel. It takes a
// qubit register as input
auto teleport = quantumProgram.getKernel<QubitRegisterType>("teleport");
// Request the quantum kernel representing
// the above source code
auto teleport = program.getKernel("teleport");
// Execute the kernel with the qubit register!
// Execute!
teleport(qubitReg);
// Pretty print the resultant state
qubitReg->printBufferState(std::cout);
// Look at results
qubitReg->print();
// Finalize the XACC Framework
xacc::Finalize();
return 0;
......
......@@ -39,8 +39,8 @@ namespace quantum {
/**
*
*/
template<typename BitsType>
class QPUGate: virtual public Accelerator<BitsType> {
//template<typename BitsType>
class QPUGate: virtual public Accelerator {
public:
/**
......
#ifndef QUANTUM_GATE_SIMULATEDQUBITS_HPP_
#define QUANTUM_GATE_SIMULATEDQUBITS_HPP_
#include "Accelerator.hpp"
#include "AcceleratorBuffer.hpp"
#include <complex>
#include "Tensor.hpp"
#include <bitset>
namespace xacc {
......@@ -120,7 +121,7 @@ public:
*
* @param stream
*/
void printBufferState(std::ostream& stream) {
virtual void print(std::ostream& stream) {
if (size() < TotalNumberOfQubits) {
for (int i = 0; i < bufferState.dimension(0); i++) {
stream
......@@ -137,6 +138,23 @@ public:
}
}
virtual void print() {
auto console = spdlog::get("console");
if (size() < TotalNumberOfQubits) {
for (int i = 0; i < bufferState.dimension(0); i++) {
console->info(std::bitset<TotalNumberOfQubits>(i).to_string().substr(
TotalNumberOfQubits - size(), TotalNumberOfQubits) + " -> "
+ std::to_string(std::real(bufferState(i))));
}
} else {
for (int i = 0; i < bufferState.dimension(0); i++) {
console->info(std::bitset<TotalNumberOfQubits>(i).to_string()
+ " -> " + std::to_string(std::real(bufferState(i))));
}
}
}
virtual ~SimulatedQubits() {}
};
}
......
......@@ -50,10 +50,29 @@ using QuantumGraphIR = xacc::GraphIR<QuantumCircuit>;
* Framework's tensor module to model a specific set of quantum gates. It uses these
* tensors to build up the unitary matrix described by the circuit.
*/
template<const int NQubits>
class FireTensorAccelerator : virtual public QPUGate<SimulatedQubits<NQubits>> {
class FireTensorAccelerator : virtual public QPUGate {
public:
std::shared_ptr<AcceleratorBuffer> createBuffer(const std::string& varId) {
auto buffer = std::make_shared<SimulatedQubits<10>>(varId);
storeBuffer(varId, buffer);
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<SimulatedQubits<10>>(varId, size);
storeBuffer(varId, buffer);
return buffer;
}
virtual bool isValidBufferSize(const int NBits) {
return NBits <= 10;
}
/**
* The constructor, create tensor gates
*/
......@@ -81,13 +100,10 @@ public:
*
* @param ir
*/
virtual void execute(const std::string& bufferId, const std::shared_ptr<xacc::IR> ir) {
virtual void execute(std::shared_ptr<AcceleratorBuffer> buffer, const std::shared_ptr<xacc::IR> ir) {
// Get the requested qubit buffer
auto qubits = this->allocatedBuffers[bufferId];
if (!qubits) {
XACCError("Invalid buffer id. Could not get qubit buffer.");
}
auto qubits = std::static_pointer_cast<SimulatedQubits<10>>(buffer);
// Set the size
int nQubits = qubits->size();
......@@ -210,11 +226,6 @@ public:
if (gateName != "FinalState" && gateName != "InitialState") {
// Regular Gate operations...
if (isParameterized(gate)) {
auto g = getParameterizedGate(gate);
gates.insert(std::make_pair(gateName, g));
}
if (actingQubits.size() == 1) {
// If this is a one qubit gate, just replace
......@@ -271,34 +282,16 @@ public:
protected:
bool isParameterized(CircuitNode& node) {
return !std::get<5>(node.properties).empty();
}
fire::Tensor<2, fire::EigenProvider, std::complex<double>> getParameterizedGate(
CircuitNode& node) {
fire::Tensor<2, fire::EigenProvider, std::complex<double>> g(2, 2);
if (std::get<0>(node.properties) == "rz") {
// Fixme... How to avoid the double here???
auto param = this->template getRuntimeParameter<double>(
std::get<5>(node.properties)[0]);
std::complex<double> i(0, 1);
auto rotation = std::exp(i * param);
g.setValues( { { 1, 0 }, { 0, rotation } });
} else {
XACCError("We don't know what this gate is... yet.");
}
return g;
}
/**
* Mapping of gate names to actual gate matrices.
*/
std::map<std::string, fire::Tensor<2, fire::EigenProvider, std::complex<double>>> gates;
};
// Register the ScaffoldCompiler with the CompilerRegistry.
static xacc::RegisterAccelerator<xacc::quantum::FireTensorAccelerator> X("firetensor");
}
}
......
......@@ -40,8 +40,8 @@ using namespace xacc::quantum;
BOOST_AUTO_TEST_CASE(checkConstruction) {
FireTensorAccelerator<3> acc;
auto qreg = acc.createBuffer("qreg", 3);
FireTensorAccelerator acc;
auto qreg1 = acc.createBuffer("qreg", 3);
// Create a graph IR modeling a
// quantum teleportation kernel
......@@ -95,7 +95,9 @@ BOOST_AUTO_TEST_CASE(checkConstruction) {
auto graphir = std::make_shared<xacc::GraphIR<QuantumCircuit>>();
graphir->read(iss);
acc.execute("qreg", graphir);
acc.execute(qreg1, graphir);
auto qreg = std::static_pointer_cast<SimulatedQubits<10>>(qreg1);
BOOST_VERIFY(std::real(qreg->getState()(1) * qreg->getState()(1)) == 1 ||
std::real(qreg->getState()(5) * qreg->getState()(5)) == 1 ||
......
......@@ -206,7 +206,7 @@ void ScaffoldCompiler::modifySource() {
std::shared_ptr<IR> ScaffoldCompiler::compile(const std::string& src,
std::shared_ptr<IAccelerator> acc) {
std::shared_ptr<Accelerator> acc) {
kernelSource = src;
......@@ -224,7 +224,8 @@ std::shared_ptr<IR> ScaffoldCompiler::compile(const std::string& src,
it++) {
if (boost::contains(it->first, bitTypeStr)) {
varName = it->second;
auto nBits = accelerator->getBufferSize(varName);
boost::trim(varName);
auto nBits = accelerator->getBuffer(varName)->size();
boost::replace_first(kernelSource,
std::string(bitTypeStr + " " + varName),
std::string(
......@@ -313,9 +314,6 @@ std::shared_ptr<IR> ScaffoldCompiler::compile(const std::string& src) {
} // end namespace xacc
//
//// Required in CPP file to be discovered by factory pattern
//REGISTER_XACCOBJECT_WITH_XACCTYPE(xacc::quantum::ScaffoldCompiler, "compiler",
// "scaffold");
// Register the ScaffoldCompiler with the CompilerRegistry.
static xacc::RegisterCompiler<xacc::quantum::ScaffoldCompiler> X("scaffold");
......@@ -60,7 +60,7 @@ public:
* @return ir XACC intermediate representation
*/
virtual std::shared_ptr<xacc::IR> compile(const std::string& src,
std::shared_ptr<IAccelerator> acc);
std::shared_ptr<Accelerator> acc);
virtual std::shared_ptr<xacc::IR> compile(const std::string& src);
......
......@@ -38,6 +38,8 @@
namespace xacc {
bool xaccFrameworkInitialized = false;
/**
* This method should be called by
* clients to initialize the XACC framework.
......@@ -50,8 +52,29 @@ void Initialize() {
auto compilerRegistry = xacc::CompilerRegistry::instance();
auto s = compilerRegistry->size();
console->info("\t[xacc::compiler] XACC has " + std::to_string(s) + " Compiler" + (s==1 ? "" : "s") + " available.");
xacc::xaccFrameworkInitialized = true;
}
std::shared_ptr<Accelerator> getAccelerator(const std::string& name) {
if (!xacc::xaccFrameworkInitialized) {
XACCError("XACC not initialized before use. Please execute xacc::Initialize() before using API.");
}
auto acc = AcceleratorRegistry::instance()->create(name);
if (acc) {
return acc;
} else {
XACCError("Invalid Accelerator. Could not find " + name + " in Accelerator Registry.");
}
}
//template<typename ... RuntimeArgs>
//std::function<void(std::shared_ptr<AcceleratorBuffer>, RuntimeArgs...)> createKernel(
// const std::string& kernelName, std::shared_ptr<Accelerator> acc,
// const std::string& src) {
// xacc::Program p(acc, src);
// return p.getKernel<RuntimeArgs...>(kernelName);
//}
/**
* This method should be called by clients to
* clean up and finalize the XACC framework. It should
......@@ -61,6 +84,7 @@ void Finalize() {
auto console = spdlog::get("console");
console->info("[xacc] XACC Finalizing\n\tCleaning up Compiler Registry.");
xacc::CompilerRegistry::instance()->destroy();
xacc::xaccFrameworkInitialized = false;
}
}
......
......@@ -35,71 +35,40 @@
#include <vector>
#include <array>
#include <bitset>
#include "spdlog/spdlog.h"
#include "IRTransformation.hpp"
#include "XACCError.hpp"
#include "AcceleratorBuffer.hpp"
#include "Registry.hpp"
namespace xacc {
/**
* Utility structs to help determine if
* we have been given valid Vertices.
*/
template<typename T, typename = void>
struct is_valid_bitstype: std::false_type {
};
template<typename T>
struct is_valid_bitstype<T, decltype(std::declval<T>().N, void())> : std::true_type {
};
/**
* The types of Accelerators that XACC interacts with
*/
enum AcceleratorType { qpu_gate, qpu_aqc, npu };
class RuntimeType {
public:
};
template<typename T>
class ConcreteRuntimeType : public RuntimeType {
public:
T value;
enum AcceleratorType {
qpu_gate, qpu_aqc, npu
};
/**
* The Accelerator class provides a high-level abstraction
* for XACC's interaction with attached post-exascale
* accelerators (quantum and neuromorphic processing units).
*
* Derived Accelerators must provide a valid execute implementation
* that takes XACC IR and executes it on the attached hardware or
* simulator.
*
* @author Alex McCaskey
* Derived Accelerators must provide a list of IRTransformation
* instances that transform XACC IR to be amenable to execution
* on the hardware.
*
* STORE ALLOCATED BUFFERS
*/
class AcceleratorBuffer {
public:
AcceleratorBuffer(const std::string& str) :
bufferId(str) {
}
AcceleratorBuffer(const std::string& str, const int N) :
bufferId(str), bufferSize(N) {
}
template<typename ... Indices>
AcceleratorBuffer(const std::string& str, int firstIndex,
Indices ... indices) :
bufferId(str), bufferSize(1 + sizeof...(indices)) {
}
int size() {
return bufferSize;
}
std::string name() {
return bufferId;
}
protected:
class Accelerator {
int bufferSize = 0;
std::string bufferId;
};
class IAccelerator {
public:
/**
* Return the type of this Accelerator.
*
......@@ -119,149 +88,55 @@ public:
*
* @param ir
*/
virtual void execute(const std::string& bufferId, const std::shared_ptr<IR> ir) = 0;
/**
* Return the number of bits that the user most recently
* requested.
*
* @return nBits The number of requested bits
*/
virtual int getBufferSize(const std::string& id) = 0;
virtual int getBufferSize() = 0;
template<typename T>
void setRuntimeParameter(const std::string& name, T param) {
auto type = std::make_shared<ConcreteRuntimeType<T>>();
type->value = param;
runtimeParameters.insert(std::make_pair(name, type));
}
template<typename T>
T getRuntimeParameter(const std::string& name) {
auto rp = runtimeParameters[name];
auto cp = std::static_pointer_cast<ConcreteRuntimeType<T>>(rp);
return cp->value;
}
virtual ~IAccelerator() {}
protected:
virtual void execute(std::shared_ptr<AcceleratorBuffer> buffer,
const std::shared_ptr<IR> ir) = 0;
virtual bool isValidBufferSize(const int NBits) {return true;}
virtual std::shared_ptr<AcceleratorBuffer> createBuffer(const std::string& varId) = 0;
std::map<std::string, std::shared_ptr<RuntimeType>> runtimeParameters;
virtual std::shared_ptr<AcceleratorBuffer> createBuffer(const std::string& varId, const int size) = 0;
};
/**
* The Accelerator class provides a high-level abstraction
* for XACC's interaction with attached post-exascale
* accelerators (quantum and neuromorphic processing units).
*
* Derived Accelerators must provide a valid execute implementation
* that takes XACC IR and executes it on the attached hardware or
* simulator.
*
* Derived Accelerators must provide a list of IRTransformation
* instances that transform XACC IR to be amenable to execution
* on the hardware.
*/
template<typename BitsType>
class Accelerator : public IAccelerator {
static_assert(std::is_base_of<AcceleratorBuffer, BitsType>::value, "Accelerators "
"can only be instantiated with a valid AcceleratorBuffer type as "
"the template parameter.");
using BitsTypePtr = std::shared_ptr<BitsType>;
public:
Accelerator() {
totalSystemBuffer = std::make_shared<BitsType>("default");
allocatedBuffers.insert(std::make_pair("default", totalSystemBuffer));
}
BitsTypePtr createBuffer(const std::string& varId) {
if (isValidBufferVarId(varId)) {
auto buffer = std::make_shared<BitsType>(varId);
allocatedBuffers.insert(std::make_pair(varId, buffer));
return buffer;
virtual std::shared_ptr<AcceleratorBuffer> getBuffer(const std::string& varid) {
if (isValidBuffer(varid)) {
return allocatedBuffers[varid];
} else {
XACCError("Invalid buffer variable name.");
XACCError("Could not find AcceleratorBuffer with id " + varid);
}
}
BitsTypePtr createBuffer(const std::string& varId, const int size) {
if (!isValidBufferVarId(varId)) {
XACCError("Invalid buffer variable name.");
}
if (!isValidBufferSize(size)) {
XACCError("Invalid buffer size.");
}
auto buffer = std::make_shared<BitsType>(varId, size);
allocatedBuffers.insert(std::make_pair(varId, buffer));
return buffer;
}
template<typename... Indices>
BitsTypePtr createBuffer(const std::string& varId, int firstIndex,
Indices ... indices) {
if (!isValidBufferVarId(varId)) {
XACCError("Invalid buffer variable name.");
}
if (!isValidBufferSize(sizeof...(indices) + 1)) {
XACCError("Invalid buffer size.");
}
if (!validIndices(indices...)) {
XACCError("Invalid buffer indices.");
}
auto buffer = std::make_shared<BitsType>(varId, firstIndex, indices...);
allocatedBuffers.insert(std::make_pair(varId, buffer));
return buffer;
}
/**
* Return the number of bits that the user most recently
* requested.
*
* @return nBits The number of requested bits
*/
virtual int getBufferSize(const std::string& id) {
return allocatedBuffers[id]->size();
}
virtual int getBufferSize() {
return allocatedBuffers["default"]->size();
}
BitsTypePtr getExistingBuffer(const std::string& varId) {
return allocatedBuffers[varId];
}
virtual bool isValidBufferSize(const int NBits) = 0;
/**
* Destructor
*/
virtual ~Accelerator() {}
virtual ~Accelerator() {
}
protected:
std::map<std::string, BitsTypePtr> allocatedBuffers;
void storeBuffer(const std::string& id, std::shared_ptr<AcceleratorBuffer> b) {
allocatedBuffers.insert(std::make_pair(id, b));
}
BitsTypePtr totalSystemBuffer;
private:
bool isValidBufferVarId(const std::string& str) {
return allocatedBuffers.find(str) == std::end(allocatedBuffers);
}
std::map<std::string, std::shared_ptr<AcceleratorBuffer>> allocatedBuffers;
template<typename... Indices>
bool validIndices(int firstIndex, Indices... indices) {
return false;
bool isValidBuffer(const std::string& str) {
return allocatedBuffers.find(str) != allocatedBuffers.end();
}
};
using AcceleratorRegistry = Registry<Accelerator>;
template<typename T>
class RegisterAccelerator {
public:
RegisterAccelerator(const std::string& name) {
AcceleratorRegistry::instance()->add(name,
(std::function<std::shared_ptr<xacc::Accelerator>()>) ([]() {
return std::make_shared<T>();
}));
}
};
}
#endif
/*
* AcceleratorBuffer.hpp
*
* Created on: Apr 11, 2017
* Author: aqw
*/
#ifndef XACC_ACCELERATOR_ACCELERATORBUFFER_HPP_
#define XACC_ACCELERATOR_ACCELERATORBUFFER_HPP_
#include <string>
#include "spdlog/spdlog.h"
/**
*
* @author Alex McCaskey
*/
class AcceleratorBuffer {