Skip to content

Commit

Permalink
Merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
stavros11 committed Feb 15, 2024
2 parents 7711fe9 + e2ecafa commit e02af42
Show file tree
Hide file tree
Showing 12 changed files with 857 additions and 789 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy docs
name: docs

on:
workflow_dispatch:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/rules.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# A single CI script with github workflow
name: Tests without qpu
name: tests

on:
workflow_dispatch:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repos:
- id: check-toml
- id: debug-statements
- repo: https://github.com/psf/black
rev: 24.1.1
rev: 24.2.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
Expand Down
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
# Qibolab

![Tests](https://github.com/qiboteam/qibolab/workflows/Tests/badge.svg)
[![codecov](https://codecov.io/gh/qiboteam/qibolab/branch/main/graph/badge.svg?token=11UENAPBPH)](https://codecov.io/gh/qiboteam/qibolab)
[![DOI](https://zenodo.org/badge/241307936.svg)](https://zenodo.org/badge/latestdoi/241307936)
![PyPI - Version](https://img.shields.io/pypi/v/qibolab)
![PyPI - Python Version](https://img.shields.io/pypi/pyversions/qibolab)

Qibolab is the dedicated [Qibo](https://github.com/qiboteam/qibo) backend for
the automatic deployment of quantum circuits on quantum hardware.

Some of the key features of Qibolab are:

* Deploy Qibo models on quantum hardware easily.
* Create custom experimental drivers for custom lab setup.
* Support multiple heterogeneous platforms.
* Use existing calibration procedures for experimentalists.
- Deploy Qibo models on quantum hardware easily.
- Create custom experimental drivers for custom lab setup.
- Support multiple heterogeneous platforms.
- Use existing calibration procedures for experimentalists.

## Documentation

[![docs](https://github.com/qiboteam/qibolab/actions/workflows/publish.yml/badge.svg)](https://qibo.science/qibolab/stable/)

The qibolab backend documentation is available at [https://qibo.science/qibolab/stable/](https://qibo.science/qibolab/stable/).

## Minimum working example
Expand Down Expand Up @@ -100,4 +102,7 @@ for _ in range(5):

## Citation policy

[![arXiv](https://img.shields.io/badge/arXiv-2308.06313-b31b1b.svg)](https://arxiv.org/abs/2308.06313)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.10572987.svg)](https://doi.org/10.5281/zenodo.10572987)

If you use the package please refer to [the documentation](https://qibo.science/qibo/stable/appendix/citing-qibo.html#publications) for citation instructions.
1 change: 1 addition & 0 deletions doc/source/tutorials/circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ results:

import matplotlib.pyplot as plt
import numpy as np
import qibo
from qibo import Circuit, gates


Expand Down
1,366 changes: 689 additions & 677 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pyvisa-py = { version = "0.5.3", optional = true }
qm-qua = { version = "^1.1.6", optional = true }
qualang-tools = { version = "^0.15.0", optional = true}
setuptools = { version = ">67.0.0", optional = true }
laboneq = { version = "==2.21.0", optional = true }
laboneq = { version = "==2.24.0", optional = true }
qibosoq = { version = ">=0.0.4,<0.2", optional = true }

[tool.poetry.group.dev]
Expand Down Expand Up @@ -61,7 +61,7 @@ qcodes = "^0.37.0"
qcodes_contrib_drivers = "0.18.0"
qibosoq = ">=0.0.4,<0.2"
qualang-tools = "^0.15.0"
laboneq = "==2.21.0"
laboneq = "==2.24.0"

[tool.poetry.group.tests]
optional = true
Expand Down
30 changes: 12 additions & 18 deletions src/qibolab/instruments/qblox/acquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,17 @@ class DemodulatedAcquisition:
It is advisable to have a power level at least higher than 5mV.
"""

scope: dict
"""Data returned by scope qblox acquisition."""
bins: dict
"""Binned acquisition data returned by qblox."""
duration: int
"""Duration of the readout pulse."""

@property
def raw(self):
return self.scope["acquisition"]["scope"]

@property
def integration(self):
return self.bins["integration"]
Expand All @@ -115,29 +121,17 @@ def shots_q(self):
return np.array(self.integration["path1"]) / self.duration

@property
def averaged_i(self):
"""I-component after demodulating and integrating every shot waveform
and then averaging over shots."""
return np.mean(self.shots_i)
def raw_i(self):
"""Average of the raw i waveforms for every readout pulse."""
return np.array(self.raw["path0"]["data"][0 : self.duration])

@property
def averaged_q(self):
"""Q-component after demodulating and integrating every shot waveform
and then averaging over shots."""
return np.mean(self.shots_q)
def raw_q(self):
"""Average of the raw q waveforms for every readout pulse."""
return np.array(self.raw["path1"]["data"][0 : self.duration])

@property
def classified(self):
"""List with the results of demodulating, integrating and classifying
every shot."""
return np.array(self.bins["threshold"])

@property
def data(self):
"""Acquisition data to be returned to the platform.
Ignores the data available in acquisition results and returns
only i and q voltages.
"""
# TODO: to be updated once the functionality of ExecutionResults is extended
return (self.shots_i, self.shots_q, self.classified)
21 changes: 8 additions & 13 deletions src/qibolab/instruments/qblox/cluster_qrm_rf.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,14 +613,18 @@ def process_pulse_sequence(
}

# Acquisitions
pulse = None
for acquisition_index, pulse in enumerate(sequencer.pulses.ro_pulses):
sequencer.acquisitions[pulse.serial] = {
"num_bins": num_bins,
"index": acquisition_index,
}

# Add scope_acquisition to default sequencer
if sequencer.number == self.DEFAULT_SEQUENCERS[port]:
if (
sequencer.number == self.DEFAULT_SEQUENCERS[port]
and pulse is not None
):
sequencer.acquisitions["scope_acquisition"] = {
"num_bins": 1,
"index": acquisition_index + 1,
Expand Down Expand Up @@ -977,14 +981,14 @@ def acquire(self):
for port in self._output_ports_keys:
for sequencer in self._sequencers[port]:
# Store scope acquisition data on 'scope_acquisition' acquisition of the default sequencer
# TODO: Maybe this store_scope can be done only if needed to optimize the process!
if sequencer.number == self.DEFAULT_SEQUENCERS[port]:
self.device.store_scope_acquisition(
sequencer.number, "scope_acquisition"
)
scope = self.device.get_acquisitions(sequencer.number)[
"scope_acquisition"
]

if not hardware_demod_enabled: # Software Demodulation
if len(sequencer.pulses.ro_pulses) == 1:
pulse = sequencer.pulses.ro_pulses[0]
Expand All @@ -1002,20 +1006,11 @@ def acquire(self):
for pulse in sequencer.pulses.ro_pulses:
bins = results[pulse.serial]["acquisition"]["bins"]
acquisitions[pulse.qubit] = acquisitions[pulse.serial] = (
DemodulatedAcquisition(bins, duration)
)

# Provide Scope Data for verification (assuming memory reseet is being done)
if len(sequencer.pulses.ro_pulses) == 1:
pulse = sequencer.pulses.ro_pulses[0]
frequency = self.get_if(pulse)
acquisitions[pulse.serial].averaged = AveragedAcquisition(
scope, duration, frequency
DemodulatedAcquisition(scope, bins, duration)
)

# grab only the data required by the platform
# TODO: to be updated once the functionality of ExecutionResults is extended
return {key: acquisition.data for key, acquisition in acquisitions.items()}
return {key: acquisition for key, acquisition in acquisitions.items()}

def disconnect(self):
"""Stops all sequencers, disconnect all the outputs from the AWG paths
Expand Down
19 changes: 9 additions & 10 deletions src/qibolab/instruments/qblox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,24 @@ def _execute_pulse_sequence(
for name, module in self.modules.items():
if isinstance(module, QrmRf) and not module_pulses[name].ro_pulses.is_empty:
results = module.acquire()
existing_keys = set(acquisition_results.keys()) & set(results.keys())
for key, value in results.items():
if key in existing_keys:
acquisition_results[key].update(value)
else:
acquisition_results[key] = value

acquisition_results[key] = value
# TODO: move to QRM_RF.acquire()
shape = tuple(len(sweeper.values) for sweeper in reversed(sweepers))
shots_shape = (nshots,) + shape
for ro_pulse in sequence.ro_pulses:
if options.acquisition_type is AcquisitionType.DISCRIMINATION:
_res = acquisition_results[ro_pulse.serial][2]
_res = acquisition_results[ro_pulse.serial].classified
_res = np.reshape(_res, shots_shape)
if options.averaging_mode is not AveragingMode.SINGLESHOT:
_res = np.mean(_res, axis=0)
else:
ires = acquisition_results[ro_pulse.serial][0]
qres = acquisition_results[ro_pulse.serial][1]
elif options.acquisition_type is AcquisitionType.RAW:
i_raw = acquisition_results[ro_pulse.serial].raw_i
q_raw = acquisition_results[ro_pulse.serial].raw_q
_res = i_raw + 1j * q_raw
elif options.acquisition_type is AcquisitionType.INTEGRATION:
ires = acquisition_results[ro_pulse.serial].shots_i
qres = acquisition_results[ro_pulse.serial].shots_q
_res = ires + 1j * qres
if options.averaging_mode is AveragingMode.SINGLESHOT:
_res = np.reshape(_res, shots_shape)
Expand Down
Loading

0 comments on commit e02af42

Please sign in to comment.