mirror of https://github.com/Qiskit/qiskit.git
209 lines
8.1 KiB
Python
209 lines
8.1 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) Copyright IBM 2024.
|
|
#
|
|
# This code is licensed under the Apache License, Version 2.0. You may
|
|
# obtain a copy of this license in the LICENSE.txt file in the root directory
|
|
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
|
#
|
|
# Any modifications or derivative works of this code must retain this
|
|
# copyright notice, and modified files need to carry a notice indicating
|
|
# that they have been altered from the originals.
|
|
|
|
"""Tests for the DropNegligible transpiler pass."""
|
|
|
|
import ddt
|
|
import numpy as np
|
|
|
|
from qiskit.circuit import Parameter, QuantumCircuit, QuantumRegister, Gate
|
|
from qiskit.circuit.library import (
|
|
CPhaseGate,
|
|
RXGate,
|
|
RXXGate,
|
|
RYGate,
|
|
RYYGate,
|
|
RZGate,
|
|
RZZGate,
|
|
XXMinusYYGate,
|
|
XXPlusYYGate,
|
|
GlobalPhaseGate,
|
|
UnitaryGate,
|
|
)
|
|
from qiskit.quantum_info import Operator
|
|
from qiskit.transpiler.passes import RemoveIdentityEquivalent
|
|
from qiskit.transpiler.target import Target, InstructionProperties
|
|
|
|
from test import QiskitTestCase # pylint: disable=wrong-import-order
|
|
|
|
|
|
@ddt.ddt
|
|
class TestDropNegligible(QiskitTestCase):
|
|
"""Test the DropNegligible pass."""
|
|
|
|
def test_drops_negligible_gates(self):
|
|
"""Test that negligible gates are dropped."""
|
|
qubits = QuantumRegister(2)
|
|
circuit = QuantumCircuit(qubits)
|
|
a, b = qubits
|
|
circuit.append(CPhaseGate(1e-5), [a, b])
|
|
circuit.append(CPhaseGate(1e-8), [a, b])
|
|
circuit.append(RXGate(1e-5), [a])
|
|
circuit.append(RXGate(1e-8), [a])
|
|
circuit.append(RYGate(1e-5), [a])
|
|
circuit.append(RYGate(1e-8), [a])
|
|
circuit.append(RZGate(1e-5), [a])
|
|
circuit.append(RZGate(1e-8), [a])
|
|
circuit.append(RXXGate(1e-5), [a, b])
|
|
circuit.append(RXXGate(1e-8), [a, b])
|
|
circuit.append(RYYGate(1e-5), [a, b])
|
|
circuit.append(RYYGate(1e-8), [a, b])
|
|
circuit.append(RZZGate(1e-5), [a, b])
|
|
circuit.append(RZZGate(1e-8), [a, b])
|
|
circuit.append(XXPlusYYGate(1e-5, 1e-8), [a, b])
|
|
circuit.append(XXPlusYYGate(1e-8, 1e-8), [a, b])
|
|
circuit.append(XXMinusYYGate(1e-5, 1e-8), [a, b])
|
|
circuit.append(XXMinusYYGate(1e-8, 1e-8), [a, b])
|
|
transpiled = RemoveIdentityEquivalent()(circuit)
|
|
self.assertEqual(circuit.count_ops()["cp"], 2)
|
|
self.assertEqual(transpiled.count_ops()["cp"], 1)
|
|
self.assertEqual(circuit.count_ops()["rx"], 2)
|
|
self.assertEqual(transpiled.count_ops()["rx"], 1)
|
|
self.assertEqual(circuit.count_ops()["ry"], 2)
|
|
self.assertEqual(transpiled.count_ops()["ry"], 1)
|
|
self.assertEqual(circuit.count_ops()["rz"], 2)
|
|
self.assertEqual(transpiled.count_ops()["rz"], 1)
|
|
self.assertEqual(circuit.count_ops()["rxx"], 2)
|
|
self.assertEqual(transpiled.count_ops()["rxx"], 1)
|
|
self.assertEqual(circuit.count_ops()["ryy"], 2)
|
|
self.assertEqual(transpiled.count_ops()["ryy"], 1)
|
|
self.assertEqual(circuit.count_ops()["rzz"], 2)
|
|
self.assertEqual(transpiled.count_ops()["rzz"], 1)
|
|
self.assertEqual(circuit.count_ops()["xx_plus_yy"], 2)
|
|
self.assertEqual(transpiled.count_ops()["xx_plus_yy"], 1)
|
|
self.assertEqual(circuit.count_ops()["xx_minus_yy"], 2)
|
|
self.assertEqual(transpiled.count_ops()["xx_minus_yy"], 1)
|
|
np.testing.assert_allclose(
|
|
np.array(Operator(circuit)), np.array(Operator(transpiled)), atol=1e-7
|
|
)
|
|
|
|
def test_handles_parameters(self):
|
|
"""Test that gates with parameters are ignored gracefully."""
|
|
qubits = QuantumRegister(2)
|
|
circuit = QuantumCircuit(qubits)
|
|
a, b = qubits
|
|
theta = Parameter("theta")
|
|
circuit.append(CPhaseGate(theta), [a, b])
|
|
circuit.append(CPhaseGate(1e-5), [a, b])
|
|
circuit.append(CPhaseGate(1e-8), [a, b])
|
|
transpiled = RemoveIdentityEquivalent()(circuit)
|
|
self.assertEqual(circuit.count_ops()["cp"], 3)
|
|
self.assertEqual(transpiled.count_ops()["cp"], 2)
|
|
|
|
def test_approximation_degree(self):
|
|
"""Test that approximation degree handled correctly."""
|
|
qubits = QuantumRegister(2)
|
|
circuit = QuantumCircuit(qubits)
|
|
a, b = qubits
|
|
circuit.append(CPhaseGate(1e-4), [a, b])
|
|
# fidelity 0.9999850001249996 which is above the threshold and not excluded
|
|
# so 1e-2 is the only gate remaining
|
|
circuit.append(CPhaseGate(1e-2), [a, b])
|
|
circuit.append(CPhaseGate(1e-20), [a, b])
|
|
transpiled = RemoveIdentityEquivalent(approximation_degree=0.9999999)(circuit)
|
|
self.assertEqual(circuit.count_ops()["cp"], 3)
|
|
self.assertEqual(transpiled.count_ops()["cp"], 1)
|
|
self.assertEqual(transpiled.data[0].operation.params[0], 1e-2)
|
|
|
|
def test_target_approx_none(self):
|
|
"""Test error rate with target."""
|
|
|
|
target = Target()
|
|
props = {(0, 1): InstructionProperties(error=1e-10)}
|
|
target.add_instruction(CPhaseGate(Parameter("theta")), props)
|
|
circuit = QuantumCircuit(2)
|
|
circuit.append(CPhaseGate(1e-4), [0, 1])
|
|
circuit.append(CPhaseGate(1e-2), [0, 1])
|
|
circuit.append(CPhaseGate(1e-20), [0, 1])
|
|
transpiled = RemoveIdentityEquivalent(approximation_degree=None, target=target)(circuit)
|
|
self.assertEqual(circuit.count_ops()["cp"], 3)
|
|
self.assertEqual(transpiled.count_ops()["cp"], 2)
|
|
|
|
def test_target_approx_approx_degree(self):
|
|
"""Test error rate with target."""
|
|
|
|
target = Target()
|
|
props = {(0, 1): InstructionProperties(error=1e-10)}
|
|
target.add_instruction(CPhaseGate(Parameter("theta")), props)
|
|
circuit = QuantumCircuit(2)
|
|
circuit.append(CPhaseGate(1e-4), [0, 1])
|
|
circuit.append(CPhaseGate(1e-2), [0, 1])
|
|
circuit.append(CPhaseGate(1e-20), [0, 1])
|
|
transpiled = RemoveIdentityEquivalent(approximation_degree=0.9999999, target=target)(
|
|
circuit
|
|
)
|
|
self.assertEqual(circuit.count_ops()["cp"], 3)
|
|
self.assertEqual(transpiled.count_ops()["cp"], 2)
|
|
|
|
def test_custom_gate_no_matrix(self):
|
|
"""Test that opaque gates are ignored."""
|
|
|
|
class CustomOpaqueGate(Gate):
|
|
"""Custom opaque gate."""
|
|
|
|
def __init__(self):
|
|
super().__init__("opaque", 2, [])
|
|
|
|
qc = QuantumCircuit(3)
|
|
qc.append(CustomOpaqueGate(), [0, 1])
|
|
transpiled = RemoveIdentityEquivalent()(qc)
|
|
self.assertEqual(qc, transpiled)
|
|
|
|
def test_custom_gate_identity_matrix(self):
|
|
"""Test that custom gates with matrix are evaluated."""
|
|
|
|
class CustomGate(Gate):
|
|
"""Custom gate."""
|
|
|
|
def __init__(self):
|
|
super().__init__("custom", 3, [])
|
|
|
|
def to_matrix(self):
|
|
return np.eye(8, dtype=complex)
|
|
|
|
qc = QuantumCircuit(3)
|
|
qc.append(CustomGate(), [0, 1, 2])
|
|
transpiled = RemoveIdentityEquivalent()(qc)
|
|
expected = QuantumCircuit(3)
|
|
self.assertEqual(expected, transpiled)
|
|
|
|
@ddt.data(
|
|
RXGate(0),
|
|
RXGate(2 * np.pi),
|
|
RYGate(0),
|
|
RYGate(2 * np.pi),
|
|
RZGate(0),
|
|
RZGate(2 * np.pi),
|
|
UnitaryGate(np.array([[1, 0], [0, 1]])),
|
|
UnitaryGate(np.array([[-1, 0], [0, -1]])),
|
|
UnitaryGate(np.array([[np.exp(1j * np.pi / 4), 0], [0, np.exp(1j * np.pi / 4)]])),
|
|
GlobalPhaseGate(0),
|
|
GlobalPhaseGate(np.pi / 4),
|
|
)
|
|
def test_remove_identity_up_to_global_phase(self, gate):
|
|
"""Test that gates equivalent to identity up to a global phase are removed from the circuit,
|
|
and the global phase of the circuit is updated correctly.
|
|
"""
|
|
qc = QuantumCircuit(gate.num_qubits)
|
|
qc.append(gate, qc.qubits)
|
|
transpiled = RemoveIdentityEquivalent()(qc)
|
|
self.assertEqual(transpiled.size(), 0)
|
|
self.assertEqual(Operator(qc), Operator(transpiled))
|
|
|
|
def test_parameterized_global_phase_ignored(self):
|
|
"""Test that parameterized global phase gates are not removed by the pass."""
|
|
theta = Parameter("theta")
|
|
qc = QuantumCircuit(1)
|
|
qc.append(GlobalPhaseGate(theta), [])
|
|
transpiled = RemoveIdentityEquivalent()(qc)
|
|
self.assertEqual(qc, transpiled)
|