Merge pull request #476 from tnguyen-ornl/tnguyen/getNativeCode

First pass of implementing Accelerator::getNativeCode
parents f820332d c61dbb6d
Pipeline #158333 failed with stage
in 11 minutes and 51 seconds
 import xacc xacc.qasm(''' .compiler xasm .circuit iterative_qpe .qbit q H(q); X(q); // Prepare the state: CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); H(q); // Measure and reset Measure(q, c); Reset(q); H(q); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); // Conditional rotation if(c) { Rz(q, -pi/2); } H(q); Measure(q, c); Reset(q); H(q); CPhase(q, q, -5*pi/8); CPhase(q, q, -5*pi/8); if(c) { Rz(q, -pi/4); } if(c) { Rz(q, -pi/2); } H(q); Measure(q, c); Reset(q); H(q); CPhase(q, q, -5*pi/8); if(c) { Rz(q, -pi/8); } if(c) { Rz(q, -pi/4); } if(c) { Rz(q, -pi/2); } H(q); Measure(q, c); ''') f = xacc.getCompiled('iterative_qpe') qpu = xacc.getAccelerator('ibm:ibmq_manhattan') # Note: this QASM represents the circuit in the *native* gateset of the backend: # e.g. {sx, rz, cx} print('HOWDY QASM:\n', qpu.getNativeCode(f, {'format': 'qasm'})) # we can also see the native circuit as a QObj json print('HOWDY QObj:\n', qpu.getNativeCode(f, {'format': 'QObj'})) # Make sure the native QASM is valid by recompiling with Qiskit. from qiskit import QuantumCircuit qiskit_qc = QuantumCircuit.from_qasm_str(qpu.getNativeCode(f, {'format': 'qasm'})) qiskit_qc.draw()
 ... ... @@ -112,6 +112,24 @@ void bind_accelerator(py::module &m) { xacc::Accelerator::updateConfiguration, "") .def("getConnectivity", &xacc::Accelerator::getConnectivity, "") .def( "getNativeCode", [](xacc::Accelerator &qpu, std::shared_ptr f) { return qpu.getNativeCode(f); }, "") .def( "getNativeCode", [](xacc::Accelerator &qpu, std::shared_ptr f, PyHeterogeneousMap &options) { HeterogeneousMap m; for (auto &item : options) { PyHeterogeneousMap2HeterogeneousMap vis(m, item.first); mpark::visit(vis, item.second); } return qpu.getNativeCode(f, m); }, "") .def("configurationKeys", &xacc::Accelerator::configurationKeys, "") .def("contributeInstructions", &xacc::Accelerator::contributeInstructions, ""); ... ...
 ... ... @@ -1237,6 +1237,125 @@ void IBMAccelerator::put(const std::string &_url, const std::string &postStr, return; } std::string IBMAccelerator::getNativeCode(std::shared_ptr program, const HeterogeneousMap &config) { std::string format = "QObj"; // QObj/QASM if (config.stringExists("format")) { format = config.getString("format"); } // Handle different ways to specify the format: if (format == "QObj" || format == "QOBJ" || format == "JSON") { chosenBackend = availableBackends[backend]; auto connectivity = getConnectivity(); // Get the correct QObject Generator auto qobjGen = xacc::getService(mode); // Generate the QObject JSON auto jsonStr = qobjGen->getQObjJsonStr( {program}, shots, chosenBackend, getBackendPropsResponse, connectivity, json::parse(defaults_response)); return jsonStr; } else if (format == "qasm" || format == "Qasm" || format == "QASM" || format == "OpenQASM" || format == "OPENQASM") { chosenBackend = availableBackends[backend]; const auto basis_gates = chosenBackend["basis_gates"].get>(); // If the gate set has "u3" -> old gateset. const auto gateSet = (xacc::container::contains(basis_gates, "u3")) ? QObjectExperimentVisitor::GateSet::U_CX : QObjectExperimentVisitor::GateSet::RZ_SX_CX; std::stringstream ss; InstructionIterator it(program); int memSlots = 0; std::map cbit_reg_map; while (it.hasNext()) { auto nextInst = it.next(); if (nextInst->isEnabled() && !nextInst->isComposite()) { auto visitor = std::make_shared( program->name(), program->nLogicalBits(), gateSet); visitor->maxMemorySlots = memSlots; nextInst->accept(visitor); if (nextInst->name() == "Measure") { ++memSlots; } auto experiment = visitor->getExperiment(); for (auto &inst : experiment.get_instructions()) { // std::cout << "HOWDY: " << inst.toString() << "\n"; ss << inst.toString() << "\n"; } } else if (nextInst->name() == "ifstmt") { auto ifStmt = std::dynamic_pointer_cast(nextInst); // !! NOTE!! OpenQASM2 doesn't allow multi-statement if block // so need to wrap each statement individually. if (ifStmt) { for (auto &i : ifStmt->getInstructions()) { auto visitor = std::make_shared( program->name(), program->nLogicalBits(), gateSet); i->accept(visitor); auto experiment = visitor->getExperiment(); // Note: OpenQASM2 cannot express conditional on a single cbit // e.g., if (c[k] == 1) (c is a multi-bit register) // Ref: // https://quantumcomputing.stackexchange.com/questions/17901/if-statement-in-openqasm2-0-on-ibm-quantum-experience-error/17902#17902 // Also see: https://github.com/Qiskit/qiskit-terra/pull/6018 // qc.qasm() breaks when circuit qc contains gates with classical conditioning on a single cbit // Please note that this is a limitation of **OpenQASM** only, // i.e., qiskit's QuantumCircuit and QObj can both handle classical conditioning on a single cbit. // Our native code gen strategy here is to // convert multi-qreg indexing into multiple single-cbit registers: // i.e., c -> c3 (single-bit register) // This only happens when classical conditioning on a single cbit is needed. for (auto &inst : experiment.get_instructions()) { // std::cout << "HOWDY: " << inst.toString() << "\n"; const std::string orig_reg_name = "c[" + std::to_string(nextInst->bits()) + "]"; if (cbit_reg_map.find(orig_reg_name) != cbit_reg_map.end()) { const std::string single_reg_name = cbit_reg_map[orig_reg_name]; ss << "if (" + single_reg_name + " == 1) "; } else { const std::string single_reg_name = "cReg" + std::to_string(cbit_reg_map.size()); cbit_reg_map[orig_reg_name] = single_reg_name; ss << "if (" + single_reg_name + " == 1) "; } ss << inst.toString() << "\n"; } } } } } const auto replaceAll = [](const std::string &t, const std::string &s, std::string &str) { std::string::size_type n = 0; while ((n = str.find(s, n)) != std::string::npos) { str.replace(n, s.size(), t); n += t.size(); } }; std::string preAmple = R"(OPENQASM 2.0; include "qelib1.inc"; qreg q[)" + std::to_string(program->nLogicalBits()) + "];\ncreg c[" + std::to_string(memSlots) + "];\n"; auto qasm_body = ss.str(); for (const auto &[org_name, new_name] : cbit_reg_map) { const std::string creg_decl = "creg " + new_name + ";\n"; preAmple += creg_decl; // Replace the target of the measurement as well. replaceAll(new_name, org_name, qasm_body); } return preAmple + qasm_body; } xacc::error("Unknown native code format '" + format + "'"); return ""; } std::string IBMAccelerator::get(const std::string &_url, const std::string &path, std::map headers, ... ...
 ... ... @@ -131,6 +131,8 @@ public: std::vector> getConnectivity() override; std::string getNativeCode(std::shared_ptr program, const HeterogeneousMap &config) override; // Return the name of an IRTransformation of type Placement that is // preferred for this Accelerator const std::string defaultPlacementTransformation() override { ... ...
 ... ... @@ -399,6 +399,33 @@ public: std::optional get_condition_reg_id() const { return conditional; } void set_condition_reg_id(int64_t value) { this->conditional = value; } std::string toString() const { std::stringstream ss; ss << name; if (!params.empty()) { ss << "("; for (int i = 0; i < params.size(); ++i) { ss << params[i]; if (i != params.size() - 1) { ss << ", "; } } ss << ")"; } for (int i = 0; i < qubits.size(); ++i) { ss << " q[" << qubits[i] << "]"; if (i != qubits.size() - 1) { ss << ", "; } } if (!get_memory().empty()) { ss << " -> c[" << get_memory() << "]"; } ss << ";"; return ss.str(); } }; class Experiment { ... ...
 ... ... @@ -106,6 +106,14 @@ public: return std::vector>{}; } // Get circuit representation that the backend would be submitting to the // physical QPU virtual std::string getNativeCode(std::shared_ptr program, const HeterogeneousMap &config = {}) { return program->toString(); } virtual const std::vector> getAcceleratorState(std::shared_ptr program) { return std::vector>{}; ... ...
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!