Commit bb877d5c authored by Mccaskey, Alex's avatar Mccaskey, Alex
Browse files

implemented gateqir read and write. documentation throughout

parent 3a9222a2
......@@ -56,13 +56,10 @@ void GateFunction::replaceInstruction(int instId, InstPtr replacingInst) {
}
const std::string GateFunction::toString(const std::string bufferVarName) {
std::string retStr = "";
for (auto i : instructions) {
retStr += i->toString(bufferVarName) + "\n";
}
return retStr;
}
......
......@@ -32,26 +32,54 @@
#define QUANTUM_GATEQIR_QFUNCTION_HPP_
#include "QFunction.hpp"
#include "GateInstruction.hpp"
namespace xacc {
namespace quantum {
/**
* The GateFunction is a QFunction for gate-model
* quantum computing. It is composed of QInstructions that
* are themselves derivations of the GateInstruction class.
*/
class GateFunction: public virtual QFunction {
protected:
/**
* The list of QInstructions that this GateFunction
* contains.
*/
std::vector<std::shared_ptr<QInstruction>> instructions;
/**
* The name of this function
*/
std::string functionName;
/**
* The unique id integer for this function
*/
int functionId;
/**
* The list of qubits this function acts on.
*/
std::vector<int> qbits;
public:
/**
* The nullary constructor.
*/
GateFunction();
/**
* The constructor, takes the function unique id and its name.
*
* @param id
* @param name
*/
GateFunction(int id, const std::string name);
/**
......@@ -82,16 +110,43 @@ public:
virtual void replaceInstruction(int instId,
InstPtr replacingInst);
/**
* Return the id of this function
* @return
*/
virtual const int getId();
/**
* Return the name of this function
* @return
*/
virtual const std::string getName();
/**
* Return the qubits this function acts on.
* @return
*/
virtual const std::vector<int> qubits();
/**
* Return an assembly-like string representation for this function .
* @param bufferVarName
* @return
*/
virtual const std::string toString(const std::string bufferVarName);
/**
* This method should simply be implemented to invoke the
* visit() method on the provided QInstructionVisitor.
*
* @param visitor
*/
virtual void accept(QInstructionVisitor& visitor);
/**
* Return the number of instructions in this function.
* @return
*/
const int nInstructions();
};
}
......
......@@ -37,40 +37,95 @@ namespace xacc {
namespace quantum {
/**
*
* The GateInstruction is an implementation of QInstruction
* for gate-model quantum computing.
*/
class GateInstruction: public virtual QInstruction {
protected:
/**
* Reference to this instructions id
*/
int gateId;
/**
* Reference to this instructions name
*/
std::string gateName;
/**
* Reference to the circuit layer for this instruction.
*/
int circuitLayer;
/**
* Reference to the qubits this instruction acts on
*/
std::vector<int> qbits;
public:
/**
* The nullary contructor.
*/
GateInstruction() :
gateId(0), gateName("UNKNOWN"), circuitLayer(0), qbits(
std::vector<int> { }) {
}
/**
* The constructor, takes the id, name, layer, and qubits
* this instruction acts on.
*
* @param id
* @param layer
* @param name
* @param qubts
*/
GateInstruction(int id, int layer, std::string name, std::vector<int> qubts) :
gateId(id), circuitLayer(layer), gateName(name), qbits(qubts) {
}
/**
* Return the unique instruction id.
* @return
*/
virtual const int getId() {
return gateId;
}
/**
* Return the instruction name.
* @return
*/
virtual const std::string getName() {
return gateName;
}
/**
* Return the instruction layer.
*
* @return
*/
virtual const int layer() {
return circuitLayer;
}
/**
* Return the list of qubits this instruction acts on.
* @return
*/
virtual const std::vector<int> qubits() {
return qbits;
}
/**
* Return this instruction's assembly-like string
* representation.
* @param bufferVarName
* @return
*/
virtual const std::string toString(const std::string bufferVarName) {
auto str = gateName + " ";
for (auto q : qubits()) {
......@@ -83,6 +138,9 @@ public:
return str;
}
/**
* The destructor
*/
virtual ~GateInstruction() {
}
};
......
......@@ -29,16 +29,211 @@
*
**********************************************************************************/
#include "GateQIR.hpp"
#include <boost/algorithm/string.hpp>
#include <regex>
namespace xacc {
namespace quantum {
void GateQIR::generateGraph() {
// Local Declarations
auto flatQasmStr = toString();
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;
std::string qubitVarName;
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;
splitQubitLine[1].erase(
std::remove_if(splitQubitLine[1].begin(), splitQubitLine[1].end(), &isdigit),
splitQubitLine[1].end());
qubitVarName = splitQubitLine[1];
allQbitIds.push_back(qbitId);
qbitId++;
}
// Set the number of qubits
nQubits = qubitVarNameToId.size();
// First create a starting node for the initial
// wave function - it should have nQubits outgoing
// edges
addVertex("InitialState", 0, 0, allQbitIds, true, std::vector<std::string>{});
std::vector<CircuitNode> gateOperations;
for (auto line : qasmLines) {
// If this is a gate line...
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";
std::get<0>(node.properties) = g;
// 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]]);
} else {
// FIXME Need to differentiate between qubits and parameters here
// First we need the qubit register variable name
int counter = 0;
std::vector<std::string> splitComma, props;
boost::split(splitComma, gateCommand[1], boost::is_any_of(","));
for (auto segment : splitComma) {
if (boost::contains(segment, qubitVarName)) {
actingQubits.push_back(qubitVarNameToId[segment]);
} else {
// This is not a qubit, it must be a parameter for gate
props.push_back("PARAM_" + std::to_string(counter));
std::get<5>(node.properties) = props;
counter++;
}
}
}
// 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);
addVertex(node);
}
}
// Add a final layer for the graph sink
CircuitNode finalNode;
std::get<0>(finalNode.properties) = "FinalState";
std::get<1>(finalNode.properties) = layer+1;
std::get<2>(finalNode.properties) = gateId;
std::get<3>(finalNode.properties) = allQbitIds;
std::get<4>(finalNode.properties) = true;
addVertex(finalNode);
gateOperations.push_back(finalNode);
// Set how many layers are in this circuit
int maxLayer = layer+1;
generateEdgesFromLayer(1, gateOperations, 0);
return;
}
std::string GateQIR::toString() {
void GateQIR::generateEdgesFromLayer(const int layer,
std::vector<CircuitNode>& gateOperations, int initialStateId) {
int nQubits = std::get<3>(getVertexProperties(0)).size();
int maxLayer = std::get<1>(
gateOperations[gateOperations.size() - 1].properties);
std::map<int,int> qubitToCurrentGateId;
for (int i = 0 ; i < nQubits; i++) {
qubitToCurrentGateId[i] = initialStateId;
}
int currentLayer = layer;
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];
addEdge(currentQubitGateId, std::get<2>(n.properties));
qubitToCurrentGateId[qubit] = std::get<2>(n.properties);
}
}
currentLayer++;
}
}
bool GateQIR::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()
&& (std::get<0>(gates[gates.size() - 1].properties)
== "measure") && g != "measure") {
return true;
}
return false;
}
std::string GateQIR::toString() {
int nQubits = buffer->size();
auto bufVarName = buffer->name();
std::string retStr = "";
......@@ -48,27 +243,92 @@ std::string GateQIR::toString() {
for (auto f : kernels) {
retStr += f->toString(bufVarName);
}
return retStr;
}
void GateQIR::persist(std::ostream& outStream) {
write(outStream);
}
// FOR IR
void GateQIR::load(std::istream& inStream) {
read(inStream);
}
// FOR GRAPH
void GateQIR::read(std::istream& stream) {
}
// IMPLEMENT GRAPH READ STUFF
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]));
}
}
}
}
......@@ -63,6 +63,9 @@ public:
};
/**
* The GateQIR is an implementation of the QIR for gate model quantum
* computing. It provides a Graph node type that models a quantum
* circuit gate (CircuitNode).
*
*/
class GateQIR: public virtual xacc::quantum::QIR<xacc::quantum::CircuitNode> {
......@@ -70,24 +73,39 @@ class GateQIR: public virtual xacc::quantum::QIR<xacc::quantum::CircuitNode> {
protected:
/**
*
* Reference to the AcceleratorBuffer that this
* QIR operates on.
*/
std::shared_ptr<AcceleratorBuffer> buffer;
public:
/**
* The nullary Constructor
*/
GateQIR() {
}
/**
* The constructor, takes an accelerator buffer at construction.
* @param buf
*/
GateQIR(std::shared_ptr<AcceleratorBuffer> buf) :
buffer(buf) {
}
/**
* Provide a new AcceleratorBuffer for this Gate QIR.
* @param buf
*/
virtual void setAcceleratorBuffer(std::shared_ptr<AcceleratorBuffer> buf) {
buffer = buf;
}
/**
*
* This method takes the list of quantum instructions that this
* QIR contains and creates a graph representation of the
* quantum circuit.
*/
virtual void generateGraph();
......@@ -130,6 +148,45 @@ public:
virtual ~GateQIR() {
}
private:
/**
* This method determines if a new layer should be added to the circuit.
*
* @param gateCommand
* @param qubitVarNameToId
* @param gates
* @param currentLayer
* @return
*/
bool incrementLayer(const std::vector<std::string>& gateCommand,
std::map<std::string, int>& qubitVarNameToId,
const std::vector<CircuitNode>& gates, const int& currentLayer);
/**
* Generate all edges for the circuit graph starting at
* the given layer.
*
* @param layer
* @param graph
* @param gateOperations
* @param initialStateId
*/
void generateEdgesFromLayer(const int layer,
std::vector<CircuitNode>& gateOperations, int initialStateId);
/**