Skip to content

Commit

Permalink
Merge branch 'main' into EA/code-of-conduct
Browse files Browse the repository at this point in the history
  • Loading branch information
kt474 authored Jul 23, 2024
2 parents 3addc1b + d5b0b83 commit dddf23a
Show file tree
Hide file tree
Showing 20 changed files with 123 additions and 51 deletions.
1 change: 0 additions & 1 deletion qiskit_ibm_runtime/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,6 @@
IBMBackend
RuntimeJob
RuntimeJobV2
RuntimeOptions
RuntimeEncoder
RuntimeDecoder
"""
Expand Down
2 changes: 1 addition & 1 deletion qiskit_ibm_runtime/accounts/account.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from ..utils import resolve_crn

AccountType = Optional[Literal["cloud", "legacy"]]
ChannelType = Optional[Literal["ibm_cloud", "ibm_quantum"]]
ChannelType = Optional[Literal["ibm_cloud", "ibm_quantum", "local"]]

IBM_QUANTUM_API_URL = "https://auth.quantum-computing.ibm.com/api"
IBM_CLOUD_API_URL = "https://cloud.ibm.com"
Expand Down
4 changes: 2 additions & 2 deletions qiskit_ibm_runtime/base_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def _run(self, pubs: Union[list[EstimatorPub], list[SamplerPub]]) -> RuntimeJobV
result_decoder=DEFAULT_DECODERS.get(self._program_id()),
)

return self._service.run(
return self._service._run(
program_id=self._program_id(), # type: ignore[arg-type]
options=runtime_options,
inputs=primitive_inputs,
Expand Down Expand Up @@ -400,7 +400,7 @@ def _run_primitive(self, primitive_inputs: Dict, user_kwargs: Dict) -> RuntimeJo
callback=combined.get("environment", {}).get("callback", None),
result_decoder=DEFAULT_DECODERS.get(self._program_id()),
)
return self._service.run( # type: ignore[call-arg]
return self._service._run( # type: ignore[call-arg]
program_id=self._program_id(), # type: ignore[arg-type]
options=runtime_options,
inputs=primitive_inputs,
Expand Down
10 changes: 4 additions & 6 deletions qiskit_ibm_runtime/estimator.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@ def __init__(
Refer to the `Qiskit Runtime documentation <https://docs.quantum.ibm.com/run>`_.
for more information about the ``Execution modes``.
backend: Backend to run the primitive. This can be a backend name or an :class:`IBMBackend`
instance. If a name is specified, the default account (e.g. ``QiskitRuntimeService()``)
is used.
backend: (DEPRECATED) Backend to run the primitive. This can be a backend name
or an :class:`IBMBackend` instance. If a name is specified, the default account
(e.g. ``QiskitRuntimeService()``) is used.
session: Session in which to call the primitive.
session: (DEPRECATED) Session in which to call the primitive.
If both ``session`` and ``backend`` are specified, ``session`` takes precedence.
If neither is specified, and the primitive is created inside a
Expand Down Expand Up @@ -334,7 +334,6 @@ def run( # pylint: disable=arguments-differ
parameter_values: Concrete parameters to be bound.
**kwargs: Individual options to overwrite the default primitive options.
These include the runtime options in :class:`qiskit_ibm_runtime.RuntimeOptions`.
Returns:
Submitted job.
Expand Down Expand Up @@ -370,7 +369,6 @@ def _run( # pylint: disable=arguments-differ
parameter_values: An optional list of concrete parameters to be bound.
**kwargs: Individual options to overwrite the default primitive options.
These include the runtime options in :class:`~qiskit_ibm_runtime.RuntimeOptions`.
Returns:
Submitted job
Expand Down
7 changes: 7 additions & 0 deletions qiskit_ibm_runtime/fake_provider/fake_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,15 @@ def refresh(self, service: QiskitRuntimeService) -> None:
service: A :class:`QiskitRuntimeService` instance
Raises:
ValueError: if the provided service is a non-QiskitRuntimeService instance.
Exception: If the real target doesn't exist or can't be accessed
"""
if not isinstance(service, QiskitRuntimeService):
raise ValueError(
"The provided service to update the fake backend is invalid. A QiskitRuntimeService is"
" required to retrieve the real backend's current properties and settings."
)

