From 2cdbb127c883a1815ef29d7e032b0ce9e1229599 Mon Sep 17 00:00:00 2001 From: Alex McCaskey <mccaskeyaj@ornl.gov> Date: Fri, 10 Feb 2017 16:16:43 +0000 Subject: [PATCH] Implemented QuantumCircuit graph with graphviz read method, updated tests for FireTensorAccelerator and SimulatedQubits --- quantum/gate/accelerators/CMakeLists.txt | 2 +- quantum/gate/accelerators/SimulatedQubits.hpp | 31 ++- .../FireTensorAccelerator.hpp | 5 +- ...er.hpp => FireTensorAcceleratorTester.cpp} | 58 +++--- .../tests/SimulatedQubitsTester.cpp | 18 ++ .../compilers/scaffold/ScaffoldCompiler.cpp | 6 +- .../scaffold/tests/ScaffoldCompilerTester.cpp | 4 +- quantum/gate/utils/QasmToGraph.hpp | 118 +----------- quantum/gate/utils/QuantumCircuit.hpp | 148 +++++++++++++++ .../gate/utils/tests/QuantumCircuitTester.cpp | 177 ++++++++++++++++++ xacc/accelerator/Accelerator.hpp | 4 +- 11 files changed, 425 insertions(+), 146 deletions(-) rename quantum/gate/accelerators/tests/{FireTensorAcceleratorTester.hpp => FireTensorAcceleratorTester.cpp} (62%) create mode 100644 quantum/gate/utils/QuantumCircuit.hpp create mode 100644 quantum/gate/utils/tests/QuantumCircuitTester.cpp diff --git a/quantum/gate/accelerators/CMakeLists.txt b/quantum/gate/accelerators/CMakeLists.txt index cedd6e342..dc8c602b1 100644 --- a/quantum/gate/accelerators/CMakeLists.txt +++ b/quantum/gate/accelerators/CMakeLists.txt @@ -34,5 +34,5 @@ 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_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}") +add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/firetensoraccelerator;${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/SimulatedQubits.hpp b/quantum/gate/accelerators/SimulatedQubits.hpp index d5e8b7375..6181f94f8 100644 --- a/quantum/gate/accelerators/SimulatedQubits.hpp +++ b/quantum/gate/accelerators/SimulatedQubits.hpp @@ -42,6 +42,7 @@ public: (int) std::pow(2, TotalNumberOfQubits)) { // Initialize to |000...000> state bufferState(0) = 1.0; + this->bufferSize = TotalNumberOfQubits; } /** @@ -104,19 +105,39 @@ public: bufferState = st; } + /** + * Allocating this buffer type is only valid + * if N <= TotalNumberOfQubits. + * @param N + * @return + */ + virtual bool isValidBufferSize(const int N) { + return N <= TotalNumberOfQubits; + } + /** * Print the state to the provided output stream. * * @param stream */ void printBufferState(std::ostream& stream) { - for (int i = 0; i < bufferState.dimension(0); i++) { - stream - << std::bitset<TotalNumberOfQubits>(i).to_string().substr( - size(), TotalNumberOfQubits) << " -> " - << bufferState(i) << "\n"; + if (size() < TotalNumberOfQubits) { + for (int i = 0; i < bufferState.dimension(0); i++) { + stream + << std::bitset<TotalNumberOfQubits>(i).to_string().substr( + size(), TotalNumberOfQubits) << " -> " + << bufferState(i) << "\n"; + } + } else { + for (int i = 0; i < bufferState.dimension(0); i++) { + + stream << std::bitset<TotalNumberOfQubits>(i).to_string() + << " -> " << bufferState(i) << "\n"; + } } } + + virtual ~SimulatedQubits() {} }; } } diff --git a/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp b/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp index 2f03bd9d0..89ca46de9 100644 --- a/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp +++ b/quantum/gate/accelerators/firetensoraccelerator/FireTensorAccelerator.hpp @@ -32,8 +32,8 @@ #define QUANTUM_GATE_ACCELERATORS_EIGENACCELERATOR_HPP_ #include "QPUGate.hpp" -#include "QasmToGraph.hpp" #include "GraphIR.hpp" +#include "QuantumCircuit.hpp" #include "SimulatedQubits.hpp" #include <random> @@ -41,8 +41,7 @@ namespace xacc { namespace quantum { double sqrt2 = std::sqrt(2.0); -using GraphType = qci::common::Graph<CircuitNode>; -using QuantumGraphIR = xacc::GraphIR<GraphType>; +using QuantumGraphIR = xacc::GraphIR<QuantumCircuit>; /** * The FireTensorAccelerator is an XACC Accelerator that simulates diff --git a/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.hpp b/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp similarity index 62% rename from quantum/gate/accelerators/tests/FireTensorAcceleratorTester.hpp rename to quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp index 37211f990..0ec2255e5 100644 --- a/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.hpp +++ b/quantum/gate/accelerators/tests/FireTensorAcceleratorTester.cpp @@ -41,26 +41,30 @@ using namespace xacc::quantum; BOOST_AUTO_TEST_CASE(checkConstruction) { FireTensorAccelerator<3> acc; -// auto qreg = acc.allocate("qreg"); - + auto qreg = acc.createBuffer("qreg", 3); // 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" + "node [shape=box style=filled]\n" + "0 [label=\"Gate=InitialState,Circuit Layer=0,Gate Vertex Id=0,Gate Acting Qubits=[0 1 2],Enabled=1\"];\n" + "1 [label=\"Gate=x,Circuit Layer=1,Gate Vertex Id=1,Gate Acting Qubits=[0],Enabled=1\"];\n" + "2 [label=\"Gate=h,Circuit Layer=1,Gate Vertex Id=2,Gate Acting Qubits=[1],Enabled=1\"];\n" + "3 [label=\"Gate=cnot,Circuit Layer=2,Gate Vertex Id=3,Gate Acting Qubits=[1 2],Enabled=1\"];\n" + "4 [label=\"Gate=cnot,Circuit Layer=3,Gate Vertex Id=4,Gate Acting Qubits=[0 1],Enabled=1\"];\n" + "5 [label=\"Gate=h,Circuit Layer=4,Gate Vertex Id=5,Gate Acting Qubits=[0],Enabled=1\"];\n" + "6 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=6,Gate Acting Qubits=[0],Enabled=1\"];\n" + "7 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=7,Gate Acting Qubits=[1],Enabled=1\"];\n" + "8 [label=\"Gate=FinalState,Circuit Layer=6,Gate Vertex Id=8,Gate Acting Qubits=[0 1 2],Enabled=1\"];\n" + "9 [label=\"Gate=conditional,Circuit Layer=0,Gate Vertex Id=9,Gate Acting Qubits=[0],Enabled=1\"];\n" + "10 [label=\"Gate=InitialState,Circuit Layer=7,Gate Vertex Id=10,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" + "11 [label=\"Gate=z,Circuit Layer=8,Gate Vertex Id=11,Gate Acting Qubits=[2],Enabled=0\"];\n" + "12 [label=\"Gate=FinalState,Circuit Layer=9,Gate Vertex Id=12,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" + "13 [label=\"Gate=conditional,Circuit Layer=0,Gate Vertex Id=13,Gate Acting Qubits=[1],Enabled=1\"];\n" + "14 [label=\"Gate=InitialState,Circuit Layer=10,Gate Vertex Id=14,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" + "15 [label=\"Gate=x,Circuit Layer=11,Gate Vertex Id=15,Gate Acting Qubits=[2],Enabled=0\"];\n" + "16 [label=\"Gate=FinalState,Circuit Layer=12,Gate Vertex Id=16,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" "}\n" "0--1 ;\n" "0--2 ;\n" @@ -71,19 +75,31 @@ BOOST_AUTO_TEST_CASE(checkConstruction) { "4--5 ;\n" "5--6 ;\n" "4--7 ;\n" + "6--8 ;\n" + "7--8 ;\n" "3--8 ;\n" "8--9 ;\n" - "7--9 ;\n" "9--10 ;\n" "10--11 ;\n" - "6--11 ;\n" - "11--12 ;\n" + "10--12 ;\n" + "10--12 ;\n" "11--12 ;\n" - "9--12 ;\n" + "8--13 ;\n" + "13--14 ;\n" + "14--15 ;\n" + "14--16 ;\n" + "14--16 ;\n" + "15--16 ;\n" "}"; std::istringstream iss(irstr); - auto graphir = std::make_shared<xacc::GraphIR<qci::common::Graph<CircuitNode>>>(); + auto graphir = std::make_shared<xacc::GraphIR<QuantumCircuit>>(); graphir->read(iss); + acc.execute("qreg", graphir); + + BOOST_VERIFY(qreg->getState()(1) * qreg->getState()(1) == 1 || + qreg->getState()(5) * qreg->getState()(5) == 1 || + qreg->getState()(3) * qreg->getState()(3) == 1 || + qreg->getState()(7) * qreg->getState()(7) == 1); } diff --git a/quantum/gate/accelerators/tests/SimulatedQubitsTester.cpp b/quantum/gate/accelerators/tests/SimulatedQubitsTester.cpp index df3a7c635..5e8abdd7a 100644 --- a/quantum/gate/accelerators/tests/SimulatedQubitsTester.cpp +++ b/quantum/gate/accelerators/tests/SimulatedQubitsTester.cpp @@ -38,5 +38,23 @@ using namespace qci::common; using namespace xacc::quantum; BOOST_AUTO_TEST_CASE(checkConstruction) { + + fire::Tensor<1> initialState1(8); + initialState1(0) = 1; + SimulatedQubits<3> qubits1("name1"); + BOOST_VERIFY(qubits1.size() == 3); + BOOST_VERIFY(qubits1.name() == "name1"); + BOOST_VERIFY(qubits1.getState().dimension(0) == 8); + BOOST_VERIFY(qubits1.getState() == initialState1); + + fire::Tensor<1> initialState2(4); + initialState2(0) = 1; + SimulatedQubits<3> qubits2("name2", 2); + BOOST_VERIFY(qubits2.size() == 2); + BOOST_VERIFY(qubits2.name() == "name2"); + BOOST_VERIFY(qubits2.getState().dimension(0) == 4); + BOOST_VERIFY(qubits2.getState() == initialState2); + } + diff --git a/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp b/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp index 9ac31c84a..3fed7012e 100644 --- a/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp +++ b/quantum/gate/compilers/scaffold/ScaffoldCompiler.cpp @@ -33,7 +33,7 @@ #include <regex> #include "ScaffCCAPI.hpp" #include "QasmToGraph.hpp" -#include <boost/algorithm/string.hpp> +#include "QuantumCircuit.hpp" namespace xacc { @@ -187,7 +187,7 @@ std::shared_ptr<IR> ScaffoldCompiler::compile() { // so that we can interact with a locally installed // scaffcc executable scaffold::ScaffCCAPI scaffcc; - using ScaffoldGraphIR = GraphIR<Graph<CircuitNode>>; + using ScaffoldGraphIR = GraphIR<QuantumCircuit>; // Compile the source code and return the QASM form // This will throw if it fails. @@ -207,7 +207,7 @@ std::shared_ptr<IR> ScaffoldCompiler::compile() { // So a COND node needs to know the gate id of the measurement gate // and the nodes to mark enabled if the measurement is a 1, if (!conditionalCodeSegments.empty()) { - std::vector<qci::common::Graph<CircuitNode>> condGraphs; + std::vector<QuantumCircuit> condGraphs; for (auto cond : conditionalCodeSegments) { auto condQasm = scaffcc.getFlatQASMFromSource(cond); auto g = QasmToGraph::getCircuitGraph(condQasm); diff --git a/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp b/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp index 74f630fc4..d9d2193f9 100644 --- a/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp +++ b/quantum/gate/compilers/scaffold/tests/ScaffoldCompilerTester.cpp @@ -42,7 +42,7 @@ using namespace qci::common; using namespace xacc::quantum; BOOST_AUTO_TEST_CASE(checkSimpleCompile) { - using GraphType = Graph<CircuitNode>; + using GraphType = QuantumCircuit; auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold"); BOOST_VERIFY(compiler); @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE(checkSimpleCompile) { } BOOST_AUTO_TEST_CASE(checkCodeWithMeasurementIf) { - using GraphType = Graph<CircuitNode>; + using GraphType = QuantumCircuit; auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>( diff --git a/quantum/gate/utils/QasmToGraph.hpp b/quantum/gate/utils/QasmToGraph.hpp index 8b8bc1d9f..c4cbd8667 100644 --- a/quantum/gate/utils/QasmToGraph.hpp +++ b/quantum/gate/utils/QasmToGraph.hpp @@ -31,114 +31,12 @@ #ifndef QUANTUM_GATE_QASMTOGRAPH_HPP_ #define QUANTUM_GATE_QASMTOGRAPH_HPP_ -#include "Graph.hpp" +#include "QuantumCircuit.hpp" #include <regex> -#include <boost/algorithm/string.hpp> namespace xacc { namespace quantum { -/** - * CircuitNode subclasses QCIVertex to provide the following - * parameters in the given order: - * - * Parameters: Gate, Layer (ie time sequence), Gate Vertex Id, - * Qubit Ids that the gate acts on - */ -class CircuitNode: public qci::common::QCIVertex<std::string, int, int, - std::vector<int>, bool> { -public: - CircuitNode() : - QCIVertex() { - propertyNames[0] = "Gate"; - propertyNames[1] = "Circuit Layer"; - propertyNames[2] = "Gate Vertex Id"; - propertyNames[3] = "Gate Acting Qubits"; - propertyNames[4] = "Enabled"; - - // by default all circuit nodes - // are enabled and - std::get<4>(properties) = true; - } -}; - -class QuantumCircuit : virtual public qci::common::Graph<CircuitNode> { -public: - - virtual void read(std::istream& stream) { - std::string content { std::istreambuf_iterator<char>(stream), - std::istreambuf_iterator<char>() }; - - std::vector<std::string> lines, sections; - boost::split(sections, content, boost::is_any_of("}")); - - // Sections should be size 2 for a valid dot file - boost::split(lines, sections[0], boost::is_any_of("\n")); - for (auto line : lines) { - if (boost::contains(line, "label")) { - CircuitNode v; - std::vector<std::string> labelLineSplit, attrSplit; - boost::split(labelLineSplit, line, boost::is_any_of("=")); - auto attributes = labelLineSplit[1].substr(1, labelLineSplit.size()-3); - boost::split(attrSplit, attributes, boost::is_any_of(",")); - - std::tuple<std::string, int, int, std::vector<int>, bool> props; - - std::map<std::string, std::string> attrMap; - for (auto a : attrSplit) { - std::vector<std::string> eqsplit; - boost::split(eqsplit, a, boost::is_any_of("=")); - - if (eqsplit[0] == "Gate") { - std::get<0>(v.properties) = eqsplit[1]; - } else if (eqsplit[0] == "Circuit Layer") { - std::get<1>(v.properties) = std::stoi(eqsplit[1]); - } else if (eqsplit[0] == "Vertex Id") { - std::get<2>(v.properties) = std::stoi(eqsplit[1]); - } else if (eqsplit[0] == "Gate Acting Qubits") { - auto qubitsStr = eqsplit[1]; - boost::replace_all(qubitsStr, "[", ""); - boost::replace_all(qubitsStr, "[", ""); - std::vector<std::string> elementsStr; - std::vector<int> qubits; - boost::split(elementsStr, qubitsStr, - boost::is_any_of(" ")); - for (auto element : elementsStr) { - qubits.push_back(std::stoi(element)); - } - std::get<3>(v.properties) = qubits; - } else if (eqsplit[0] == "Enabled") { - std::get<4>(v.properties) = (bool) std::stoi( - eqsplit[1]); - } - - std::cout << "adding vertex " << std::get<0>(v.properties) - << ", " << std::get<1>(v.properties) << ", " - << std::get<2>(v.properties) << ", " - << std::get<4>(v.properties) << "\n"; - this->addVertex(v); - } - - } - } - - // Now add the edges - lines.clear(); - boost::split(lines, sections[1], boost::is_any_of(";\n")); - for (auto line : lines) { - boost::trim(line); - if (line == "}") continue; - std::vector<std::string> vertexPairs; - boost::split(vertexPairs, line, boost::is_any_of("--")); - this->addEdge(std::stoi(vertexPairs[0]), std::stoi(vertexPairs[1])); - std::cout << "Adding Edge between " << vertexPairs[0] << " and " << vertexPairs[1] << "\n"; - } - } - - - virtual ~QuantumCircuit() {} -}; - /** * The QasmToGraph class provides a static * utility method that maps a flat qasm string @@ -155,12 +53,12 @@ public: * @param flatQasmStr The qasm to be converted to a Graph. * @return graph Graph modeling a quantum circuit. */ - static qci::common::Graph<CircuitNode> getCircuitGraph( + static QuantumCircuit getCircuitGraph( const std::string& flatQasmStr) { // Local Declarations using namespace qci::common; - Graph<CircuitNode> graph; + QuantumCircuit graph; std::map<std::string, int> qubitVarNameToId; std::vector<std::string> qasmLines; std::vector<int> allQbitIds; @@ -276,8 +174,8 @@ public: * @param mainGraph * @param conditionalGraphs */ - static void linkConditionalQasm(qci::common::Graph<CircuitNode>& mainGraph, - std::vector<qci::common::Graph<CircuitNode>>& conditionalGraphs, + static void linkConditionalQasm(QuantumCircuit& mainGraph, + std::vector<QuantumCircuit>& conditionalGraphs, std::vector<int>& conditionalQubits) { // At this point we have a main circuit graph, @@ -356,12 +254,12 @@ private: * @param gateOperations * @param initialStateId */ - static void generateEdgesFromLayer(const int layer, - qci::common::Graph<CircuitNode>& graph, + static void generateEdgesFromLayer(const int layer, QuantumCircuit& graph, std::vector<CircuitNode>& gateOperations, int initialStateId) { int nQubits = std::get<3>(graph.getVertexProperties(0)).size(); - int maxLayer = std::get<1>(gateOperations[gateOperations.size() - 1].properties); + int maxLayer = std::get<1>( + gateOperations[gateOperations.size() - 1].properties); std::map<int,int> qubitToCurrentGateId; for (int i = 0 ; i < nQubits; i++) { diff --git a/quantum/gate/utils/QuantumCircuit.hpp b/quantum/gate/utils/QuantumCircuit.hpp new file mode 100644 index 000000000..1d61f892b --- /dev/null +++ b/quantum/gate/utils/QuantumCircuit.hpp @@ -0,0 +1,148 @@ +/*********************************************************************************** + * 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 + * + **********************************************************************************/ +#ifndef QUANTUM_GATE_UTILS_QUANTUMCIRCUIT_HPP_ +#define QUANTUM_GATE_UTILS_QUANTUMCIRCUIT_HPP_ + +#include "Graph.hpp" +#include <boost/algorithm/string.hpp> + +namespace xacc { +namespace quantum { +/** + * CircuitNode subclasses QCIVertex to provide the following + * parameters in the given order: + * + * Parameters: Gate, Layer (ie time sequence), Gate Vertex Id, + * Qubit Ids that the gate acts on + */ +class CircuitNode: public qci::common::QCIVertex<std::string, int, int, + std::vector<int>, bool> { +public: + CircuitNode() : + QCIVertex() { + propertyNames[0] = "Gate"; + propertyNames[1] = "Circuit Layer"; + propertyNames[2] = "Gate Vertex Id"; + propertyNames[3] = "Gate Acting Qubits"; + propertyNames[4] = "Enabled"; + + // by default all circuit nodes + // are enabled and + std::get<4>(properties) = true; + } +}; + +/** + * The QuantumCircuit is a subclass of Graph that provides + * its Vertex template parameter as a CircuitNode. It adds the + * ability to read QuantumCircuits from a graphviz dot file. + */ +class QuantumCircuit : virtual public qci::common::Graph<CircuitNode> { +public: + + virtual void read(std::istream& stream) { + std::string content { std::istreambuf_iterator<char>(stream), + std::istreambuf_iterator<char>() }; + + std::vector<std::string> lines, sections; + boost::split(sections, content, boost::is_any_of("}")); + + // Sections should be size 2 for a valid dot file + boost::split(lines, sections[0], boost::is_any_of("\n")); + for (auto line : lines) { + if (boost::contains(line, "label")) { + CircuitNode v; + + auto firstBracket = line.find_first_of('['); + line = line.substr(firstBracket+1, line.size()-2); + + boost::replace_all(line, ";", ""); + boost::replace_all(line, "[", ""); + boost::replace_all(line, "]", ""); + boost::replace_all(line, "\"", ""); + boost::replace_all(line, "label=", ""); + boost::trim(line); + std::vector<std::string> labelLineSplit, removeId; + boost::split(labelLineSplit, line, boost::is_any_of(",")); + + for (auto a : labelLineSplit) { + std::vector<std::string> eqsplit; + boost::split(eqsplit, a, boost::is_any_of("=")); + if (eqsplit[0] == "Gate") { + std::get<0>(v.properties) = eqsplit[1]; + } else if (eqsplit[0] == "Circuit Layer") { + std::get<1>(v.properties) = std::stoi(eqsplit[1]); + } else if (eqsplit[0] == "Gate Vertex Id") { + std::get<2>(v.properties) = std::stoi(eqsplit[1]); + } else if (eqsplit[0] == "Gate Acting Qubits") { + auto qubitsStr = eqsplit[1]; + boost::replace_all(qubitsStr, "[", ""); + boost::replace_all(qubitsStr, "[", ""); + std::vector<std::string> elementsStr; + std::vector<int> qubits; + boost::split(elementsStr, qubitsStr, + boost::is_any_of(" ")); + for (auto element : elementsStr) { + qubits.push_back(std::stoi(element)); + } + std::get<3>(v.properties) = qubits; + } else if (eqsplit[0] == "Enabled") { + std::get<4>(v.properties) = (bool) std::stoi( + eqsplit[1]); + } + + } + addVertex(v); + } + } + + // Now add the edges + lines.clear(); + boost::split(lines, sections[1], boost::is_any_of(";\n")); + for (auto line : lines) { + boost::trim(line); + if (line == "}" || line.empty()) continue; + boost::trim(line); + boost::replace_all(line, "--", " "); + std::vector<std::string> vertexPairs; + boost::split(vertexPairs, line, boost::is_any_of(" ")); + addEdge(std::stoi(vertexPairs[0]), std::stoi(vertexPairs[1])); + } + } + + + virtual ~QuantumCircuit() {} +}; + +} +} + +#endif /* QUANTUM_GATE_UTILS_QUANTUMCIRCUIT_HPP_ */ diff --git a/quantum/gate/utils/tests/QuantumCircuitTester.cpp b/quantum/gate/utils/tests/QuantumCircuitTester.cpp new file mode 100644 index 000000000..a5bbb1da9 --- /dev/null +++ b/quantum/gate/utils/tests/QuantumCircuitTester.cpp @@ -0,0 +1,177 @@ +/*********************************************************************************** + * 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 ScaffoldCompilerTester + +#include <boost/test/included/unit_test.hpp> +#include "QuantumCircuit.hpp" + +using namespace xacc::quantum; + +BOOST_AUTO_TEST_CASE(checkReadGraph) { + + // Create a graph IR modeling a + // quantum teleportation kernel + std::string irstr = "graph G {\n" + "{\n" + "node [shape=box style=filled]\n" + "0 [label=\"Gate=InitialState,Circuit Layer=0,Gate Vertex Id=0,Gate Acting Qubits=[0 1 2],Enabled=1\"];\n" + "1 [label=\"Gate=x,Circuit Layer=1,Gate Vertex Id=1,Gate Acting Qubits=[0],Enabled=1\"];\n" + "2 [label=\"Gate=h,Circuit Layer=1,Gate Vertex Id=2,Gate Acting Qubits=[1],Enabled=1\"];\n" + "3 [label=\"Gate=cnot,Circuit Layer=2,Gate Vertex Id=3,Gate Acting Qubits=[1 2],Enabled=1\"];\n" + "4 [label=\"Gate=cnot,Circuit Layer=3,Gate Vertex Id=4,Gate Acting Qubits=[0 1],Enabled=1\"];\n" + "5 [label=\"Gate=h,Circuit Layer=4,Gate Vertex Id=5,Gate Acting Qubits=[0],Enabled=1\"];\n" + "6 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=6,Gate Acting Qubits=[0],Enabled=1\"];\n" + "7 [label=\"Gate=measure,Circuit Layer=5,Gate Vertex Id=7,Gate Acting Qubits=[1],Enabled=1\"];\n" + "8 [label=\"Gate=FinalState,Circuit Layer=6,Gate Vertex Id=8,Gate Acting Qubits=[0 1 2],Enabled=1\"];\n" + "9 [label=\"Gate=conditional,Circuit Layer=0,Gate Vertex Id=9,Gate Acting Qubits=[0],Enabled=1\"];\n" + "10 [label=\"Gate=InitialState,Circuit Layer=7,Gate Vertex Id=10,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" + "11 [label=\"Gate=z,Circuit Layer=8,Gate Vertex Id=11,Gate Acting Qubits=[2],Enabled=0\"];\n" + "12 [label=\"Gate=FinalState,Circuit Layer=9,Gate Vertex Id=12,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" + "13 [label=\"Gate=conditional,Circuit Layer=0,Gate Vertex Id=13,Gate Acting Qubits=[1],Enabled=1\"];\n" + "14 [label=\"Gate=InitialState,Circuit Layer=10,Gate Vertex Id=14,Gate Acting Qubits=[0 1 2],Enabled=0\"];\n" + "15 [label=\"Gate=x,Circuit Layer=11,Gate Vertex Id=15,Gate Acting Qubits=[2],Enabled=0\"];\n" + "16 [label=\"Gate=FinalState,Circuit Layer=12,Gate Vertex Id=16,Gate Acting Qubits=[0 1 2],Enabled=0\"];\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" + "6--8 ;\n" + "7--8 ;\n" + "3--8 ;\n" + "8--9 ;\n" + "9--10 ;\n" + "10--11 ;\n" + "10--12 ;\n" + "10--12 ;\n" + "11--12 ;\n" + "8--13 ;\n" + "13--14 ;\n" + "14--15 ;\n" + "14--16 ;\n" + "14--16 ;\n" + "15--16 ;\n" + "}"; + std::istringstream iss(irstr); + + QuantumCircuit circuit; + circuit.read(iss); + + std::map<int, std::vector<int>> expectedQubits; + expectedQubits.insert(std::make_pair(0, std::vector<int>{0, 1, 2})); + expectedQubits.insert(std::make_pair(1, std::vector<int>{0})); + expectedQubits.insert(std::make_pair(2, std::vector<int>{1})); + expectedQubits.insert(std::make_pair(3, std::vector<int>{1, 2})); + expectedQubits.insert(std::make_pair(4, std::vector<int>{0, 1})); + expectedQubits.insert(std::make_pair(5, std::vector<int>{0})); + expectedQubits.insert(std::make_pair(6, std::vector<int>{0})); + expectedQubits.insert(std::make_pair(7, std::vector<int>{1})); + expectedQubits.insert(std::make_pair(8, std::vector<int>{0, 1, 2})); + expectedQubits.insert(std::make_pair(9, std::vector<int>{0})); + expectedQubits.insert(std::make_pair(10, std::vector<int>{0, 1, 2})); + expectedQubits.insert(std::make_pair(11, std::vector<int>{2})); + expectedQubits.insert(std::make_pair(12, std::vector<int>{0, 1, 2})); + expectedQubits.insert(std::make_pair(13, std::vector<int>{1})); + expectedQubits.insert(std::make_pair(14, std::vector<int>{0, 1, 2})); + expectedQubits.insert(std::make_pair(15, std::vector<int>{2})); + expectedQubits.insert(std::make_pair(16, std::vector<int>{0, 1, 2})); + + BOOST_VERIFY(circuit.order() == 17); + BOOST_VERIFY(circuit.size() == 24); + + BOOST_VERIFY(circuit.getVertexProperty<0>(0) == "InitialState"); + BOOST_VERIFY(circuit.getVertexProperty<0>(1) == "x"); + BOOST_VERIFY(circuit.getVertexProperty<0>(2) == "h"); + BOOST_VERIFY(circuit.getVertexProperty<0>(3) == "cnot"); + BOOST_VERIFY(circuit.getVertexProperty<0>(4) == "cnot"); + BOOST_VERIFY(circuit.getVertexProperty<0>(5) == "h"); + BOOST_VERIFY(circuit.getVertexProperty<0>(6) == "measure"); + BOOST_VERIFY(circuit.getVertexProperty<0>(7) == "measure"); + BOOST_VERIFY(circuit.getVertexProperty<0>(8) == "FinalState"); + BOOST_VERIFY(circuit.getVertexProperty<0>(9) == "conditional"); + BOOST_VERIFY(circuit.getVertexProperty<0>(10) == "InitialState"); + BOOST_VERIFY(circuit.getVertexProperty<0>(11) == "z"); + BOOST_VERIFY(circuit.getVertexProperty<0>(12) == "FinalState"); + BOOST_VERIFY(circuit.getVertexProperty<0>(13) == "conditional"); + BOOST_VERIFY(circuit.getVertexProperty<0>(14) == "InitialState"); + BOOST_VERIFY(circuit.getVertexProperty<0>(15) == "x"); + BOOST_VERIFY(circuit.getVertexProperty<0>(16) == "FinalState"); + + for (int i = 0; i < 17; i++) { + BOOST_VERIFY(circuit.getVertexProperty<2>(i) == i); + BOOST_VERIFY(circuit.getVertexProperty<3>(i) == expectedQubits[i]); + } + + BOOST_VERIFY(circuit.getVertexProperty<1>(0) == 0); + BOOST_VERIFY(circuit.getVertexProperty<1>(1) == 1); + BOOST_VERIFY(circuit.getVertexProperty<1>(2) == 1); + BOOST_VERIFY(circuit.getVertexProperty<1>(3) == 2); + BOOST_VERIFY(circuit.getVertexProperty<1>(4) == 3); + BOOST_VERIFY(circuit.getVertexProperty<1>(5) == 4); + BOOST_VERIFY(circuit.getVertexProperty<1>(6) == 5); + BOOST_VERIFY(circuit.getVertexProperty<1>(7) == 5); + BOOST_VERIFY(circuit.getVertexProperty<1>(8) == 6); + BOOST_VERIFY(circuit.getVertexProperty<1>(9) == 0); + BOOST_VERIFY(circuit.getVertexProperty<1>(10) == 7); + BOOST_VERIFY(circuit.getVertexProperty<1>(11) == 8); + BOOST_VERIFY(circuit.getVertexProperty<1>(12) == 9); + BOOST_VERIFY(circuit.getVertexProperty<1>(13) == 0); + BOOST_VERIFY(circuit.getVertexProperty<1>(14) == 10); + BOOST_VERIFY(circuit.getVertexProperty<1>(15) == 11); + BOOST_VERIFY(circuit.getVertexProperty<1>(16) == 12); + + BOOST_VERIFY(circuit.getVertexProperty<4>(0)); + BOOST_VERIFY(circuit.getVertexProperty<4>(1)); + BOOST_VERIFY(circuit.getVertexProperty<4>(2)); + BOOST_VERIFY(circuit.getVertexProperty<4>(3)); + BOOST_VERIFY(circuit.getVertexProperty<4>(4)); + BOOST_VERIFY(circuit.getVertexProperty<4>(5)); + BOOST_VERIFY(circuit.getVertexProperty<4>(6)); + BOOST_VERIFY(circuit.getVertexProperty<4>(7)); + BOOST_VERIFY(circuit.getVertexProperty<4>(8)); + BOOST_VERIFY(circuit.getVertexProperty<4>(9)); + BOOST_VERIFY(!circuit.getVertexProperty<4>(10)); + BOOST_VERIFY(!circuit.getVertexProperty<4>(11)); + BOOST_VERIFY(!circuit.getVertexProperty<4>(12)); + BOOST_VERIFY(circuit.getVertexProperty<4>(13)); + BOOST_VERIFY(!circuit.getVertexProperty<4>(14)); + BOOST_VERIFY(!circuit.getVertexProperty<4>(15)); + BOOST_VERIFY(!circuit.getVertexProperty<4>(16)); + + + +} diff --git a/xacc/accelerator/Accelerator.hpp b/xacc/accelerator/Accelerator.hpp index 562100c52..0fbef44ea 100644 --- a/xacc/accelerator/Accelerator.hpp +++ b/xacc/accelerator/Accelerator.hpp @@ -139,7 +139,9 @@ protected: template<typename BitsType> class Accelerator : public IAccelerator { - static_assert(std::is_base_of<AcceleratorBuffer, BitsType>::value, ""); + 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>; -- GitLab