Skip to content
Snippets Groups Projects
Commit 8584913b authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

Fixed the way levels were set on quantum circuit graph, added persist method to IR

parent 0f06731a
No related branches found
No related tags found
No related merge requests found
...@@ -59,11 +59,11 @@ BOOST_AUTO_TEST_CASE(checkSimpleCompile) { ...@@ -59,11 +59,11 @@ BOOST_AUTO_TEST_CASE(checkSimpleCompile) {
BOOST_VERIFY(graphir); BOOST_VERIFY(graphir);
// The above code should produce a graph // The above code should produce a graph
// with 3 nodes (initial qubits state, Hadamard, and CNot), // with 4 nodes (initial qubits state, Hadamard, and CNot, sink final state),
// with 3 edges (q0 lifeline to H, q0 lifeline from H to CNot, // with 3 edges (q0 lifeline to H, q0 lifeline from H to CNot,
// and q1 lifeline to CNot) // and q1 lifeline to CNot)
BOOST_VERIFY(graphir->order() == 3); BOOST_VERIFY(graphir->order() == 4);
BOOST_VERIFY(graphir->size() == 3); BOOST_VERIFY(graphir->size() == 5);
} }
...@@ -73,26 +73,21 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) { ...@@ -73,26 +73,21 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold"); auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold");
BOOST_VERIFY(compiler); BOOST_VERIFY(compiler);
const std::string src("__qpu__ threeBitQFT () {\n" const std::string src("__qpu__ teleport () {\n"
" qbit q[3];\n" " qbit q[3];\n"
" H(q[0]);\n" " cbit c[2];\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" " H(q[1]);\n"
" T(q[1]);\n" " CNOT(q[1],q[2]);\n"
" Rz(q[2],3.1415 / 4.0);\n" " CNOT(q[0],q[1]);\n"
" CNOT(q[2], q[1]);\n" " H(q[0]);\n"
" Rz(q[2], -1.0 * 3.1415 / 4.0);\n" " MeasZ(q[0]);\n"
" MeasZ(q[1]);\n"
" // Cz\n"
" H(q[2]);\n"
" CNOT(q[2], q[1]);\n" " CNOT(q[2], q[1]);\n"
" H(q[2]);\n" " H(q[2]);\n"
" // CX = CNOT\n"
" CNOT(q[2], q[0]);\n"
"}\n"); "}\n");
auto ir = compiler->compile(src); auto ir = compiler->compile(src);
...@@ -100,6 +95,8 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) { ...@@ -100,6 +95,8 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir); auto graphir = std::dynamic_pointer_cast<xacc::GraphIR<GraphType>>(ir);
BOOST_VERIFY(graphir); BOOST_VERIFY(graphir);
// Scaffold decomposes Rz into H and T gates. // I drew this out on paper, we should have 12
BOOST_VERIFY(graphir->order() > 1400); // nodes and 17 edges...
BOOST_VERIFY(graphir->order() == 12);
BOOST_VERIFY(graphir->size() == 17);
} }
...@@ -42,32 +42,59 @@ namespace quantum { ...@@ -42,32 +42,59 @@ namespace quantum {
using boost::assign::map_list_of; using boost::assign::map_list_of;
/**
* Enumeration of gates we support
*/
enum SupportedGates { enum SupportedGates {
H, CNot, C_Z, C_X, Measure, X, Y, Z, T, S, ZZ, SS, Swap, Toffoli, InitialState H, CNot, C_Z, C_X, Measure, X, Y, Z, T, S, ZZ, SS, Swap, Toffoli, InitialState, FinalState
}; };
/**
* Create a string to SupportedGates mapping
*/
const boost::unordered_map<std::string, SupportedGates> strToGate = const boost::unordered_map<std::string, SupportedGates> strToGate =
map_list_of("h", H)("cnot", CNot)("c_z", C_Z)("c_x", C_X)("measure", 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", Measure)("x", X)("y", Y)("z", Z)("t", T)("s", S)("zz", ZZ)("ss",
SS)("swap", Swap)("toffoli", Toffoli); SS)("swap", Swap)("toffoli", Toffoli);
/**
* Create a SupportedGates to string mapping
*/
const boost::unordered_map<SupportedGates, std::string> gateToStr = const boost::unordered_map<SupportedGates, std::string> gateToStr =
map_list_of(H, "h")(CNot, "cnot")(C_Z, "c_z")(C_X, "c_x")(Measure, 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, "measure")(X, "x")(Y, "y")(Z, "z")(T, "t")(S, "s")(ZZ, "zz")(SS,
"ss")(Swap, "swap")(Toffoli, "toffoli"); "ss")(Swap, "swap")(Toffoli, "toffoli");
/** /**
* Params - gate name, layer (ie time sequence), vertex id, * CircuitNode subclasses QCIVertex to provide the following
* qubit ids that gate acts on * 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<SupportedGates, int, int, std::vector<int>> {}; class CircuitNode: public qci::common::QCIVertex<SupportedGates, int, int,
std::vector<int>> {
};
/**
* The QasmToGraph class provides a static
* utility method that maps a flat qasm string
* to a QCI Common Graph data structure.
*/
class QasmToGraph { class QasmToGraph {
public: public:
/**
* Create a Graph data structure that models a quantum
* circuit from the provided qasm string.
*
* @param flatQasmStr The qasm to be converted to a Graph.
* @return graph Graph modeling a quantum circuit.
*/
static qci::common::Graph<CircuitNode> getCircuitGraph( static qci::common::Graph<CircuitNode> getCircuitGraph(
const std::string& flatQasmStr) { const std::string& flatQasmStr) {
// Local Declarations
using namespace qci::common; using namespace qci::common;
Graph<CircuitNode> graph; Graph<CircuitNode> graph;
std::map<std::string, int> qubitVarNameToId; std::map<std::string, int> qubitVarNameToId;
...@@ -76,7 +103,7 @@ public: ...@@ -76,7 +103,7 @@ public:
std::regex newLineDelim("\n"), spaceDelim(" "); std::regex newLineDelim("\n"), spaceDelim(" ");
std::regex qubitDeclarations("\\s*qubit\\s*\\w+"); std::regex qubitDeclarations("\\s*qubit\\s*\\w+");
std::sregex_token_iterator first{flatQasmStr.begin(), flatQasmStr.end(), newLineDelim, -1}, last; std::sregex_token_iterator first{flatQasmStr.begin(), flatQasmStr.end(), newLineDelim, -1}, last;
int nQubits = 0, qbitId = 0, layer = 1, gateId = 1; int nQubits = 0, qbitId = 0, layer = 0, gateId = 1;
qasmLines = {first, last}; qasmLines = {first, last};
// Let's now loop over the qubit declarations, // Let's now loop over the qubit declarations,
...@@ -93,12 +120,11 @@ public: ...@@ -93,12 +120,11 @@ public:
qbitId++; qbitId++;
} }
// Set the number of qubits
nQubits = qubitVarNameToId.size(); nQubits = qubitVarNameToId.size();
std::cout << "Number of Qubits is " << nQubits << std::endl; std::cout << "Number of Qubits is " << nQubits << std::endl;
// Fill the Graph...
// First create a starting node for the initial // First create a starting node for the initial
// wave function - it should have nQubits outgoing // wave function - it should have nQubits outgoing
// edges // edges
...@@ -107,31 +133,39 @@ public: ...@@ -107,31 +133,39 @@ public:
std::vector<CircuitNode> gateOperations; std::vector<CircuitNode> gateOperations;
for (auto line : qasmLines) { for (auto line : qasmLines) {
// If this is a gate line... // If this is a gate line...
if (!boost::contains(line, "qubit")) { if (!boost::contains(line, "qubit") && !boost::contains(line, "cbit")) {
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 // Create a new CircuitNode
CircuitNode node; CircuitNode node;
// Split the current qasm command at the spaces
std::sregex_token_iterator first { line.begin(),
line.end(), spaceDelim, -1 }, last;
std::vector<std::string> gateCommand = {first, last};
// Set the gate as a lowercase gate name string // Set the gate as a lowercase gate name string
auto g = boost::to_lower_copy(gateCommand[0]); auto g = boost::to_lower_copy(gateCommand[0]);
boost::trim(g); boost::trim(g);
if (g == "measz") g = "measure";
auto s = strToGate.at(g); auto s = strToGate.at(g);
std::get<0>(node.properties) = s; std::get<0>(node.properties) = s;
// If not a 2 qubit gate, and if the acting
// qubit is different than the last one, then
// keep the layer the same, otherwise increment
if (incrementLayer(gateCommand, qubitVarNameToId,
gateOperations, layer)) {
layer++;
}
// Set the current layer // Set the current layer
std::get<1>(node.properties) = layer; std::get<1>(node.properties) = layer;
// Set the gate vertex id
std::get<2>(node.properties) = gateId; std::get<2>(node.properties) = gateId;
gateId++; gateId++;
// Set the qubits this gate acts on
std::vector<int> actingQubits; std::vector<int> actingQubits;
if (!boost::contains(gateCommand[1], ",")) { if (!boost::contains(gateCommand[1], ",")) {
actingQubits.push_back(qubitVarNameToId[gateCommand[1]]); actingQubits.push_back(qubitVarNameToId[gateCommand[1]]);
...@@ -146,11 +180,16 @@ public: ...@@ -146,11 +180,16 @@ public:
// Set the acting qubits // Set the acting qubits
std::get<3>(node.properties) = actingQubits; std::get<3>(node.properties) = actingQubits;
// Add this gate to the local vector
// and to the graph
gateOperations.push_back(node); gateOperations.push_back(node);
graph.addVertex(node); graph.addVertex(node);
} }
} }
// Add a final layer for the graph sink
graph.addVertex(SupportedGates::FinalState, layer+1, gateId, allQbitIds);
// Set how many layers are in this circuit // Set how many layers are in this circuit
int maxLayer = layer; int maxLayer = layer;
...@@ -163,11 +202,7 @@ public: ...@@ -163,11 +202,7 @@ public:
std::cout << "\tActing Qubits: "; std::cout << "\tActing Qubits: ";
std::vector<int> qubits = std::get<3>(cn.properties); std::vector<int> qubits = std::get<3>(cn.properties);
for (auto v : qubits) { for (auto v : qubits) {
if (!(v == *qubits.end())) { std::cout << v << ", ";
std::cout << v << ", ";
} else {
std::cout << v;
}
} }
std::cout << "\n\n"; std::cout << "\n\n";
} }
...@@ -178,19 +213,8 @@ public: ...@@ -178,19 +213,8 @@ public:
for (int i = 0 ; i < nQubits; i++) { for (int i = 0 ; i < nQubits; i++) {
qubitToCurrentGateId[i] = 0; qubitToCurrentGateId[i] = 0;
} }
// std::vector<CircuitNode> layerOneGates;
// std::copy_if(gateOperations.begin(), gateOperations.end(), int currentLayer = 0;
// 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) { while (currentLayer <= maxLayer) {
std::vector<CircuitNode> currentLayerGates; std::vector<CircuitNode> currentLayerGates;
std::copy_if(gateOperations.begin(), gateOperations.end(), std::copy_if(gateOperations.begin(), gateOperations.end(),
...@@ -209,13 +233,78 @@ public: ...@@ -209,13 +233,78 @@ public:
currentLayer++; currentLayer++;
} }
// Add a graph sink - ie a final node representing
// the final system state
int counter = 0;
// Walk the list downward, skip first node since is
// the graph sink
for (int i = gateOperations.size() - 1; i >= 0; i--) {
auto gate = gateOperations[i];
int currentGateId = std::get<2>(gate.properties);
int nQubitsActing = std::get<3>(gate.properties).size();
int gateDegree = graph.degree(currentGateId);
for (int j = gateDegree; j < 2 * nQubitsActing; j++) {
graph.addEdge(gateId, gateId);
counter++;
}
// Then we can go through and assign edges // Break early if we can...
// to all vertices if (counter == nQubits)
break;
}
return graph; return graph;
} }
private:
/**
* This method determines if a new layer should be added to the circuit.
*
* @param gateCommand
* @param qubitVarNameToId
* @param gates
* @param currentLayer
* @return
*/
static bool incrementLayer(const std::vector<std::string>& gateCommand,
std::map<std::string, int>& qubitVarNameToId,
const std::vector<CircuitNode>& gates, const int& currentLayer) {
bool oneQubitGate = !boost::contains(gateCommand[1], ","), noGateAtQOnL = true;
auto g = boost::to_lower_copy(gateCommand[0]);
boost::trim(g);
if (g == "measz") g = "measure";
std::vector<CircuitNode> thisLayerGates;
std::copy_if(gates.begin(), gates.end(),
std::back_inserter(thisLayerGates),
[&](const CircuitNode& c) {return std::get<1>(c.properties) == currentLayer;});
for (auto layerGate : thisLayerGates) {
std::vector<int> qubits = std::get<3>(layerGate.properties);
for (auto q : qubits) {
if (qubitVarNameToId[gateCommand[1]] == q) {
noGateAtQOnL = false;
}
}
}
if (!oneQubitGate) {
return true;
} else if (!noGateAtQOnL) {
return true;
} else if (!gates.empty()
&& (gateToStr.at(
std::get<0>(gates[gates.size() - 1].properties))
== "measure") && g != "measure") {
return true;
}
return false;
}
}; };
} }
} }
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#ifndef QUANTUM_GRAPHIR_HPP_ #ifndef QUANTUM_GRAPHIR_HPP_
#define QUANTUM_GRAPHIR_HPP_ #define QUANTUM_GRAPHIR_HPP_
#include "Compiler.hpp" #include "IR.hpp"
#include "Graph.hpp" #include "Graph.hpp"
namespace xacc { namespace xacc {
...@@ -61,6 +61,10 @@ public: ...@@ -61,6 +61,10 @@ public:
return ""; return "";
} }
virtual void persist(std::ostream& outStream) {
}
}; };
} }
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define XACC_COMPILER_IR_HPP_ #define XACC_COMPILER_IR_HPP_
#include "AbstractFactory.hpp" #include "AbstractFactory.hpp"
#include <ostream>
namespace xacc { namespace xacc {
...@@ -41,6 +42,7 @@ namespace xacc { ...@@ -41,6 +42,7 @@ namespace xacc {
class IR { class IR {
public: public:
virtual std::string toString() = 0; virtual std::string toString() = 0;
virtual void persist(std::ostream& outStream) = 0;
virtual ~IR() {} virtual ~IR() {}
}; };
......
...@@ -41,6 +41,7 @@ public: ...@@ -41,6 +41,7 @@ public:
FakeIR() { FakeIR() {
} }
virtual std::string toString() { return std::string();} virtual std::string toString() { return std::string();}
virtual void persist(std::ostream& stream) {}
}; };
class FakeCompiler: public Compiler<FakeCompiler> { class FakeCompiler: public Compiler<FakeCompiler> {
friend Compiler<FakeCompiler>; friend Compiler<FakeCompiler>;
......
...@@ -53,7 +53,9 @@ public: ...@@ -53,7 +53,9 @@ public:
FakeIR() { FakeIR() {
} }
virtual std::string toString() { return std::string();} virtual std::string toString() { return std::string();}
virtual void persist(std::ostream& stream) {}
}; };
class DummyCompiler : public Compiler<DummyCompiler> { class DummyCompiler : public Compiler<DummyCompiler> {
public: public:
virtual std::shared_ptr<IR> compile() { virtual std::shared_ptr<IR> compile() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment