mirror of https://github.com/Qiskit/qiskit.git
Fix `UnitaryGate.repeat()` method (#12986)
* fix: deal with special case for `UnitaryGate` * add test * add release note * typo * generalize the fix to other gates * fix seeds * update unittests * Add missing unittests --------- Co-authored-by: Luciano Bello <bel@zurich.ibm.com> Co-authored-by: Elena Peña Tapia <57907331+ElePT@users.noreply.github.com>
This commit is contained in:
parent
54ac8f1751
commit
83ecf39656
|
@ -97,7 +97,10 @@ class Gate(Instruction):
|
|||
return self.power(exponent)
|
||||
|
||||
def _return_repeat(self, exponent: float) -> "Gate":
|
||||
return Gate(name=f"{self.name}*{exponent}", num_qubits=self.num_qubits, params=self.params)
|
||||
gate = Gate(name=f"{self.name}*{exponent}", num_qubits=self.num_qubits, params=[])
|
||||
gate.validate_parameter = self.validate_parameter
|
||||
gate.params = self.params
|
||||
return gate
|
||||
|
||||
def control(
|
||||
self,
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
fixes:
|
||||
- |
|
||||
Fixes an error when calling the method :meth:`.UnitaryGate.repeat`.
|
||||
Refer to `#11990 <https://github.com/Qiskit/qiskit/issues/11990>`_ for more
|
||||
details.
|
|
@ -502,6 +502,19 @@ class TestLinearFunctions(QiskitTestCase):
|
|||
self.assertEqual(Clifford(qc_to_linear_function), qc_to_clifford)
|
||||
self.assertEqual(qc_to_linear_function, LinearFunction(qc_to_clifford))
|
||||
|
||||
@data(2, 3)
|
||||
def test_repeat_method(self, num_qubits):
|
||||
"""Test the repeat() method."""
|
||||
rng = np.random.default_rng(127)
|
||||
for num_gates, seed in zip(
|
||||
[0, 5, 5 * num_qubits], rng.integers(100000, size=10, dtype=np.uint64)
|
||||
):
|
||||
# create a random linear circuit
|
||||
linear_circuit = random_linear_circuit(num_qubits, num_gates, seed=seed)
|
||||
operator = Operator(linear_circuit)
|
||||
linear_function = LinearFunction(linear_circuit)
|
||||
self.assertTrue(Operator(linear_function.repeat(2)), operator @ operator)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -104,6 +104,12 @@ class TestPermutationGate(QiskitTestCase):
|
|||
expected_inverse_perm = PermutationGate([3, 0, 5, 1, 4, 2])
|
||||
self.assertTrue(np.array_equal(inverse_perm.pattern, expected_inverse_perm.pattern))
|
||||
|
||||
def test_repeat(self):
|
||||
"""Test the ``repeat`` method."""
|
||||
pattern = [2, 4, 1, 3, 0]
|
||||
perm = PermutationGate(pattern)
|
||||
self.assertTrue(np.allclose(Operator(perm.repeat(2)), Operator(perm) @ Operator(perm)))
|
||||
|
||||
|
||||
class TestPermutationGatesOnCircuit(QiskitTestCase):
|
||||
"""Tests for quantum circuits containing permutations."""
|
||||
|
|
|
@ -83,6 +83,19 @@ class TestDiagonalGate(QiskitTestCase):
|
|||
all(isinstance(p, complex) and not isinstance(p, np.number) for p in params)
|
||||
)
|
||||
|
||||
def test_repeat(self):
|
||||
"""Test the repeat() method."""
|
||||
for phases in [
|
||||
[0, 0],
|
||||
np.array([0, 0.8, 1, 0]),
|
||||
(2 * np.pi * np.random.rand(2**3)).tolist(),
|
||||
]:
|
||||
with self.subTest(phases=phases):
|
||||
diag = [np.exp(1j * ph) for ph in phases]
|
||||
gate = DiagonalGate(diag)
|
||||
operator = Operator(gate)
|
||||
self.assertTrue(np.allclose(Operator(gate.repeat(2)), operator @ operator))
|
||||
|
||||
|
||||
def _get_diag_gate_matrix(diag):
|
||||
return np.diagflat(diag)
|
||||
|
|
|
@ -54,6 +54,8 @@ from qiskit.circuit.library import (
|
|||
CZGate,
|
||||
RYYGate,
|
||||
PhaseGate,
|
||||
PauliGate,
|
||||
UCPauliRotGate,
|
||||
CPhaseGate,
|
||||
UGate,
|
||||
CUGate,
|
||||
|
@ -184,6 +186,18 @@ class TestGateDefinitions(QiskitTestCase):
|
|||
self.assertTrue(len(decomposed_circuit) > len(circuit))
|
||||
self.assertTrue(Operator(circuit).equiv(Operator(decomposed_circuit), atol=1e-7))
|
||||
|
||||
def test_pauligate_repeat(self):
|
||||
"""Test `repeat` method for `PauliGate`."""
|
||||
gate = PauliGate("XYZ")
|
||||
operator = Operator(gate)
|
||||
self.assertTrue(np.allclose(Operator(gate.repeat(2)), operator @ operator))
|
||||
|
||||
def test_ucpaulirotgate_repeat(self):
|
||||
"""Test `repeat` method for `UCPauliRotGate`."""
|
||||
gate = UCPauliRotGate([0.3, 0.5], "X")
|
||||
operator = Operator(gate)
|
||||
self.assertTrue(np.allclose(Operator(gate.repeat(2)), operator @ operator))
|
||||
|
||||
|
||||
@ddt
|
||||
class TestStandardGates(QiskitTestCase):
|
||||
|
|
|
@ -62,6 +62,12 @@ class TestHamiltonianGate(QiskitTestCase):
|
|||
ham.adjoint().to_matrix(), np.transpose(np.conj(ham.to_matrix()))
|
||||
)
|
||||
|
||||
def test_repeat(self):
|
||||
"""test repeat operation"""
|
||||
ham = HamiltonianGate(np.array([[1, 0.5 + 4j], [0.5 - 4j, -0.2]]), np.pi * 0.143)
|
||||
operator = Operator(ham)
|
||||
self.assertTrue(np.allclose(Operator(ham.repeat(2)), operator @ operator))
|
||||
|
||||
|
||||
class TestHamiltonianCircuit(QiskitTestCase):
|
||||
"""Hamiltonian gate circuit tests."""
|
||||
|
|
|
@ -473,6 +473,16 @@ class TestInitialize(QiskitTestCase):
|
|||
vec = Statevector(qc)
|
||||
self.assertTrue(vec == Statevector(desired_vector))
|
||||
|
||||
def test_repeat(self):
|
||||
"""Test the repeat() method."""
|
||||
desired_vector = np.array([0.5, 0.5, 0.5, 0.5])
|
||||
initialize = Initialize(desired_vector)
|
||||
qr = QuantumRegister(2)
|
||||
qc = QuantumCircuit(qr)
|
||||
qc.append(initialize.repeat(2), qr)
|
||||
statevector = Statevector(qc)
|
||||
self.assertTrue(np.allclose(statevector, desired_vector))
|
||||
|
||||
|
||||
class TestInstructionParam(QiskitTestCase):
|
||||
"""Test conversion of numpy type parameters."""
|
||||
|
|
|
@ -133,6 +133,21 @@ class TestIsometry(QiskitTestCase):
|
|||
result = Operator(qc)
|
||||
np.testing.assert_array_almost_equal(result.data, np.identity(result.dim[0]))
|
||||
|
||||
@data(
|
||||
np.eye(2, 2),
|
||||
random_unitary(2, seed=297102).data,
|
||||
np.eye(4, 4),
|
||||
random_unitary(4, seed=123642).data,
|
||||
random_unitary(8, seed=568288).data,
|
||||
)
|
||||
def test_isometry_repeat(self, iso):
|
||||
"""Tests for the repeat of isometries from n to n qubits"""
|
||||
iso_gate = Isometry(iso, 0, 0)
|
||||
|
||||
op = Operator(iso_gate)
|
||||
op_double = Operator(iso_gate.repeat(2))
|
||||
np.testing.assert_array_almost_equal(op @ op, op_double)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -100,6 +100,13 @@ class TestUCGate(QiskitTestCase):
|
|||
|
||||
self.assertTrue(np.allclose(unitary_desired, unitary))
|
||||
|
||||
def test_repeat(self):
|
||||
"""test repeat operation"""
|
||||
gates = [random_unitary(2, seed=seed).data for seed in [124435, 876345, 687462, 928365]]
|
||||
|
||||
uc = UCGate(gates, up_to_diagonal=False)
|
||||
self.assertTrue(np.allclose(Operator(uc.repeat(2)), Operator(uc) @ Operator(uc)))
|
||||
|
||||
|
||||
def _get_ucg_matrix(squs):
|
||||
return block_diag(*squs)
|
||||
|
|
|
@ -67,6 +67,11 @@ class TestUnitaryGate(QiskitTestCase):
|
|||
uni = UnitaryGate([[0, 1j], [-1j, 0]])
|
||||
self.assertTrue(numpy.array_equal(uni.adjoint().to_matrix(), uni.to_matrix()))
|
||||
|
||||
def test_repeat(self):
|
||||
"""test repeat operation"""
|
||||
uni = UnitaryGate([[1, 0], [0, 1j]])
|
||||
self.assertTrue(numpy.array_equal(Operator(uni.repeat(2)), Operator(uni) @ Operator(uni)))
|
||||
|
||||
|
||||
class TestUnitaryCircuit(QiskitTestCase):
|
||||
"""Matrix gate circuit tests."""
|
||||
|
|
Loading…
Reference in New Issue