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

Native gates directly defined by the platform #1077

Merged
merged 18 commits into from
Feb 14, 2025
Merged
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
68 changes: 63 additions & 5 deletions src/qibocal/auto/transpile.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
from typing import Optional

from qibo import Circuit
from qibo import Circuit, gates
from qibo.backends import Backend
from qibo.transpiler.pipeline import Passes
from qibo.transpiler.unroller import NativeGates, Unroller
from qibolab.compilers.compiler import Compiler
from qibolab.pulses import PulseSequence
from qibolab.qubits import QubitId

REPLACEMENTS = {
"RX": "GPI2",
"MZ": "M",
}


def transpile_circuits(
circuits: list[Circuit],
Expand Down Expand Up @@ -97,19 +104,70 @@ def execute_transpiled_circuit(
backend,
transpiler,
)[0]

return transpiled_circ, backend.execute_circuit(
transpiled_circ, initial_state=initial_state, nshots=nshots
)


def natives(platform):
"""
Return the list of native gates defined in the `platform`.
This function assumes the native gates to be the same for each
qubit and pair.
"""
pair = next(iter(platform.pairs.values()))
qubit = next(iter(platform.qubits.values()))
two_qubit_natives = list(pair.native_gates.raw)
single_qubit_natives = list(qubit.native_gates.raw)
# Solve Qibo-Qibolab mismatch
single_qubit_natives.append("RZ")
single_qubit_natives.append("Z")
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if Z should be somehow directly inferred from RZ by the transpiler itself...

(implying that is not platform's/Qibocal's business)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In theory yes, I am using Qibolab compiler and NativeGates convention to differentiate between the two.

Copy link
Member

Choose a reason for hiding this comment

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

Fine, but is there a reason to differentiate?

I.e. with the current compiler, the RZ will always be implemented as virtual phase, and that will be the same for the Z as well...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fine, but is there a reason to differentiate?

No, maybe @andrea-pasquale could have an explanation.

single_qubit_natives.remove("RX12")
new_single_natives = [REPLACEMENTS.get(i, i) for i in single_qubit_natives]
return new_single_natives + two_qubit_natives


def create_rule(native):
def rule(qubits_ids, platform, parameters=None):
if len(qubits_ids[1]) == 1:
native_gate = platform.qubits[tuple(qubits_ids[1])].native_gates
else:
native_gate = platform.pairs[tuple(qubits_ids[1])].native_gates
pulses = getattr(native_gate, native).pulses
return PulseSequence(pulses), {}

return rule


def set_compiler(backend, natives_):
"""
Set the compiler to execute the native gates defined by the platform.
"""
compiler = backend.compiler
rules = {}
for native in natives_:
gate = getattr(gates, native)
if gate not in compiler.rules:
rules[gate] = create_rule(native)
else:
rules[gate] = compiler.rules[gate]
rules[gates.I] = compiler.rules[gates.I]
backend.compiler = Compiler(rules=rules)


def dummy_transpiler(backend: Backend) -> Passes:
"""
If the backend is `qibolab`, a transpiler with just an unroller is returned,
otherwise None.
otherwise `None`. This function overwrites the compiler defined in the
backend, taking into account the native gates defined in the`platform` (see
:func:`set_compiler`).
"""
unroller = Unroller(NativeGates.default())
return Passes(connectivity=backend.platform.topology, passes=[unroller])
platform = backend.platform
native_gates = natives(platform)
set_compiler(backend, native_gates)
native_gates = [getattr(gates, x) for x in native_gates]
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:
Expand Down