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

Add fake generic and modify tests #10266

Merged
merged 65 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
060d56b
Added a FakeGeneric BackendV2 backend, this is just a bare minimum wo…
MozammilQ Jun 6, 2023
ae26ee5
All FakeBackends (like FakeMelbourne, FakeBoeblingen ,etc) is replace…
MozammilQ Jun 8, 2023
c15254e
relocated FakeGeneric in fake_provider directory; replaced if-elif wi…
MozammilQ Jun 11, 2023
7f544d4
added tests for FakeGeneric
MozammilQ Jun 12, 2023
c864645
This commit just reformats test_transpiler.py fake_generic.py and tes…
MozammilQ Jun 12, 2023
1531e84
Update qiskit/providers/fake_provider/fake_generic.py
MozammilQ Jul 1, 2023
bf91f35
Update qiskit/providers/fake_provider/fake_generic.py
MozammilQ Jul 1, 2023
c34316a
Update test/python/providers/fake_provider/test_fake_generic.py
MozammilQ Jul 1, 2023
dc24618
Update test/python/providers/fake_provider/test_fake_generic.py
MozammilQ Jul 1, 2023
0e57867
Merge branch 'main' into add_FakeGeneric_and_modify_tests
ElePT Oct 2, 2023
02099a0
Fix some tests
ElePT Oct 2, 2023
680c3ce
Add calibration schedules, fix transpiler tests
ElePT Oct 2, 2023
6131e31
Fix lint
ElePT Oct 3, 2023
04914f2
Refactor, add pulse functionality
ElePT Oct 5, 2023
2523707
Latest updates to FakeGeneric
ElePT Oct 10, 2023
7ec720d
Fix some unit tests
ElePT Oct 10, 2023
8ce51ee
Fix some unit tests
ElePT Oct 11, 2023
5592167
Fix tests, lint, refactor
ElePT Oct 11, 2023
f2f3320
Remove unused inputs
ElePT Oct 11, 2023
22de937
Make calibrations optional
ElePT Oct 11, 2023
550234b
Attempt to speed up test: only add calibrations if option enabled
ElePT Oct 11, 2023
4fdf780
Revert some tests to V1
ElePT Oct 16, 2023
d2c1ba9
Fix conflict
ElePT Oct 17, 2023
177953b
Refactor FakeGeneric
ElePT Oct 18, 2023
96c46e1
Update unit test
ElePT Oct 19, 2023
242d5fb
Rename supported instructions to operations, fix tests
ElePT Nov 13, 2023
e8305e3
Restore vf2postlayout test to V1
ElePT Nov 23, 2023
be2393b
Add pulse test to validate pulse capabilities of new fake backend
ElePT Nov 23, 2023
a6b3fe6
Update docs, fix lint
ElePT Nov 23, 2023
fbd1aad
Avoid set for basis gates to allow reproducibility in the error/durat…
ElePT Nov 24, 2023
349141c
Merge branch 'main' into add_FakeGeneric_and_modify_tests
ElePT Nov 28, 2023
6f3bb4b
Update calibrations
ElePT Nov 30, 2023
c9c72e1
Merge branch 'main' of https://github.com/ElePT/qiskit-terra into add…
ElePT Nov 30, 2023
cacd296
Merge branch 'add_FakeGeneric_and_modify_tests' of https://github.com…
ElePT Nov 30, 2023
ba14dc1
Fix transpiler test
ElePT Nov 30, 2023
5b87345
Add run test to confirm noise defaults
ElePT Dec 4, 2023
01343ad
Add CZ to basis gates, dtm, update backend names, fix docs
ElePT Dec 7, 2023
982deb7
Remove GenericTarget, add default for basis_gates, remove supported_o…
ElePT Jan 17, 2024
d69c01d
Merge branch 'main' into add_FakeGeneric_and_modify_tests
ElePT Jan 17, 2024
09bc015
Apply review comments, modify calibrate_instructions to avoid public …
ElePT Jan 22, 2024
e0c5aa7
New name proposal
ElePT Jan 22, 2024
6b0817a
Fix conflict
ElePT Jan 22, 2024
12e253d
Fix lint and test
ElePT Jan 22, 2024
0db8035
Fix comment
ElePT Jan 22, 2024
abef228
Apply Kevin's suggestions to extract defaults from class
ElePT Jan 23, 2024
0d303bb
Make defaults private
ElePT Jan 23, 2024
9e276e9
Fix lint
ElePT Jan 23, 2024
e98f059
Revert previous 3 comments.
ElePT Jan 24, 2024
d44a517
Privatize GenericFakeBackend
ElePT Jan 24, 2024
a54fb64
Remove from docs
ElePT Jan 24, 2024
99c643f
Revert privatization
ElePT Jan 25, 2024
de63a9d
Apply review comments
ElePT Jan 25, 2024
fca016a
Add reno
ElePT Jan 25, 2024
de5bc0e
Fix lint
ElePT Jan 25, 2024
099143f
Apply suggestions from Matt's code review
ElePT Jan 26, 2024
54496db
Apply comments from code review
ElePT Jan 27, 2024
0e00b22
Fix conflict
ElePT Jan 27, 2024
fe37393
Fix lint
ElePT Jan 27, 2024
a36acaf
Rename to GenericBackendV2 and adjust docs.
ElePT Jan 29, 2024
f1816ea
Fix lint
ElePT Jan 29, 2024
741831e
Apply comments from code review
ElePT Jan 29, 2024
ee588cc
It's not 2023 anymore
ElePT Jan 29, 2024
93cdb36
Merge branch 'main' into add_FakeGeneric_and_modify_tests
ElePT Jan 29, 2024
cba3eba
Fix conflict
ElePT Jan 29, 2024
72d1dee
Fix test conflict.
kevinhartman Jan 29, 2024
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
1 change: 1 addition & 0 deletions qiskit/providers/fake_provider/__init__.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the interest of time we should leave this for after the release candidate is shipped, but I think it would be good to get some proper top-level documentation and examples written for how people should build and use these backends. We want to show people best practices for testing their compilation / whatever workloads before shipping them off to real hardware.

