Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix name of AerSimulator generated by AerProvider #2038

Merged
merged 13 commits into from
Mar 21, 2024
29 changes: 16 additions & 13 deletions qiskit_aer/aerprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,22 @@ def _get_backends():
devices = AerSimulator().available_devices()
backends = []
for method in methods:
name = "aer_simulator"
if method not in [None, "automatic"]:
name += f"_{method}"
device_name = "CPU"
backends.append((name, AerSimulator, method, device_name))

# Add GPU device backends
if method in ["statevector", "density_matrix", "unitary"]:
for device in devices:
if device != "CPU":
new_name = f"{name}_{device}".lower()
device_name = device
backends.append((new_name, AerSimulator, method, device_name))
for device in devices:
name = "aer_simulator"
if method in [None, "automatic"]:
backends.append((name, AerSimulator, method, device))
else:
name += f"_{method}"
if method == "tensor_network":
if device == "GPU":
name += f"_{device}".lower()
backends.append((name, AerSimulator, method, device))
else:
if device == "CPU":
backends.append((name, AerSimulator, method, device))
elif method in ["statevector", "density_matrix", "unitary"]:
name += f"_{device}".lower()
backends.append((name, AerSimulator, method, device))

# Add legacy backend names
backends += [
Expand Down
51 changes: 36 additions & 15 deletions qiskit_aer/backends/aer_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,20 @@ def __init__(
if configuration is None:
configuration = QasmBackendConfiguration.from_dict(AerSimulator._DEFAULT_CONFIGURATION)

# set backend name from method and device in option
if "from" not in configuration.backend_name:
method = "automatic"
device = "CPU"
for key, value in backend_options.items():
if key == "method":
method = value
if key == "device":
device = value
if method not in [None, "automatic"]:
configuration.backend_name += f"_{method}"
if device not in [None, "CPU"]:
configuration.backend_name += f"_{device}".lower()

# Cache basis gates since computing the intersection
# of noise model, method, and config gates is expensive.
self._cached_basis_gates = self._BASIS_GATES["automatic"]
Expand Down Expand Up @@ -806,17 +820,6 @@ def __repr__(self):
pad = " " * (len(self.__class__.__name__) + 1)
return f"{display[:-1]}\n{pad}noise_model={repr(noise_model)})"

def _name(self):
"""Format backend name string for simulator"""
name = self._configuration.backend_name
method = getattr(self.options, "method", None)
if method not in [None, "automatic"]:
name += f"_{method}"
device = getattr(self.options, "device", None)
if device not in [None, "CPU"]:
name += f"_{device}".lower()
return name

@classmethod
def from_backend(cls, backend, **options):
"""Initialize simulator from backend."""
Expand All @@ -827,7 +830,7 @@ def from_backend(cls, backend, **options):
description = backend.description

configuration = QasmBackendConfiguration(
backend_name=f"'aer_simulator({backend.name})",
backend_name=f"aer_simulator_from({backend.name})",
backend_version=backend.backend_version,
n_qubits=backend.num_qubits,
basis_gates=backend.operation_names,
Expand All @@ -851,7 +854,7 @@ def from_backend(cls, backend, **options):

# Customize configuration name
name = configuration.backend_name
configuration.backend_name = f"aer_simulator({name})"
configuration.backend_name = f"aer_simulator_from({name})"

target = None
else:
Expand Down Expand Up @@ -879,6 +882,8 @@ def available_methods(self):

def available_devices(self):
"""Return the available simulation methods."""
if "_gpu" in self.name:
return ["GPU"]
return copy.copy(self._AVAILABLE_DEVICES)

def configuration(self):
Expand All @@ -896,8 +901,6 @@ def configuration(self):
getattr(self.options, "method", "automatic")
]
config.basis_gates = self._cached_basis_gates + config.custom_instructions
# Update simulator name
config.backend_name = self._name()
return config

def _execute_circuits(self, aer_circuits, noise_model, config):
Expand Down Expand Up @@ -931,6 +934,24 @@ def set_option(self, key, value):
if key in ["method", "noise_model", "basis_gates"]:
self._cached_basis_gates = self._basis_gates()

# update backend name
if key in ["method", "device"]:
if "from" not in self.name:
if key == "method":
self.name = "aer_simulator"
if value != "automatic":
self.name += f"_{value}"
device = getattr(self.options, "device", "CPU")
if device != "CPU":
self.name += f"_{device}".lower()
if key == "device":
method = getattr(self.options, "method", "auto")
self.name = "aer_simulator"
if method != "automatic":
self.name += f"_{method}"
if value != "CPU":
self.name += f"_{value}".lower()

def _validate(self, qobj):
"""Semantic validations of the qobj which cannot be done via schemas.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
Fixed backend name in backend.configuration when method and device is
specified from AerProvider, this issue is caused by upgrading
AerBackend to V2 backend.

Also fixed issue AerProvider did not enumerate tensor_network method
when GPU device is available
63 changes: 63 additions & 0 deletions test/terra/backends/test_aer_provider.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2021, 2024.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
Tests for AerProvider and AerSimulator
"""

from qiskit import *
from qiskit.circuit.library import *
from qiskit_aer import *

from test.terra.common import QiskitAerTestCase


class TestAerProvider(QiskitAerTestCase):
"""Tests for AerProvider."""

def test_enum_backends(self):
"""Test backends enumrated by AerProvider."""
provider = AerProvider()
for backend in provider.backends():
if "aer_simulator" in backend.name:
method = getattr(backend.options, "method", "automatic")
device = getattr(backend.options, "device", "CPU")
if method == "automatic":
self.assertEqual(backend.name, "aer_simulator")
else:
name = "aer_simulator"
name += f"_{method}"
if device != "CPU":
name += f"_{device}".lower()
self.assertEqual(backend.name, name)

def test_get_backend(self):
"""Test running backend from AerProvider."""
provider = AerProvider()
backend = provider.get_backend("aer_simulator_density_matrix")
circuit = transpile(QuantumVolume(4, 10, seed=0), backend=backend, optimization_level=0)
circuit.measure_all()
results = backend.run(circuit, shots=100, seed_simulator=0).result()

self.assertEqual(results.results[0].metadata["method"], "density_matrix")
self.assertEqual(results.results[0].metadata["device"], "CPU")

def test_backend_name_by_set_option(self):
"""Test backend name of AerSimulator by set_option."""
backend = AerSimulator()
if "GPU" in backend.available_devices():
backend.set_option("device", "GPU")
backend.set_option("method", "density_matrix")
self.assertEqual(backend.name, "aer_simulator_density_matrix_gpu")
else:
backend.set_option("device", "Thrust")
backend.set_option("method", "density_matrix")
self.assertEqual(backend.name, "aer_simulator_density_matrix_thrust")
Loading