Commit d72952c2 authored by Nguyen, Thien's avatar Nguyen, Thien
Browse files

Staq translate to handle explicit creg



Creg can be larger than qreg (e.g., IQPE) and need to handle explicit Measure assignment.

Tested by: validating with Honeywell APIVAL
Signed-off-by: Nguyen, Thien's avatarThien Nguyen <nguyentm@ornl.gov>
parent de265997
......@@ -76,6 +76,9 @@ public:
std::vector<InstructionParameter> getParameters() override {
return {bufferName};
}
std::vector<std::string> getBufferNames() override { return {bufferName}; }
const int nParameters() override { return 1; }
const int nRequiredBits() const override { return 1; }
......
......@@ -428,27 +428,56 @@ std::shared_ptr<IR> StaqCompiler::compile(const std::string &src) {
const std::string
StaqCompiler::translate(std::shared_ptr<xacc::CompositeInstruction> function) {
std::map<std::string, int> bufNamesToSize;
std::map<std::string, int> cRegNamesToSize;
InstructionIterator iter(function);
// First search buffer names and see if we have
while (iter.hasNext()) {
auto &next = *iter.next();
if (!next.isComposite() && next.isEnabled()) {
for (int i = 0; i < next.nRequiredBits(); i++) {
auto bufName = next.getBufferName(i);
int size = next.bits()[i] + 1;
if (bufNamesToSize.count(bufName)) {
if (bufNamesToSize[bufName] < size) {
bufNamesToSize[bufName] = size;
if (next.name() == "Measure") {
xacc::quantum::Measure &m = (xacc::quantum::Measure &)next;
if (m.hasClassicalRegAssignment()) {
auto cregName = next.getBufferName(1);
int size = m.getClassicalBitIndex() + 1;
if (cRegNamesToSize.count(cregName)) {
if (cRegNamesToSize[cregName] < size) {
cRegNamesToSize[cregName] = size;
}
} else {
cRegNamesToSize.insert({cregName, size});
}
} else {
bufNamesToSize.insert({bufName, size});
auto bufName = next.getBufferName(0);
int size = next.bits()[0] + 1;
if (bufNamesToSize.count(bufName)) {
if (bufNamesToSize[bufName] < size) {
bufNamesToSize[bufName] = size;
}
} else {
bufNamesToSize.insert({bufName, size});
}
}
} else {
for (int i = 0; i < next.nRequiredBits(); i++) {
auto bufName = next.getBufferName(i);
int size = next.bits()[i] + 1;
if (bufNamesToSize.count(bufName)) {
if (bufNamesToSize[bufName] < size) {
bufNamesToSize[bufName] = size;
}
} else {
bufNamesToSize.insert({bufName, size});
}
}
}
}
}
auto translate =
std::make_shared<internal_staq::XACCToStaqOpenQasm>(bufNamesToSize);
cRegNamesToSize.empty()
? std::make_shared<internal_staq::XACCToStaqOpenQasm>(bufNamesToSize)
: std::make_shared<internal_staq::XACCToStaqOpenQasm>(
bufNamesToSize, cRegNamesToSize);
InstructionIterator iter2(function);
while (iter2.hasNext()) {
auto &next = *iter2.next();
......
......@@ -24,6 +24,18 @@ XACCToStaqOpenQasm::XACCToStaqOpenQasm(std::map<std::string, int> bufNamesToSize
}
}
XACCToStaqOpenQasm::XACCToStaqOpenQasm(
std::map<std::string, int> bufNamesToSize,
std::map<std::string, int> cRegNameToSize) {
ss << "OPENQASM 2.0;\ninclude \"qelib1.inc\";\n";
for (auto &kv : bufNamesToSize) {
ss << "qreg " << kv.first << "[" << kv.second << "];\n";
}
for (auto &kv : cRegNameToSize) {
ss << "creg " << kv.first << "[" << kv.second << "];\n";
}
}
void XACCToStaqOpenQasm::visit(Hadamard &h) {
ss << "h " << (h.getBufferNames().empty() ? "q" : h.getBufferName(0))
<< h.bits() << ";\n";
......@@ -97,10 +109,16 @@ void XACCToStaqOpenQasm::visit(CPhase &cphase) {
<< "[" << cphase.bits()[0] << "], " << (cphase.getBufferNames().empty() ? "q" : cphase.getBufferName(1)) << "[" << cphase.bits()[1] << "];\n";
}
void XACCToStaqOpenQasm::visit(Measure &m) {
ss << "measure " << (m.getBufferNames().empty() ? "q" : m.getBufferName(0))
<< m.bits() << " -> " << cregNames[m.getBufferName(0)] << m.bits()
<< ";\n";
qubitIdxToMeasCregName[m.bits()[0]] = cregNames[m.getBufferName(0)];
if (m.hasClassicalRegAssignment()) {
ss << "measure " << (m.getBufferNames().empty() ? "q" : m.getBufferName(0))
<< m.bits() << " -> " << m.getBufferName(1) << "["
<< m.getClassicalBitIndex() << "]"
<< ";\n";
} else {
ss << "measure " << (m.getBufferNames().empty() ? "q" : m.getBufferName(0))
<< m.bits() << " -> " << cregNames[m.getBufferName(0)] << m.bits()
<< ";\n";
}
}
void XACCToStaqOpenQasm::visit(Identity &i) {}
void XACCToStaqOpenQasm::visit(U &u) {
......@@ -111,8 +129,16 @@ void XACCToStaqOpenQasm::visit(IfStmt &ifStmt) {
// Note: this extended syntax: if (creg[k] == 1) is not supported by IBM.
// (IBM requires comparison to the full register value, not a bit check)
for (auto i : ifStmt.getInstructions()) {
ss << "if (" << qubitIdxToMeasCregName[ifStmt.bits()[0]] << "["
<< ifStmt.bits()[0] << "] == 1) ";
// If statement was specified by the qreg name -> find the associated cReg
if (cregNames.find(ifStmt.getBufferNames()[0]) != cregNames.end()) {
ss << "if (" << cregNames[ifStmt.getBufferNames()[0]] << "["
<< ifStmt.bits()[0] << "] == 1) ";
} else {
// Explicit creg was used:
ss << "if (" << ifStmt.getBufferNames()[0] << "[" << ifStmt.bits()[0]
<< "] == 1) ";
}
i->accept(this);
}
}
......
......@@ -266,9 +266,13 @@ class XACCToStaqOpenQasm : public AllGateVisitor {
public:
std::stringstream ss;
std::map<std::string, std::string> cregNames;
// Last known creg that stored the measurement result of a qubit
std::map<size_t, std::string> qubitIdxToMeasCregName;
// Default: assume each qreg is accompanied by a creg of the same size
XACCToStaqOpenQasm(std::map<std::string, int> bufNamesToSize);
// Explicit list of creg:
// e.g., IQPE algo: we requires a much larger creg than qreg to store all
// measurements.
XACCToStaqOpenQasm(std::map<std::string, int> bufNamesToSize,
std::map<std::string, int> cRegNameToSize);
void visit(Hadamard &h) override;
void visit(CNOT &cnot) override;
void visit(Rz &rz) override;
......
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