Skip to content

Commit

Permalink
Handle sliced assignments
Browse files Browse the repository at this point in the history
  • Loading branch information
jakelishman committed Oct 18, 2023
1 parent 1d3f5a5 commit 4b74b1d
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
22 changes: 15 additions & 7 deletions qiskit/circuit/library/standard_gates/u.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,23 @@ def __init__(self, gate):
self._gate = gate

def __setitem__(self, key, value):
if isinstance(key, slice):
raise TypeError("'CUGate' only supports setting parameters by single index")
super().__setitem__(key, value)
self._gate._params[key] = value
# Magic numbers: CUGate has 4 parameters, UGate has 3.
if key < 0:
key = 4 + key
if key < 3:
self._gate.base_gate.params[key] = value
# Magic numbers: CUGate has 4 parameters, UGate has 3, with the last of CUGate's missing.
if isinstance(key, slice):
# We don't need to worry about the case of the slice being used to insert extra / remove
# elements because that would be "undefined behaviour" in a gate already, so we're
# within our rights to do anything at all.
for i, base_key in enumerate(range(*key.indices(4))):
if base_key < 0:
base_key = 4 + base_key
if base_key < 3:
self._gate.base_gate.params[base_key] = value[i]
else:
if key < 0:
key = 4 + key
if key < 3:
self._gate.base_gate.params[key] = value


class CUGate(ControlledGate):
Expand Down
25 changes: 25 additions & 0 deletions test/python/circuit/test_controlled_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -1193,6 +1193,31 @@ def test_assign_cugate(self):
self.assertEqual(assigned.data[0].operation.base_gate, expected.data[0].operation.base_gate)
self.assertEqual(assigned, expected)

def test_modify_cugate_params_slice(self):
"""Test that CUGate.params can be modified by a standard slice (without changing the number
of elements) and changes propagate to the base gate. This is only needed for as long as
CUGate's `base_gate` is `UGate`, which has the "wrong" number of parameters."""
cu = CUGate(0.1, 0.2, 0.3, 0.4)
self.assertEqual(cu.params, [0.1, 0.2, 0.3, 0.4])
self.assertEqual(cu.base_gate.params, [0.1, 0.2, 0.3])

cu.params[0:4] = [0.5, 0.4, 0.3, 0.2]
self.assertEqual(cu.params, [0.5, 0.4, 0.3, 0.2])
self.assertEqual(cu.base_gate.params, [0.5, 0.4, 0.3])

cu.params[:] = [0.1, 0.2, 0.3, 0.4]
self.assertEqual(cu.params, [0.1, 0.2, 0.3, 0.4])
self.assertEqual(cu.base_gate.params, [0.1, 0.2, 0.3])

cu.params[:3] = [0.5, 0.4, 0.3]
self.assertEqual(cu.params, [0.5, 0.4, 0.3, 0.4])
self.assertEqual(cu.base_gate.params, [0.5, 0.4, 0.3])

# indices (3, 2, 1, 0), note that the assignment is in reverse.
cu.params[-1::-1] = [0.1, 0.2, 0.3, 0.4]
self.assertEqual(cu.params, [0.4, 0.3, 0.2, 0.1])
self.assertEqual(cu.base_gate.params, [0.4, 0.3, 0.2])

def test_assign_nested_controlled_cu(self):
"""Test assignment of an arbitrary controlled parametrised gate that appears through the
`Gate.control()` method on an already-controlled gate."""
Expand Down

0 comments on commit 4b74b1d

Please sign in to comment.