Skip to content

Commit

Permalink
Merge branch 'main' into cz_sweep
Browse files Browse the repository at this point in the history
  • Loading branch information
andrea-pasquale committed May 20, 2024
2 parents 2552cea + 4c23ced commit 3f0382b
Show file tree
Hide file tree
Showing 111 changed files with 1,239 additions and 850 deletions.
497 changes: 250 additions & 247 deletions poetry.lock

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ classifiers = [

[tool.poetry.dependencies]
python = ">=3.9,<3.12"
qibolab = "^0.1.6"
qibo ="^0.2.6"
qibolab = { git = "https://github.com/qiboteam/qibolab.git"}
qibo = "^0.2.7"
numpy = "^1.26.4"
scipy = "^1.10.1"
pandas = "^1.4.3"
Expand All @@ -30,7 +30,7 @@ dash = "^2.6.0"
skops = "^0.6.0"
scikit-learn = "^1.2.1"
# Explicit dependency required to cope for dash: https://github.com/plotly/dash/issues/2557
setuptools = "^67.8.0"
setuptools = "^69.0.0"
matplotlib = { version = "^3.7.0", optional = true }
seaborn = { version = "^0.12.2", optional = true }
pydot = { version = "^1.4.2", optional = true }
Expand Down
11 changes: 2 additions & 9 deletions src/qibocal/auto/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ class Executor:
"""Qubits/Qubit Pairs to be calibrated."""
platform: Platform
"""Qubits' platform."""
max_iterations: int
"""Maximum number of iterations."""
update: bool = True
"""Runcard update mechanism."""

Expand All @@ -46,7 +44,6 @@ def load(
return cls(
actions=card.actions,
history=History({}),
max_iterations=card.max_iterations,
output=output,
platform=platform,
targets=targets,
Expand All @@ -62,12 +59,8 @@ def run(self, mode):
"""
for action in self.actions:
task = Task(action)
task.iteration = self.history.iterations(task.id)
log.info(
f"Executing mode {mode.name} on {task.id} iteration {task.iteration}."
)
log.info(f"Executing mode {mode.name} on {task.id}.")
completed = task.run(
max_iterations=self.max_iterations,
platform=self.platform,
targets=self.targets,
folder=self.output,
Expand All @@ -78,4 +71,4 @@ def run(self, mode):
if mode.name in ["autocalibration", "fit"] and self.platform is not None:
completed.update_platform(platform=self.platform, update=self.update)

yield completed.task.uid
yield completed.task.id
14 changes: 3 additions & 11 deletions src/qibocal/auto/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@


def add_timings_to_meta(meta, history):
for task_id, iteration in history:
completed = history[(task_id, iteration)]
for task_id in history:
completed = history[task_id]
if task_id not in meta:
meta[task_id] = {}

Expand All @@ -33,14 +33,6 @@ class History(dict[tuple[Id, int], Completed]):

def push(self, completed: Completed):
"""Adding completed task to history."""
self[completed.task.uid] = completed

def iterations(self, task_id: Id):
"""Count task id present in history."""
counter = 0
for task, _ in self:
if task == task_id:
counter += 1
return counter
self[completed.task.id] = completed

# TODO: implemet time_travel()
12 changes: 1 addition & 11 deletions src/qibocal/auto/runcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from pydantic.dataclasses import dataclass
from qibo.backends import Backend, GlobalBackend
from qibo.transpiler.pipeline import Passes
from qibolab.platform import Platform
from qibolab.qubits import QubitId, QubitPairId

Expand All @@ -17,9 +16,6 @@
Targets = Union[list[QubitId], list[QubitPairId], list[tuple[QubitId, ...]]]
"""Elements to be calibrated by a single protocol."""

MAX_ITERATIONS = 5
"""Default max iterations."""


@dataclass(config=dict(smart_union=True))
class Action:
Expand Down Expand Up @@ -55,8 +51,6 @@ class Runcard:
"""Qibo backend."""
platform: str = os.environ.get("QIBO_PLATFORM", "dummy")
"""Qibolab platform."""
max_iterations: int = MAX_ITERATIONS
"""Maximum number of iterations."""

def __post_init__(self):
if self.targets is None and self.platform_obj is not None:
Expand All @@ -66,11 +60,7 @@ def __post_init__(self):
def backend_obj(self) -> Backend:
"""Allocate backend."""
GlobalBackend.set_backend(self.backend, platform=self.platform)
backend = GlobalBackend()
if backend.platform is not None:
backend.transpiler = Passes(connectivity=backend.platform.topology)
backend.transpiler.passes = backend.transpiler.passes[-1:]
return backend
return GlobalBackend()

@property
def platform_obj(self) -> Platform:
Expand Down
19 changes: 3 additions & 16 deletions src/qibocal/auto/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
from qibolab.platform import Platform
from qibolab.serialize import dump_platform

from ..config import log, raise_error
from ..protocols.characterization import Operation
from ..config import log
from ..protocols import Operation
from .mode import ExecutionMode
from .operation import Data, DummyPars, Results, Routine, dummy_operation
from .runcard import Action, Id, Targets
Expand All @@ -29,8 +29,6 @@
class Task:
action: Action
"""Action object parsed from Runcard."""
iteration: int = 0
"""Task iteration."""

@property
def targets(self) -> Targets:
Expand All @@ -42,11 +40,6 @@ def id(self) -> Id:
"""Task Id."""
return self.action.id

@property
def uid(self) -> TaskId:
"""Task unique Id."""
return (self.action.id, self.iteration)

@property
def operation(self):
"""Routine object from Operation Enum."""
Expand All @@ -67,17 +60,11 @@ def update(self):

def run(
self,
max_iterations: int,
platform: Platform = None,
targets: Targets = list,
mode: ExecutionMode = None,
folder: Path = None,
):
if self.iteration > max_iterations:
raise_error(
ValueError,
f"Maximum number of iterations {max_iterations} reached!",
)

if self.targets is None:
self.action.targets = targets
Expand Down Expand Up @@ -150,7 +137,7 @@ def __post_init__(self):
@property
def datapath(self):
"""Path contaning data and results file for task."""
path = self.folder / "data" / f"{self.task.id}_{self.task.iteration}"
path = self.folder / "data" / f"{self.task.id}"
if not path.is_dir():
path.mkdir(parents=True)
return path
Expand Down
87 changes: 87 additions & 0 deletions src/qibocal/auto/transpile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from typing import Optional

from qibo import Circuit
from qibo.backends import Backend
from qibo.transpiler.pipeline import Passes
from qibo.transpiler.unroller import NativeGates, Unroller


def execute_transpiled_circuits(
circuits: list[Circuit],
qubit_maps: list[list[int]],
backend: Backend,
initial_states=None,
nshots=1000,
transpiler: Optional[Passes] = None,
):
"""
If the `qibolab` backend is used, this function pads the `circuits` in new
ones with a number of qubits equal to the one provided by the platform.
At the end, the circuits are transpiled, executed and the results returned.
The input `transpiler` is optional, but it should be provided if the backend
is `qibolab`.
For the qubit map look :func:`dummy_transpiler`.
This function returns the list of transpiled circuits and the execution results.
"""
new_circuits = []
if backend.name == "qibolab":
platform_nqubits = backend.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)
new_circuits.append(transpiled_circ)
else:
new_circuits = circuits
return new_circuits, backend.execute_circuits(
new_circuits, initial_states=initial_states, nshots=nshots
)


def execute_transpiled_circuit(
circuit: Circuit,
qubit_map: list[int],
backend: Backend,
initial_state=None,
nshots=1000,
transpiler: Optional[Passes] = None,
):
"""
If the `qibolab` backend is used, this function pads the `circuit` in new a
one with a number of qubits equal to the one provided by the platform.
At the end, the circuit is transpiled, executed and the results returned.
The input `transpiler` is optional, but it should be provided if the backend
is `qibolab`.
For the qubit map look :func:`dummy_transpiler`.
This function returns the transpiled circuit and the execution results.
"""
if backend.name == "qibolab":
platform_nqubits = backend.platform.nqubits
new_circuit = pad_circuit(platform_nqubits, circuit, qubit_map)
transpiled_circ, _ = transpiler(new_circuit)
else:
transpiled_circ = circuit
return transpiled_circ, backend.execute_circuit(
transpiled_circ, initial_state=initial_state, nshots=nshots
)


def dummy_transpiler(backend) -> Optional[Passes]:
"""
If the backend is `qibolab`, a transpiler with just an unroller is returned,
otherwise None.
"""
if backend.name == "qibolab":
unroller = Unroller(NativeGates.default())
return Passes(connectivity=backend.platform.topology, passes=[unroller])
return None


def pad_circuit(nqubits, circuit: Circuit, qubit_map: list[int]) -> Circuit:
"""
Pad `circuit` in a new one with `nqubits` qubits, according to `qubit_map`.
`qubit_map` is a list `[i, j, k, ...]`, where the i-th physical qubit is mapped
into the 0th logical qubit and so on.
"""
new_circuit = Circuit(nqubits)
new_circuit.add(circuit.on_qubits(*qubit_map))
return new_circuit
1 change: 0 additions & 1 deletion src/qibocal/cli/acquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ def acquire(runcard, folder, force):
(path / META).write_text(json.dumps(meta, indent=4))

executor = Executor.load(runcard, path, platform, runcard.targets)

# connect and initialize platform
if platform is not None:
platform.connect()
Expand Down
5 changes: 2 additions & 3 deletions src/qibocal/cli/autocalibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from ..auto.execute import Executor
from ..auto.history import add_timings_to_meta
from ..auto.mode import ExecutionMode
from ..cli.report import ReportBuilder
from .report import report
from .utils import (
META,
PLATFORM,
Expand Down Expand Up @@ -59,9 +59,8 @@ def autocalibrate(runcard, folder, force, update):
meta["end-time"] = e.strftime("%H:%M:%S")
# dump updated meta
meta = add_timings_to_meta(meta, executor.history)
report = ReportBuilder(path, runcard.targets, executor, meta, executor.history)
report.run(path)
(path / META).write_text(json.dumps(meta, indent=4))
report(path, executor)

# stop and disconnect platform
if platform is not None:
Expand Down
Loading

0 comments on commit 3f0382b

Please sign in to comment.