Skip to content

Commit

Permalink
build: merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
BrunoLiegiBastonLiegi committed Apr 25, 2024
2 parents 823e8e5 + a514441 commit 5552598
Show file tree
Hide file tree
Showing 60 changed files with 2,611 additions and 2,305 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ ci:
autofix_prs: true
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: debug-statements
- repo: https://github.com/psf/black
rev: 24.2.0
rev: 24.4.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
Expand All @@ -25,7 +25,7 @@ repos:
additional_dependencies: [tomli]
args: [--in-place, --config, ./pyproject.toml]
- repo: https://github.com/asottile/pyupgrade
rev: v3.15.1
rev: v3.15.2
hooks:
- id: pyupgrade
- repo: https://github.com/hadialqattan/pycln
Expand Down
7 changes: 3 additions & 4 deletions capi/examples/example.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ int main() {
"include \"qelib1.inc\";" \
"qreg q[3];" \
"creg a[2];" \
"cx q[0],q[2];" \
"x q[1];" \
"swap q[0],q[1];" \
"cx q[1],q[0];" \
"cz q[0],q[2];" \
"gpi2(0.3) q[1];" \
"cz q[1],q[2];" \
"measure q[0] -> a[0];" \
"measure q[2] -> a[1];",
"dummy", 10);
Expand Down
7 changes: 3 additions & 4 deletions crate/examples/example.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ OPENQASM 2.0;
include "qelib1.inc";
qreg q[3];
creg a[2];
cx q[0],q[2];
x q[1];
swap q[0],q[1];
cx q[1],q[0];
cz q[0],q[2];
gpi2(0.3) q[1];
cz q[1],q[2];
measure q[0] -> a[0];
measure q[2] -> a[1];
"#;
Expand Down
6 changes: 3 additions & 3 deletions doc/source/getting-started/experiment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ For simplicity, the qubit will be controlled by a RFSoC-based system, althought
FOLDER = pathlib.Path.cwd()


def create(folder=FOLDER):
def create():
# Instantiate controller instruments
controller = RFSoC(NAME, ADDRESS, PORT)

