Skip to content

Commit

Permalink
Update backend.configuration() to use BackendConfiguration (Qiskit#1323)
Browse files Browse the repository at this point in the history
* update configuration for statevector simulators

* Update configuration() using BackendConfiguration

Update `BaseBackend.configuratio()` in order to use the model object
`BackendConfiguration`, removing a check from the init (as the object
will be schema-conformant) and tweaking docstrings in the process.

* Update default configuration for local simulators

Update the configuration of the rest of local simulators. Original
credit by @ajavadia in Qiskit#1279.

* Updates to simulator configurations, aer

Update the simulator configurations in order:
* remove the `coupling_map` parameter, as it needs to be a list per the
  specs and had the value "all-to-all".
* add the `gates` parameter, as an empty list (that will likely need
  to be populated once it is used anywhere) and it is a required
  parameter per the spec.

Revise the discovery during Aer building, and adjust the checks done
during instantiation to account for the usage of the object, removing
obsolete code (since the object is guaranteed to have some keys such
as backend_name).

* Adjust transpiler access to configuration(), tests

Revise the methods in transpiler that accessed backend configuration,
replacing the indexing by key with property accessing, and the
treatment of basis_gates (str vs list).

Adjust tests.

* Update configuration.gates with one gate

Update `configuration.gates` for the local simulators, as the specs
require them to have at least one element. A temporary gate was added
for the purposes of passing validation, which should be replaced with
the real gates eventually.

* Update IBMQBackend to use BackendConfiguration

Modify `IBMQBackend` in order to use `BackendConfiguration` for its
`.configuration()` method, by:
* moving the processing of the dict returned from the API to the
  `IBMQconnector` layer (cleanup case, add missing fields, handle
  specific fields). This changes has been verified against QX and IBMQ
  current returned values, and hopefully will be temporary until 0.7.
* updating `IBMQProvider` instantiation and discovery (in the provider),
  removing outdated checks.
* update `providerutils` to work with objects instead of dicts.

Adjust tests accordingly, finally enabling the real functionality for
`test_remote_backend_configuration`.

* Fix unitary simulator name during rebasing

* Update CHANGELOG
  • Loading branch information
diego-plan9 authored Nov 26, 2018
1 parent 613e250 commit 95d9404
Show file tree
Hide file tree
Showing 24 changed files with 263 additions and 171 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ Changed
- `IBMQ.save_account()` now takes an `overwrite` option to replace an existing
account on disk. Default is False (#1295).
- Backend and Provider methods defined in the specification use model objects
rather than dicts, along with validation against schemas (#1249, #1277).
rather than dicts, along with validation against schemas (#1249, #1277). The
updated methods include:
- ``backend.status()``(#1301).
- ``backend.configuration()`` (and ``__init__``) (#1323).
- ``backend.provider()`` is now a method instead of a property (#1312).
- Remove local backend (Aer) fallback (#1303)

Expand Down
11 changes: 2 additions & 9 deletions qiskit/backends/aer/aerprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def _verify_aer_backends(self):
for backend_cls in AER_STANDARD_BACKENDS:
try:
backend_instance = self._get_backend_instance(backend_cls)
backend_name = backend_instance.configuration()['name']
backend_name = backend_instance.name()
ret[backend_name] = backend_instance
except QISKitError as err:
# Ignore backends that could not be initialized.
Expand All @@ -132,8 +132,7 @@ def _get_backend_instance(self, backend_cls):
Returns:
BaseBackend: a backend instance.
Raises:
QISKitError: if the backend could not be instantiated or does not
provide a valid configuration containing a name.
QISKitError: if the backend could not be instantiated.
"""
# Verify that the backend can be instantiated.
try:
Expand All @@ -142,12 +141,6 @@ def _get_backend_instance(self, backend_cls):
raise QISKitError('Backend %s could not be instantiated: %s' %
(backend_cls, err))

# Verify that the instance has a minimal valid configuration.
try:
_ = backend_instance.configuration()['name']
except (LookupError, TypeError):
raise QISKitError('Backend %s has an invalid configuration')

return backend_instance

def __str__(self):
Expand Down
55 changes: 34 additions & 21 deletions qiskit/backends/aer/qasm_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import numpy as np

from qiskit.backends.models import BackendConfiguration
from qiskit.result._utils import copy_qasm_from_qobj_into_result, result_from_old_style_dict
from qiskit.backends import BaseBackend
from qiskit.backends.aer.aerjob import AerJob
Expand All @@ -46,34 +47,40 @@ class QasmSimulator(BaseBackend):
"""C++ quantum circuit simulator with realistic noise"""

DEFAULT_CONFIGURATION = {
'name': 'qasm_simulator',
'backend_name': 'qasm_simulator',
'backend_version': '1.0.0',
'n_qubits': -1,
'url': 'https://github.com/QISKit/qiskit-terra/src/qasm-simulator-cpp',
'simulator': True,
'local': True,
'description': 'A C++ realistic noise simulator for qobj files',
'coupling_map': 'all-to-all',
"basis_gates": 'u0,u1,u2,u3,cx,cz,id,x,y,z,h,s,sdg,t,tdg,rzz,' +
'snapshot,wait,noise,save,load'
'conditional': True,
'open_pulse': False,
'description': 'A C++ realistic noise simulator for qasm experiments',
'basis_gates': ['u0', 'u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z',
'h', 's', 'sdg', 't', 'tdg', 'rzz', 'snapshot', 'wait',
'noise', 'save', 'load'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
}

def __init__(self, configuration=None, provider=None):
super().__init__(configuration=configuration or self.DEFAULT_CONFIGURATION.copy(),
super().__init__(configuration=(configuration or
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION)),
provider=provider)

# Try to use the default executable if not specified.
if self._configuration.get('exe'):
paths = [self._configuration.get('exe')]
if 'exe' in self._configuration:
paths = [self._configuration.exe]
else:
paths = DEFAULT_SIMULATOR_PATHS

# Ensure that the executable is available.
try:
self._configuration['exe'] = next(
self._configuration.exe = next(
path for path in paths if (os.path.exists(path) and
os.path.getsize(path) > 100))
except StopIteration:
raise FileNotFoundError('Simulator executable not found (using %s)' %
self._configuration.get('exe', 'default locations'))
getattr(self._configuration, 'exe', 'default locations'))

def run(self, qobj):
"""Run a qobj on the backend."""
Expand All @@ -84,7 +91,7 @@ def run(self, qobj):

def _run_job(self, job_id, qobj):
self._validate(qobj)
result = run(qobj, self._configuration['exe'])
result = run(qobj, self._configuration.exe)
result['job_id'] = job_id
copy_qasm_from_qobj_into_result(qobj, result)

Expand All @@ -104,33 +111,39 @@ class CliffordSimulator(BaseBackend):
""""C++ Clifford circuit simulator with realistic noise."""

DEFAULT_CONFIGURATION = {
'name': 'clifford_simulator',
'url': 'https://github.com/QISKit/qiskit-terra/src/qasm-simulator',
'backend_name': 'clifford_simulator',
'backend_version': '1.0.0',
'n_qubits': -1,
'url': 'https://github.com/QISKit/qiskit-terra/src/qasm-simulator-cpp',
'simulator': True,
'local': True,
'conditional': True,
'open_pulse': False,
'description': 'A C++ Clifford simulator with approximate noise',
'coupling_map': 'all-to-all',
'basis_gates': 'cx,id,x,y,z,h,s,sdg,snapshot,wait,noise,save,load'
'basis_gates': ['cx', 'id', 'x', 'y', 'z', 'h', 's', 'sdg', 'snapshot',
'wait', 'noise', 'save', 'load'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
}

def __init__(self, configuration=None, provider=None):
super().__init__(configuration=configuration or self.DEFAULT_CONFIGURATION.copy(),
super().__init__(configuration=(configuration or
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION)),
provider=provider)

# Try to use the default executable if not specified.
if self._configuration.get('exe'):
paths = [self._configuration.get('exe')]
if 'exe' in self._configuration:
paths = [self._configuration.exe]
else:
paths = DEFAULT_SIMULATOR_PATHS

# Ensure that the executable is available.
try:
self._configuration['exe'] = next(
self._configuration.exe = next(
path for path in paths if (os.path.exists(path) and
os.path.getsize(path) > 100))
except StopIteration:
raise FileNotFoundError('Simulator executable not found (using %s)' %
self._configuration.get('exe', 'default locations'))
getattr(self._configuration, 'exe', 'default locations'))

def run(self, qobj):
"""Run a Qobj on the backend.
Expand Down Expand Up @@ -159,7 +172,7 @@ def _run_job(self, job_id, qobj):
qobj_dict['config'] = {'simulator': 'clifford'}

qobj = Qobj.from_dict(qobj_dict)
result = run(qobj, self._configuration['exe'])
result = run(qobj, self._configuration.exe)
result['job_id'] = job_id

return result_from_old_style_dict(
Expand Down
20 changes: 13 additions & 7 deletions qiskit/backends/aer/qasm_simulator_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@

import numpy as np

from qiskit.backends.models import BackendConfiguration
from qiskit.result._utils import copy_qasm_from_qobj_into_result, result_from_old_style_dict
from qiskit.backends import BaseBackend
from qiskit.backends.aer.aerjob import AerJob
Expand All @@ -90,17 +91,22 @@ class QasmSimulatorPy(BaseBackend):
"""Python implementation of a qasm simulator."""

DEFAULT_CONFIGURATION = {
'name': 'qasm_simulator_py',
'backend_name': 'qasm_simulator_py',
'backend_version': '2.0.0',
'n_qubits': -1,
'url': 'https://github.com/QISKit/qiskit-terra',
'simulator': True,
'local': True,
'description': 'A python simulator for qasm files',
'coupling_map': 'all-to-all',
'basis_gates': 'u1,u2,u3,cx,id,snapshot'
'conditional': True,
'open_pulse': False,
'description': 'A python simulator for qasm experiments',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'id', 'snapshot'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
}

def __init__(self, configuration=None, provider=None):
super().__init__(configuration=configuration or self.DEFAULT_CONFIGURATION.copy(),
super().__init__(configuration=(configuration or
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION)),
provider=provider)

self._local_random = random.Random()
Expand Down Expand Up @@ -243,7 +249,7 @@ def _run_job(self, job_id, qobj):
for circuit in qobj.experiments:
result_list.append(self.run_circuit(circuit))
end = time.time()
result = {'backend': self._configuration['name'],
result = {'backend': self.name(),
'id': qobj.qobj_id,
'job_id': job_id,
'result': result_list,
Expand Down Expand Up @@ -342,7 +348,7 @@ def run_circuit(self, circuit):
params = operation.params
self._add_qasm_snapshot(params[0])
else:
backend = self._configuration['name']
backend = self.name()
err_msg = '{0} encountered unrecognized operation "{1}"'
raise SimulatorError(err_msg.format(backend,
operation.name))
Expand Down
18 changes: 13 additions & 5 deletions qiskit/backends/aer/statevector_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import logging
import uuid

from qiskit.backends.models import BackendConfiguration
from qiskit.qobj import QobjInstruction
from .qasm_simulator import QasmSimulator
from ._simulatorerror import SimulatorError
Expand All @@ -26,17 +27,24 @@ class StatevectorSimulator(QasmSimulator):
"""C++ statevector simulator"""

DEFAULT_CONFIGURATION = {
'name': 'statevector_simulator',
'backend_name': 'statevector_simulator',
'backend_version': '1.0.0',
'n_qubits': -1,
'url': 'https://github.com/QISKit/qiskit-terra/src/qasm-simulator-cpp',
'simulator': True,
'local': True,
'description': 'A C++ statevector simulator for qobj files',
'coupling_map': 'all-to-all',
'basis_gates': 'u1,u2,u3,cx,cz,id,x,y,z,h,s,sdg,t,tdg,rzz,load,save,snapshot'
'conditional': False,
'open_pulse': False,
'description': 'A single-shot C++ statevector simulator for the |0> state evolution',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z', 'h',
's', 'sdg', 't', 'tdg', 'rzz', 'load', 'save',
'snapshot'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
}

def __init__(self, configuration=None, provider=None):
super().__init__(configuration=configuration or self.DEFAULT_CONFIGURATION.copy(),
super().__init__(configuration=(configuration or
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION)),
provider=provider)

def run(self, qobj):
Expand Down
14 changes: 10 additions & 4 deletions qiskit/backends/aer/statevector_simulator_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

from qiskit.backends.aer.aerjob import AerJob
from qiskit.backends.aer._simulatorerror import SimulatorError
from qiskit.backends.models import BackendConfiguration
from qiskit.qobj import QobjInstruction
from .qasm_simulator_py import QasmSimulatorPy

Expand All @@ -33,17 +34,22 @@ class StatevectorSimulatorPy(QasmSimulatorPy):
"""Python statevector simulator."""

DEFAULT_CONFIGURATION = {
'name': 'statevector_simulator_py',
'backend_name': 'statevector_simulator_py',
'backend_version': '1.0.0',
'n_qubits': -1,
'url': 'https://github.com/QISKit/qiskit-terra',
'simulator': True,
'local': True,
'conditional': False,
'open_pulse': False,
'description': 'A Python statevector simulator for qobj files',
'coupling_map': 'all-to-all',
'basis_gates': 'u1,u2,u3,cx,id,snapshot'
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'id', 'snapshot'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
}

def __init__(self, configuration=None, provider=None):
super().__init__(configuration=configuration or self.DEFAULT_CONFIGURATION.copy(),
super().__init__(configuration=(configuration or
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION)),
provider=provider)

def run(self, qobj):
Expand Down
18 changes: 12 additions & 6 deletions qiskit/backends/aer/unitary_simulator_py.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@

import numpy as np

from qiskit.backends.models import BackendConfiguration
from qiskit.result._utils import copy_qasm_from_qobj_into_result, result_from_old_style_dict
from qiskit.backends import BaseBackend
from qiskit.backends.aer.aerjob import AerJob
Expand All @@ -103,17 +104,22 @@ class UnitarySimulatorPy(BaseBackend):
"""Python implementation of a unitary simulator."""

DEFAULT_CONFIGURATION = {
'name': 'unitary_simulator_py',
'backend_name': 'unitary_simulator_py',
'backend_version': '1.0.0',
'n_qubits': -1,
'url': 'https://github.com/QISKit/qiskit-terra',
'simulator': True,
'local': True,
'description': 'A python simulator for unitary matrix',
'coupling_map': 'all-to-all',
'basis_gates': 'u1,u2,u3,cx,id'
'conditional': False,
'open_pulse': False,
'description': 'A python simulator for unitary matrix corresponding to a circuit',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'id'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
}

def __init__(self, configuration=None, provider=None):
super().__init__(configuration=configuration or self.DEFAULT_CONFIGURATION.copy(),
super().__init__(configuration=(configuration or
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION)),
provider=provider)

# Define attributes inside __init__.
Expand Down Expand Up @@ -189,7 +195,7 @@ def _run_job(self, job_id, qobj):
for circuit in qobj.experiments:
result_list.append(self.run_circuit(circuit))
end = time.time()
result = {'backend': self._configuration['name'],
result = {'backend': self.name(),
'id': qobj.qobj_id,
'job_id': job_id,
'result': result_list,
Expand Down
20 changes: 13 additions & 7 deletions qiskit/backends/basebackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,13 @@ def __init__(self, configuration, provider=None):
not available.
Args:
configuration (dict): configuration dictionary
configuration (BackendConfiguration): backend configuration
provider (BaseProvider): provider responsible for this backend
Raises:
FileNotFoundError if backend executable is not available.
QISKitError: if there is no name in the configuration
"""
if 'name' not in configuration:
raise qiskit.QISKitError('backend does not have a name.')
self._configuration = configuration
self._provider = provider

Expand All @@ -46,7 +44,11 @@ def run(self, qobj):
pass

def configuration(self):
"""Return backend configuration"""
"""Return the backend configuration.
Returns:
BackendConfiguration: the configuration fot the backend.
"""
return self._configuration

def properties(self):
Expand All @@ -57,7 +59,7 @@ def provider(self):
"""Return the backend Provider.
Returns:
BaseProvider: the Provider responsible for this backend.
BaseProvider: the Provider responsible for the backend.
"""
return self._provider

Expand All @@ -74,8 +76,12 @@ def status(self):
status_msg='')

def name(self):
"""Return backend name"""
return self._configuration['name']
"""Return backend name.
Returns:
str: the name of the backend.
"""
return self._configuration.backend_name

def __str__(self):
return self.name()
Expand Down
Loading

0 comments on commit 95d9404

Please sign in to comment.