Original file line number Diff line number Diff line change
Expand Up @@ -251,3 +251,4 @@

# Configurable fake backend
from .utils.configurable_backend import ConfigurableFakeBackend
from .fake_generic import FakeGeneric
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From offline discussion: we talked about making this FakeGenericV2 on the basis that it's better to be explicit for its use in testing. However, it's also a deliberately public part of the interface, and we're well into the BackendV2-is-the-default world now (finally), so the unversioned name (more strongly communicating that this is a default) is probably better.

280 changes: 280 additions & 0 deletions qiskit/providers/fake_provider/fake_generic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# 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.


import numpy as np
import statistics
from typing import Optional, List, Tuple

from qiskit.transpiler import CouplingMap
from qiskit.providers.basicaer import BasicAer
from qiskit.transpiler import Target, InstructionProperties, QubitProperties
from qiskit.providers.backend import BackendV2
from qiskit.providers.options import Options
from qiskit.exceptions import QiskitError
from qiskit.circuit.library import XGate, RZGate, SXGate, CXGate, ECRGate, IGate
from qiskit.circuit import Measure, Parameter, Delay, Reset
from qiskit.circuit.controlflow import (
IfElseOp,
WhileLoopOp,
ForLoopOp,
SwitchCaseOp,
BreakLoopOp,
ContinueLoopOp,
)


class FakeGeneric(BackendV2):
"""
Generate a generic fake backend, this backend will have properties and configuration according to the settings passed in the argument.

Argumets:
num_qubits:
Pass in the integer which is the number of qubits of the backend.
Example: num_qubits = 19

coupling_map:
Pass in the coupling Map of the backend as a list of tuples.
Example: [(1, 2), (2, 3), (3, 4), (4, 5)].

If None passed then the coupling map will be generated.
This map will be in accordance with the argument coupling_map_type.

coupling_map_type:
Pass in the type of coupling map to be generated. If coupling map is passed then this option will be overriden.
Valid types of coupling map: 'grid', 'heavy_hex'

Heavy Hex Lattice Reference:
https://journals.aps.org/prx/pdf/10.1103/PhysRevX.10.011022


basis_gates:
Pass in the basis gates of the backend as list of strings.
Example: ['cx', 'id', 'rz', 'sx', 'x'] --> This is the default basis gates of the backend.

dynamic:
Enable/Disable dynamic circuits on this backend.
True: Enable
False: Disable (Default)

bidirectional_cp_mp:
Enable/Disable bi-directional coupling map.
True: Enable
False: Disable (Default)
replace_cx_with_ecr:
True: (Default) Replace every occurance of 'cx' with 'ecr'
False: Do not replace 'cx' with 'ecr'

enable_reset:
True: (Default) this enables the reset on the backend
False: This disables the reset on the backend

dt:
The system time resolution of input signals in seconds.
Default is 0.2222ns



Returns:
None

Raises:
QiskitError: If argument basis_gates has a gate which is not a valid basis gate.


"""

def __init__(
self,
num_qubits: int,
coupling_map: Optional[List[Tuple[str, str]]] = None,
coupling_map_type: Optional[str] = "grid",
basis_gates: List[str] = ["cx", "id", "rz", "sx", "x"],
dynamic: bool = False,
bidirectional_cp_mp: bool = False,
replace_cx_with_ecr: bool = True,
enable_reset: bool = True,
dt: float = 0.222e-9,
):

super().__init__(
provider=None,
name="fake_generic",
description=f"This {num_qubits} qubit fake generic device, with generic settings has been generated right now!",
backend_version="",
)

self.basis_gates = basis_gates
self.__rng = np.random.default_rng(seed=123456789123456)
self.__coupling_map_type = coupling_map_type
if replace_cx_with_ecr:
self.basis_gates = list(map(lambda gate: gate.replace("cx", "ecr"), basis_gates))

if "delay" not in basis_gates:
self.basis_gates.append("delay")
if "measure" not in basis_gates:
self.basis_gates.append("measure")

if not coupling_map:
if self.__coupling_map_type == "heavy_hex":
distance = self._get_cmap_args(num_qubits=num_qubits)
coupling_map = CouplingMap().from_heavy_hex(
distance=distance, bidirectional=bidirectional_cp_mp
)

elif self.__coupling_map_type == "grid":
num_rows, num_columns = self._get_cmap_args(num_qubits=num_qubits)
coupling_map = CouplingMap().from_grid(
num_rows=num_rows, num_columns=num_columns, bidirectional=bidirectional_cp_mp
)
else:
coupling_map = CouplingMap(coupling_map)

num_qubits = coupling_map.size()

self._target = Target(
description="Fake Generic Backend",
num_qubits=num_qubits,
dt=dt,
qubit_properties=[
QubitProperties(
t1=self.__rng.uniform(100e-6, 200e-6),
t2=self.__rng.uniform(100e-6, 200e-6),
frequency=self.__rng.uniform(5e9, 5.5e9),
)
for _ in range(num_qubits)
],
)

instruction_dict = self._get_instruction_dict(num_qubits, coupling_map)
for gate in self.basis_gates:
try:
self._target.add_instruction(*instruction_dict[gate])
except:
raise QiskitError(f"{gate} is not a valid basis gate")

if dynamic:
self._target.add_instruction(IfElseOp, name="if_else")
self._target.add_instruction(WhileLoopOp, name="while_loop")
self._target.add_instruction(ForLoopOp, name="for_loop")
self._target.add_instruction(SwitchCaseOp, name="switch_case")
self._target.add_instruction(BreakLoopOp, name="break")
self._target.add_instruction(ContinueLoopOp, name="continue")

if enable_reset:
self._target.add_instruction(
Reset(), {(qubit_idx,): None for qubit_idx in range(num_qubits)}
)

@property
def target(self):
return self._target

@property
def max_circuits(self):
return None

def _get_cmap_args(self, num_qubits):
if self.__coupling_map_type == "heavy_hex":
for d in range(3, 20, 2):
# The description of the formula: 5*d**2 - 2*d -1 is explained in
# https://journals.aps.org/prx/pdf/10.1103/PhysRevX.10.011022 Page 011022-4
n = (5 * (d**2) - (2 * d) - 1) / 2
if n >= num_qubits:
return int(d)

elif self.__coupling_map_type == "grid":
factors = [x for x in range(2, num_qubits + 1) if num_qubits % x == 0]
first_factor = statistics.median_high(factors)
second_factor = int(num_qubits / first_factor)
return (first_factor, second_factor)

def _get_instruction_dict(self, num_qubits, coupling_map):
instruction_dict = {
"ecr": (
ECRGate(),
{
edge: InstructionProperties(
error=self.__rng.uniform(1e-5, 5e-3),
duration=self.__rng.uniform(1e-8, 9e-7),
)
for edge in coupling_map
},
),
"cx": (
CXGate(),
{
edge: InstructionProperties(
error=self.__rng.uniform(1e-5, 5e-3),
duration=self.__rng.uniform(1e-8, 9e-7),
)
for edge in coupling_map
},
),
"id": (
IGate(),
{
(qubit_idx,): InstructionProperties(error=0.0, duration=0.0)
for qubit_idx in range(num_qubits)
},
),
"rz": (
RZGate(Parameter("theta")),
{
(qubit_idx,): InstructionProperties(error=0.0, duration=0.0)
for qubit_idx in range(num_qubits)
},
),
"sx": (
SXGate(),
{
(qubit_idx,): InstructionProperties(
error=self.__rng.uniform(1e-6, 1e-4),
duration=self.__rng.uniform(1e-8, 9e-7),
)
for qubit_idx in range(num_qubits)
},
),
"x": (
XGate(),
{
(qubit_idx,): InstructionProperties(
error=self.__rng.uniform(1e-6, 1e-4),
duration=self.__rng.uniform(1e-8, 9e-7),
)
for qubit_idx in range(num_qubits)
},
),
"measure": (
Measure(),
{
(qubit_idx,): InstructionProperties(
error=self.__rng.uniform(1e-3, 1e-1),
duration=self.__rng.uniform(1e-8, 9e-7),
)
for qubit_idx in range(num_qubits)
},
),
"delay": (
Delay(Parameter("Time")),
{(qubit_idx,): None for qubit_idx in range(num_qubits)},
),
}
return instruction_dict

@classmethod
def _default_options(cls):
return Options(shots=1024)

def run(self, circuit, **kwargs):
noise_model = None
return BasicAer.get_backend("qasm_simulator").run(circuit, **kwargs)
Loading