Expand All @@ -54,7 +54,7 @@ For simplicity, the qubit will be controlled by a RFSoC-based system, althought
channels |= Channel("drive", port=controller[0])
# create qubit objects
runcard = load_runcard(folder)
runcard = load_runcard(FOLDER)
qubits, pairs = load_qubits(runcard)
# assign channels to qubits
qubits[0].readout = channels["L3-22_ro"]
Expand All @@ -75,7 +75,7 @@ For simplicity, the qubit will be controlled by a RFSoC-based system, althought
from qibolab.platform import Platform
def create(folder: Path) -> Platform:
def create() -> Platform:
"""Function that generates Qibolab platform."""
And the we can define the runcard ``my_platform/parameters.json``:
Expand Down
15 changes: 7 additions & 8 deletions doc/source/tutorials/circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ circuits definition that we leave to the `Qibo
circuit = Circuit(1)

# attach Hadamard gate and a measurement
circuit.add(gates.H(0))
circuit.add(gates.GPI2(0, phi=np.pi / 2))
circuit.add(gates.M(0))

# execute on quantum hardware
qibo.set_backend("qibolab", "dummy")
qibo.set_backend("qibolab", platform="dummy")
hardware_result = circuit(nshots=5000)

# retrieve measured probabilities
Expand Down Expand Up @@ -80,7 +80,7 @@ results:
circuit = Circuit(1)

# attach Rotation on X-Pauli with angle = 0
circuit.add(gates.RX(0, theta=0))
circuit.add(gates.GPI2(0, phi=0))
circuit.add(gates.M(0))

# define range of angles from [0, 2pi]
Expand All @@ -104,7 +104,7 @@ results:


# execute on quantum hardware
qibo.set_backend("qibolab", "dummy")
qibo.set_backend("qibolab", platform="dummy")
hardware = execute_rotation()

# execute with classical quantum simulation
Expand Down Expand Up @@ -144,10 +144,9 @@ Qibolab also supports the execution of circuits starting from a QASM string. The
include "qelib1.inc";
qreg q[3];
creg a[2];
cx q[0],q[2];
x q[1];
swap q[0],q[1];
cx q[1],q[0];
cz q[0],q[2];
gpi2(0.3) q[1];
cz q[1],q[2];
measure q[0] -> a[0];
measure q[2] -> a[1];"""

Expand Down
31 changes: 5 additions & 26 deletions doc/source/tutorials/compiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ How to modify the default circuit transpilation.
A Qibolab platform can execute pulse sequences.
As shown in :ref:`tutorials_circuits`, Qibo circuits can be executed by invoking the :class:`qibolab.backends.QibolabBackend`, which is the object integrating Qibolab to Qibo.
When a Qibo circuit is executed, the backend will automatically transpile and compile it to a pulse sequence, which will be sent to the platform for execution.
The default transpiler and compiler outlined in the :ref:`main_doc_compiler` section will be used in this process.
The default compiler outlined in the :ref:`main_doc_compiler` section will be used in this process.
In this tutorial we will demonstrate how the user can modify this process for custom applications.

The ``transpiler`` and ``compiler`` objects used when executing a circuit are attributes of :class:`qibolab.backends.QibolabBackend`.
The ``compiler`` object used when executing a circuit are attributes of :class:`qibolab.backends.QibolabBackend`.
Creating an instance of the backend provides access to these objects:

.. testcode:: python
Expand All @@ -18,41 +18,20 @@ Creating an instance of the backend provides access to these objects:

backend = QibolabBackend(platform="dummy")

print(type(backend.transpiler))
print(type(backend.compiler))

.. testoutput:: python
:hide:

<class 'qibo.transpiler.pipeline.Passes'>
<class 'qibolab.compilers.compiler.Compiler'>

The transpiler is responsible for transforming any circuit to one that respects
the chip connectivity and native gates. The compiler then transforms this circuit
to the equivalent pulse sequence.
The user can modify the default transpilation and compilation process by changing
to the equivalent pulse sequence. Note that there is no default transpiler, therefore
the backend can only execute circuits that contain native gates by default.
The user can modify the transpilation and compilation process by changing
the ``transpiler`` and ``compiler`` attributes of the ``QibolabBackend``.

.. testcode:: python

from qibo import gates
from qibo.models import Circuit
from qibolab.backends import QibolabBackend

# define circuit
circuit = Circuit(1)
circuit.add(gates.U3(0, 0.1, 0.2, 0.3))
circuit.add(gates.M(0))

backend = QibolabBackend(platform="dummy")
# disable the transpiler
backend.transpiler = None

# execute circuit
result = backend.execute_circuit(circuit, nshots=1000)

completely disables the transpilation steps and the circuit is sent directly to the compiler.

In this example, we executed circuits using the backend ``backend.execute_circuit`` method,
unlike the previous example (:ref:`tutorials_circuits`) where circuits were executed directly using ``circuit(nshots=1000)``.
It is possible to perform transpiler and compiler manipulation in both approaches.
Expand Down
38 changes: 27 additions & 11 deletions doc/source/tutorials/lab.rst
Original file line number Diff line number Diff line change
Expand Up @@ -228,15 +228,17 @@ platform available as

.. code-block:: python
from qibolab import Platform
from qibolab import create_platform
# Define platform and load specific runcard
platform = Platform("my_platform")
platform = create_platform("my_platform")
To do so, ``create()`` needs to be saved in a module called ``my_platform.py``
and the environment flag ``QIBOLAB_PLATFORMS`` needs to point to the directory
that contains this module. Examples of advanced platforms are available at `this
To do so, ``create()`` needs to be saved in a module called ``platform.py`` inside
a folder with the name of this platform (in this case ``my_platform``).
Moreover, the environment flag ``QIBOLAB_PLATFORMS`` needs to point to the directory
that contains this folder.
Examples of advanced platforms are available at `this
repository <https://github.com/qiboteam/qibolab_platforms_qrc>`_.

.. _using_runcards:
Expand Down Expand Up @@ -441,19 +443,26 @@ should be a subset of :class:`qibolab.qubits.Qubit` attributes.
Providing the above runcard is not sufficient to instantiate a
:class:`qibolab.platform.Platform`. This should still be done using a
``create()`` method, however this is significantly simplified by
``qibolab.serialize``. Here is the ``create()`` method that loads the parameters of
``qibolab.serialize``. The ``create()`` method should be put in a
file named ``platform.py`` inside the ``my_platform`` directory.
Here is the ``create()`` method that loads the parameters of
the above runcard:

.. testcode:: python

# my_platform / platform.py

from pathlib import Path
from qibolab import Platform
from qibolab.channels import ChannelMap, Channel
from qibolab.serialize import load_runcard, load_qubits, load_settings
from qibolab.instruments.dummy import DummyInstrument

FOLDER = Path.cwd()
# assumes runcard is storred in the same folder as platform.py


def create(folder: Path):
def create():
# Create a controller instrument
instrument = DummyInstrument("my_instrument", "0.0.0.0:0")

Expand Down Expand Up @@ -489,7 +498,10 @@ With the following additions for coupler architectures:

.. testcode:: python

def create(folder):
# my_platform / platform.py


def create():
# Create a controller instrument
instrument = DummyInstrument("my_instrument", "0.0.0.0:0")

