diff --git a/examples/quantum/gate/teleport_scaffold.cpp b/examples/quantum/gate/teleport_scaffold.cpp index c10a774767921d6107e0775985ba2474d3283ef8..0675e99c39f4904b8cdfd0c7086b86b19259fa8d 100644 --- a/examples/quantum/gate/teleport_scaffold.cpp +++ b/examples/quantum/gate/teleport_scaffold.cpp @@ -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; diff --git a/quantum/gate/accelerators/QPUGate.hpp b/quantum/gate/accelerators/QPUGate.hpp index 0c212d1c044bcdfb22191c8684707392c01ad870..aceca2d1d6da531d30b70a4ea635eaafef1e8781 100644 --- a/quantum/gate/accelerators/QPUGate.hpp +++ b/quantum/gate/accelerators/QPUGate.hpp @@ -39,8 +39,8 @@ namespace quantum { /** * */ -template<typename BitsType> -class QPUGate: virtual public Accelerator<BitsType> { +//template<typename BitsType> +class QPUGate: virtual public Accelerator { public: /** diff --git a/quantum/gate/accelerators/SimulatedQubits.hpp b/quantum/gate/accelerators/SimulatedQubits.hpp index dcd956d607bbdd7b190bf4e1ffed3a7017edae08..7a33f72110a9d331b7c8840a713ef53978b09cbc 100644 --- a/quantum/gate/accelerators/SimulatedQubits.hpp +++ b/quantum/gate/accelerators/SimulatedQubits.hpp @@ -1,9 +1,10 @@ #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() {} }; } diff --git a/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp b/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp index eaf05bfa977d162a62a65a5133335dbdd1d73e47..8a374697322b16a8abf70738545cf4316dcab997 100644 --- a/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp +++ b/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp @@ -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"); + } } diff --git a/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp b/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp index 0363497c7632533a7a933dfd72eef50426fac0a5..ad3f534604d0d440564db4474f5b762fce395a25 100644 --- a/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp +++ b/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp @@ -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 || diff --git a/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp b/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp index 535988c6b30883ded20f2fb038bfb10f0673b0ca..f78cf0bbdc728adce04ef521be18a22f2d40c95c 100644 --- a/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp +++ b/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp @@ -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"); diff --git a/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp b/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp index a14b9bb57f0301af73b16385c8bde017c6c3cb0b..d2e1ab0a24dd040fa21e1d24ad076db588035968 100644 --- a/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp +++ b/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp @@ -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); diff --git a/xacc/XACC.hpp b/xacc/XACC.hpp index b552dc42027a77c0f30ff0099bb35ff95513dffe..d6f6e1f463e476c07612dd6e93e90536479b2352 100644 --- a/xacc/XACC.hpp +++ b/xacc/XACC.hpp @@ -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; } } diff --git a/xacc/accelerator/Accelerator.hpp b/xacc/accelerator/Accelerator.hpp index 2bc1ecf13e573a244be4eaf370e07d7918e04a99..3f144ccc4ee4f2089907b173043cf73d12520594 100644 --- a/xacc/accelerator/Accelerator.hpp +++ b/xacc/accelerator/Accelerator.hpp @@ -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 diff --git a/xacc/accelerator/AcceleratorBuffer.hpp b/xacc/accelerator/AcceleratorBuffer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d68ff6d5e0d5ffc5bcf6ce6a1fc03cb310d94951 --- /dev/null +++ b/xacc/accelerator/AcceleratorBuffer.hpp @@ -0,0 +1,52 @@ +/* + * 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 { +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; + } + + virtual void print() { + } + virtual void print(std::ostream& stream) { + } + + virtual ~AcceleratorBuffer() {} + +protected: + + int bufferSize = 0; + std::string bufferId; +}; + + +#endif /* XACC_ACCELERATOR_ACCELERATORBUFFER_HPP_ */ diff --git a/xacc/compiler/Compiler.hpp b/xacc/compiler/Compiler.hpp index 23ef27ddb40f3aa842e0f3fac5f9c25cf5e6e6c3..b789da6656d4eeade686f6c9604a75a7265aed81 100644 --- a/xacc/compiler/Compiler.hpp +++ b/xacc/compiler/Compiler.hpp @@ -55,7 +55,7 @@ public: * @return ir Intermediate representation for provided source kernel code. */ virtual std::shared_ptr<IR> compile(const std::string& src, - std::shared_ptr<IAccelerator> acc) = 0; + std::shared_ptr<Accelerator> acc) = 0; virtual std::shared_ptr<IR> compile(const std::string& src) = 0; @@ -71,7 +71,7 @@ protected: /** * */ - std::shared_ptr<IAccelerator> accelerator; + std::shared_ptr<Accelerator> accelerator; }; /** diff --git a/xacc/program/Program.hpp b/xacc/program/Program.hpp index 256c4a8e3469258a6fd133510b92a48d7bd754cc..09307e0da73a1727fb776785c9094a27132e013a 100644 --- a/xacc/program/Program.hpp +++ b/xacc/program/Program.hpp @@ -77,7 +77,7 @@ protected: * Reference to the attached Accelerator to * use in this compilation and execution */ - std::shared_ptr<IAccelerator> accelerator; + std::shared_ptr<Accelerator> accelerator; /** * Reference to a set of compiler command @@ -93,26 +93,6 @@ protected: std::shared_ptr<Compiler> compiler; -public: - - /** - * The Constructor, takes the Accelerator - * to execute on, and the source to compile and execute - * - * @param acc Attached Accelerator to execute - * @param sourceFile The kernel source code - */ - Program(std::shared_ptr<IAccelerator> acc, const std::string& sourceFile) : - src(sourceFile) { - accelerator = std::move(acc); - compilerOptions = std::make_shared<options_description>( - "XACC Compiler Options"); - compilerOptions->add_options()("help", "Help Message")("compiler", - value<std::string>()->default_value("scaffold"), - "Indicate the compiler to be used.") - ("writeIR", value<std::string>(), "Persist generated IR to provided file name."); - } - /** * Execute the compilation mechanism on the provided program * source kernel code to produce XACC IR that can be executed @@ -123,7 +103,6 @@ public: */ template<typename ... RuntimeArgs> void build(const std::string& compilerArgStr, RuntimeArgs ... runtimeArgs) { - // Get the user-specified compiler parameters as a map variables_map compileParameters; store( @@ -135,7 +114,6 @@ public: // Create the appropriate compiler compiler = xacc::CompilerRegistry::instance()->create(compilerToRun); - // Make sure we got a valid if (!compiler) { XACCError("Invalid Compiler.\n"); @@ -170,27 +148,37 @@ public: return; } +public: + + /** + * The Constructor, takes the Accelerator + * to execute on, and the source to compile and execute + * + * @param acc Attached Accelerator to execute + * @param sourceFile The kernel source code + */ + Program(std::shared_ptr<Accelerator> acc, const std::string& sourceFile) : + src(sourceFile) { + accelerator = std::move(acc); + compilerOptions = std::make_shared<options_description>( + "XACC Compiler Options"); + compilerOptions->add_options()("help", "Help Message")("compiler", + value<std::string>()->default_value("scaffold"), + "Indicate the compiler to be used.") + ("writeIR", value<std::string>(), "Persist generated IR to provided file name."); + } + /** * * @param name * @param args * @return */ - template<typename BitsType, typename ... RuntimeArgs> - std::function<void(BitsType, RuntimeArgs...)> getKernel(const std::string& kernelName) { - return [&](BitsType bits, RuntimeArgs... args) { - if (sizeof...(RuntimeArgs) > 0) { - auto argTuple = std::make_tuple<RuntimeArgs...>(args...); -// auto argumentNames = compiler->getKernelArgumentVariableNames(); -// assert(argumentNames.size()-1 == sizeof...(RuntimeArgs)); - int counter = 1; - xacc::for_each(argTuple, [&](auto element) { -// accelerator->setRuntimeParameter(argumentNames[counter], element); - counter++; - }); - } - - accelerator->execute(bits->name(), xaccIR); + template<typename ... RuntimeArgs> + std::function<void(std::shared_ptr<AcceleratorBuffer>, RuntimeArgs...)> getKernel(const std::string& kernelName) { + return [&](std::shared_ptr<AcceleratorBuffer> buffer, RuntimeArgs... args) { + build("--compiler scaffold", args...); + accelerator->execute(buffer, xaccIR); return; }; } diff --git a/xacc/tests/CompilerTester.cpp b/xacc/tests/CompilerTester.cpp index c60a3cb1968cc3e1f1b5df98fc556cce21b29458..7c9bf5e01a471eb784450fc492e2477fe8ef974d 100644 --- a/xacc/tests/CompilerTester.cpp +++ b/xacc/tests/CompilerTester.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(checkKernelArgs) { auto compiler = std::shared_ptr<Compiler>(new FakeCompiler()); - auto a = std::dynamic_pointer_cast<IAccelerator>(acc); + auto a = std::dynamic_pointer_cast<Accelerator>(acc); compiler->compile(src, a); auto asFake = std::dynamic_pointer_cast<FakeCompiler>(compiler); diff --git a/xacc/tests/FakeAccelerator.hpp b/xacc/tests/FakeAccelerator.hpp index cec9a90f7774e4e1acd8d9d866ba9f8836ebf3b9..5f35740f54fb58600d93086325aed1fd8d60dc8b 100644 --- a/xacc/tests/FakeAccelerator.hpp +++ b/xacc/tests/FakeAccelerator.hpp @@ -36,7 +36,7 @@ using namespace xacc; -class FakeAccelerator: virtual public Accelerator<AcceleratorBuffer> { +class FakeAccelerator: virtual public Accelerator { public: @@ -44,11 +44,29 @@ public: return qpu_gate; } + 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; + } + virtual std::vector<IRTransformation> getIRTransformations() { std::vector<IRTransformation> v; return v; } - virtual void execute(const std::string& bufferId, + virtual void execute(std::shared_ptr<AcceleratorBuffer> buffer, const std::shared_ptr<IR> ir) { } virtual ~FakeAccelerator() { diff --git a/xacc/tests/FakeCompiler.hpp b/xacc/tests/FakeCompiler.hpp index f3b406a5a3d9079cb4efbde463dd740b9870ae6a..9d5bcf73bdab92a2ec50ac390c0308b2c60c0b43 100644 --- a/xacc/tests/FakeCompiler.hpp +++ b/xacc/tests/FakeCompiler.hpp @@ -40,7 +40,7 @@ class FakeCompiler: public Compiler { public: virtual std::shared_ptr<xacc::IR> compile(const std::string& src, - std::shared_ptr<IAccelerator> acc) { + std::shared_ptr<Accelerator> acc) { return std::make_shared<FakeIR>(); } diff --git a/xacc/tests/ProgramTester.cpp b/xacc/tests/ProgramTester.cpp index 3cec30ebe1fb237bd09292741d76de523837e0e8..9f16ce8386bda7f351b96bef62ace053571dfeb0 100644 --- a/xacc/tests/ProgramTester.cpp +++ b/xacc/tests/ProgramTester.cpp @@ -32,7 +32,7 @@ #define BOOST_TEST_MODULE ProgramTester #include <boost/test/included/unit_test.hpp> -#include "Program.hpp" +#include "XACC.hpp" #include "FakeIR.hpp" #include "FakeAccelerator.hpp" #include "FireTensorAccelerator.hpp" @@ -42,7 +42,7 @@ using namespace xacc; class DummyCompiler : public Compiler { public: virtual std::shared_ptr<xacc::IR> compile(const std::string& src, - std::shared_ptr<IAccelerator> acc) { + std::shared_ptr<Accelerator> acc) { return std::make_shared<FakeIR>(); } @@ -85,7 +85,8 @@ BOOST_AUTO_TEST_CASE(checkBuildRuntimeArguments) { auto acc = std::make_shared<FakeAccelerator>(); acc->createBuffer("qreg"); Program prog(acc, src); - prog.build("--compiler dummy"); + auto k = prog.getKernel("teleport"); +// prog.build("--compiler dummy"); } BOOST_AUTO_TEST_CASE(checkRuntimeGateParameter) { @@ -149,36 +150,31 @@ BOOST_AUTO_TEST_CASE(checkTeleportScaffold) { " if (creg[1] == 1) X(qreg[2]);\n" "}\n"); - // Create a convenient alias for our simulator... - using CircuitSimulator = xacc::quantum::FireTensorAccelerator<6>; - + xacc::Initialize(); // Create a reference to the 6 qubit simulation Accelerator - auto qpu = std::make_shared<CircuitSimulator>(); + auto qpu = xacc::getAccelerator("firetensor"); // Allocate 3 qubits, give them a unique identifier... auto qreg = qpu->createBuffer("qreg", 3); - using QubitRegisterType = decltype(qreg); // 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"); - // Retrieve the created kernel. It takes a // qubit register as input - auto teleport = quantumProgram.getKernel<QubitRegisterType>("teleport"); + auto teleport = quantumProgram.getKernel("teleport"); // Execute the kernel with the qubit register! teleport(qreg); + xacc::Finalize(); // Pretty print the resultant state - qreg->printBufferState(std::cout); + auto simqreg = std::static_pointer_cast<xacc::quantum::SimulatedQubits<10>>(qreg); + simqreg->print(); - BOOST_VERIFY(std::real(qreg->getState()(1) * qreg->getState()(1)) == 1 || - std::real(qreg->getState()(5) * qreg->getState()(5)) == 1 || - std::real(qreg->getState()(3) * qreg->getState()(3)) == 1 || - std::real(qreg->getState()(7) * qreg->getState()(7)) == 1); + BOOST_VERIFY(std::real(simqreg->getState()(1) * simqreg->getState()(1)) == 1 || + std::real(simqreg->getState()(5) * simqreg->getState()(5)) == 1 || + std::real(simqreg->getState()(3) * simqreg->getState()(3)) == 1 || + std::real(simqreg->getState()(7) * simqreg->getState()(7)) == 1); } diff --git a/xacc/utils/Registry.hpp b/xacc/utils/Registry.hpp index c464e01ddc854cc779a1f5fd7c8af5d907f71f2a..c33cbac38f4d062288e7398472f485116a1dfb8c 100644 --- a/xacc/utils/Registry.hpp +++ b/xacc/utils/Registry.hpp @@ -48,7 +48,7 @@ namespace xacc { * that the Registry return a new created instance of * the template parameter T. */ -template<typename T> +template<typename T, typename... TArgs> class Registry : public Singleton<Registry<T>> { protected: diff --git a/xacc/utils/XACCError.hpp b/xacc/utils/XACCError.hpp index 51a68d2ac7b407af327b878b6b4f1d8442191203..7833057962ba12a2ed450cfbb7fe073dbc302d36 100644 --- a/xacc/utils/XACCError.hpp +++ b/xacc/utils/XACCError.hpp @@ -3,6 +3,7 @@ #include <exception> #include <sstream> +#include "spdlog/spdlog.h" namespace xacc { @@ -29,7 +30,8 @@ public: #define XACCError(errorMsg) \ { \ - throw xacc::XACCException("\n\n XACC Error caught! \n\n" \ + spdlog::get("console")->error(std::string(errorMsg)); \ + throw xacc::XACCException("\n\n XACC Error caught! \n\n" \ + std::string(errorMsg) + "\n\n"); \ }