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

Enable simulation in autocalibration layout #315

Merged
merged 6 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
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
3 changes: 2 additions & 1 deletion src/qibocal/auto/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,5 @@ def run(self):
completed = Completed(task, output, Normal())
self.history.push(completed)
self.head = self.next()
self.platform.update(completed.res.update)
if self.platform is not None:
self.platform.update(completed.res.update)
29 changes: 22 additions & 7 deletions src/qibocal/auto/operation.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import inspect
from dataclasses import dataclass, field, fields
from typing import Callable, Dict, Generic, NewType, Optional, TypeVar, Union
from dataclasses import dataclass, fields
from typing import Callable, Dict, Generic, NewType, TypeVar, Union

from qibolab.platforms.abstract import AbstractPlatform, Qubit
from qibolab.platforms.abstract import Qubit

OperationId = NewType("OperationId", str)
"""Identifier for a calibration routine."""
Expand Down Expand Up @@ -90,13 +90,19 @@ class Routine(Generic[_ParametersT, _DataT, _ResultsT]):
"""A wrapped calibration routine."""

acquisition: Callable[[_ParametersT], _DataT]
fit: Callable[[_DataT], _ResultsT]
report: Callable[[_DataT, _ResultsT], None]
fit: Callable[[_DataT], _ResultsT] = None
report: Callable[[_DataT, _ResultsT], None] = None

def __post_init__(self):
# TODO: this could be improved
if self.fit == None:
self.fit = _dummy_fit
if self.report == None:
self.report = _dummy_report
Edoardo-Pedicillo marked this conversation as resolved.
Show resolved Hide resolved

@property
def parameters_type(self):
sig = inspect.signature(self.acquisition)
# we are assuming that params is the last argument, maybe should be the first(?)
param = list(sig.parameters.values())[0]
return param.annotation

Expand All @@ -108,6 +114,15 @@ def data_type(self):
def results_type(self):
return inspect.signature(self.fit).return_annotation

# TODO: I don't like these properties but it seems to work
@property
def platform_dependent(self):
return "platform" in inspect.signature(self.acquisition).parameters

@property
def qubits_dependent(self):
return "qubits" in inspect.signature(self.acquisition).parameters


@dataclass
class DummyPars(Parameters):
Expand All @@ -133,7 +148,7 @@ def _dummy_fit(data: DummyData) -> DummyRes:


def _dummy_report(data: DummyData, result: DummyRes):
return
return [], ""


dummy_operation = Routine(_dummy_acquisition, _dummy_fit, _dummy_report)
4 changes: 2 additions & 2 deletions src/qibocal/auto/runcard.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,6 @@ def load(cls, card: Union[dict, Path]):
)
return cls(
actions=content["actions"],
qubits=content["qubits"],
format=content["format"],
qubits=content["qubits"] if "qubits" in content else [],
format=content["format"] if "format" in content else None,
)
14 changes: 10 additions & 4 deletions src/qibocal/auto/task.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Action execution tracker."""
import inspect
import os
from dataclasses import dataclass
from pathlib import Path
Expand Down Expand Up @@ -89,10 +90,15 @@ def run(self, folder: Path, platform: AbstractPlatform, qubits: Qubits) -> Resul
parameters = DummyPars()

path = self.datapath(folder)
# TODO: fix data attributes
self._data: Data = operation.acquisition(
parameters, platform=platform, qubits=qubits
)

if operation.platform_dependent and operation.qubits_dependent:
self._data: Data = operation.acquisition(
parameters, platform=platform, qubits=qubits
)
else:
self._data: Data = operation.acquisition(
parameters,
)
self._data.save(path)
# TODO: data dump
# path.write_text(yaml.dump(pydantic_encoder(self.data(base_dir))))
Expand Down
20 changes: 18 additions & 2 deletions src/qibocal/cli/auto_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ def dump_report(self):
create_autocalibration_report(self.folder, self.executor.history)

def dump_platform_runcard(self):
self.platform.dump(self.folder / UPDATED_PLATFORM)
if self.platform is not None:
self.platform.dump(self.folder / UPDATED_PLATFORM)


class AutoCalibrationReportBuilder:
Expand All @@ -71,7 +72,7 @@ def routine_name(self, routine, iteration):
name = routine.replace("_", " ").title()
return f"{name} - {iteration}"

def plot(self, routine_name, iteration, qubit):
def single_qubit_plot(self, routine_name, iteration, qubit):
node = self.history[(routine_name, iteration)]
data = node.task.data
figures, fitting_report = node.task.operation.report(data, node.res, qubit)
Expand All @@ -85,3 +86,18 @@ def plot(self, routine_name, iteration, qubit):

all_html = "".join(html_list)
return all_html, fitting_report

def plot(self, routine_name, iteration):
node = self.history[(routine_name, iteration)]
data = node.task.data
figures, fitting_report = node.task.operation.report(data)
with tempfile.NamedTemporaryFile(delete=False) as temp:
html_list = []
for figure in figures:
figure.write_html(temp.name, include_plotlyjs=False, full_html=False)
temp.seek(0)
fightml = temp.read().decode("utf-8")
html_list.append(fightml)

all_html = "".join(html_list)
return all_html, fitting_report
20 changes: 12 additions & 8 deletions src/qibocal/cli/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,15 +150,19 @@ def __init__(self, runcard, folder=None, force=False):
self.backend, self.platform = self._allocate_backend(
backend_name, platform_name, path, platform_runcard
)
if self.platform is not None:
self.qubits = {
q: self.platform.qubits[q]
for q in self.runcard["qubits"]
if q in self.platform.qubits
}
if "qubits" in self.runcard:
if self.platform is not None:
self.qubits = {
q: self.platform.qubits[q]
for q in self.runcard["qubits"]
if q in self.platform.qubits
}
else:
self.qubits = self.runcard.get("qubits")
else:
self.qubits = self.runcard.get("qubits")
self.format = self.runcard["format"]
self.qubits = []
if "format" in runcard:
self.format = self.runcard["format"]

# Saving runcard
shutil.copy(runcard, f"{path}/runcard.yml")
Expand Down
8 changes: 6 additions & 2 deletions src/qibocal/web/templates/autocalibration.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,15 +151,15 @@ <h1>{{ report.title }}</h1>
<h4
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
{{ report.routine_name(routine, iteration) }}</h4>

{% if report.qubits != [] %}
{% for qubit in report.qubits %}
<div id="{{ routine }}-{{ iteration }}-{{ qubit }}" style="scroll-margin-top: 4em;">
<h5
class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
{{ header }} - Qubit {{ qubit }}</h5>


{% set figures, fitting_report = report.plot(routine, iteration, qubit) %}
{% set figures, fitting_report = report.single_qubit_plot(routine, iteration, qubit) %}
{% if "No fitting data" not in fitting_report %}
{% set fitting_params= fitting_report.split('<br>') %}
<div class="div-fitting">
Expand Down Expand Up @@ -191,6 +191,10 @@ <h1>{{ report.title }}</h1>

</div>
{% endfor %}
{% else %}
{% set figures, fitting_report = report.plot(routine, iteration) %}
{{ figures }}
{% endif %}
</div>
{% endfor %}

Expand Down