mirror of https://github.com/Qiskit/qiskit.git
797 lines
29 KiB
Python
797 lines
29 KiB
Python
# This code is part of Qiskit.
|
|
#
|
|
# (C) Copyright IBM 2020, 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.
|
|
|
|
# pylint: disable=missing-class-docstring,missing-function-docstring
|
|
# pylint: disable=missing-module-docstring
|
|
|
|
import datetime
|
|
import itertools
|
|
import operator
|
|
import unittest
|
|
import warnings
|
|
|
|
from test import combine
|
|
from ddt import ddt, data
|
|
|
|
from qiskit.circuit import QuantumCircuit
|
|
from qiskit.compiler import transpile
|
|
from qiskit.providers.fake_provider import (
|
|
Fake5QV1,
|
|
Fake20QV1,
|
|
Fake7QPulseV1,
|
|
Fake27QPulseV1,
|
|
Fake127QPulseV1,
|
|
FakeOpenPulse2Q,
|
|
GenericBackendV2,
|
|
)
|
|
from qiskit.providers.backend_compat import BackendV2Converter, convert_to_target
|
|
from qiskit.providers.models.backendproperties import BackendProperties
|
|
from qiskit.providers.models.backendconfiguration import GateConfig
|
|
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,
|
|
CZGate,
|
|
ECRGate,
|
|
UnitaryGate,
|
|
UCGate,
|
|
Initialize,
|
|
DiagonalGate,
|
|
)
|
|
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.circuit.controlflow import (
|
|
IfElseOp,
|
|
WhileLoopOp,
|
|
ForLoopOp,
|
|
ContinueLoopOp,
|
|
BreakLoopOp,
|
|
SwitchCaseOp,
|
|
)
|
|
from qiskit.transpiler.coupling import CouplingMap
|
|
from test.utils.base import QiskitTestCase # pylint: disable=wrong-import-order
|
|
|
|
with warnings.catch_warnings():
|
|
BACKENDS = [Fake5QV1(), Fake20QV1(), Fake7QPulseV1(), Fake27QPulseV1(), Fake127QPulseV1()]
|
|
|
|
BACKENDS_V2 = []
|
|
for n in [5, 7, 16, 20, 27, 65, 127]:
|
|
cmap = CouplingMap.from_ring(n)
|
|
BACKENDS_V2.append(GenericBackendV2(num_qubits=n, coupling_map=cmap, seed=42))
|
|
|
|
|
|
@ddt
|
|
class TestFakeBackends(QiskitTestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.circuit = QuantumCircuit(2)
|
|
cls.circuit.h(0)
|
|
cls.circuit.h(1)
|
|
cls.circuit.h(0)
|
|
cls.circuit.h(1)
|
|
cls.circuit.x(0)
|
|
cls.circuit.x(1)
|
|
cls.circuit.measure_all()
|
|
|
|
@combine(
|
|
backend=BACKENDS_V2,
|
|
optimization_level=[0, 1, 2, 3],
|
|
)
|
|
def test_circuit_on_fake_backend_v2(self, backend, optimization_level):
|
|
if not optionals.HAS_AER and backend.num_qubits > 20:
|
|
self.skipTest(f"Unable to run fake_backend {backend.name} without qiskit-aer")
|
|
job = backend.run(
|
|
transpile(
|
|
self.circuit, backend, seed_transpiler=42, optimization_level=optimization_level
|
|
),
|
|
seed_simulator=42,
|
|
)
|
|
result = job.result()
|
|
counts = result.get_counts()
|
|
max_count = max(counts.items(), key=operator.itemgetter(1))[0]
|
|
self.assertEqual(max_count, "11")
|
|
|
|
@combine(
|
|
backend=BACKENDS,
|
|
optimization_level=[0, 1, 2, 3],
|
|
dsc="Test execution path on {backend} with optimization level {optimization_level}",
|
|
name="{backend}_opt_level_{optimization_level}",
|
|
)
|
|
def test_circuit_on_fake_backend(self, backend, optimization_level):
|
|
if not optionals.HAS_AER and backend.configuration().num_qubits > 20:
|
|
self.skipTest(
|
|
f"Unable to run fake_backend {backend.configuration().backend_name} without qiskit-aer"
|
|
)
|
|
with self.assertWarnsRegex(
|
|
DeprecationWarning,
|
|
expected_regex="The `transpile` function will "
|
|
"stop supporting inputs of type `BackendV1`",
|
|
):
|
|
transpiled = transpile(
|
|
self.circuit, backend, seed_transpiler=42, optimization_level=optimization_level
|
|
)
|
|
job = backend.run(transpiled, seed_simulator=42)
|
|
result = job.result()
|
|
counts = result.get_counts()
|
|
max_count = max(counts.items(), key=operator.itemgetter(1))[0]
|
|
self.assertEqual(max_count, "11")
|
|
|
|
@data(*BACKENDS)
|
|
def test_to_dict_properties(self, backend):
|
|
with warnings.catch_warnings():
|
|
# The class QobjExperimentHeader is deprecated
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning, module="qiskit")
|
|
properties = backend.properties()
|
|
if properties:
|
|
self.assertIsInstance(backend.properties().to_dict(), dict)
|
|
else:
|
|
self.assertTrue(backend.configuration().simulator)
|
|
|
|
@data(*BACKENDS_V2)
|
|
def test_convert_to_target(self, backend):
|
|
target = backend.target
|
|
if target.dt is not None:
|
|
self.assertLess(target.dt, 1e-6)
|
|
|
|
@data(*BACKENDS_V2)
|
|
def test_backend_v2_dtm(self, backend):
|
|
if backend.dtm:
|
|
self.assertLess(backend.dtm, 1e-6)
|
|
|
|
@data(*BACKENDS)
|
|
def test_to_dict_configuration(self, backend):
|
|
configuration = backend.configuration()
|
|
if configuration.open_pulse:
|
|
self.assertLess(configuration.dt, 1e-6)
|
|
self.assertLess(configuration.dtm, 1e-6)
|
|
for i in configuration.qubit_lo_range:
|
|
self.assertGreater(i[0], 1e6)
|
|
self.assertGreater(i[1], 1e6)
|
|
self.assertLess(i[0], i[1])
|
|
|
|
for i in configuration.meas_lo_range:
|
|
self.assertGreater(i[0], 1e6)
|
|
self.assertGreater(i[0], 1e6)
|
|
self.assertLess(i[0], i[1])
|
|
|
|
for i in configuration.rep_times:
|
|
self.assertGreater(i, 0)
|
|
self.assertLess(i, 1)
|
|
|
|
self.assertIsInstance(configuration.to_dict(), dict)
|
|
|
|
@data(*BACKENDS)
|
|
def test_defaults_to_dict(self, backend):
|
|
if hasattr(backend, "defaults"):
|
|
defaults = backend.defaults()
|
|
self.assertIsInstance(defaults.to_dict(), dict)
|
|
|
|
for i in defaults.qubit_freq_est:
|
|
self.assertGreater(i, 1e6)
|
|
self.assertGreater(i, 1e6)
|
|
|
|
for i in defaults.meas_freq_est:
|
|
self.assertGreater(i, 1e6)
|
|
self.assertGreater(i, 1e6)
|
|
else:
|
|
self.skipTest(f"Backend {backend} does not have defaults")
|
|
|
|
def test_delay_circuit(self):
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake27QPulseV1()
|
|
backend.configuration().timing_constraints = {
|
|
"acquire_alignment": 1,
|
|
"granularity": 1,
|
|
"min_length": 1,
|
|
"pulse_alignment": 1,
|
|
}
|
|
qc = QuantumCircuit(2)
|
|
qc.delay(502, 0, unit="ns")
|
|
qc.x(1)
|
|
qc.delay(250, 1, unit="ns")
|
|
qc.measure_all()
|
|
with self.assertWarnsRegex(
|
|
DeprecationWarning,
|
|
expected_regex="The `transpile` function will "
|
|
"stop supporting inputs of type `BackendV1`",
|
|
):
|
|
res = transpile(qc, backend)
|
|
self.assertIn("delay", res.count_ops())
|
|
|
|
@data(0, 1, 2, 3)
|
|
def test_converter(self, opt_level):
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake5QV1()
|
|
backend_v2 = BackendV2Converter(backend)
|
|
self.assertIsInstance(backend_v2, BackendV2)
|
|
res = transpile(self.circuit, backend_v2, optimization_level=opt_level)
|
|
job = backend_v2.run(res)
|
|
with warnings.catch_warnings():
|
|
# TODO remove this catch once Aer stops using QobjDictField
|
|
warnings.filterwarnings("ignore", category=DeprecationWarning, module="qiskit")
|
|
result = job.result()
|
|
counts = result.get_counts()
|
|
max_count = max(counts.items(), key=operator.itemgetter(1))[0]
|
|
self.assertEqual(max_count, "11")
|
|
|
|
def test_converter_delay_circuit(self):
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake27QPulseV1()
|
|
backend.configuration().timing_constraints = {
|
|
"acquire_alignment": 1,
|
|
"granularity": 1,
|
|
"min_length": 1,
|
|
"pulse_alignment": 1,
|
|
}
|
|
backend_v2 = BackendV2Converter(backend, add_delay=True)
|
|
self.assertIsInstance(backend_v2, BackendV2)
|
|
qc = QuantumCircuit(2)
|
|
qc.delay(502, 0, unit="ns")
|
|
qc.x(1)
|
|
qc.delay(250, 1, unit="ns")
|
|
qc.measure_all()
|
|
res = transpile(qc, backend_v2)
|
|
self.assertIn("delay", res.count_ops())
|
|
|
|
def test_converter_with_missing_gate_property(self):
|
|
"""Test converting to V2 model with irregular backend data."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = FakeOpenPulse2Q()
|
|
# The backend includes pulse calibration definition for U2, but its property is gone.
|
|
# Note that u2 is a basis gate of this device.
|
|
# Since gate property is not provided, the gate broadcasts to all qubits as ideal instruction.
|
|
del backend._properties._gates["u2"]
|
|
|
|
# This should not raise error
|
|
backend_v2 = BackendV2Converter(backend, add_delay=True)
|
|
self.assertDictEqual(backend_v2.target["u2"], {None: None})
|
|
|
|
def test_non_cx_tests(self):
|
|
backend = GenericBackendV2(num_qubits=5, basis_gates=["cz", "x", "sx", "id", "rz"], seed=42)
|
|
self.assertIsInstance(backend.target.operation_from_name("cz"), CZGate)
|
|
backend = GenericBackendV2(
|
|
num_qubits=5, basis_gates=["ecr", "x", "sx", "id", "rz"], seed=42
|
|
)
|
|
self.assertIsInstance(backend.target.operation_from_name("ecr"), ECRGate)
|
|
|
|
@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()
|
|
# test only if simulator's backend is V1
|
|
if sim.version > 1:
|
|
return
|
|
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,
|
|
"switch_case": SwitchCaseOp,
|
|
"break_loop": BreakLoopOp,
|
|
"continue_loop": ContinueLoopOp,
|
|
"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")
|
|
|
|
def test_filter_faulty_qubits_backend_v2_converter(self):
|
|
"""Test faulty qubits in v2 conversion."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake127QPulseV1()
|
|
# Get properties dict to make it easier to work with the properties API
|
|
# is difficult to edit because of the multiple layers of nesting and
|
|
# different object types
|
|
props_dict = backend.properties().to_dict()
|
|
for i in range(62, 67):
|
|
non_operational = {
|
|
"date": datetime.datetime.now(datetime.timezone.utc),
|
|
"name": "operational",
|
|
"unit": "",
|
|
"value": 0,
|
|
}
|
|
props_dict["qubits"][i].append(non_operational)
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend._properties = BackendProperties.from_dict(props_dict)
|
|
v2_backend = BackendV2Converter(backend, filter_faulty=True)
|
|
for i in range(62, 67):
|
|
for qarg in v2_backend.target.qargs:
|
|
self.assertNotIn(i, qarg)
|
|
|
|
def test_filter_faulty_qubits_backend_v2_converter_with_delay(self):
|
|
"""Test faulty qubits in v2 conversion."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake127QPulseV1()
|
|
# Get properties dict to make it easier to work with the properties API
|
|
# is difficult to edit because of the multiple layers of nesting and
|
|
# different object types
|
|
props_dict = backend.properties().to_dict()
|
|
for i in range(62, 67):
|
|
non_operational = {
|
|
"date": datetime.datetime.now(datetime.timezone.utc),
|
|
"name": "operational",
|
|
"unit": "",
|
|
"value": 0,
|
|
}
|
|
props_dict["qubits"][i].append(non_operational)
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend._properties = BackendProperties.from_dict(props_dict)
|
|
v2_backend = BackendV2Converter(backend, filter_faulty=True, add_delay=True)
|
|
for i in range(62, 67):
|
|
for qarg in v2_backend.target.qargs:
|
|
self.assertNotIn(i, qarg)
|
|
|
|
def test_backend_v2_converter_without_delay(self):
|
|
"""Test setting :code:`add_delay`argument of :func:`.BackendV2Converter`
|
|
to :code:`False`."""
|
|
|
|
expected = {
|
|
(0,),
|
|
(0, 1),
|
|
(0, 2),
|
|
(1,),
|
|
(1, 0),
|
|
(1, 2),
|
|
(2,),
|
|
(2, 0),
|
|
(2, 1),
|
|
(2, 3),
|
|
(2, 4),
|
|
(3,),
|
|
(3, 2),
|
|
(3, 4),
|
|
(4,),
|
|
(4, 2),
|
|
(4, 3),
|
|
}
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake5QV1()
|
|
backend = BackendV2Converter(backend=backend, filter_faulty=True, add_delay=False)
|
|
|
|
self.assertEqual(backend.target.qargs, expected)
|
|
|
|
def test_backend_v2_converter_with_meaningless_gate_config(self):
|
|
"""Test backend with broken gate config can be converted only with properties data."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend_v1 = Fake5QV1()
|
|
backend_v1.configuration().gates = [
|
|
GateConfig(name="NotValidGate", parameters=[], qasm_def="not_valid_gate")
|
|
]
|
|
backend_v2 = BackendV2Converter(
|
|
backend=backend_v1,
|
|
filter_faulty=True,
|
|
add_delay=False,
|
|
)
|
|
ops_with_measure = backend_v2.target.operation_names
|
|
self.assertCountEqual(
|
|
ops_with_measure,
|
|
backend_v1.configuration().basis_gates + ["measure"],
|
|
)
|
|
|
|
def test_filter_faulty_qubits_and_gates_backend_v2_converter(self):
|
|
"""Test faulty gates and qubits."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake127QPulseV1()
|
|
# Get properties dict to make it easier to work with the properties API
|
|
# is difficult to edit because of the multiple layers of nesting and
|
|
# different object types
|
|
props_dict = backend.properties().to_dict()
|
|
for i in range(62, 67):
|
|
non_operational = {
|
|
"date": datetime.datetime.now(datetime.timezone.utc),
|
|
"name": "operational",
|
|
"unit": "",
|
|
"value": 0,
|
|
}
|
|
props_dict["qubits"][i].append(non_operational)
|
|
invalid_cx_edges = {
|
|
(113, 114),
|
|
(114, 113),
|
|
(96, 100),
|
|
(100, 96),
|
|
(114, 109),
|
|
(109, 114),
|
|
(24, 34),
|
|
(34, 24),
|
|
}
|
|
non_operational_gate = {
|
|
"date": datetime.datetime.now(datetime.timezone.utc),
|
|
"name": "operational",
|
|
"unit": "",
|
|
"value": 0,
|
|
}
|
|
for gate in props_dict["gates"]:
|
|
if tuple(gate["qubits"]) in invalid_cx_edges:
|
|
gate["parameters"].append(non_operational_gate)
|
|
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend._properties = BackendProperties.from_dict(props_dict)
|
|
v2_backend = BackendV2Converter(backend, filter_faulty=True)
|
|
for i in range(62, 67):
|
|
for qarg in v2_backend.target.qargs:
|
|
self.assertNotIn(i, qarg)
|
|
for edge in invalid_cx_edges:
|
|
self.assertNotIn(edge, v2_backend.target["cx"])
|
|
|
|
def test_filter_faulty_gates_v2_converter(self):
|
|
"""Test just faulty gates in conversion."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake127QPulseV1()
|
|
# Get properties dict to make it easier to work with the properties API
|
|
# is difficult to edit because of the multiple layers of nesting and
|
|
# different object types
|
|
props_dict = backend.properties().to_dict()
|
|
invalid_cx_edges = {
|
|
(113, 114),
|
|
(114, 113),
|
|
(96, 100),
|
|
(100, 96),
|
|
(114, 109),
|
|
(109, 114),
|
|
(24, 34),
|
|
(34, 24),
|
|
}
|
|
non_operational_gate = {
|
|
"date": datetime.datetime.now(datetime.timezone.utc),
|
|
"name": "operational",
|
|
"unit": "",
|
|
"value": 0,
|
|
}
|
|
for gate in props_dict["gates"]:
|
|
if tuple(gate["qubits"]) in invalid_cx_edges:
|
|
gate["parameters"].append(non_operational_gate)
|
|
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend._properties = BackendProperties.from_dict(props_dict)
|
|
v2_backend = BackendV2Converter(backend, filter_faulty=True)
|
|
for i in range(62, 67):
|
|
self.assertIn((i,), v2_backend.target.qargs)
|
|
for edge in invalid_cx_edges:
|
|
self.assertNotIn(edge, v2_backend.target["cx"])
|
|
|
|
def test_filter_faulty_no_faults_v2_converter(self):
|
|
"""Test that faulty qubit filtering does nothing with all operational qubits and gates."""
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake127QPulseV1()
|
|
v2_backend = BackendV2Converter(backend, filter_faulty=True)
|
|
for i in range(v2_backend.num_qubits):
|
|
self.assertIn((i,), v2_backend.target.qargs)
|
|
|
|
@data(0, 1, 2, 3)
|
|
def test_faulty_full_path_transpile_connected_cmap(self, opt_level):
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake5QV1()
|
|
props = backend.properties().to_dict()
|
|
|
|
non_operational_gate = {
|
|
"date": datetime.datetime.now(datetime.timezone.utc),
|
|
"name": "operational",
|
|
"unit": "",
|
|
"value": 0,
|
|
}
|
|
for gate in props["gates"]:
|
|
if tuple(sorted(gate["qubits"])) == (0, 1):
|
|
gate["parameters"].append(non_operational_gate)
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend._properties = BackendProperties.from_dict(props)
|
|
v2_backend = BackendV2Converter(backend, filter_faulty=True)
|
|
qc = QuantumCircuit(5)
|
|
for x, y in itertools.product(range(5), range(5)):
|
|
if x == y:
|
|
continue
|
|
qc.cx(x, y)
|
|
tqc = transpile(qc, v2_backend, seed_transpiler=433, optimization_level=opt_level)
|
|
connections = [tuple(sorted(tqc.find_bit(q).index for q in x.qubits)) for x in tqc.data]
|
|
self.assertNotIn((0, 1), connections)
|
|
|
|
def test_convert_to_target_control_flow(self):
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake27QPulseV1()
|
|
properties = backend.properties()
|
|
configuration = backend.configuration()
|
|
configuration.supported_instructions = [
|
|
"cx",
|
|
"id",
|
|
"delay",
|
|
"measure",
|
|
"reset",
|
|
"rz",
|
|
"sx",
|
|
"x",
|
|
"if_else",
|
|
"for_loop",
|
|
"switch_case",
|
|
]
|
|
defaults = backend.defaults()
|
|
with self.assertWarns(DeprecationWarning):
|
|
target = convert_to_target(configuration, properties, defaults)
|
|
self.assertTrue(target.instruction_supported("if_else", ()))
|
|
self.assertFalse(target.instruction_supported("while_loop", ()))
|
|
self.assertTrue(target.instruction_supported("for_loop", ()))
|
|
self.assertTrue(target.instruction_supported("switch_case", ()))
|
|
|
|
def test_convert_unrelated_supported_instructions(self):
|
|
with self.assertWarns(DeprecationWarning):
|
|
backend = Fake27QPulseV1()
|
|
properties = backend.properties()
|
|
configuration = backend.configuration()
|
|
configuration.supported_instructions = [
|
|
"cx",
|
|
"id",
|
|
"delay",
|
|
"measure",
|
|
"reset",
|
|
"rz",
|
|
"sx",
|
|
"x",
|
|
"play",
|
|
"u2",
|
|
"u3",
|
|
"u1",
|
|
"shiftf",
|
|
"acquire",
|
|
"setf",
|
|
"if_else",
|
|
"for_loop",
|
|
"switch_case",
|
|
]
|
|
defaults = backend.defaults()
|
|
with self.assertWarns(DeprecationWarning):
|
|
target = convert_to_target(configuration, properties, defaults)
|
|
self.assertTrue(target.instruction_supported("if_else", ()))
|
|
self.assertFalse(target.instruction_supported("while_loop", ()))
|
|
self.assertTrue(target.instruction_supported("for_loop", ()))
|
|
self.assertTrue(target.instruction_supported("switch_case", ()))
|
|
self.assertFalse(target.instruction_supported("u3", (0,)))
|