Commit 44841b6d authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Committing initial work on QasmToGraph utility

parent f0003f2c
add_subdirectory(scaffold)
add_subdirectory(utils)
......@@ -12,5 +12,5 @@ install(TARGETS ${LIBRARY_NAME} DESTINATION lib)
# Gather tests
file (GLOB test_files tests/*.cpp)
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR}" "${LIBRARY_NAME}")
add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_SOURCE_DIR}/../utils" "${LIBRARY_NAME}")
......@@ -2,6 +2,7 @@
#include "GraphIR.hpp"
#include <regex>
#include "ScaffCCAPI.hpp"
#include "QasmToGraph.hpp"
namespace xacc {
......@@ -36,6 +37,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>>;
// Compile the source code and return the QASM form
// This will throw if it fails.
......@@ -44,7 +46,15 @@ std::shared_ptr<IR> ScaffoldCompiler::compile() {
// Generate a GraphIR instance, ie a graph
// tensor references making up this QASM
std::cout << "Flat QASM: \n" << qasm << "\n";
return std::make_shared<GraphIR>();
// Get the Qasm as a Graph...
auto circuitGraph = QasmToGraph::getCircuitGraph(qasm);
// Create a GraphIR instance from that graph
auto graphIR = std::make_shared<ScaffoldGraphIR>(circuitGraph);
// Return the IR.
return graphIR;
}
} // end namespace quantum
......
......@@ -34,27 +34,73 @@
#include <boost/test/included/unit_test.hpp>
#include "AbstractFactory.hpp"
#include "Compiler.hpp"
#include "QasmToGraph.hpp"
#include "GraphIR.hpp"
#include "ScaffoldCompiler.hpp"
using namespace qci::common;
using namespace xacc::quantum;
BOOST_AUTO_TEST_CASE(checkSimpleCompile) {
using GraphType = Graph<CircuitNode>;
BOOST_AUTO_TEST_CASE(checkScaffoldCompiler) {
auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold");
BOOST_VERIFY(compiler);
const std::string src("__qpu__ teleport () {\n"
" qbit qs[3];\n"
" cbit cs[2];\n"
" H(qs[1]);\n"
" CNOT(qs[1],qs[2]);\n"
" CNOT(qs[0], qs[1]);\n"
const std::string src("__qpu__ eprCreation () {\n"
" qbit qs[2];\n"
" H(qs[0]);\n"
" cs[0] = MeasZ(qs[0]);\n"
" cs[1] = MeasZ(qs[1]);\n"
// " if(cs[0]) {\n"
// " X(qs[2]);\n"
// " }\n"
// " if(cs[1]) {\n"
// " Z(qs[2]);\n"
// " }\n"
" CNOT(qs[0],qs[1]);\n"
"}\n");
auto ir = compiler->compile(src);
BOOST_VERIFY(ir);
auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir);
BOOST_VERIFY(graphir);
// The above code should produce a graph
// with 3 nodes (initial qubits state, Hadamard, and CNot),
// with 3 edges (q0 lifeline to H, q0 lifeline from H to CNot,
// and q1 lifeline to CNot)
BOOST_VERIFY(graphir->order() == 3);
BOOST_VERIFY(graphir->size() == 3);
}
BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
using GraphType = Graph<CircuitNode>;
auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold");
BOOST_VERIFY(compiler);
const std::string src("__qpu__ threeBitQFT () {\n"
" qbit q[3];\n"
" H(q[0]);\n"
" T(q[0]);\n"
" Rz(q[1],3.1415 / 4.0);\n"
" CNOT(q[1], q[0]);\n"
" Rz(q[1], -1.0 * 3.1415 / 4.0);\n"
" CNOT(q[1], q[0]);\n"
" Rz(q[0], 3.1415 / 8.0);\n"
" Rz(q[2], 3.1415 / 8.0);\n"
" CNOT(q[2], q[0]);\n"
" Rz(q[2], -1.0 * 3.1415 / 4.0);\n"
" CNOT(q[2], q[0]);\n"
" H(q[1]);\n"
" T(q[1]);\n"
" Rz(q[2],3.1415 / 4.0);\n"
" CNOT(q[2], q[1]);\n"
" Rz(q[2], -1.0 * 3.1415 / 4.0);\n"
" CNOT(q[2], q[1]);\n"
" H(q[2]);\n"
"}\n");
compiler->compile(src);
auto ir = compiler->compile(src);
BOOST_VERIFY(ir);
auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir);
BOOST_VERIFY(graphir);
// Scaffold decomposes Rz into H and T gates.
BOOST_VERIFY(graphir->order() > 1400);
}
set (PACKAGE_NAME "Quantum XACC Utils Runtime")
set (PACKAGE_DESCIPTION "Quantum XACC Common Utilities")
file (GLOB HEADERS *.hpp)
install(FILES ${HEADERS} DESTINATION include)
# Gather tests
#file (GLOB test_files tests/*.cpp)
#add_tests("${test_files}" "${CMAKE_CURRENT_SOURCE_DIR}" "${LIBRARY_NAME}")
/***********************************************************************************
* 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 <organization> 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_QASMTOGRAPH_HPP_
#define QUANTUM_GATE_QASMTOGRAPH_HPP_
#include "Graph.hpp"
#include <regex>
#include <boost/unordered_map.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/algorithm/string.hpp>
namespace xacc {
namespace quantum {
using boost::assign::map_list_of;
enum SupportedGates {
H, CNot, C_Z, C_X, Measure, X, Y, Z, T, S, ZZ, SS, Swap, Toffoli, InitialState
};
const boost::unordered_map<std::string, SupportedGates> strToGate =
map_list_of("h", H)("cnot", CNot)("c_z", C_Z)("c_x", C_X)("measure",
Measure)("x", X)("y", Y)("z", Z)("t", T)("s", S)("zz", ZZ)("ss",
SS)("swap", Swap)("toffoli", Toffoli);
const boost::unordered_map<SupportedGates, std::string> gateToStr =
map_list_of(H, "h")(CNot, "cnot")(C_Z, "c_z")(C_X, "c_x")(Measure,
"measure")(X, "x")(Y, "y")(Z, "z")(T, "t")(S, "s")(ZZ, "zz")(SS,
"ss")(Swap, "swap")(Toffoli, "toffoli");
/**
* Params - gate name, layer (ie time sequence), vertex id,
* qubit ids that gate acts on
*/
class CircuitNode : public qci::common::QCIVertex<SupportedGates, int, int, std::vector<int>> {};
class QasmToGraph {
public:
static qci::common::Graph<CircuitNode> getCircuitGraph(
const std::string& flatQasmStr) {
using namespace qci::common;
Graph<CircuitNode> graph;
std::map<std::string, int> qubitVarNameToId;
std::vector<std::string> qasmLines;
std::vector<int> allQbitIds;
std::regex newLineDelim("\n"), spaceDelim(" ");
std::regex qubitDeclarations("\\s*qubit\\s*\\w+");
std::sregex_token_iterator first{flatQasmStr.begin(), flatQasmStr.end(), newLineDelim, -1}, last;
int nQubits = 0, qbitId = 0, layer = 1, gateId = 1;
qasmLines = {first, last};
// Let's now loop over the qubit declarations,
// and construct a mapping of qubit var names to integer id,
// and get the total number of qubits
for (auto i = std::sregex_iterator(flatQasmStr.begin(), flatQasmStr.end(),
qubitDeclarations); i != std::sregex_iterator(); ++i) {
std::string qubitLine = (*i).str();
qubitLine.erase(std::remove(qubitLine.begin(), qubitLine.end(), '\n'), qubitLine.end());
std::sregex_token_iterator first{qubitLine.begin(), qubitLine.end(), spaceDelim, -1}, last;
std::vector<std::string> splitQubitLine = {first, last};
qubitVarNameToId[splitQubitLine[1]] = qbitId;
allQbitIds.push_back(qbitId);
qbitId++;
}
nQubits = qubitVarNameToId.size();
std::cout << "Number of Qubits is " << nQubits << std::endl;
// Fill the Graph...
// First create a starting node for the initial
// wave function - it should have nQubits outgoing
// edges
graph.addVertex(SupportedGates::InitialState, 0, 0, allQbitIds);
std::vector<CircuitNode> gateOperations;
for (auto line : qasmLines) {
// If this is a gate line...
if (!boost::contains(line, "qubit")) {
std::sregex_token_iterator first { line.begin(),
line.end(), spaceDelim, -1 }, last;
std::vector<std::string> gateCommand = {first, last};
// If we have a > 2 qubit gate, make a new layer
if (boost::contains(gateCommand[1], ",")) {
layer++;
}
// Create a new CircuitNode
CircuitNode node;
// Set the gate as a lowercase gate name string
auto g = boost::to_lower_copy(gateCommand[0]);
boost::trim(g);
auto s = strToGate.at(g);
std::get<0>(node.properties) = s;
// Set the current layer
std::get<1>(node.properties) = layer;
std::get<2>(node.properties) = gateId;
gateId++;
std::vector<int> actingQubits;
if (!boost::contains(gateCommand[1], ",")) {
actingQubits.push_back(qubitVarNameToId[gateCommand[1]]);
} else {
std::vector<std::string> qbits;
boost::split(qbits, gateCommand[1], boost::is_any_of(","));
for (auto q : qbits) {
actingQubits.push_back(qubitVarNameToId[q]);
}
}
// Set the acting qubits
std::get<3>(node.properties) = actingQubits;
gateOperations.push_back(node);
graph.addVertex(node);
}
}
// Set how many layers are in this circuit
int maxLayer = layer;
// Print info...
for (auto cn : gateOperations) {
std::cout << "Gate Operation: \n";
std::cout << "\tName: " << gateToStr.at(std::get<0>(cn.properties)) << "\n";
std::cout << "\tLayer: " << std::get<1>(cn.properties) << "\n";
std::cout << "\tGate Vertex Id: " << std::get<2>(cn.properties) << "\n";
std::cout << "\tActing Qubits: ";
std::vector<int> qubits = std::get<3>(cn.properties);
for (auto v : qubits) {
if (!(v == *qubits.end())) {
std::cout << v << ", ";
} else {
std::cout << v;
}
}
std::cout << "\n\n";
}
// Add an edge between the initial state node
// and the layer 1 gates
std::map<int,int> qubitToCurrentGateId;
for (int i = 0 ; i < nQubits; i++) {
qubitToCurrentGateId[i] = 0;
}
// std::vector<CircuitNode> layerOneGates;
// std::copy_if(gateOperations.begin(), gateOperations.end(),
// std::back_inserter(layerOneGates),
// [](const CircuitNode& c) {return std::get<1>(c.properties) == 1;});
// for (auto i : layerOneGates) {
// std::vector<int> actingQubits = std::get<3>(i.properties);
// for (auto qubit : actingQubits) {
// graph.addEdge(0, std::get<2>(i.properties));
// qubitToCurrentGateId[qubit] = std::get<2>(i.properties);
// }
// }
int currentLayer = 1;
while (currentLayer <= maxLayer) {
std::vector<CircuitNode> currentLayerGates;
std::copy_if(gateOperations.begin(), gateOperations.end(),
std::back_inserter(currentLayerGates),
[&](const CircuitNode& c) {return std::get<1>(c.properties) == currentLayer;});
for (auto n : currentLayerGates) {
std::vector<int> actingQubits = std::get<3>(n.properties);
for (auto qubit : actingQubits) {
int currentQubitGateId = qubitToCurrentGateId[qubit];
graph.addEdge(currentQubitGateId, std::get<2>(n.properties));
qubitToCurrentGateId[qubit] = std::get<2>(n.properties);
}
}
currentLayer++;
}
// Then we can go through and assign edges
// to all vertices
return graph;
}
};
}
}
#endif /* QUANTUM_GATE_QASMTOGRAPH_HPP_ */
......@@ -31,18 +31,15 @@
#ifndef XACC_XACC_HPP_
#define XACC_XACC_HPP_
#include "Program.hpp"
#include "Accelerator.hpp"
namespace xacc {
std::shared_ptr<xacc::Program> createProgram(std::string src, Accelerator& acc,
std::string compileArgs) {
std::shared_ptr<xacc::Program> program;
return program;
std::vector<IRTransformation> getAcceleratorIndependentTransformations(
Accelerator::AcceleratorType& accType) {
std::vector<IRTransformation> transformations;
return transformations;
}
}
......
......@@ -32,12 +32,18 @@
#define XACC_ACCELERATOR_HPP_
#include <string>
#include "IRTransformation.hpp"
namespace xacc {
class Accelerator {
public:
enum AcceleratorType { qpu_gate, qpu_aqc, npu };
virtual AcceleratorType getType() = 0;
virtual std::vector<IRTransformation> getIRTransformations() = 0;
template<typename T>
T executeKernel(std::string accArgs) {
......
/***********************************************************************************
* 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 <organization> 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_GRAPHIR_HPP_
#define QUANTUM_GRAPHIR_HPP_
#include "Compiler.hpp"
#include "Graph.hpp"
namespace xacc {
class GraphIR : public IR {
template<typename DerivedGraph>
class GraphIR: public IR {
protected:
DerivedGraph graph;
public:
virtual std::string toString() {return "";}
GraphIR(DerivedGraph& g) :
graph(g) {
}
virtual int order() {
return graph.order();
}
virtual int size() {
return graph.size();
}
virtual std::string toString() {
return "";
}
};
}
......
......@@ -32,7 +32,6 @@
#define XACC_COMPILER_IR_HPP_
#include "AbstractFactory.hpp"
#include "QCIError.hpp"
namespace xacc {
......
......@@ -31,14 +31,13 @@
#ifndef XACC_COMPILER_IROPTIMIZATION_HPP_
#define XACC_COMPILER_IROPTIMIZATION_HPP_
#include "AbstractFactory.hpp"
#include "QCIError.hpp"
#include "IR.hpp"
namespace xacc {
class IROptimization {
public:
virtual IR * optimize(IR * ir) = 0;
virtual void optimize(IR& ir) = 0;
virtual ~IROptimization() {}
};
......
......@@ -31,15 +31,14 @@
#ifndef XACC_COMPILER_IRTRANSLATION_HPP_
#define XACC_COMPILER_IRTRANSLATION_HPP_
#include "AbstractFactory.hpp"
#include "QCIError.hpp"
#include "IR.hpp"
namespace xacc {
class IRTranslation {
class IRTransformation {
public:
virtual IR * translate(IR * ir) = 0;
virtual ~IRTranslation() {}
virtual void transform(IR& ir) = 0;
virtual ~IRTransformation() {}
};
}
......
......@@ -42,6 +42,7 @@
#include <algorithm>
#include "QCIError.hpp"
#include "XaccUtils.hpp"
#include "XACC.hpp"
using namespace boost::program_options;
using namespace qci::common;
......@@ -57,14 +58,15 @@ protected:
std::string src;
Accelerator accelerator;
std::shared_ptr<Accelerator> accelerator;
std::shared_ptr<options_description> compilerOptions;
public:
Program(Accelerator& acc, const std::string& sourceFile) :
accelerator(acc), src(sourceFile) {
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",
......@@ -103,8 +105,22 @@ public:
}
// Execute IR Translations and Optimizations
// FIXME GET LIST OF TRANSFORMATION FROM
auto acceleratorType = accelerator->getType();
auto defaultTransforms = getAcceleratorIndependentTransformations(acceleratorType);
auto accDepTransforms = accelerator->getIRTransformations();
for (IRTransformation& t : defaultTransforms) {
t.transform(*ir.get());
}
for (IRTransformation& t : accDepTransforms) {
t.transform(*ir.get());
}
// Create Kernel from IR
return;
}
void getKernel(std::string& name) {}
......
......@@ -38,6 +38,14 @@ using namespace xacc;
class FakeAccelerator : public Accelerator {
public:
virtual AcceleratorType getType() { return qpu_gate; }
virtual std::vector<IRTransformation> getIRTransformations() {std::vector<IRTransformation> v; return v;}
virtual ~FakeAccelerator() {}
};
class FakeIR: public IR {
......@@ -79,7 +87,8 @@ BOOST_AUTO_TEST_CASE(checkBuildRuntimeArguments) {
" }"
"}");
FakeAccelerator acc;
auto acc = std::make_shared<FakeAccelerator>();
Program prog(acc, src);
prog.build("--compiler dummy");
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment