-
Notifications
You must be signed in to change notification settings - Fork 6
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
Native gates directly defined by the platform #1077
Changes from 1 commit
8423633
0886c0d
0674c61
ed0f495
5190fe0
ee44f8d
ec80474
efd70aa
b433c46
266e3a7
3331404
aa92440
f8f69de
68e2cd7
2d6d8ce
2ae7fde
e1c0047
a04745a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -1,33 +1,17 @@ | ||||||||||
from typing import Optional | ||||||||||
|
||||||||||
from qibo import Circuit, gates | ||||||||||
from qibo.backends import construct_backend, get_backend | ||||||||||
from qibo.backends import Backend | ||||||||||
from qibo.transpiler.pipeline import Passes | ||||||||||
from qibo.transpiler.unroller import NativeGates, Unroller | ||||||||||
from qibolab import MetaBackend | ||||||||||
from qibolab.platform import Platform | ||||||||||
from qibolab.platform.platform import PulseSequence | ||||||||||
from qibolab.pulses import PulseSequence | ||||||||||
from qibolab.qubits import QubitId | ||||||||||
|
||||||||||
|
||||||||||
def _get_platforms(): | ||||||||||
"""Qibolab platforms.""" | ||||||||||
try: | ||||||||||
platforms = list(MetaBackend().list_available()) | ||||||||||
except RuntimeError: | ||||||||||
platforms = [] | ||||||||||
|
||||||||||
return platforms + ["dummy"] | ||||||||||
|
||||||||||
|
||||||||||
AVAILABLE_PLATFORMS = _get_platforms() | ||||||||||
"""Available qibolab platforms.""" | ||||||||||
|
||||||||||
|
||||||||||
def transpile_circuits( | ||||||||||
circuits: list[Circuit], | ||||||||||
qubit_maps: list[list[QubitId]], | ||||||||||
platform: Platform, | ||||||||||
backend: Backend, | ||||||||||
transpiler: Optional[Passes], | ||||||||||
): | ||||||||||
"""Transpile and pad `circuits` according to the platform. | ||||||||||
|
@@ -45,26 +29,25 @@ def transpile_circuits( | |||||||||
are all string or all integers. | ||||||||||
""" | ||||||||||
transpiled_circuits = [] | ||||||||||
if platform.name in AVAILABLE_PLATFORMS: | ||||||||||
qubits = list(platform.qubits) | ||||||||||
if isinstance(qubit_maps[0][0], str): | ||||||||||
for i, qubit_map in enumerate(qubit_maps): | ||||||||||
qubit_map = map(lambda x: qubits.index(x), qubit_map) | ||||||||||
qubit_maps[i] = list(qubit_map) | ||||||||||
platform_nqubits = platform.nqubits | ||||||||||
for circuit, qubit_map in zip(circuits, qubit_maps): | ||||||||||
new_circuit = pad_circuit(platform_nqubits, circuit, qubit_map) | ||||||||||
transpiled_circ, _ = transpiler(new_circuit) | ||||||||||
transpiled_circuits.append(transpiled_circ) | ||||||||||
else: | ||||||||||
transpiled_circuits = circuits | ||||||||||
platform = backend.platform | ||||||||||
qubits = list(platform.qubits) | ||||||||||
if isinstance(qubit_maps[0][0], str): | ||||||||||
for i, qubit_map in enumerate(qubit_maps): | ||||||||||
qubit_map = map(lambda x: qubits.index(x), qubit_map) | ||||||||||
qubit_maps[i] = list(qubit_map) | ||||||||||
platform_nqubits = platform.nqubits | ||||||||||
for circuit, qubit_map in zip(circuits, qubit_maps): | ||||||||||
new_circuit = pad_circuit(platform_nqubits, circuit, qubit_map) | ||||||||||
transpiled_circ, _ = transpiler(new_circuit) | ||||||||||
transpiled_circuits.append(transpiled_circ) | ||||||||||
|
||||||||||
return transpiled_circuits | ||||||||||
|
||||||||||
|
||||||||||
def execute_transpiled_circuits( | ||||||||||
circuits: list[Circuit], | ||||||||||
qubit_maps: list[list[QubitId]], | ||||||||||
platform: Platform, | ||||||||||
backend: Backend, | ||||||||||
transpiler: Optional[Passes], | ||||||||||
initial_states=None, | ||||||||||
nshots=1000, | ||||||||||
|
@@ -82,13 +65,9 @@ def execute_transpiled_circuits( | |||||||||
transpiled_circuits = transpile_circuits( | ||||||||||
circuits, | ||||||||||
qubit_maps, | ||||||||||
platform, | ||||||||||
backend, | ||||||||||
transpiler, | ||||||||||
) | ||||||||||
if platform.name in AVAILABLE_PLATFORMS: | ||||||||||
backend = construct_backend(backend="qibolab", platform=platform) | ||||||||||
else: | ||||||||||
backend = get_backend() | ||||||||||
return transpiled_circuits, backend.execute_circuits( | ||||||||||
transpiled_circuits, initial_states=initial_states, nshots=nshots | ||||||||||
) | ||||||||||
|
@@ -97,7 +76,7 @@ def execute_transpiled_circuits( | |||||||||
def execute_transpiled_circuit( | ||||||||||
circuit: Circuit, | ||||||||||
qubit_map: list[QubitId], | ||||||||||
platform: Platform, | ||||||||||
backend: Backend, | ||||||||||
transpiler: Optional[Passes], | ||||||||||
initial_state=None, | ||||||||||
nshots=1000, | ||||||||||
|
@@ -116,14 +95,9 @@ def execute_transpiled_circuit( | |||||||||
transpiled_circ = transpile_circuits( | ||||||||||
[circuit], | ||||||||||
[qubit_map], | ||||||||||
platform, | ||||||||||
backend, | ||||||||||
transpiler, | ||||||||||
)[0] | ||||||||||
if platform.name in AVAILABLE_PLATFORMS: | ||||||||||
backend = construct_backend(backend="qibolab", platform=platform) | ||||||||||
else: | ||||||||||
backend = get_backend() | ||||||||||
set_compiler(backend) | ||||||||||
return transpiled_circ, backend.execute_circuit( | ||||||||||
transpiled_circ, initial_state=initial_state, nshots=nshots | ||||||||||
) | ||||||||||
|
@@ -152,12 +126,10 @@ def get_natives(platform): | |||||||||
return natives | ||||||||||
|
||||||||||
|
||||||||||
def set_compiler(backend): | ||||||||||
def set_compiler(backend, natives): | ||||||||||
""" | ||||||||||
Set the compiler to execute the native gates defined by the platform. | ||||||||||
""" | ||||||||||
platform = backend.platform | ||||||||||
natives = get_natives(platform) | ||||||||||
compiler = backend.compiler | ||||||||||
for native in natives: | ||||||||||
gate = getattr(gates, native) | ||||||||||
|
@@ -174,17 +146,17 @@ def rule(qubits_ids, platform, parameters=None): | |||||||||
backend.compiler[gate] = rule | ||||||||||
|
||||||||||
|
||||||||||
def dummy_transpiler(platform) -> Optional[Passes]: | ||||||||||
def dummy_transpiler(backend: Backend) -> Passes: | ||||||||||
""" | ||||||||||
If the backend is `qibolab`, a transpiler with just an unroller is returned, | ||||||||||
otherwise None. | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Properly document that this function is not pure, since it has the side effect of modifying the input I know this seems pedantic, but losing track of this changes may have effects later on, when they will become unexpected. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My idea at the beginning was to make the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No need. I agree with your choice, since there is nothing protocol-specific, so it should not be repeated over and over.
Everyone's life easier. Good choice :)
Even better, you could have put it here qibocal/src/qibocal/auto/execute.py Lines 263 to 264 in f8f69de
if it were the single place where the backend was created. Since unfortunately it is not, instead of this: qibocal/src/qibocal/protocols/state_tomography.py Lines 105 to 106 in f8f69de
you could actually just make a single function, and invoke as backend, transpiler = construct_qibolab_backend(platform) considering that this double functions invocation is repeat over and over. https://github.com/search?q=repo%3Aqiboteam%2Fqibocal%20construct_backend&type=code (in any case, this one could be an issue - but it's especially relevant for |
||||||||||
""" | ||||||||||
if platform.name in AVAILABLE_PLATFORMS: | ||||||||||
native_gates = get_natives(platform) | ||||||||||
native_gates = list(map(lambda x: getattr(gates, x), native_gates)) | ||||||||||
|
||||||||||
unroller = Unroller(NativeGates.from_gatelist(native_gates)) | ||||||||||
return Passes(connectivity=platform.topology, passes=[unroller]) | ||||||||||
platform = backend.platform | ||||||||||
native_gates = get_natives(platform) | ||||||||||
set_compiler(backend, native_gates) | ||||||||||
native_gates = list(map(lambda x: getattr(gates, x), native_gates)) | ||||||||||
Edoardo-Pedicillo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
unroller = Unroller(NativeGates.from_gatelist(native_gates)) | ||||||||||
return Passes(connectivity=platform.topology, passes=[unroller]) | ||||||||||
|
||||||||||
|
||||||||||
def pad_circuit(nqubits, circuit: Circuit, qubit_map: list[int]) -> Circuit: | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, usually it is better to avoid mutating objects, especially nested ones.
I could lift the suggestion by one level, and suggest creating the entire backend (here just returning the compiler, instead of modifying the backend). But let's limit to the compiler itself.
You could create an empty dictionary
rules
, and here doeventually setting the compiler out of the loops as:
(in principle, you can avoid even modifying the dictionary
rules
, by defining it immediately through comprehension - but I get this is a bit unfamiliar).