Skip to content

Commit

Permalink
Add checks for parameter expressions with gen3-turbo runtime. (#2046)
Browse files Browse the repository at this point in the history
* Add checks for parameter expressions with gen3-turbo runtime.

* Workaround for linting failures.

---------

Co-authored-by: Ian Hincks <[email protected]>
  • Loading branch information
blakejohnson and ihincks authored Nov 19, 2024
1 parent 5270a0b commit ade2cb4
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 3 deletions.
7 changes: 6 additions & 1 deletion qiskit_ibm_runtime/base_primitive.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
from .options.utils import merge_options_v2
from .runtime_job_v2 import RuntimeJobV2
from .ibm_backend import IBMBackend
from .utils import validate_isa_circuits, validate_no_dd_with_dynamic_circuits
from .utils import (
validate_isa_circuits,
validate_no_dd_with_dynamic_circuits,
validate_no_param_expressions_gen3_runtime,
)
from .utils.default_session import get_cm_session
from .utils.deprecation import issue_deprecation_msg
from .utils.utils import is_simulator
Expand Down Expand Up @@ -170,6 +174,7 @@ def _run(self, pubs: Union[list[EstimatorPub], list[SamplerPub]]) -> RuntimeJobV
runtime_options = self._options_class._get_runtime_options(options_dict)

validate_no_dd_with_dynamic_circuits([pub.circuit for pub in pubs], self.options)
validate_no_param_expressions_gen3_runtime([pub.circuit for pub in pubs], self.options)
if self._backend:
for pub in pubs:
if getattr(self._backend, "target", None) and not is_simulator(self._backend):
Expand Down
1 change: 1 addition & 0 deletions qiskit_ibm_runtime/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
validate_no_dd_with_dynamic_circuits,
validate_isa_circuits,
validate_job_tags,
validate_no_param_expressions_gen3_runtime,
)

from .json import RuntimeEncoder, RuntimeDecoder, to_base64_string
Expand Down
12 changes: 11 additions & 1 deletion qiskit_ibm_runtime/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
IAMAuthenticator,
)
from ibm_platform_services import ResourceControllerV2 # pylint: disable=import-error
from qiskit.circuit import QuantumCircuit, ControlFlowOp, ParameterExpression
from qiskit.circuit import QuantumCircuit, ControlFlowOp, ParameterExpression, Parameter
from qiskit.transpiler import Target
from qiskit.providers.backend import BackendV1, BackendV2
from .deprecation import deprecate_function
Expand Down Expand Up @@ -130,6 +130,16 @@ def are_circuits_dynamic(circuits: List[QuantumCircuit], qasm_default: bool = Tr
return False


def has_param_expressions(circuits: List[QuantumCircuit]) -> bool:
"""Checks if the input circuits contain `ParameterExpression`s"""
for circuit in circuits:
for instruction in circuit.data:
for p in instruction.operation.params:
if isinstance(p, ParameterExpression) and not isinstance(p, Parameter):
return True
return False


def get_iam_api_url(cloud_url: str) -> str:
"""Computes the IAM API URL for the given IBM Cloud URL."""
parsed_url = urlparse(cloud_url)
Expand Down
27 changes: 26 additions & 1 deletion qiskit_ibm_runtime/utils/validations.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@
from qiskit.transpiler import Target
from qiskit.primitives.containers.sampler_pub import SamplerPub
from qiskit.primitives.containers.estimator_pub import EstimatorPub
from qiskit_ibm_runtime.utils.utils import is_isa_circuit, are_circuits_dynamic
from qiskit_ibm_runtime.utils.utils import (
is_isa_circuit,
are_circuits_dynamic,
has_param_expressions,
)
from qiskit_ibm_runtime.exceptions import IBMInputValueError


Expand Down Expand Up @@ -127,3 +131,24 @@ def validate_job_tags(job_tags: Optional[List[str]]) -> None:
not isinstance(job_tags, list) or not all(isinstance(tag, str) for tag in job_tags)
):
raise IBMInputValueError("job_tags needs to be a list of strings.")


def validate_no_param_expressions_gen3_runtime(
circuits: List[QuantumCircuit], options: Any
) -> None:
"""Validate that when the gen3 runtime is used, no circuit in the pubs contain
ParameterExpressions.
Args:
circuits: A list of QuantumCircuits
options: The runtime options
"""
if (
not hasattr(options.experimental, "get")
or options.experimental.get("execution_path", None) != "gen3-turbo"
):
return
if has_param_expressions(circuits):
raise IBMInputValueError(
"The gen3-turbo runtime currently does not support parameter expressions"
)
30 changes: 30 additions & 0 deletions test/unit/test_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,36 @@ def test_rzz_validates_only_for_fixed_angles(self):
# Should run without an error
SamplerV2(backend).run(pubs=[(circ, [0.5])])

def test_param_expressions_gen3_runtime(self):
"""Verify that parameter expressions are not used in combination with the gen3-turbo
execution path."""
backend = FakeCusco()
x = Parameter("x")
y = Parameter("y")
# pylint: disable-next=unexpected-keyword-arg
opts = SamplerOptions(experimental={"execution_path": "gen3-turbo"})

with self.subTest("float"):
circ = QuantumCircuit(1, 1)
circ.rz(x, 0)
circ.measure(0, 0)
bound_circ = circ.assign_parameters({x: 0.1})
# expect no error (parameter is bound to a float)
SamplerV2(backend, opts).run(pubs=[(bound_circ,)])
# expect no error (simple parameter, not a parameter expression)
SamplerV2(backend, opts).run(pubs=[(circ, [0.2])])

with self.subTest("parameter expressions"):
circ = QuantumCircuit(1, 1)
circ.rz(x + 2 * y, 0)
circ.measure(0, 0)
with self.assertRaises(IBMInputValueError):
SamplerV2(backend, opts).run(pubs=[(circ, [0.1, 0.2])])
# without the gen3-turbo execution path, we expect no error
# pylint: disable-next=unsupported-assignment-operation
opts.experimental["execution_path"] = ""
SamplerV2(backend, opts).run(pubs=[(circ, [0.1, 0.2])])

@data(
"classified",
"kerneled",
Expand Down

0 comments on commit ade2cb4

Please sign in to comment.