version = self.backend_version
prod_name = self.backend_name.replace("fake", "ibm")
try:
Expand Down
3 changes: 1 addition & 2 deletions qiskit_ibm_runtime/fake_provider/local_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def least_busy(
"""
return self.backends(min_num_qubits=min_num_qubits, filters=filters)[0]

def run(
def _run(
self,
program_id: Literal["sampler", "estimator"],
inputs: Dict,
Expand All @@ -154,7 +154,6 @@ def run(
inputs: Program input parameters. These input values are passed
to the runtime program.
options: Runtime options that control the execution environment.
See :class:`RuntimeOptions` for all available options.
Returns:
A job representing the execution.
Expand Down
39 changes: 33 additions & 6 deletions qiskit_ibm_runtime/options/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
.. currentmodule:: qiskit_ibm_runtime.options
Options that can be passed to the primitives.
Options that can be passed to the Qiskit Runtime primitives.
V2 Primitives
=============
Expand Down Expand Up @@ -75,11 +75,23 @@
Classes
=======
Base primitive options
----------------------
.. autosummary::
:toctree: ../stubs/
EstimatorOptions
SamplerOptions
Options
Suboptions for V2 primitives only
---------------------------------
.. autosummary::
:toctree: ../stubs/
DynamicalDecouplingOptions
ResilienceOptionsV2
LayerNoiseLearningOptions
Expand All @@ -88,13 +100,28 @@
ZneOptions
TwirlingOptions
ExecutionOptionsV2
Options
TranspilationOptions
ResilienceOptions
ExecutionOptions
SamplerExecutionOptionsV2
Suboptions for both V1 and V2 primitives
----------------------------------------
.. autosummary::
:toctree: ../stubs/
EnvironmentOptions
SimulatorOptions
SamplerExecutionOptionsV2
Suboptions for V1 primitives only
---------------------------------
.. autosummary::
:toctree: ../stubs/
TranspilationOptions
ExecutionOptions
ResilienceOptions
"""

Expand Down
2 changes: 1 addition & 1 deletion qiskit_ibm_runtime/options/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def _set_if_exists(name: str, _inputs: dict, _options: dict) -> None:

@dataclass
class Options(BaseOptions):
"""Options for the primitives, used by V1 primitives.
"""Options for V1 primitives.
Args:
optimization_level: How much optimization to perform on the circuits.
Expand Down
10 changes: 7 additions & 3 deletions qiskit_ibm_runtime/options/resilience_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,25 @@ class ResilienceOptionsV2:
Args:
measure_mitigation: Whether to enable measurement error mitigation method.
Further suboptions are available in :attr:`~measure_noise_learning`.
If you enable measurement mitigation, you can fine tune its noise learning
by using :attr:`~measure_noise_learning`. See :class:`MeasureNoiseLearningOptions`
for all measurement mitigation noise learning options.
Default: True.
measure_noise_learning: Additional measurement noise learning options.
See :class:`MeasureNoiseLearningOptions` for all options.
zne_mitigation: Whether to turn on Zero Noise Extrapolation error mitigation method.
Further suboptions are available in :attr:`~zne`.
If you enable ZNE, you can fine tune its options by using :attr:`~zne`.
See :class:`ZneOptions` for additional ZNE related options.
Default: False.
zne: Additional zero noise extrapolation mitigation options.
See :class:`ZneOptions` for all options.
pec_mitigation: Whether to turn on Probabilistic Error Cancellation error mitigation method.
Further suboptions are available in :attr:`~pec`.
If you enable PEC, you can fine tune its options by using :attr:`~pec`.
See :class:`PecOptions` for additional PEC related options.
Default: False.
pec: Additional probabalistic error cancellation mitigation options.
Expand Down
18 changes: 15 additions & 3 deletions qiskit_ibm_runtime/qiskit_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ class QiskitRuntimeService:

global_service = None

def __new__(cls, *args, **kwargs): # type: ignore[no-untyped-def]
channel = kwargs.get("channel", None)
if channel == "local":
# pylint: disable=import-outside-toplevel
from .fake_provider.local_service import QiskitRuntimeLocalService

return super().__new__(QiskitRuntimeLocalService)
else:
return super().__new__(cls)

def __init__(
self,
channel: Optional[ChannelType] = None,
Expand Down Expand Up @@ -85,7 +95,10 @@ def __init__(
values in the loaded account.
Args:
channel: Channel type. ``ibm_cloud`` or ``ibm_quantum``.
channel: Channel type. ``ibm_cloud``, ``ibm_quantum`` or ``local``. If ``local`` is selected,
the local testing mode will be used, and primitive queries will run on a local simulator.
For more details, check the `Qiskit Runtime local testing mode
<https://docs.quantum.ibm.com/guides/local-testing-mode>`_ documentation.
token: IBM Cloud API key or IBM Quantum API token.
url: The API URL.
Defaults to https://cloud.ibm.com (ibm_cloud) or
Expand All @@ -106,7 +119,7 @@ def __init__(
private_endpoint: Connect to private API URL.
Returns:
An instance of QiskitRuntimeService.
An instance of QiskitRuntimeService or QiskitRuntimeLocalService for local channel.
Raises:
IBMInputValueError: If an input is invalid.
Expand Down Expand Up @@ -804,7 +817,6 @@ def run(
inputs: Program input parameters. These input values are passed
to the runtime program.
options: Runtime options that control the execution environment.
See :class:`RuntimeOptions` for all available options.
callback: Callback function to be invoked for any interim results and final result.
The callback function will receive 2 positional parameters:
Expand Down
10 changes: 4 additions & 6 deletions qiskit_ibm_runtime/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ def __init__(
Refer to the `Qiskit Runtime documentation <https://docs.quantum.ibm.com/run>`_.
for more information about the ``Execution modes``.
backend: Backend to run the primitive. This can be a backend name or an :class:`IBMBackend`
instance. If a name is specified, the default account (e.g. ``QiskitRuntimeService()``)
is used.
backend: (DEPRECATED) Backend to run the primitive. This can be a backend name or
an :class:`IBMBackend` instance. If a name is specified, the default account
(e.g. ``QiskitRuntimeService()``) is used.
session: Session in which to call the primitive.
session: (DEPRECATED) Session in which to call the primitive.
If both ``session`` and ``backend`` are specified, ``session`` takes precedence.
If neither is specified, and the primitive is created inside a
Expand Down Expand Up @@ -266,7 +266,6 @@ def run( # pylint: disable=arguments-differ
a list of (parameterized) :class:`~qiskit.circuit.QuantumCircuit`.
parameter_values: Concrete parameters to be bound.
**kwargs: Individual options to overwrite the default primitive options.
These include the runtime options in :class:`qiskit_ibm_runtime.RuntimeOptions`.
Returns:
Submitted job.
Expand Down Expand Up @@ -296,7 +295,6 @@ def _run( # pylint: disable=arguments-differ
a list of (parameterized) :class:`~qiskit.circuit.QuantumCircuit`.
parameter_values: An optional list of concrete parameters to be bound.
**kwargs: Individual options to overwrite the default primitive options.
These include the runtime options in :class:`qiskit_ibm_runtime.RuntimeOptions`.
Returns:
Submitted job.
Expand Down
3 changes: 1 addition & 2 deletions qiskit_ibm_runtime/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ def run(
inputs: Program input parameters. These input values are passed
to the runtime program.
options: Runtime options that control the execution environment.
See :class:`qiskit_ibm_runtime.RuntimeOptions` for all available options.
callback: Callback function to be invoked for any interim results and final result.
Returns:
Expand Down Expand Up @@ -214,7 +213,7 @@ def run(
if self._backend is None:
self._backend = job.backend()
else:
job = self._service.run( # type: ignore[call-arg]
job = self._service._run( # type: ignore[call-arg]
program_id=program_id, # type: ignore[arg-type]
options=options,
inputs=inputs,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,17 +490,17 @@ def _pad(
theta, phi, lam, phase = OneQubitEulerDecomposer().angles_and_phase(u_inv)
if isinstance(next_node, DAGOpNode) and isinstance(next_node.op, (UGate, U3Gate)):
# Absorb the inverse into the successor (from left in circuit)
theta_r, phi_r, lam_r = next_node.op.params
next_node.op.params = Optimize1qGates.compose_u3(
theta_r, phi_r, lam_r, theta, phi, lam
)
op = next_node.op
theta_r, phi_r, lam_r = op.params
op.params = Optimize1qGates.compose_u3(theta_r, phi_r, lam_r, theta, phi, lam)
next_node.op = op
sequence_gphase += phase
elif isinstance(prev_node, DAGOpNode) and isinstance(prev_node.op, (UGate, U3Gate)):
# Absorb the inverse into the predecessor (from right in circuit)
theta_l, phi_l, lam_l = prev_node.op.params
prev_node.op.params = Optimize1qGates.compose_u3(
theta, phi, lam, theta_l, phi_l, lam_l
)
op = prev_node.op
theta_l, phi_l, lam_l = op.params
op.params = Optimize1qGates.compose_u3(theta, phi, lam, theta_l, phi_l, lam_l)
prev_node.op = op
sequence_gphase += phase
else:
# Don't do anything if there's no single-qubit gate to absorb the inverse
Expand Down
5 changes: 4 additions & 1 deletion qiskit_ibm_runtime/transpiler/passes/scheduling/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,10 @@ def _get_duration(self, node: DAGNode, dag: Optional[DAGCircuit] = None) -> int:
# If node has calibration, this value should be the highest priority
cal_key = tuple(indices), tuple(float(p) for p in node.op.params)
duration = dag.calibrations[node.op.name][cal_key].duration
node.op.duration = duration

op = node.op.to_mutable()
op.duration = duration
node.op = op
else:
# map to outer dag to get the appropriate durations
duration = self._durations.get(node.op, indices, unit="dt")
Expand Down
8 changes: 8 additions & 0 deletions release-notes/unreleased/1793.feat.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
The :class:`QiskitRuntimeLocalService` was created to support a local
testing mode. To avoid having to initialize a separate class, "local"
has been added to the valid :class:`QiskitRuntimeService` channel.

.. code:: python
service=QiskitRuntimeService(channel="local")
a :class:`QiskitRuntimeLocalService` instance will be returned.
16 changes: 16 additions & 0 deletions test/integration/test_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime.accounts import CloudResourceNameResolutionError
from qiskit_ibm_runtime.fake_provider.local_service import QiskitRuntimeLocalService
from qiskit_ibm_runtime.utils.utils import (
get_resource_controller_api_url,
get_iam_api_url,
Expand Down Expand Up @@ -74,6 +75,21 @@ def test_channel_strategy(self):
)
self.assertTrue(service)

def test_local_channel(self):
"""Test local channel mode"""
local_service = QiskitRuntimeService(
channel="local",
)
local_service1 = QiskitRuntimeService(
channel="local",
url=self.dependencies.url,
token=self.dependencies.token,
instance=self.dependencies.instance,
channel_strategy="default",
)
self.assertIsInstance(local_service, QiskitRuntimeLocalService)
self.assertIsInstance(local_service1, QiskitRuntimeLocalService)

def test_resolve_crn_for_valid_service_instance_name(self):
"""Verify if CRN is transparently resolved based for an existing service instance name."""
self._skip_on_ibm_quantum()
Expand Down
3 changes: 3 additions & 0 deletions test/unit/mock/fake_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ class FakeRuntimeService(QiskitRuntimeService):
DEFAULT_COMMON_BACKEND = "common_backend"
DEFAULT_UNIQUE_BACKEND_PREFIX = "unique_backend_"

def __new__(cls, *args, num_hgps=2, runtime_client=None, backend_specs=None, **kwargs):
return super().__new__(cls, *args, **kwargs)

def __init__(self, *args, num_hgps=2, runtime_client=None, backend_specs=None, **kwargs):
self._test_num_hgps = num_hgps
self._fake_runtime_client = runtime_client
Expand Down
Loading

0 comments on commit dddf23a

Please sign in to comment.