Skip to content

Commit

Permalink
Allow string keys in QuantumCircuit.assign_parameters
Browse files Browse the repository at this point in the history
These are looked up using the new `get_parameter` method to convert them
into an actual `Parameter` instance.  This is not available in the fast
path (which is allowed to assume that the caller has taken care of
providing the most efficient inputs).
  • Loading branch information
jakelishman committed Jan 8, 2024
1 parent 3263355 commit ab0af2f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 5 deletions.
21 changes: 17 additions & 4 deletions qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -3075,7 +3075,7 @@ def assign_parameters( # pylint: disable=missing-raises-doc
) -> Optional["QuantumCircuit"]:
"""Assign parameters to new parameters or values.
If ``parameters`` is passed as a dictionary, the keys must be :class:`.Parameter`
If ``parameters`` is passed as a dictionary, the keys should be :class:`.Parameter`
instances in the current circuit. The values of the dictionary can either be numeric values
or new parameter objects.
Expand All @@ -3085,14 +3085,26 @@ def assign_parameters( # pylint: disable=missing-raises-doc
The values can be assigned to the current circuit object or to a copy of it.
.. note::
When ``parameters`` is given as a mapping, it is permissible to have keys that are
strings of the parameter names; these will be looked up using :meth:`get_parameter`.
You can also have keys that are :class:`.ParameterVector` instances, and in this case,
the dictionary value should be a sequence of values of the same length as the vector.
If you use either of these cases, you must leave the setting ``flat_input=False``;
changing this to ``True`` enables the fast path, where all keys must be
:class:`.Parameter` instances.
Args:
parameters: Either a dictionary or iterable specifying the new parameter values.
inplace: If False, a copy of the circuit with the bound parameters is returned.
If True the circuit instance itself is modified.
flat_input: If ``True`` and ``parameters`` is a mapping type, it is assumed to be
exactly a mapping of ``{parameter: value}``. By default (``False``), the mapping
may also contain :class:`.ParameterVector` keys that point to a corresponding
sequence of values, and these will be unrolled during the mapping.
sequence of values, and these will be unrolled during the mapping, or string keys,
which will be converted to :class:`.Parameter` instances using
:meth:`get_parameter`.
strict: If ``False``, any parameters given in the mapping that are not used in the
circuit will be ignored. If ``True`` (the default), an error will be raised
indicating a logic error.
Expand Down Expand Up @@ -3270,9 +3282,8 @@ def map_calibration(qubits, parameters, schedule):
)
return None if inplace else target

@staticmethod
def _unroll_param_dict(
parameter_binds: Mapping[Parameter, ParameterValueType]
self, parameter_binds: Mapping[Parameter, ParameterValueType]
) -> Mapping[Parameter, ParameterValueType]:
out = {}
for parameter, value in parameter_binds.items():
Expand All @@ -3283,6 +3294,8 @@ def _unroll_param_dict(
f" but was assigned to {len(value)} values."
)
out.update(zip(parameter, value))
elif isinstance(parameter, str):
out[self.get_parameter(parameter)] = value
else:
out[parameter] = value
return out
Expand Down
14 changes: 14 additions & 0 deletions releasenotes/notes/assign-by-name-305f2bbf89099174.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
features:
- |
:meth:`.QuantumCircuit.assign_parameters` now accepts string keys in the mapping form of input.
These names are used to look up the corresponding :class:`.Parameter` instance using
:meth:`~.QuantumCircuit.get_parameter`. This lets you do::
from qiskit.circuit import QuantumCircuit, Parameter
a = Parameter("a")
qc = QuantumCircuit(1)
qc.rx(a, 0)
qc.assign_parameters({"a": 1}) == qc.assign_parameters({a: 1})
14 changes: 13 additions & 1 deletion test/python/circuit/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,18 @@ def test_bind_parameters_allow_unknown(self):
c = a.bind({a: 1, b: 1}, allow_unknown_parameters=True)
self.assertEqual(c, a.bind({a: 1}))

def test_assign_parameters_by_name(self):
"""Test that parameters can be assigned by name as well as value."""
a = Parameter("a")
b = Parameter("b")
c = Parameter("c")
qc = QuantumCircuit(2, global_phase=a * 2)
qc.rx(b + 0.125 * c, 0)

self.assertEqual(
qc.assign_parameters({a: 1, b: 2, c: 3}), qc.assign_parameters({"a": 1, "b": 2, "c": 3})
)

def test_bind_parameters_custom_definition_global_phase(self):
"""Test that a custom gate with a parametrised `global_phase` is assigned correctly."""
x = Parameter("x")
Expand Down Expand Up @@ -536,7 +548,7 @@ def test_raise_if_assigning_params_not_in_circuit(self):
with self.assertRaises(CircuitError):
qc.assign_parameters({z: [3, 4, 5]})
with self.assertRaises(CircuitError):
qc.assign_parameters({"a_str": 6})
qc.assign_parameters({6: 6})
with self.assertRaises(CircuitError):
qc.assign_parameters({None: 7})

Expand Down

0 comments on commit ab0af2f

Please sign in to comment.