diff --git a/qiskit/providers/backend_compat.py b/qiskit/providers/backend_compat.py index 29bd2ae1fb21..af3360bfae25 100644 --- a/qiskit/providers/backend_compat.py +++ b/qiskit/providers/backend_compat.py @@ -138,9 +138,7 @@ def convert_to_target( for op in combined_global_ops: if op not in target: if op in name_mapping: - target.add_instruction( - name_mapping[op], {(bit,): None for bit in range(target.num_qubits)} - ) + target.add_instruction(name_mapping[op], name=op) else: raise QiskitError( f"Operation name '{op}' does not have a known mapping. Use " @@ -220,7 +218,7 @@ def __init__( provider=backend.provider, name=backend.name(), description=self._config.description, - online_date=self._config.online_date, + online_date=getattr(self._config, "online_date", None), backend_version=self._config.backend_version, ) self._options = self._backend._options diff --git a/releasenotes/notes/fix-backendv2-converter-simulator-e8f150d1fd6861fe.yaml b/releasenotes/notes/fix-backendv2-converter-simulator-e8f150d1fd6861fe.yaml new file mode 100644 index 000000000000..44d6ffdd9e0f --- /dev/null +++ b/releasenotes/notes/fix-backendv2-converter-simulator-e8f150d1fd6861fe.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixed an issue with the :class:`~.BackendV2Converter` class when wrapping + a :class:`~.BackendV1` based simulator which would error if either + the ``online_date`` field in the :class:`~.BackendConfiguration` for the + simulator was not present or if the simulator backend supports ideal + implementations of gates that involve more than 1 qubit. + Fixed `#9562 `__ diff --git a/test/python/providers/test_fake_backends.py b/test/python/providers/test_fake_backends.py index 5c0da0f35dbf..67a5e555dcc1 100644 --- a/test/python/providers/test_fake_backends.py +++ b/test/python/providers/test_fake_backends.py @@ -14,6 +14,7 @@ # pylint: disable=missing-module-docstring import operator +import unittest from test import combine from ddt import ddt, data @@ -34,6 +35,30 @@ from qiskit.providers.backend_compat import BackendV2Converter from qiskit.providers.backend import BackendV2 from qiskit.utils import optionals +from qiskit.circuit.library import ( + SXGate, + MCPhaseGate, + MCXGate, + RZGate, + RXGate, + U2Gate, + U1Gate, + U3Gate, + YGate, + ZGate, + PauliGate, + SwapGate, + RGate, + MCXGrayCode, + RYGate, +) +from qiskit.circuit import ControlledGate, Parameter +from qiskit.quantum_info.operators.channel.quantum_channel import QuantumChannel +from qiskit.quantum_info.operators.channel.kraus import Kraus +from qiskit.quantum_info.operators.channel import SuperOp +from qiskit.extensions import Initialize, UnitaryGate +from qiskit.extensions.quantum_initializer import DiagonalGate, UCGate +from qiskit.circuit.controlflow import IfElseOp, WhileLoopOp, ForLoopOp FAKE_PROVIDER_FOR_BACKEND_V2 = FakeProviderForBackendV2() FAKE_PROVIDER = FakeProvider() @@ -193,3 +218,243 @@ def test_converter_delay_circuit(self): qc.measure_all() res = transpile(qc, backend_v2) self.assertIn("delay", res.count_ops()) + + @unittest.skipUnless(optionals.HAS_AER, "Aer required for this test") + def test_converter_simulator(self): + class MCSXGate(ControlledGate): + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcsx", + 1 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=SXGate(), + ) + + class MCYGate(ControlledGate): + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcy", + 1 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=YGate(), + ) + + class MCZGate(ControlledGate): + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcz", + 1 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=ZGate(), + ) + + class MCRXGate(ControlledGate): + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcrx", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=RXGate(theta), + ) + + class MCRYGate(ControlledGate): + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcry", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=RYGate(theta), + ) + + class MCRZGate(ControlledGate): + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcrz", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=RZGate(theta), + ) + + class MCRGate(ControlledGate): + def __init__(self, theta, phi, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcr", + 1 + num_ctrl_qubits, + [theta, phi], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=RGate(theta, phi), + ) + + class MCU1Gate(ControlledGate): + def __init__(self, theta, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu1", + 1 + num_ctrl_qubits, + [theta], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=U1Gate(theta), + ) + + class MCU2Gate(ControlledGate): + def __init__(self, theta, lam, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu2", + 1 + num_ctrl_qubits, + [theta, lam], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=U2Gate(theta, lam), + ) + + class MCU3Gate(ControlledGate): + def __init__(self, theta, lam, phi, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu3", + 1 + num_ctrl_qubits, + [theta, phi, lam], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=U3Gate(theta, phi, lam), + ) + + class MCUGate(ControlledGate): + def __init__(self, theta, lam, phi, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcu", + 1 + num_ctrl_qubits, + [theta, phi, lam], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=U3Gate(theta, phi, lam), + ) + + class MCSwapGate(ControlledGate): + def __init__(self, num_ctrl_qubits, ctrl_state=None): + super().__init__( + "mcswap", + 2 + num_ctrl_qubits, + [], + None, + num_ctrl_qubits, + ctrl_state=ctrl_state, + base_gate=SwapGate(), + ) + + from qiskit_aer import AerSimulator + from qiskit_aer.library import ( + SaveExpectationValue, + SaveAmplitudes, + SaveStatevectorDict, + SaveSuperOp, + SaveClifford, + SaveMatrixProductState, + SaveDensityMatrix, + SaveProbabilities, + SaveStatevector, + SetDensityMatrix, + SetUnitary, + SaveState, + SetMatrixProductState, + SaveUnitary, + SetSuperOp, + SaveExpectationValueVariance, + SaveStabilizer, + SetStatevector, + SetStabilizer, + SaveAmplitudesSquared, + SaveProbabilitiesDict, + ) + from qiskit_aer.noise.errors import ReadoutError + from qiskit_aer.noise.noise_model import QuantumErrorLocation + + sim = AerSimulator() + phi = Parameter("phi") + lam = Parameter("lam") + backend = BackendV2Converter( + sim, + name_mapping={ + "mcsx": MCSXGate, + "mcp": MCPhaseGate, + "mcphase": MCPhaseGate, + "quantum_channel": QuantumChannel, + "initialize": Initialize, + "save_expval": SaveExpectationValue, + "diagonal": DiagonalGate, + "save_amplitudes": SaveAmplitudes, + "roerror": ReadoutError, + "mcrx": MCRXGate, + "kraus": Kraus, + "save_statevector_dict": SaveStatevectorDict, + "mcx": MCXGate, + "mcu1": MCU1Gate, + "mcu2": MCU2Gate, + "mcu3": MCU3Gate, + "save_superop": SaveSuperOp, + "multiplexer": UCGate, + "mcy": MCYGate, + "superop": SuperOp, + "save_clifford": SaveClifford, + "save_matrix_product_state": SaveMatrixProductState, + "save_density_matrix": SaveDensityMatrix, + "save_probabilities": SaveProbabilities, + "if_else": IfElseOp, + "while_loop": WhileLoopOp, + "for_loop": ForLoopOp, + "save_statevector": SaveStatevector, + "mcu": MCUGate, + "set_density_matrix": SetDensityMatrix, + "qerror_loc": QuantumErrorLocation, + "unitary": UnitaryGate, + "mcz": MCZGate, + "pauli": PauliGate, + "set_unitary": SetUnitary, + "save_state": SaveState, + "mcswap": MCSwapGate, + "set_matrix_product_state": SetMatrixProductState, + "save_unitary": SaveUnitary, + "mcr": MCRGate, + "mcx_gray": MCXGrayCode, + "mcrz": MCRZGate, + "set_superop": SetSuperOp, + "save_expval_var": SaveExpectationValueVariance, + "save_stabilizer": SaveStabilizer, + "set_statevector": SetStatevector, + "mcry": MCRYGate, + "set_stabilizer": SetStabilizer, + "save_amplitudes_sq": SaveAmplitudesSquared, + "save_probabilities_dict": SaveProbabilitiesDict, + "cu2": U2Gate(phi, lam).control(), + }, + ) + self.assertIsInstance(backend, BackendV2) + res = transpile(self.circuit, backend) + job = backend.run(res) + result = job.result() + counts = result.get_counts() + max_count = max(counts.items(), key=operator.itemgetter(1))[0] + self.assertEqual(max_count, "11")