diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d8e2b4b493b7670738aa1925406e9a016ba04fa..d728ec13040359dd924cafa0f36221145d3fe6d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ cmake_minimum_required(VERSION 2.8) set(CMAKE_DISABLE_IN_SOURCE_BUILDS ON) set(CMAKE_DISABLE_SOURCE_CHANGES ON) set(CMAKE_STANDARD_REQUIRED ON) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 14) message(STATUS "C++ version ${CXX_STANDARD} configured.") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules") diff --git a/examples/quantum/gate/CMakeLists.txt b/examples/quantum/gate/CMakeLists.txt index 77bd2da428a55883881264df094cdd861cf0c337..f0fb15b997030b0acac4447ff4b0749cb7152254 100644 --- a/examples/quantum/gate/CMakeLists.txt +++ b/examples/quantum/gate/CMakeLists.txt @@ -29,5 +29,11 @@ # #**********************************************************************************/ include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/accelerators) +include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/accelerators/eigenaccelerator) +include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen) +include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors) +include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors/impl) +include_directories(${CMAKE_SOURCE_DIR}/quantum/gate/utils) + add_executable(teleport_scaffold teleport_scaffold.cpp) target_link_libraries(teleport_scaffold xacc-scaffold ${Boost_LIBRARIES}) \ No newline at end of file diff --git a/examples/quantum/gate/teleport_scaffold.cpp b/examples/quantum/gate/teleport_scaffold.cpp index 69ed70240ba8ba64b29e06f78a94765ee0ca7894..7f5eb6008bca298863b99f4280a3e8afc73b6d19 100644 --- a/examples/quantum/gate/teleport_scaffold.cpp +++ b/examples/quantum/gate/teleport_scaffold.cpp @@ -28,17 +28,17 @@ * Initial API and implementation - Alex McCaskey * **********************************************************************************/ -#include "Program.hpp" -#include "Qubits.hpp" +#include "XACC.hpp" +#include "EigenAccelerator.hpp" /** * FIXME For now, create a fake accelerator * This will later come from QVM */ -class IBM5Qubit: public xacc::Accelerator { +class IBM5Qubit: public xacc::quantum::QPUGate<5> { public: - virtual AcceleratorType getType() { - return AcceleratorType::qpu_gate; + virtual xacc::AcceleratorType getType() { + return xacc::AcceleratorType::qpu_gate; } virtual std::vector<xacc::IRTransformation> getIRTransformations() { std::vector<xacc::IRTransformation> v; @@ -77,10 +77,10 @@ const std::string src("__qpu__ teleport () {\n" int main (int argc, char** argv) { // Create a reference to the IBM5Qubit Accelerator - auto ibm_qpu = std::make_shared<IBM5Qubit>(); + auto ibm_qpu = std::make_shared<xacc::quantum::EigenAccelerator<3>>(); // Allocate some qubits, give them a unique identifier... - auto qreg = ibm_qpu->allocate<xacc::quantum::Qubits<3>>("qreg"); + auto qreg = ibm_qpu->allocate("qreg"); // Construct a new Program xacc::Program quantumProgram(ibm_qpu, src); @@ -95,7 +95,8 @@ int main (int argc, char** argv) { teleport(); // Get the execution result - auto bits = qreg.toBits(); + qreg->printState(std::cout); + auto bits = qreg->toBits(); return 0; } diff --git a/quantum/gate/accelerators/CMakeLists.txt b/quantum/gate/accelerators/CMakeLists.txt index 121ba18ad3aefbeab98e486e438186c7e8d06d4c..cedd6e342f89b23ec40bb75bd70acec2ca712b6a 100644 --- a/quantum/gate/accelerators/CMakeLists.txt +++ b/quantum/gate/accelerators/CMakeLists.txt @@ -30,8 +30,9 @@ #**********************************************************************************/ include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensor) +include_directories(${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen) # Gather tests file (GLOB test_files tests/*.cpp) -add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors/impl;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen" "${Boost_LIBRARIES}") +add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/eigenaccelerator;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tensors/impl;${CMAKE_SOURCE_DIR}/tpls/common/tpls/fire/tpls/eigen" "${Boost_LIBRARIES}") diff --git a/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp b/quantum/gate/accelerators/QPUGate.hpp similarity index 66% rename from quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp rename to quantum/gate/accelerators/QPUGate.hpp index 19dda0d9b86c5e148199b91599f2e566fa253d4a..42b83217c5617c2d49c4e44e1b88233785f6d4d7 100644 --- a/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp +++ b/quantum/gate/accelerators/QPUGate.hpp @@ -28,13 +28,56 @@ * Initial API and implementation - Alex McCaskey * **********************************************************************************/ -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE FireTensorAcceleratorTester +#ifndef QUANTUM_GATE_ACCELERATORS_QPUGATE_HPP_ +#define QUANTUM_GATE_ACCELERATORS_QPU_HPP_ -#include <boost/test/included/unit_test.hpp> -#include "FireTensorAccelerator.hpp" +#include "Accelerator.hpp" +#include "Qubits.hpp" +namespace xacc { +namespace quantum { -BOOST_AUTO_TEST_CASE(checkConstruction) { -} +/** + * + */ +template<const int NQubits> +class QPUGate: virtual public Accelerator<Qubits<NQubits>> { +public: + + /** + * This Accelerator models QPU Gate accelerators. + * @return + */ + virtual AcceleratorType getType() { + return AcceleratorType::qpu_gate; + } + + /** + * We have no need to transform the IR for this Accelerator, + * so return an empty list + * @return + */ + virtual std::vector<xacc::IRTransformation> getIRTransformations() { + std::vector<xacc::IRTransformation> v; + return v; + } + + virtual ~QPUGate() {} +protected: + + /** + * This Accelerator can allocate any number of + * qubits (at a great computational cost...) + * + * @param N + * @return + */ + bool canAllocate(const int N) { + return N <= NQubits; + } +}; + +} +} +#endif diff --git a/quantum/gate/accelerators/Qubits.hpp b/quantum/gate/accelerators/Qubits.hpp index 66998ec50521751afecc6ed5fc7df6fcf2fbba29..b7039f333b18ea38d71ce23aac7a060bdf22e96c 100644 --- a/quantum/gate/accelerators/Qubits.hpp +++ b/quantum/gate/accelerators/Qubits.hpp @@ -3,29 +3,36 @@ #include "Accelerator.hpp" #include <complex> +#include <Eigen/Dense> namespace xacc { namespace quantum { -using QubitState = std::vector<std::complex<double>>; +using QubitState = Eigen::VectorXcd; /** * */ template<const int NumberOfQubits> class Qubits: public AcceleratorBits<NumberOfQubits> { +protected: QubitState state; public: + Qubits() : + state((int) std::pow(2, NumberOfQubits)) { + } - QubitState& getState() { - return state; + void applyUnitary(Eigen::MatrixXcd& U) { + state = U * state; } -}; + void printState(std::ostream& stream) { + stream << state << "\n"; + } +}; } - } #endif diff --git a/quantum/gate/accelerators/FireTensorAccelerator.hpp b/quantum/gate/accelerators/eigenaccelerator/EigenAccelerator.hpp similarity index 54% rename from quantum/gate/accelerators/FireTensorAccelerator.hpp rename to quantum/gate/accelerators/eigenaccelerator/EigenAccelerator.hpp index c9379707d5155c7412eb11943581ac97f837def2..3c3433fed91973c5a3755eda71312d5422372d3c 100644 --- a/quantum/gate/accelerators/FireTensorAccelerator.hpp +++ b/quantum/gate/accelerators/eigenaccelerator/EigenAccelerator.hpp @@ -28,56 +28,59 @@ * Initial API and implementation - Alex McCaskey * **********************************************************************************/ -#ifndef QUANTUM_GATE_ACCELERATORS_FIRETENSORACCELERATOR_HPP_ -#define QUANTUM_GATE_ACCELERATORS_FIRETENSORACCELERATOR_HPP_ +#ifndef QUANTUM_GATE_ACCELERATORS_EIGENACCELERATOR_HPP_ +#define QUANTUM_GATE_ACCELERATORS_EIGENACCELERATOR_HPP_ -#include "Accelerator.hpp" -#include "Tensor.hpp" -#include "Graph.hpp" +#include "QPUGate.hpp" #include "QasmToGraph.hpp" #include "GraphIR.hpp" +#include <unsupported/Eigen/KroneckerProduct> namespace xacc { namespace quantum { -using namespace fire; - double sqrt2 = std::sqrt(2.0); +using GraphType = qci::common::Graph<CircuitNode>; +using QuantumGraphIR = xacc::GraphIR<GraphType>; /** * */ -class FireTensorAccelerator : public Accelerator { +template<const int NQubits> +class EigenAccelerator : public QPUGate<NQubits> { public: - FireTensorAccelerator() { - Tensor<2> h(2,2), cnot(4,4); - h.setValues({{1.0/sqrt2,1.0/sqrt2},{1.0/sqrt2,-1.0/sqrt2}}); - cnot.setValues({{1, 0, 0, 0},{0, 1, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}}); - gates.emplace("h",h); - gates.emplace("cnot",cnot); - } - virtual AcceleratorType getType() { - return AcceleratorType::qpu_gate; - } - - virtual std::vector<xacc::IRTransformation> getIRTransformations() { - std::vector<xacc::IRTransformation> v; - return v; + /** + * The constructor, create tensor gates + */ + EigenAccelerator() { + Eigen::MatrixXcd h(2,2), cnot(4,4), I(2,2), x(2,2); + h << 1.0/sqrt2,1.0/sqrt2, 1.0/sqrt2,-1.0/sqrt2; + cnot << 1, 0, 0, 0,0, 1, 0, 0,0, 0, 0, 1, 0, 0, 1, 0; + x << 0, 1, 1, 0; + I << 1,0,0,1; + gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("h",h)); + gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("cnot",cnot)); + gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("I",I)); + gates.insert(std::map<std::string, Eigen::MatrixXcd>::value_type("x",x)); } + /** + * + * @param ir + */ virtual void execute(const std::shared_ptr<xacc::IR> ir) { - using GraphType = qci::common::Graph<CircuitNode>; + auto qubitsType = std::dynamic_pointer_cast<Qubits<NQubits>>(this->bits); // Cast to a GraphIR, if we can... - auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir); + auto graphir = std::dynamic_pointer_cast<QuantumGraphIR>(ir); if (!graphir) { - QCIError("Invalid IR - this Accelerator on accepts GraphIR<Graph<CircuitNode>>."); + QCIError("Invalid IR - this Accelerator only accepts GraphIR<Graph<CircuitNode>>."); } - std::vector<CircuitNode> gateOperations; // Get the Graph + std::vector<CircuitNode> gateOperations; auto graph = graphir->getGraph(); int nNodes = graph.order(), layer = 1; int finalLayer = graph.getVertexProperty<1>(nNodes - 1); @@ -88,6 +91,10 @@ public: gateOperations.emplace_back(n); } + + Eigen::MatrixXcd U = Eigen::MatrixXcd::Identity(std::pow(2, NQubits), + std::pow(2, NQubits)); + while (layer < finalLayer) { std::vector<CircuitNode> currentLayerGates; @@ -95,32 +102,63 @@ public: std::back_inserter(currentLayerGates), [&](const CircuitNode& c) {return std::get<1>(c.properties) == layer;}); + std::vector<Eigen::MatrixXcd> productList(NQubits); + for (int i = 0; i < NQubits; i++) { + productList[i] = gates["I"]; + } + // Can parallize this... for (auto n : currentLayerGates) { + auto gateName = std::get<0>(n.properties); auto actingQubits = std::get<3>(n.properties); - } + if (gateName != "measure") { + auto gate = gates[gateName]; + + if (actingQubits.size() == 1) { + productList[actingQubits[0]] = gate; + } else if (actingQubits.size() == 2) { + productList[actingQubits[0]] = gate; + productList.erase(productList.begin() + actingQubits[1]); + } else { + QCIError("Can only simulate one and two qubit gates."); + } + } else { + // Setup measurement gate + } + + // Create a total unitary for this layer of the circuit + Eigen::MatrixXcd result = productList[0]; + for (int i = 1; i < productList.size(); i++) { + result = kroneckerProduct(result, productList[i]).eval(); + } + assert(result.rows() == std::pow(2, NQubits) && result.cols() == std::pow(2,NQubits)); + + // Update the circuit unitary matrix + U = result * U; + + } layer++; } - + qubitsType->applyUnitary(U); } - virtual ~FireTensorAccelerator() { + /** + * The destructor + */ + virtual ~EigenAccelerator() { } protected: - bool canAllocate(const int N) { - return true; - } - std::map<std::string, Tensor<2>> gates; + std::map<std::string, Eigen::MatrixXcd> gates; }; } } -#endif /* QUANTUM_GATE_ACCELERATORS_FIRETENSORACCELERATOR_HPP_ */ +#endif diff --git a/quantum/gate/accelerators/tests/EigenAcceleratorTester.cpp b/quantum/gate/accelerators/tests/EigenAcceleratorTester.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f5b0bd4925b9173119dc34120eeabebacab0d829 --- /dev/null +++ b/quantum/gate/accelerators/tests/EigenAcceleratorTester.cpp @@ -0,0 +1,89 @@ +/*********************************************************************************** + * Copyright (c) 2016, UT-Battelle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the xacc nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * Initial API and implementation - Alex McCaskey + * + **********************************************************************************/ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE FireTensorAcceleratorTester + +#include <memory> +#include <boost/test/included/unit_test.hpp> +#include "EigenAccelerator.hpp" +#include "GraphIR.hpp" + +using namespace xacc::quantum; + +BOOST_AUTO_TEST_CASE(checkConstruction) { + + EigenAccelerator<3> acc; + auto qreg = acc.allocate("qreg"); + + + // Create a graph IR modeling a + // quantum teleportation kernel + std::string irstr = "graph G {\n" + "{\nnode [shape=box style=filled]\n" + "0 [label=\"Gate=InitialState,Circuit Layer=0,Gate Vertex Id=0,Gate Acting Qubits=[0 1 2 3 4]\"];\n" + "1 [label=\"Gate=x,Circuit Layer=1,Gate Vertex Id=1,Gate Acting Qubits=[0]\"];\n" + "2 [label=\"Gate=h,Circuit Layer=1,Gate Vertex Id=2,Gate Acting Qubits=[1]\"];\n" + "3 [label=\"Gate=cnot,Circuit Layer=2,Gate Vertex Id=3,Gate Acting Qubits=[1 2]\"];\n" + "4 [label=\"Gate=cnot,Circuit Layer=3,Gate Vertex Id=4,Gate Acting Qubits=[0 1]\"];\n" + "5 [label=\"Gate=h,Circuit Layer=4,Gate Vertex Id=5,Gate Acting Qubits=[0]\"];\n" + "6 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=6,Gate Acting Qubits=[0]\"];\n" + "7 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=7,Gate Acting Qubits=[1]\"];\n" + "8 [label=\"Gate=h,Circuit Layer=6,Gate Vertex Id=8,Gate Acting Qubits=[2]\"];\n" + "9 [label=\"Gate=cnot,Circuit Layer=7,Gate Vertex Id=9,Gate Acting Qubits=[2 1]\"];\n" + "10 [label=\"Gate=h,Circuit Layer=8,Gate Vertex Id=10,Gate Acting Qubits=[2]\"];\n" + "11 [label=\"Gate=cnot,Circuit Layer=9,Gate Vertex Id=11,Gate Acting Qubits=[2 0]\"];\n" + "12 [label=\"Gate=FinalState,Circuit Layer=10,Gate Vertex Id=12,Gate Acting Qubits=[0 1 2 3 4]\"];\n" + "}\n" + "0--1 ;\n" + "0--2 ;\n" + "2--3 ;\n" + "0--3 ;\n" + "1--4 ;\n" + "3--4 ;\n" + "4--5 ;\n" + "5--6 ;\n" + "4--7 ;\n" + "3--8 ;\n" + "8--9 ;\n" + "7--9 ;\n" + "9--10 ;\n" + "10--11 ;\n" + "6--11 ;\n" + "11--12 ;\n" + "11--12 ;\n" + "9--12 ;\n" + "}"; + std::istringstream iss(irstr); + + auto graphir = std::make_shared<xacc::GraphIR<qci::common::Graph<CircuitNode>>>(); + graphir->read(iss); +} + diff --git a/quantum/gate/compilers/scaffold/CMakeLists.txt b/quantum/gate/compilers/scaffold/CMakeLists.txt index a3db2d18840e3ef1073d06efa58473621d212b87..f98f1059f944fd3dbd951b6596b4e0122b129e42 100644 --- a/quantum/gate/compilers/scaffold/CMakeLists.txt +++ b/quantum/gate/compilers/scaffold/CMakeLists.txt @@ -44,5 +44,5 @@ install(TARGETS ${LIBRARY_NAME} DESTINATION lib) # Gather tests file (GLOB test_files tests/*.cpp) -add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/../utils" "${LIBRARY_NAME}") +add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_SOURCE_DIR}/quantum/gate/utils" "${LIBRARY_NAME}") diff --git a/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp b/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp index 44577af4e946d461fc1b50a5eea780c43129030e..15b9381744fe7b9074c26827b9f31b8478e70dc7 100644 --- a/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp +++ b/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp @@ -40,26 +40,6 @@ namespace quantum { void ScaffoldCompiler::modifySource() { - // Execute default QuantumCompiler method - auto qubitTypeStr = std::string("qbit"); - auto nBits = this->hardware->getAllocationSize(); - auto varName = this->hardware->getVariableName(); - std::cout << "HELLO WORLD: " << nBits << ", " << varName << "\n"; - std::string qubitAllocationSrc = qubitTypeStr + " " + varName + "[" - + std::to_string(nBits) + "];\n"; - - std::vector<std::string> srcLines; - boost::split(srcLines, this->kernelSource, boost::is_any_of("\n")); - - // First line should be function __qpu__ call, next one - // is where we should put the qubit allocation src - srcLines.insert(srcLines.begin() + 1, qubitAllocationSrc); - - // Merge all into new kernel source string - std::stringstream combine; - std::for_each(srcLines.begin(), srcLines.end(), [&](const std::string& elem) { combine << elem << "\n"; }); - this->kernelSource = combine.str(); - // Here we assume we've been given just // the body of the quantum code, as part // of an xacc __qpu__ kernel function. diff --git a/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp b/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp index 6616dfea9ae7c1c8068cc50873e82ae9ac22b875..be662f3689bdd9669845c5de14062b5b8da41813 100644 --- a/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp +++ b/quantum/gate/compilers/scaffold/ScaffoldCompiler.hpp @@ -60,6 +60,14 @@ public: */ virtual std::shared_ptr<IR> compile(); + /** + * + * @return + */ + virtual std::string getBitType() { + return "qbit"; + } + /** * This method is intended to modify the incoming * source code to be compiled to be amenable to the diff --git a/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp b/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp index 222ff1bb7fe5967651c9b2b7711f57caa03ccc26..15797311389975101c3815382ad014b88ea94648 100644 --- a/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp +++ b/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp @@ -41,49 +41,19 @@ using namespace qci::common; using namespace xacc::quantum; -template<const int n> -class FakeAccelerator: public xacc::Accelerator { -public: - virtual int getAllocationSize() { - return n; - } - - virtual const std::string getVariableName() { - return "qreg"; - } - virtual AcceleratorType getType() { - return AcceleratorType::qpu_gate; - } - virtual std::vector<xacc::IRTransformation> getIRTransformations() { - std::vector<xacc::IRTransformation> v; - return v; - } - virtual void execute(const std::shared_ptr<xacc::IR> ir) { - } - virtual ~FakeAccelerator() { - } - -protected: - bool canAllocate(const int N) { - return true; - } -}; - - BOOST_AUTO_TEST_CASE(checkSimpleCompile) { using GraphType = Graph<CircuitNode>; - auto accelerator = std::make_shared<FakeAccelerator<2>>(); auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold"); BOOST_VERIFY(compiler); const std::string src("__qpu__ eprCreation () {\n" -// " qbit qs[2];\n" + " qbit qreg[2];\n" " H(qreg[0]);\n" " CNOT(qreg[0],qreg[1]);\n" "}\n"); - auto ir = compiler->compile(src, accelerator); + auto ir = compiler->compile(src); BOOST_VERIFY(ir); auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir); BOOST_VERIFY(graphir); @@ -101,7 +71,6 @@ BOOST_AUTO_TEST_CASE(checkSimpleCompile) { BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) { using GraphType = Graph<CircuitNode>; - auto accelerator = std::make_shared<FakeAccelerator<3>>(); auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>( @@ -109,7 +78,7 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) { BOOST_VERIFY(compiler); const std::string src("__qpu__ teleport () {\n" -// " qbit q[3];\n" + " qbit qreg[3];\n" " H(qreg[1]);\n" " CNOT(qreg[1],qreg[2]);\n" " CNOT(qreg[0],qreg[1]);\n" @@ -124,7 +93,7 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) { " CNOT(qreg[2], qreg[0]);\n" "}\n"); - auto ir = compiler->compile(src, accelerator); + auto ir = compiler->compile(src); BOOST_VERIFY(ir); auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir); BOOST_VERIFY(graphir); diff --git a/xacc/XACC.hpp b/xacc/XACC.hpp index b30b2a2907ec3a94af6c78206bb2d947f3aa1738..8ae2296ecaf739d11f2c5a97644bbdd5f50b3ca9 100644 --- a/xacc/XACC.hpp +++ b/xacc/XACC.hpp @@ -31,17 +31,14 @@ #ifndef XACC_XACC_HPP_ #define XACC_XACC_HPP_ +#include <iostream> +#include <memory> #include "Accelerator.hpp" +#include "Program.hpp" +#include "AbstractFactory.hpp" namespace xacc { -std::vector<IRTransformation> getAcceleratorIndependentTransformations( - Accelerator::AcceleratorType& accType) { - std::vector<IRTransformation> transformations; - - return transformations; -} - } diff --git a/xacc/accelerator/Accelerator.hpp b/xacc/accelerator/Accelerator.hpp index af8c41b27201660c2bd21b3be5c63ee2646cb631..8c45a89c3a4d9c233d80e5b25e41d20a5a0b9ebf 100644 --- a/xacc/accelerator/Accelerator.hpp +++ b/xacc/accelerator/Accelerator.hpp @@ -38,6 +38,22 @@ 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 }; + /** * The AcceleratorBits class provides a common * base class for allocating accelerator-specific @@ -62,10 +78,12 @@ public: * Return the current state of the bits * @return */ - std::bitset<(size_t) Number> toBits() { + virtual std::bitset<(size_t) Number> toBits() { return bits; } + virtual ~AcceleratorBits() {} + private: /** @@ -75,28 +93,8 @@ private: }; -/** - * 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. - */ -class Accelerator : public qci::common::QCIObject { - +class IAccelerator : public qci::common::QCIObject { public: - - /** - * The types of Accelerators that XACC interacts with - */ - enum AcceleratorType { qpu_gate, qpu_aqc, npu }; - /** * Return the type of this Accelerator. * @@ -118,18 +116,54 @@ public: */ virtual void execute(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 getAllocationSize() = 0; + + /** + * Return the variable name provided upon bit allocation + * (for example - qreg for gate model quantum bits in (qbit qreg[2];)) + * + * @return varName The name of the bits allocated. + */ + virtual const std::string getVariableName() = 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(is_valid_bitstype<BitsType>::value, "Derived BitsType parameter must contain N int member for number of bits."); + static_assert(std::is_base_of<AcceleratorBits<BitsType::N>, BitsType>::value, ""); + +public: + /** * Allocate bit resources (if needed). * * @return bits The AcceleratorBits derived type */ - template<typename BitsType> - BitsType allocate(const std::string& variableNameId) { - static_assert(std::is_base_of<AcceleratorBits<BitsType::N>, BitsType>::value, ""); + std::shared_ptr<BitsType> allocate(const std::string& variableNameId) { if (!canAllocate(BitsType::N)) { QCIError("Error in allocated requested bits"); } - BitsType bits; + bits = std::make_shared<BitsType>(); NBitsAllocated = BitsType::N; bitVarId = variableNameId; return bits; @@ -173,6 +207,11 @@ protected: */ std::string bitVarId; + /** + * + */ + std::shared_ptr<BitsType> bits; + /** * Return true if this Accelerator can allocate * the provided number of bits. @@ -180,6 +219,8 @@ protected: * @return canAllocate True if can allocate, false if not. */ virtual bool canAllocate(const int NBits) = 0; + + }; } #endif diff --git a/xacc/compiler/Compiler.hpp b/xacc/compiler/Compiler.hpp index 662b4e6be2bec92649bce97419a3fe9ed8f713a6..2386b2629bd1f843cbeae13d3203894ad4a7ebe6 100644 --- a/xacc/compiler/Compiler.hpp +++ b/xacc/compiler/Compiler.hpp @@ -57,8 +57,13 @@ public: * @param src * @return */ - virtual std::shared_ptr<IR> compile(const std::string& src, - const std::shared_ptr<Accelerator>& accelerator) = 0; + virtual std::shared_ptr<IR> compile(const std::string& src) = 0; + + /** + * + * @return + */ + virtual std::string getBitType() = 0; }; /** @@ -83,15 +88,12 @@ public: * @param src The kernel source string. * @return ir Intermediate representation for provided source kernel code. */ - virtual std::shared_ptr<IR> compile(const std::string& src, - const std::shared_ptr<Accelerator>& acc) { + virtual std::shared_ptr<IR> compile(const std::string& src) { // Set the provided kernel source string // so derived types can have reference to it kernelSource = src; - hardware = acc; - // Xacc requires that clients provide // only the body code for an attached // accelerator... Some language compilers @@ -102,9 +104,15 @@ public: return getAsDerived().compile(); } - virtual ~Compiler() {} + /** + * + * @return + */ + virtual std::string getBitType() { + QCIError("getBitType must be overridden by derived types.\n"); + } -protected: + virtual ~Compiler() {} protected: @@ -113,8 +121,6 @@ protected: */ std::string kernelSource; - std::shared_ptr<Accelerator> hardware; - /** * * Derived types implementing compile should perform language diff --git a/xacc/compiler/GraphIR.hpp b/xacc/compiler/GraphIR.hpp index ca26ceb9054d2f169e3e5ed8338d1adb67fd9e25..671fcd370d762e80a21aeafc041192ef3c28f74f 100644 --- a/xacc/compiler/GraphIR.hpp +++ b/xacc/compiler/GraphIR.hpp @@ -45,6 +45,8 @@ protected: public: + GraphIR() {} + GraphIR(DerivedGraph& g) : graph(g) { } @@ -66,7 +68,7 @@ public: } virtual void read(std::istream& inStream) { - + graph.read(inStream); } DerivedGraph& getGraph() { diff --git a/xacc/compiler/IR.hpp b/xacc/compiler/IR.hpp index d4b102b4af13053c6d790faea6f78ec66a2e2f9d..c93b631bab486be04434e6809f6fbf704dfeedaa 100644 --- a/xacc/compiler/IR.hpp +++ b/xacc/compiler/IR.hpp @@ -30,9 +30,8 @@ **********************************************************************************/ #ifndef XACC_COMPILER_IR_HPP_ #define XACC_COMPILER_IR_HPP_ - -#include "AbstractFactory.hpp" #include <iostream> +#include "AbstractFactory.hpp" namespace xacc { diff --git a/xacc/program/Program.hpp b/xacc/program/Program.hpp index b8789a8204227fd782fdf025c816e7cdd9d89b8e..7d0447fd3bf78a6e93f34b15ef129dc6e968113d 100644 --- a/xacc/program/Program.hpp +++ b/xacc/program/Program.hpp @@ -33,23 +33,29 @@ #include <string> #include <vector> -#include "Compiler.hpp" -#include "Kernel.hpp" -#include "Accelerator.hpp" +#include <fstream> #include <memory> #include <queue> #include <boost/program_options.hpp> +#include <boost/algorithm/string.hpp> #include <algorithm> #include "QCIError.hpp" #include "XaccUtils.hpp" -#include "XACC.hpp" -#include <fstream> +#include "Compiler.hpp" +#include "Accelerator.hpp" using namespace boost::program_options; using namespace qci::common; namespace xacc { +std::vector<IRTransformation> getAcceleratorIndependentTransformations( + AcceleratorType& accType) { + std::vector<IRTransformation> transformations; + + return transformations; +} + /** * The Program is the main entrypoint for the XACC * API. Users with accelerator kernels must construct a @@ -58,6 +64,7 @@ namespace xacc { * Accelerator reference to be used and kernel source * code at construction time. */ +//template<typename AccType> class Program { protected: @@ -72,7 +79,7 @@ protected: * Reference to the attached Accelerator to * use in this compilation and execution */ - std::shared_ptr<Accelerator> accelerator; + std::shared_ptr<IAccelerator> accelerator; /** * Reference to a set of compiler command @@ -94,7 +101,7 @@ public: * @param acc Attached Accelerator to execute * @param sourceFile The kernel source code */ - Program(std::shared_ptr<Accelerator> acc, const std::string& sourceFile) : + Program(std::shared_ptr<IAccelerator> acc, const std::string& sourceFile) : src(sourceFile) { accelerator = std::move(acc); compilerOptions = std::make_shared<options_description>( @@ -135,8 +142,29 @@ public: QCIError("Invalid Compiler.\n"); } + // Update source with hardware bits information... + // FIXME Make this more robust in the future... + auto bitTypeStr = compiler->getBitType(); + auto nBits = accelerator->getAllocationSize(); + auto varName = accelerator->getVariableName(); + std::cout << "HELLO WORLD: " << nBits << ", " << varName << "\n"; + std::string bitAllocationSrc = bitTypeStr + " " + varName + "[" + + std::to_string(nBits) + "];\n"; + + std::vector<std::string> srcLines; + boost::split(srcLines, src, boost::is_any_of("\n")); + + // First line should be function __qpu__ call, next one + // is where we should put the qubit allocation src + srcLines.insert(srcLines.begin() + 1, bitAllocationSrc); + + // Merge all into new kernel source string + std::stringstream combine; + std::for_each(srcLines.begin(), srcLines.end(), [&](const std::string& elem) { combine << elem << "\n"; }); + src = combine.str(); + // Execute the compilation - auto xaccIR = compiler->compile(src, accelerator); + xaccIR = compiler->compile(src); // Validate the compilation if (!xaccIR) { diff --git a/xacc/tests/CompilerTester.cpp b/xacc/tests/CompilerTester.cpp index 161e0c3f29b23661c68bf527d3081f23ffbf4e0e..bfa3200a1f4a7a12eccef9f81a0b7098a3e822a0 100644 --- a/xacc/tests/CompilerTester.cpp +++ b/xacc/tests/CompilerTester.cpp @@ -52,6 +52,9 @@ protected: return std::make_shared<FakeIR>(); } + virtual std::string getBitType() { + return "qbit"; + } virtual void modifySource() { } diff --git a/xacc/tests/ProgramTester.cpp b/xacc/tests/ProgramTester.cpp index 1db2d7e92d1928e07d1c622b6892bb001566593f..62c55e1cbc3fbcb50455110082ac0359830fd916 100644 --- a/xacc/tests/ProgramTester.cpp +++ b/xacc/tests/ProgramTester.cpp @@ -36,7 +36,7 @@ using namespace xacc; -class FakeAccelerator : public Accelerator { +class FakeAccelerator : public Accelerator<AcceleratorBits<5>> { public: @@ -69,6 +69,9 @@ public: virtual void modifySource() { } + virtual std::string getBitType() { + return "hello"; + } virtual ~DummyCompiler() { }