Skip to content

Commit

Permalink
merge code from Qiskit#2187 partialy to reduce deprecation warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
doichanj committed Aug 9, 2024
1 parent 2e10d29 commit ecce171
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 253 deletions.
1 change: 0 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ jobs:
- name: Run Tests
run: |
set -e
pip check
rm -rf qiskit_aer
stestr run --slowest
shell: bash
Expand Down
5 changes: 2 additions & 3 deletions qiskit_aer/backends/aer_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
from qiskit.transpiler.passes import Decompose


from qiskit.qobj import QobjExperimentHeader
from qiskit_aer.aererror import AerError
from qiskit_aer.noise import NoiseModel

Expand All @@ -62,7 +61,7 @@
AerConfig,
)

from .backend_utils import circuit_optypes
from .backend_utils import circuit_optypes, CircuitHeader
from ..library.control_flow_instructions import AerMark, AerJump, AerStore


Expand Down Expand Up @@ -680,7 +679,7 @@ def assemble_circuit(circuit: QuantumCircuit, basis_gates=None):
for inst in circuit.data
)

header = QobjExperimentHeader(
header = CircuitHeader(
n_qubits=num_qubits,
qreg_sizes=qreg_sizes,
memory_slots=num_memory,
Expand Down
67 changes: 3 additions & 64 deletions qiskit_aer/backends/aerbackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,12 @@ def _convert_binds(self, circuits, parameter_binds, idx_maps=None):
return parameterizations

# pylint: disable=arguments-renamed
def run(self, circuits, validate=False, parameter_binds=None, **run_options):
def run(self, circuits, parameter_binds=None, **run_options):
"""Run circuits on the backend.
Args:
circuits (QuantumCircuit or list): The QuantumCircuit (or list
of QuantumCircuit objects) to run
validate (bool): validate the Qobj before running (default: False).
parameter_binds (list): A list of parameter binding dictionaries.
See additional information (default: None).
run_options (kwargs): additional run time backend options.
Expand All @@ -158,7 +157,7 @@ def run(self, circuits, validate=False, parameter_binds=None, **run_options):
AerJob: The simulation job.
Raises:
TypeError: If ``parameter_binds`` is specified with a qobj input or
TypeError: If ``parameter_binds`` is specified with an input or
has a length mismatch with the number of circuits.
Additional Information:
Expand All @@ -183,67 +182,7 @@ def run(self, circuits, validate=False, parameter_binds=None, **run_options):
if isinstance(circuits, (QuantumCircuit, Schedule, ScheduleBlock)):
circuits = [circuits]

if isinstance(circuits, (QasmQobj, PulseQobj)):
warnings.warn(
"Using a qobj for run() is deprecated as of qiskit-aer 0.14"
" and will be removed no sooner than 3 months from that release"
" date. Transpiled circuits should now be passed directly using"
" `backend.run(circuits, **run_options).",
DeprecationWarning,
stacklevel=2,
)
if parameter_binds:
raise TypeError("Parameter binds can't be used with an input qobj")
# A work around to support both qobj options and run options until
# qobj is deprecated is to copy all the set qobj.config fields into
# run_options that don't override existing fields. This means set
# run_options fields will take precidence over the value for those
# fields that are set via assemble.
if not run_options:
run_options = circuits.config.__dict__
else:
run_options = copy.copy(run_options)
for key, value in circuits.config.__dict__.items():
if key not in run_options and value is not None:
run_options[key] = value
if "parameter_binds" in run_options:
parameter_binds = run_options.pop("parameter_binds")
return self._run_qobj(circuits, validate, parameter_binds, **run_options)

only_circuits = True
only_pulse = True
for circ in circuits:
only_circuits &= isinstance(circ, QuantumCircuit)
only_pulse &= isinstance(circ, (ScheduleBlock, Schedule))

if only_circuits and not only_pulse:
if validate:
raise TypeError(
"bad input to run() function;"
"`validation` argument is only effective for input qobj"
)

executor = run_options.get("executor", None)
if executor is None and "executor" in self.options.__dict__:
executor = self.options.__dict__.get("executor", None)
if executor:
# This path remains for DASK execution to split a qobj insttance
# into sub-qobj instances. This will be replaced with _run_circuits path
# in the near releases
return self._run_qobj(circuits, validate, parameter_binds, **run_options)
else:
return self._run_circuits(circuits, parameter_binds, **run_options)
elif not only_circuits and only_pulse:
return self._run_qobj(circuits, validate, parameter_binds, **run_options)
elif not only_circuits and not only_pulse:
raise TypeError(
"bad input to run() function;"
"circuits and schedules cannot be mixed in a single run"
)
else:
raise TypeError(
"bad input to run() function; circuits must be either circuits or schedules"
)
return self._run_circuits(circuits, parameter_binds, **run_options)

def _run_circuits(self, circuits, parameter_binds, **run_options):
"""Run circuits by generating native circuits."""
Expand Down
43 changes: 43 additions & 0 deletions qiskit_aer/backends/backend_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import os
from math import log2

from types import SimpleNamespace

import psutil
from qiskit.circuit import QuantumCircuit
from qiskit.qobj import QasmQobjInstruction
Expand Down Expand Up @@ -559,3 +561,44 @@ def circuit_optypes(circuit):
optypes.update(type(instruction.operation).mro())
optypes.discard(object)
return optypes


class CircuitHeader(SimpleNamespace):
"""A class used to represent a dictionary header in circuit objects."""

def __init__(self, **kwargs):
"""Instantiate a new circuit dict field object.
Args:
kwargs: arbitrary keyword arguments that can be accessed as
attributes of the object.
"""
self.__dict__.update(kwargs)

def to_dict(self):
"""Return a dictionary format representation of the circuit.
Returns:
dict: The dictionary form of the CircuitHeader.
"""
return self.__dict__

@classmethod
def from_dict(cls, data):
"""Create a new header object from a dictionary.
Args:
data (dict): A dictionary representing the header to create. It
will be in the same format as output by :func:`to_dict`.
Returns:
CircuitHeader: The CircuitHeader from the input dictionary.
"""

return cls(**data)

def __eq__(self, other):
if isinstance(other, self.__class__):
if self.__dict__ == other.__dict__:
return True
return False
11 changes: 4 additions & 7 deletions src/framework/pybind_json.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,10 +221,9 @@ json_t JSON::iterable_to_json_list(const py::handle &obj) {
void std::to_json(json_t &js, const py::handle &obj) {
static py::object PyNoiseModel =
py::module::import("qiskit_aer.noise.noise_model").attr("NoiseModel");
static py::object PyQasmQobj =
py::module::import("qiskit.qobj.qasm_qobj").attr("QasmQobj");
static py::object PyQasmQobjHeader =
py::module::import("qiskit.qobj.common").attr("QobjExperimentHeader");
static py::object PyCircuitHeader =
py::module::import("qiskit_aer.backends.backend_utils")
.attr("CircuitHeader");
if (py::isinstance<py::float_>(obj)) {
js = obj.cast<nl::json::number_float_t>();
} else if (py::isinstance<py::bool_>(obj)) {
Expand All @@ -249,9 +248,7 @@ void std::to_json(json_t &js, const py::handle &obj) {
return;
} else if (py::isinstance(obj, PyNoiseModel)) {
std::to_json(js, obj.attr("to_dict")());
} else if (py::isinstance(obj, PyQasmQobj)) {
std::to_json(js, obj.attr("to_dict")());
} else if (py::isinstance(obj, PyQasmQobjHeader)) {
} else if (py::isinstance(obj, PyCircuitHeader)) {
std::to_json(js, obj.attr("to_dict")());
} else {
auto type_str = std::string(py::str(obj.get_type()));
Expand Down
64 changes: 1 addition & 63 deletions test/terra/backends/aer_simulator/test_executors.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,10 @@
from qiskit.quantum_info import Statevector
from qiskit_aer.noise.noise_model import AerJSONEncoder
from test.terra.reference import ref_kraus_noise
from qiskit_aer.jobs import AerJob, AerJobSet
from qiskit_aer.jobs import AerJob
from test.terra.backends.simulator_test_case import SimulatorTestCase, supported_methods


DASK = False

try:
from dask.distributed import LocalCluster, Client

DASK = True
except ImportError:
DASK = False


def run_random_circuits(backend, shots=None, **run_options):
"""Test random circuits on different executor fictures"""
job_size = 10
Expand Down Expand Up @@ -107,58 +97,6 @@ def backend(self, **options):
return super().backend(executor=self._test_executor, **options)


@ddt
class TestDaskExecutor(CBFixture):
"""Tests of Dask executor"""

@classmethod
def setUpClass(cls):
super().setUpClass()
if DASK:
cls._test_executor = Client(address=LocalCluster(n_workers=1, processes=True))

def setUp(self):
super().setUp()
if not DASK:
self.skipTest("Dask not installed, skipping ClusterBackend-dask tests")

@supported_methods(["statevector"], [None, 1, 2, 3])
def test_random_circuits_job(self, method, device, max_job_size):
"""Test random circuits with custom executor."""
shots = 4000
backend = self.backend(method=method, device=device, max_job_size=max_job_size)
result, circuits, targets = run_random_circuits(backend, shots=shots)
self.assertSuccess(result)
self.compare_counts(result, circuits, targets, hex_counts=False, delta=0.05 * shots)

@supported_methods(["statevector"], [None, 1, 1, 1], [None, 100, 500, 1000])
def test_noise_circuits_job(self, method, device, max_job_size, max_shot_size):
"""Test random circuits with custom executor."""
shots = 4000
backend = self.backend(
method=method, device=device, max_job_size=max_job_size, max_shot_size=max_shot_size
)

circuits = ref_kraus_noise.kraus_gate_error_circuits()
noise_models = ref_kraus_noise.kraus_gate_error_noise_models()
targets = ref_kraus_noise.kraus_gate_error_counts(shots)

for circuit, noise_model, target in zip(circuits, noise_models, targets):
backend.set_options(noise_model=noise_model)
result = backend.run(circuit, shots=shots).result()
self.assertSuccess(result)
self.compare_counts(result, [circuit], [target], delta=0.05 * shots)

@supported_methods(["statevector"], [None, 1, 2, 3])
def test_result_time_val(self, method, device, max_job_size):
"""Test random circuits with custom executor."""
shots = 4000
backend = self.backend(method=method, device=device, max_job_size=max_job_size)
result, _, _ = run_random_circuits(backend, shots=shots)
self.assertSuccess(result)
self.assertGreaterEqual(result.time_taken, 0)


@ddt
class TestThreadPoolExecutor(CBFixture):
"""Tests of ThreadPool executor"""
Expand Down
9 changes: 7 additions & 2 deletions test/terra/noise/test_device_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,11 @@ def test_basic_device_gate_errors_from_target_with_non_operational_qubits(self):
target = target_7q()
# tweak target to have non-operational qubits
faulty_qubits = (1, 2)
q_prop = target.qubit_properties
for q in faulty_qubits:
target.qubit_properties[q] = QubitProperties(t1=None, t2=None, frequency=0)
q_prop[q] = QubitProperties(t1=None, t2=None, frequency=0)
target.qubit_properties = q_prop

# build gate errors with only relaxation errors i.e. without depolarizing errors
gate_errors = basic_device_gate_errors(target=target, gate_error=False)
errors_on_sx = {qubits: error for name, qubits, error in gate_errors if name == "sx"}
Expand Down Expand Up @@ -128,7 +131,9 @@ def test_non_zero_temperature(self):
"""Test if non-zero excited_state_population is obtained when positive temperature is supplied.
See https://github.com/Qiskit/qiskit-aer/issues/1937 for the details."""
t1, t2, frequency, duration = 1e-4, 1e-4, 5e9, 5e-8
target = Target(qubit_properties=[QubitProperties(t1=t1, t2=t2, frequency=frequency)])
target = Target(
num_qubits=1, qubit_properties=[QubitProperties(t1=t1, t2=t2, frequency=frequency)]
)
target.add_instruction(library.XGate(), {(0,): InstructionProperties(duration=duration)})
errors = basic_device_gate_errors(target=target, gate_error=False, temperature=100)
_, _, x_error = errors[0]
Expand Down
Loading

0 comments on commit ecce171

Please sign in to comment.