Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix handling of simulator backends in BackendV2Converter (backport #9630) #9632

Merged
merged 1 commit into from
Feb 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions qiskit/providers/backend_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 "
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <https://github.com/Qiskit/qiskit-terra/issues/9562>`__
265 changes: 265 additions & 0 deletions test/python/providers/test_fake_backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# pylint: disable=missing-module-docstring

import operator
import unittest

from test import combine
from ddt import ddt, data
Expand All @@ -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()
Expand Down Expand Up @@ -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")