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
......@@ -59,11 +59,11 @@ BOOST_AUTO_TEST_CASE(checkSimpleCompile) {
BOOST_VERIFY(graphir);
// 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,
// and q1 lifeline to CNot)
BOOST_VERIFY(graphir->order() == 3);
BOOST_VERIFY(graphir->size() == 3);
BOOST_VERIFY(graphir->order() == 4);
BOOST_VERIFY(graphir->size() == 5);
}
......@@ -73,26 +73,21 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
auto compiler = qci::common::AbstractFactory::createAndCast<xacc::ICompiler>("compiler", "scaffold");
BOOST_VERIFY(compiler);
const std::string src("__qpu__ threeBitQFT () {\n"
const std::string src("__qpu__ teleport () {\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"
" cbit c[2];\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[1],q[2]);\n"
" CNOT(q[0],q[1]);\n"
" H(q[0]);\n"
" MeasZ(q[0]);\n"
" MeasZ(q[1]);\n"
" // Cz\n"
" H(q[2]);\n"
" CNOT(q[2], q[1]);\n"
" H(q[2]);\n"
" // CX = CNOT\n"
" CNOT(q[2], q[0]);\n"
"}\n");
auto ir = compiler->compile(src);
......@@ -100,6 +95,8 @@ BOOST_AUTO_TEST_CASE(checkAnotherSimpleCompile) {
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);
// I drew this out on paper, we should have 12
// nodes and 17 edges...
BOOST_VERIFY(graphir->order() == 12);
BOOST_VERIFY(graphir->size() == 17);
}
......@@ -42,32 +42,59 @@ namespace quantum {
using boost::assign::map_list_of;
/**
* Enumeration of gates we support
*/
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 =
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);
/**
* Create a SupportedGates to string mapping
*/
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
* 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<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 {
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(
const std::string& flatQasmStr) {
// Local Declarations
using namespace qci::common;
Graph<CircuitNode> graph;
std::map<std::string, int> qubitVarNameToId;
......@@ -76,7 +103,7 @@ public:
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;
int nQubits = 0, qbitId = 0, layer = 0, gateId = 1;
qasmLines = {first, last};
// Let's now loop over the qubit declarations,
......@@ -93,12 +120,11 @@ public:
qbitId++;
}
// Set the number of qubits
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
......@@ -107,31 +133,39 @@ public:
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++;
}
if (!boost::contains(line, "qubit") && !boost::contains(line, "cbit")) {
// Create a new CircuitNode
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
auto g = boost::to_lower_copy(gateCommand[0]);
boost::trim(g);
if (g == "measz") g = "measure";
auto s = strToGate.at(g);
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
std::get<1>(node.properties) = layer;
// Set the gate vertex id
std::get<2>(node.properties) = gateId;
gateId++;
// Set the qubits this gate acts on
std::vector<int> actingQubits;
if (!boost::contains(gateCommand[1], ",")) {
actingQubits.push_back(qubitVarNameToId[gateCommand[1]]);
......@@ -146,11 +180,16 @@ public:
// Set the acting qubits
std::get<3>(node.properties) = actingQubits;
// Add this gate to the local vector
// and to the graph
gateOperations.push_back(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
int maxLayer = layer;
......@@ -163,11 +202,7 @@ public:
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 << v << ", ";
}
std::cout << "\n\n";
}
......@@ -178,19 +213,8 @@ public:
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;
int currentLayer = 0;
while (currentLayer <= maxLayer) {
std::vector<CircuitNode> currentLayerGates;
std::copy_if(gateOperations.begin(), gateOperations.end(),
......@@ -209,13 +233,78 @@ public:
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
// to all vertices
// Break early if we can...
if (counter == nQubits)
break;
}
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 @@
#ifndef QUANTUM_GRAPHIR_HPP_
#define QUANTUM_GRAPHIR_HPP_
#include "Compiler.hpp"
#include "IR.hpp"
#include "Graph.hpp"
namespace xacc {
......@@ -61,6 +61,10 @@ public:
return "";
}
virtual void persist(std::ostream& outStream) {
}
};
}
......
......@@ -32,6 +32,7 @@
#define XACC_COMPILER_IR_HPP_
#include "AbstractFactory.hpp"
#include <ostream>
namespace xacc {
......@@ -41,6 +42,7 @@ namespace xacc {
class IR {
public:
virtual std::string toString() = 0;
virtual void persist(std::ostream& outStream) = 0;
virtual ~IR() {}
};
......
......@@ -41,6 +41,7 @@ public:
FakeIR() {
}
virtual std::string toString() { return std::string();}
virtual void persist(std::ostream& stream) {}
};
class FakeCompiler: public Compiler<FakeCompiler> {
friend Compiler<FakeCompiler>;
......
......@@ -53,7 +53,9 @@ public:
FakeIR() {
}
virtual std::string toString() { return std::string();}
virtual void persist(std::ostream& stream) {}
};
class DummyCompiler : public Compiler<DummyCompiler> {
public:
virtual std::shared_ptr<IR> compile() {
......
Markdown is supported
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