Skip to content

Commit

Permalink
Fix performance regression from QuantumError assemble
Browse files Browse the repository at this point in the history
Fixes issue with QuantumError.to_dict causing a huge performance regression in noisy simulations from its calling of `qiskit.assemble` inside Pybind11 code.
  • Loading branch information
chriseclectic committed Dec 15, 2021
1 parent 61b028b commit 595886a
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 29 deletions.
6 changes: 2 additions & 4 deletions qiskit/providers/aer/noise/errors/quantum_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from qiskit.circuit.exceptions import CircuitError
from qiskit.circuit.library.generalized_gates import PauliGate
from qiskit.circuit.library.standard_gates import IGate
from qiskit.compiler import assemble
from qiskit.exceptions import QiskitError
from qiskit.extensions import UnitaryGate
from qiskit.quantum_info.operators.base_operator import BaseOperator
Expand Down Expand Up @@ -453,13 +452,12 @@ def error_term(self, position):

def to_dict(self):
"""Return the current error as a dictionary."""
qobj = assemble(self.circuits)
instructions = [exp.to_dict()['instructions'] for exp in qobj.experiments]
error = {
"type": "qerror",
"id": self.id,
"operations": [],
"instructions": instructions,
"instructions": [[op[0].assemble().to_dict() for op in circ.data]
for circ in self._circs],
"probabilities": list(self.probabilities)
}
return error
Expand Down
7 changes: 7 additions & 0 deletions releasenotes/notes/fix-qerror-assemble-9919a93b210ca776.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
Fix performance regression in noisy simulations due to large increase in
serialization overhead for loading noise models from Python into C++.
See `issue 1407 <https://github.com/Qiskit/qiskit-aer/issues/1407>`_ for
details.
38 changes: 16 additions & 22 deletions src/controllers/aer_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -846,37 +846,31 @@ Result Controller::execute(const inputdata_t &input_qobj) {
// Start QOBJ timer
auto timer_start = myclock_t::now();

Noise::NoiseModel noise_model;
json_t config;

// Check for config
if (Parser<inputdata_t>::get_value(config, "config", input_qobj)) {
// Set config
set_config(config);
// Load noise model
Parser<json_t>::get_value(noise_model, "noise_model", config);
}
// Initialize QOBJ
Qobj qobj(input_qobj, enable_truncation_);
auto qobj_time_taken =
std::chrono::duration<double>(myclock_t::now() - timer_start).count();

// Initialize qobj
Qobj qobj;
if (noise_model.has_nonlocal_quantum_errors()) {
// Non-local noise does not work with optimized initialization
qobj = Qobj(input_qobj, false);
} else {
qobj = Qobj(input_qobj, enable_truncation_);
}
// Set config
set_config(qobj.config);

// Run qobj circuits
auto result = execute(qobj.circuits, qobj.noise_model, qobj.config);

// Add QOBJ loading time
result.metadata.add(qobj_time_taken, "time_taken_load_qobj");

auto result = execute(qobj.circuits, noise_model, config);
// Get QOBJ id and pass through header to result
result.qobj_id = qobj.id;
if (!qobj.header.empty()) {
result.header = qobj.header;
}

// Stop the timer and add total timing data including qobj parsing
auto timer_stop = myclock_t::now();
auto time_taken =
std::chrono::duration<double>(timer_stop - timer_start).count();
std::chrono::duration<double>(myclock_t::now() - timer_start).count();
result.metadata.add(time_taken, "time_taken");

return result;
} catch (std::exception &e) {
// qobj was invalid, return valid output containing error message
Expand Down Expand Up @@ -1007,7 +1001,7 @@ Result Controller::execute(std::vector<Circuit> &circuits,
auto timer_stop = myclock_t::now();
auto time_taken =
std::chrono::duration<double>(timer_stop - timer_start).count();
result.metadata.add(time_taken, "time_taken");
result.metadata.add(time_taken, "time_taken_execute");
}
// If execution failed return valid output reporting error
catch (std::exception &e) {
Expand Down
22 changes: 19 additions & 3 deletions src/framework/qobj.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <vector>

#include "framework/circuit.hpp"
#include "noise/noise_model.hpp"

namespace AER {

Expand Down Expand Up @@ -50,6 +51,7 @@ class Qobj {
std::vector<Circuit> circuits; // List of circuits
json_t header; // (optional) passed through to result
json_t config; // (optional) qobj level config data
Noise::NoiseModel noise_model; // (optional) noise model
};

//============================================================================
Expand All @@ -73,9 +75,23 @@ Qobj::Qobj(const inputdata_t &input, bool truncation) {
throw std::invalid_argument(R"(Invalid qobj: no "experiments" field.)");
}

// Get header and config;
Parser<inputdata_t>::get_value(config, "config", input);
Parser<inputdata_t>::get_value(header, "header", input);
// Get config
if (Parser<inputdata_t>::get_value(config, "config", input)) {
// Parse noise model
Parser<json_t>::get_value(noise_model, "noise_model", config);

// If noise model has non-local errors disable trunction
if (noise_model.has_nonlocal_quantum_errors()) {
truncation = false;
}
} else {
config = json_t::object();
}

// Parse header
if (!Parser<inputdata_t>::get_value(header, "header", input)) {
header = json_t::object();
}

// Check for fixed simulator seed
// If simulator seed is set, each experiment will be set to a fixed (but different) seed
Expand Down

0 comments on commit 595886a

Please sign in to comment.