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

updated staq tpl with latest bug fix, minor cleanup throughout


Signed-off-by: Mccaskey, Alex's avatarAlex McCaskey <mccaskeyaj@ornl.gov>
parent 8db62292
Pipeline #118352 passed with stage
in 13 minutes and 14 seconds
......@@ -27,18 +27,16 @@ class MitiqDecorator(xacc.AcceleratorDecorator):
def noisy_sim(circ : QuantumCircuit):
# Convert circ to a CompositeInstruction
out_src = circ.qasm()
# print('hello src:\n', out_src)
out_prog = self.openqasm_compiler.compile(out_src).getComposites()[0]
# print('after compile:\n', out_prog.toString())
# Execute on a tmp buffer
tmp_buffer = xacc.qalloc(buffer.size())
self.decoratedAccelerator.execute(tmp_buffer, out_prog)
# tmp_buffer.addExtraInfo('exp-val-z', tmp_buffer.getExpectationValueZ())
# record the noisy exp val
buffer.addExtraInfo('noisy-exp-val-z', tmp_buffer.getExpectationValueZ())
buffer.appendChild('mitiq-noisy-exec-'+buffer.name(), tmp_buffer)
# buffer.appendChild('mitiq-noisy-exec-'+buffer.name(), tmp_buffer)
return tmp_buffer.getExpectationValueZ()
# easiest thing to do is map to Qiskit
......@@ -47,22 +45,27 @@ class MitiqDecorator(xacc.AcceleratorDecorator):
# Create a QuantumCircuit
circuit = QuantumCircuit.from_qasm_str(src)
# print(circuit.qasm())
# print('New Circuit:\n', circuit.qasm())
fixed_exp = mitiq.execute_with_zne(circuit, noisy_sim)
# print(fixed_exp)
buffer.addExtraInfo('exp-val-z', fixed_exp)
return
def execute(self, buffer, programs):
print('[mitiq] executing Mitiq')
# Translate IR to a Qobj Json String
if isinstance(programs, list) and len(programs) > 1:
for p in programs:
tmpBuffer = xacc.qalloc(buffer.size())
tmpBuffer.setName(p.name())
self.execute_single(tmpBuffer, p)
print('\t[mitiq] <', p.name(), '>_noisy = ', tmpBuffer['noisy-exp-val-z'] ,' -> <', p.name(), '>_fixed = ', tmpBuffer['exp-val-z'])
buffer.appendChild(p.name(),tmpBuffer)
# print(tmpBuffer)
else:
if isinstance(programs, list):
programs = programs[0]
self.execute_single(buffer, programs)
# print('returning from mitiq')
return
......@@ -163,6 +163,7 @@ void VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const {
// posts the energy automatically at a given key
// on the buffer extra info.
double energy = identityCoeff;
double variance = 0.0;
// Create buffer child for the Identity term
auto idBuffer = xacc::qalloc(buffer->size());
......@@ -194,12 +195,27 @@ void VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const {
for (int i = 0; i < nInstructionsEnergy; i++) { // compute energy
auto expval = buffers[i]->getExpectationValueZ();
if (!got_aggregate)
if (!got_aggregate) {
energy += expval * coefficients[i];
if (!buffers[i]->getMeasurementCounts().empty()) {
auto paulvar = 1. - expval * expval;
buffers[i]->addExtraInfo("pauli-variance", paulvar);
variance += coefficients[i] * coefficients[i] * paulvar;
}
}
buffers[i]->addExtraInfo("coefficient", coefficients[i]);
buffers[i]->addExtraInfo("kernel", fsToExec[i]->name());
buffers[i]->addExtraInfo("exp-val-z", expval);
buffers[i]->addExtraInfo("parameters", x);
if (!buffers[i]->getMeasurementCounts().empty()) {
int n_shots = 0;
for (auto [k, v] : buffers[i]->getMeasurementCounts()) {
n_shots += v;
}
buffers[i]->addExtraInfo("energy-standard-deviation",
std::sqrt(variance / n_shots));
}
buffer->appendChild(fsToExec[i]->name(), buffers[i]);
}
......@@ -225,6 +241,11 @@ void VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const {
for (int i = 0; i < fsToExec.size(); i++) {
auto expval = buffers[i]->getExpectationValueZ();
energy += expval * coefficients[i];
if (!buffers[i]->getMeasurementCounts().empty()) {
auto paulvar = 1. - expval * expval;
buffers[i]->addExtraInfo("pauli-variance", paulvar);
variance += coefficients[i] * coefficients[i] * paulvar;
}
}
for (int i = 0; i < fsToExec.size(); i++) {
......@@ -233,6 +254,16 @@ void VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer) const {
buffers[i]->addExtraInfo("exp-val-z",
buffers[i]->getExpectationValueZ());
buffers[i]->addExtraInfo("parameters", x);
if (!buffers[i]->getMeasurementCounts().empty()) {
int n_shots = 0;
for (auto [k, v] : buffers[i]->getMeasurementCounts()) {
n_shots += v;
}
buffers[i]->addExtraInfo("energy-standard-deviation",
std::sqrt(variance / n_shots));
}
buffer->appendChild(fsToExec[i]->name(), buffers[i]);
}
}
......@@ -305,6 +336,7 @@ VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer,
// posts the energy automatically at a given key
// on the buffer extra info.
double energy = identityCoeff;
double variance = 0.0;
// Create buffer child for the Identity term
auto idBuffer = xacc::qalloc(buffer->size());
......@@ -334,6 +366,11 @@ VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer,
for (int i = 0; i < fsToExec.size(); i++) { // compute energy
auto expval = buffers[i]->getExpectationValueZ();
energy += expval * coefficients[i];
if (!buffers[i]->getMeasurementCounts().empty()) {
auto paulvar = 1. - expval * expval;
buffers[i]->addExtraInfo("pauli-variance", paulvar);
variance += coefficients[i] * coefficients[i] * paulvar;
}
}
for (int i = 0; i < fsToExec.size(); i++) {
......@@ -341,6 +378,15 @@ VQE::execute(const std::shared_ptr<AcceleratorBuffer> buffer,
buffers[i]->addExtraInfo("kernel", fsToExec[i]->name());
buffers[i]->addExtraInfo("exp-val-z", buffers[i]->getExpectationValueZ());
buffers[i]->addExtraInfo("parameters", x);
if (!buffers[i]->getMeasurementCounts().empty()) {
int n_shots = 0;
for (auto [k, v] : buffers[i]->getMeasurementCounts()) {
n_shots += v;
}
buffers[i]->addExtraInfo("energy-standard-deviation",
std::sqrt(variance / n_shots));
}
buffer->appendChild(fsToExec[i]->name(), buffers[i]);
}
}
......
......@@ -73,37 +73,10 @@ void AerAccelerator::initialize(const HeterogeneousMap &params) {
}
if (params.stringExists("backend")) {
auto ibm = xacc::getAccelerator("ibm:" + params.getString("backend"));
physical_backend_properties = ibm->getProperties();
auto props = physical_backend_properties.get<std::string>("total-json");
auto props_json = nlohmann::json::parse(props);
connectivity = ibm->getConnectivity();
// nlohmann::json errors_json;
std::vector<nlohmann::json> elements;
std::size_t qbit = 0;
for (auto it = props_json["qubits"].begin();
it != props_json["qubits"].end(); ++it) {
std::vector<double> value{(*(it->begin() + 5))["value"].get<double>(),
(*(it->begin() + 4))["value"].get<double>()};
std::vector<std::vector<double>> probs{{1 - value[0], value[0]},
{value[1], 1 - value[1]}};
nlohmann::json element;
element["type"] = "roerror";
element["operations"] = std::vector<std::string>{"measure"};
element["probabilities"] = probs;
element["gate_qubits"] = std::vector<std::vector<std::size_t>>{{qbit}};
elements.push_back(element);
qbit++;
}
noise_model["errors"] = elements;
// noise_model["x90_gates"] = std::vecto
// std::cout << "NoiseModelJson:\n" << noise_model.dump(4) << "\n";
auto ibm_noise_model = xacc::getService<NoiseModel>("IBM");
ibm_noise_model->initialize(params);
auto json_str = ibm_noise_model->toJson();
noise_model = nlohmann::json::parse(json_str);
} else if (params.stringExists("noise-model")) {
std::string noise_model_str = params.getString("noise-model");
// Check if this is a file name
......@@ -152,7 +125,9 @@ void AerAccelerator::execute(
nlohmann::json j = nlohmann::json::parse(qobj_str)["qObject"];
j["config"]["shots"] = m_shots;
j["config"]["noise_model"] = noise_model;
xacc::info("Qobj:\n" + j.dump(2));
// xacc::set_verbose(true);
// xacc::info("Shots Qobj:\n" + j.dump(2));
auto results_json = nlohmann::json::parse(
AER::controller_execute_json<AER::Simulator::QasmController>(j.dump()));
......@@ -193,11 +168,18 @@ void AerAccelerator::execute(
auto qobj_str = xacc_to_qobj->translate(tmp);
nlohmann::json j = nlohmann::json::parse(qobj_str)["qObject"];
j["config"]["noise_model"] = noise_model;
// xacc::info("StateVec Qobj:\n" + j.dump(2));
auto results_json = nlohmann::json::parse(
AER::controller_execute_json<AER::Simulator::StatevectorController>(
j.dump()));
if (results_json["status"].get<std::string>().find("ERROR") != std::string::npos) {
std::cout << results_json["status"].get<std::string>() << "\n";
xacc::error("Aer Error: " + results_json["status"].get<std::string>());
}
auto results = *results_json["results"].begin();
auto state_vector = results["data"]["statevector"]
......
......@@ -192,11 +192,20 @@ std::shared_ptr<IR> StaqCompiler::compile(const std::string &src,
// std::cout << " HELLO:\n" << _src << "\n";
using namespace staq;
auto prog = parser::parse_string(_src);
transformations::desugar(*prog);
transformations::synthesize_oracles(*prog);
ast::ptr<ast::Program> prog;
try {
prog = parser::parse_string(src);
transformations::desugar(*prog);
transformations::synthesize_oracles(*prog);
} catch (std::exception &e) {
std::stringstream ss;
ss << e.what();
ss << "\nXACC Error in Staq Compiler, here was the src:\n" << src << "\n";
xacc::error(ss.str());
}
if (run_staq_optimize) optimization::simplify(*prog);
if (run_staq_optimize)
optimization::simplify(*prog);
// at this point we have to find out if we have any ancilla
// registers
......
......@@ -36,7 +36,6 @@ void SwapShort::apply(std::shared_ptr<CompositeInstruction> program,
return;
}
// First get total number of qubits on device
std::set<int> qbitIdxs;
auto connectivity = qpu->getConnectivity();
......@@ -62,12 +61,21 @@ void SwapShort::apply(std::shared_ptr<CompositeInstruction> program,
auto staq = xacc::getCompiler("staq");
auto src = staq->translate(program);
// std::cout << "HELLO WORLD:\n" << src << "\n";
// parse that to get staq ast
auto prog = parser::parse_string(src);
ast::ptr<ast::Program> prog;
try {
prog = parser::parse_string(src);
} catch (std::exception &e) {
std::stringstream ss;
ss << e.what();
ss << "\nXACC Error in Staq Swap Short, here was the src:\n" << src << "\n";
xacc::error(ss.str());
}
mapping::Device device(qpu->getSignature(), nQubits, adj);
mapping::Device device(qpu->getSignature(), nQubits,
adj);
// map qreg_NAME -> q
auto layout = mapping::compute_basic_layout(device, *prog);
mapping::apply_layout(layout, device, *prog);
......@@ -80,7 +88,9 @@ void SwapShort::apply(std::shared_ptr<CompositeInstruction> program,
prog->pretty_print(ss);
src = ss.str();
// std::cout << "AGAIN\n" << src << "\n";
auto ir = staq->compile(src);
// std::cout << "PASSED HERE\n";
// reset the program and add optimized instructions
program->clear();
......
/*
* This file is part of staq.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#pragma once
/**
* \file ast/ast.hpp
*/
#include "ast/visitor.hpp"
#include "ast/base.hpp"
#include "ast/expr.hpp"
#include "ast/stmt.hpp"
#include "ast/decl.hpp"
#include "ast/program.hpp"
#include "ast/semantic.hpp"
/*
* This file is part of staq.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* \file ast/base.hpp
* \brief openQASM syntax trees
*/
#pragma once
#include "parser/position.hpp"
#include "visitor.hpp"
#include <set>
#include <memory>
namespace staq {
namespace ast {
template <typename T>
using ptr = std::unique_ptr<T>;
using symbol = std::string;
/**
* \class staq::ast::ASTNode
* \brief Base class for AST nodes
*/
class ASTNode {
static int& max_uid_() {
static int v;
return v;
} ///< the maximum uid that has been assigned
protected:
const int uid_; ///< the node's unique ID
const parser::Position pos_; ///< the node's source code position
public:
ASTNode(parser::Position pos) : uid_(++max_uid_()), pos_(pos) {}
virtual ~ASTNode() = default;
/**
* \brief Get the ID of the node
*
* \return The node's unique ID
*/
int uid() const { return uid_; }
/**
* \brief Get the position of the node
*
* \return The node's position in source
*/
parser::Position pos() const { return pos_; }
/**
* \brief Provides dispatch for the Visitor pattern
*/
virtual void accept(Visitor& visitor) = 0;
/**
* \brief Print the formatted QASM source code of the node
*
* \param os Output stream
*/
virtual std::ostream& pretty_print(std::ostream& os) const = 0;
/**
* \brief Generate a deep copy of the node
*/
virtual ASTNode* clone() const = 0;
/**
* \brief Extraction operator override
*
* Extraction is non-virtual and delegates to pretty_print
*
* \param os Output stream
* \param node Node to print
*/
friend std::ostream& operator<<(std::ostream& os, const ASTNode& node) {
return node.pretty_print(os);
}
};
} // namespace ast
} // namespace staq
/*
* This file is part of staq.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* \file ast/decl.hpp
* \brief openQASM declarations
*/
#pragma once
#include "stmt.hpp"
#include <list>
namespace staq {
namespace ast {
static const std::set<std::string_view> qelib_defs{
"u3", "u2", "u1", "cx", "id", "u0", "x", "y", "z",
"h", "s", "sdg", "t", "tdg", "rx", "ry", "rz", "cz",
"cy", "swap", "ch", "ccx", "crz", "cu1", "cu3"};
/**
* \brief Tests whether identifier is part of the standard openQASM qelib or not
*
* \param id Identifier
* \return True if \a id is part of the standard openQASM qelib, false otherwise
*/
inline bool is_std_qelib(const std::string& id) {
return qelib_defs.find(id) != qelib_defs.end();
}
/**
* \class staq::ast::Decl
* \brief Base class for openQASM declarations
*
* Declarations are attribute classes as they can occur in different
* statement contexts. To avoid diamond inheritance, any derived declaration
* should also inherit from a statement class
*/
class Decl {
protected:
symbol id_; ///< the name of the declaration
public:
Decl(symbol id) : id_(id) {}
virtual ~Decl() = default;
/**
* \brief Return the name being declared
*
* \return Constant reference to the identifier
*/
const symbol& id() { return id_; }
};
/**
* \class staq::ast::GateDecl
* \brief Class for gate declarations
* \see staq::ast::Stmt
* \see staq::ast::Decl
*/
class GateDecl final : public Stmt, public Decl {
bool opaque_; ///< whether the declaration is opaque
std::vector<symbol> c_params_; ///< classical parameters
std::vector<symbol> q_params_; ///< quantum parameters
std::list<ptr<Gate>> body_; ///< gate body
public:
/**
* \brief Constructs a gate declaration
*
* \param pos The source position
* \param id The gate identifier
* \param c_params List of classical parameters
* \param q_params List of quantum parameters
* \param body List of gate statements
*/
GateDecl(parser::Position pos, symbol id, bool opaque,
std::vector<symbol> c_params, std::vector<symbol> q_params,
std::list<ptr<Gate>>&& body)
: Stmt(pos), Decl(id), opaque_(opaque), c_params_(c_params),
q_params_(q_params), body_(std::move(body)) {}
/**
* \brief Protected heap-allocated construction
*/
static ptr<GateDecl> create(parser::Position pos, symbol id, bool opaque,
std::vector<symbol> c_params,
std::vector<symbol> q_params,
std::list<ptr<Gate>>&& body) {
return std::make_unique<GateDecl>(pos, id, opaque, c_params, q_params,
std::move(body));
}
/**
* \brief Whether the declaration is opaque
*
* \return true is the declaration is opaque
*/
bool is_opaque() { return opaque_; }
/**
* \brief Get the classical parameter list
*
* \return Reference to the list of classical parameter names
*/
std::vector<symbol>& c_params() { return c_params_; }
/**
* \brief Get the quantum parameter list
*
* \return Reference to the list of quantum parameter names
*/
std::vector<symbol>& q_params() { return q_params_; }
/**
* \brief Get the gate body
*
* \return Reference to the body of the gate as a list of gate statements
*/
std::list<ptr<Gate>>& body() { return body_; }
/**
* \brief Apply a function to each statement of the gate
*
* \param f A void function taking a reference to a Gate
*/
void foreach_stmt(std::function<void(Gate&)> f) {
for (auto it = body_.begin(); it != body_.end(); it++)
f(**it);
}
/**
* \brief Get an iterator to the beginning of the body
*
* \return std::list iterator
*/
std::list<ptr<Gate>>::iterator begin() { return body_.begin(); }
/**
* \brief Get an iterator to the end of the body
*
* \return std::list iterator