Expand All @@ -504,7 +516,7 @@ With the following additions for coupler architectures:
channels |= Channel("chfc0", port=instrument["o6"])
# create ``Qubit`` and ``QubitPair`` objects by loading the runcard
runcard = load_runcard(folder)
runcard = load_runcard(FOLDER)
qubits, couplers, pairs = load_qubits(runcard)

# assign channels to the qubit
Expand Down Expand Up @@ -669,6 +681,8 @@ in this case ``"twpa_pump"``.

.. testcode:: python

# my_platform / platform.py

from pathlib import Path
from qibolab import Platform
from qibolab.channels import ChannelMap, Channel
Expand All @@ -681,8 +695,10 @@ in this case ``"twpa_pump"``.
from qibolab.instruments.dummy import DummyInstrument
from qibolab.instruments.oscillator import LocalOscillator

FOLDER = Path.cwd()

def create(folder: Path):

def create():
# Create a controller instrument
instrument = DummyInstrument("my_instrument", "0.0.0.0:0")
twpa = LocalOscillator("twpa_pump", "0.0.0.1")
Expand All @@ -695,7 +711,7 @@ in this case ``"twpa_pump"``.
channels |= Channel("ch1in", port=instrument["i1"])
# create ``Qubit`` and ``QubitPair`` objects by loading the runcard
runcard = load_runcard(folder)
runcard = load_runcard(FOLDER)
qubits, pairs = load_qubits(runcard)

# assign channels to the qubit
Expand Down
91 changes: 91 additions & 0 deletions extras/test819.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import numpy as np
from qibo.backends import GlobalBackend

from qibolab import Platform
from qibolab.execution_parameters import (
AcquisitionType,
AveragingMode,
ExecutionParameters,
)
from qibolab.instruments.qblox.controller import QbloxController
from qibolab.platform import NS_TO_SEC
from qibolab.pulses import PulseSequence
from qibolab.sweeper import Parameter, Sweeper, SweeperType

GlobalBackend.set_backend("qibolab", "spinq10q")
platform: Platform = GlobalBackend().platform
controller: QbloxController = platform.instruments["qblox_controller"]

sequence = PulseSequence()
ro_pulses = {}

qid = 0
qubit = platform.qubits[qid]
qubits = {qid: qubit}

ro_pulse = platform.create_qubit_readout_pulse(qid, start=0)
ro_pulse.frequency = int(2e9)
sequence.add(ro_pulse)

freq_width = 2e7
freq_step = 2e5
bias_width = 0.8
bias_step = 0.01
nshots = 1024
relaxation_time = 5000

navgs = nshots
repetition_duration = sequence.finish + relaxation_time

# define the parameters to sweep and their range:
delta_frequency_range = np.arange(-freq_width // 2, freq_width // 2, freq_step)
freq_sweeper = Sweeper(
Parameter.frequency, delta_frequency_range, [ro_pulse], type=SweeperType.OFFSET
)

delta_bias_range = np.arange(-bias_width / 2, bias_width / 2, bias_step)
bias_sweeper = Sweeper(
Parameter.bias, delta_bias_range, qubits=[qubit], type=SweeperType.OFFSET
)

options = ExecutionParameters(
nshots=nshots,
relaxation_time=relaxation_time,
acquisition_type=AcquisitionType.INTEGRATION,
averaging_mode=AveragingMode.CYCLIC,
)
time = (sequence.duration + relaxation_time) * nshots * NS_TO_SEC
sweepers = (bias_sweeper, freq_sweeper)
for sweep in sweepers:
time *= len(sweep.values)

# mock
controller.is_connected = True


class Sequencers:
def __getitem__(self, index):
return self

def set(self, *args):
pass


class Device:
sequencers = Sequencers()


for mod in controller.modules.values():
mod.device = Device()
mod._device_num_sequencers = 0
# end mock

# for name, mod in controller.modules.items():
# if "qcm_rf" in name:
# continue

mod = controller.modules["qcm_bb0"]
channels = controller._set_module_channel_map(mod, qubits)
pulses = sequence.get_channel_pulses(*channels)
mod.process_pulse_sequence(qubits, pulses, navgs, nshots, repetition_duration, sweepers)
print(mod._sequencers["o1"][0].program)
4 changes: 4 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
forEachSystem
(system: let
pkgs = nixpkgs.legacyPackages.${system};
pwd = builtins.getEnv "PWD";
platforms = builtins.toPath "${pwd}/../qibolab_platforms_qrc/";
in {
default = devenv.lib.mkShell {
inherit inputs pkgs;
Expand All @@ -43,6 +45,8 @@
{
packages = with pkgs; [pre-commit poethepoet jupyter stdenv.cc.cc.lib zlib];

env.QIBOLAB_PLATFORMS = platforms;

languages.c = {
enable = true;
};
Expand Down
Loading

0 comments on commit 5552598

Please sign in to comment.