Skip to content

Commit

Permalink
Merge pull request #739 from qiboteam/rmstart
Browse files Browse the repository at this point in the history
Remove platform start and stop
  • Loading branch information
stavros11 authored Jan 12, 2024
2 parents 9745314 + fc55f79 commit 47d1d55
Show file tree
Hide file tree
Showing 41 changed files with 115 additions and 607 deletions.
6 changes: 0 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ platform = create_platform("my_platform")

# Connects to lab instruments using the details specified in the calibration settings.
platform.connect()
# Configures instruments using the loaded calibration settings.
platform.setup()
# Turns on the local oscillators
platform.start()

# Execute a pulse sequence
options = ExecutionParameters(nshots=1000)
Expand All @@ -70,8 +66,6 @@ results = platform.execute_pulse_sequence(sequence, options)
# Print the acquired shots
print(results.samples)

# Turn off lab instruments
platform.stop()
# Disconnect from the instruments
platform.disconnect()
```
Expand Down
18 changes: 6 additions & 12 deletions doc/source/main-documentation/qibolab.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The API reference section provides a description of all the attributes and metho
In the platform, the main methods can be divided in different sections:

- functions save and change qubit parameters (``dump``, ``update``)
- functions to coordinate the instruments (``connect``, ``setup``, ``start``, ``stop``, ``disconnect``)
- functions to coordinate the instruments (``connect``, ``setup``, ``disconnect``)
- functions to execute experiments (``execute_pulse_sequence``, ``execute_pulse_sequences``, ``sweep``)
- functions to initialize gates (``create_RX90_pulse``, ``create_RX_pulse``, ``create_CZ_pulse``, ``create_MZ_pulse``, ``create_qubit_drive_pulse``, ``create_qubit_readout_pulse``, ``create_RX90_drag_pulse``, ``create_RX_drag_pulse``)
- setters and getters of channel/qubit parameters (local oscillator parameters, attenuations, gain and biases)
Expand All @@ -29,13 +29,11 @@ For example, let's first define a platform (that we consider to be a single qubi

platform = create_platform("dummy")

Now we connect and start the instruments (note that we, the user, do not need to know which instruments are connected).
Now we connect to the instruments (note that we, the user, do not need to know which instruments are connected).

.. testcode:: python

platform.connect()
platform.setup()
platform.start()

We can easily print some of the parameters of the channels (similarly we can set those, if needed):

Expand Down Expand Up @@ -93,7 +91,6 @@ Finally, we can stop instruments and close connections.

.. testcode:: python

platform.stop()
platform.disconnect()


Expand Down Expand Up @@ -204,9 +201,9 @@ Note that while channels are defined in a device-independent manner, the port pa
from qibolab.instruments.rfsoc import RFSoC

controller = RFSoC(name="dummy", address="192.168.0.10", port="6000")
channel1 = Channel("my_channel_name_1", port=controller[1])
channel2 = Channel("my_channel_name_2", port=controller[2])
channel3 = Channel("my_channel_name_3", port=controller[3])
channel1 = Channel("my_channel_name_1", port=controller.ports(1))
channel2 = Channel("my_channel_name_2", port=controller.ports(2))
channel3 = Channel("my_channel_name_3", port=controller.ports(3))

Channels are then organized in :class:`qibolab.channels.ChannelMap` to be passed as a single argument to the platform.
Following the tutorial in :doc:`/tutorials/lab`, we can continue the initialization:
Expand Down Expand Up @@ -707,20 +704,17 @@ Controllers (subclasses of :class:`qibolab.instruments.abstract.Controller`):
- Dummy Instrument: :class:`qibolab.instruments.dummy.DummyInstrument`
- Zurich Instruments: :class:`qibolab.instruments.zhinst.Zurich`
- Quantum Machines: :class:`qibolab.instruments.qm.driver.QMOPX`
- Qblox: :class:`qibolab.instruments.qblox.cluster.Cluster`
- Qblox: :class:`qibolab.instruments.qblox.controller.QbloxCluster`
- Xilinx RFSoCs: :class:`qibolab.instruments.rfsoc.driver.RFSoC`

Other Instruments (subclasses of :class:`qibolab.instruments.abstract.Instrument`):
- Erasynth++: :class:`qibolab.instruments.erasynth.ERA`
- RohseSchwarz SGS100A: :class:`qibolab.instruments.rohde_schwarz.SGS100A`
- Qutech SPI rack: :class:`qibolab.instruments.qutech.SPI`

Instruments all implement a set of methods:

- connect
- setup
- start
- stop
- disconnect

While the controllers, the main instruments in a typical setup, add other two methods:
Expand Down
2 changes: 1 addition & 1 deletion doc/source/tutorials/instrument.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ write something like this:

instrument = DummyInstrument("my_instrument", "0.0.0.0:0")
channels = ChannelMap()
channels |= Channel("ch1out", port=instrument["o1"])
channels |= Channel("ch1out", port=instrument.ports("o1"))

The interesting part of this section is the ``port`` parameter that works as an
Expand Down
9 changes: 0 additions & 9 deletions doc/source/tutorials/pulses.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,10 @@ pulse sequence according to the number of shots ``nshots`` specified.
# Connects to lab instruments using the details specified in the calibration settings.
platform.connect()

# Configures instruments using the loaded calibration settings.
platform.setup()

# Turns on the local oscillators
platform.start()

# Executes a pulse sequence.
options = ExecutionParameters(nshots=1000, relaxation_time=100)
results = platform.execute_pulse_sequence(sequence, options=options)

# Turn off lab instruments
platform.stop()

# Disconnect from the instruments
platform.disconnect()

Expand Down
4 changes: 2 additions & 2 deletions doc/source/tutorials/transpiler.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,14 @@ Instead of completely disabling, custom transpilation steps can be given:


Now circuits will only be transpiled to native gates, without any connectivity matching steps.
The :class:`qibolab.transpilers.gate_decompositions.NativeGates` transpiler used in this example assumes Z, RZ, GPI2 or U3 as the single-qubit native gates, and supports CZ and iSWAP as two-qubit natives.
The transpiler used in this example assumes Z, RZ, GPI2 or U3 as the single-qubit native gates, and supports CZ and iSWAP as two-qubit natives.
In this case we restricted the two-qubit gate set to CZ only.
If the circuit to be executed contains gates that are not included in this gate set, they will be transformed to multiple gates from the gate set.
Arbitrary single-qubit gates are typically transformed to U3.
Arbitrary two-qubit gates are transformed to two or three CZ gates following their `universal CNOT decomposition <https://arxiv.org/abs/quant-ph/0307177>`_.
The decomposition of some common gates such as the SWAP and CNOT is hard-coded for efficiency.

Multiple transpilation steps can be implemented using the :class:`qibolab.transpilers.pipeline.Pipeline`:
Multiple transpilation steps can be implemented using the transpiler ``Passes``:

.. testcode:: python

Expand Down
6 changes: 0 additions & 6 deletions examples/fidelity_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,10 @@

# Connects to lab instruments using the details specified in the calibration settings.
platform.connect()
# Configures instruments using the loaded calibration settings.
platform.setup()
# Turns on the local oscillators
platform.start()
# Executes a pulse sequence.
results = platform.measure_fidelity(qubits=[1, 2, 3, 4], nshots=3000)
print(
f"results[qubit] (rotation_angle, threshold, fidelity, assignment_fidelity): {results}"
)
# Turn off lab instruments
platform.stop()
# Disconnect from the instruments
platform.disconnect()
6 changes: 0 additions & 6 deletions examples/minimum_working_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,8 @@

# Connects to lab instruments using the details specified in the calibration settings.
platform.connect()
# Configures instruments using the loaded calibration settings.
platform.setup()
# Turns on the local oscillators
platform.start()
# Executes a pulse sequence.
results = platform.execute_pulse_sequence(sequence, nshots=3000)
print(f"results (amplitude, phase, i, q): {results}")
# Turn off lab instruments
platform.stop()
# Disconnect from the instruments
platform.disconnect()
8 changes: 2 additions & 6 deletions src/qibolab/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,11 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000):

if not self.platform.is_connected:
self.platform.connect()
self.platform.setup()
self.platform.start()

readout = self.platform.execute_pulse_sequence(
sequence,
ExecutionParameters(nshots=nshots),
)
self.platform.stop()
result = MeasurementOutcomes(circuit.measurements, self, nshots=nshots)
self.assign_measurements(measurement_map, readout)
return result
Expand Down Expand Up @@ -145,13 +143,11 @@ def execute_circuits(self, circuits, initial_state=None, nshots=1000):

if not self.platform.is_connected:
self.platform.connect()
self.platform.setup()
self.platform.start()

readout = self.platform.execute_pulse_sequences(
sequences,
ExecutionParameters(nshots=nshots),
)
self.platform.stop()

results = []
readout = {k: deque(v) for k, v in readout.items()}
Expand Down
9 changes: 3 additions & 6 deletions src/qibolab/channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,9 @@ class ChannelMap:
def add(self, *items):
"""Add multiple items to the channel map.
If
:class: `qibolab.channels.Channel` objects are given they are
added to the channel map. If a different type is
given, a
:class: `qibolab.channels.Channel` with the corresponding name
is created and added to the channel map.
If :class: `qibolab.channels.Channel` objects are given they are dded to the channel map.
If a different type is given, a :class: `qibolab.channels.Channel` with the corresponding name
is created and added to the channel map.
"""
for item in items:
if isinstance(item, Channel):
Expand Down
20 changes: 17 additions & 3 deletions src/qibolab/couplers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class Coupler:
"""Representation of a physical coupler.
Coupler objects are instantiated by
:class: `qibolab.platforms.platform.Platform` but they are
passed to instrument designs in order to play pulses.
:class: `qibolab.platforms.platform.Platform`
and are passed to instruments to play pulses on them.
"""

name: QubitId
Expand All @@ -25,14 +25,28 @@ class Coupler:
native_pulse: CouplerNatives = field(default_factory=CouplerNatives)
"For now this only contains the calibrated pulse to activate the coupler."

flux: Optional[Channel] = None
_flux: Optional[Channel] = None
"flux (:class:`qibolab.platforms.utils.Channel`): Channel used to send flux pulses to the qubit."

# TODO: With topology or conectivity
# qubits: Optional[Dict[QubitId, Qubit]] = field(default_factory=dict)
qubits: Dict = field(default_factory=dict)
"Qubits the coupler acts on"

def __post_init__(self):
if self.flux is not None and self.sweetspot != 0:
self.flux.offset = self.sweetspot

@property
def flux(self):
return self._flux

@flux.setter
def flux(self, channel):
if self.sweetspot != 0:
channel.offset = self.sweetspot
self._flux = channel

@property
def channels(self):
if self.flux is not None:
Expand Down
9 changes: 5 additions & 4 deletions src/qibolab/dummy.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,18 @@ def create_dummy(with_couplers: bool = True):
# Create channel objects
nqubits = runcard["nqubits"]
channels = ChannelMap()
channels |= Channel("readout", port=instrument["readout"])
channels |= Channel("readout", port=instrument.ports("readout"))
channels |= (
Channel(f"drive-{i}", port=instrument[f"drive-{i}"]) for i in range(nqubits)
Channel(f"drive-{i}", port=instrument.ports(f"drive-{i}"))
for i in range(nqubits)
)
channels |= (
Channel(f"flux-{i}", port=instrument[f"flux-{i}"]) for i in range(nqubits)
Channel(f"flux-{i}", port=instrument.ports(f"flux-{i}")) for i in range(nqubits)
)
channels |= Channel("twpa", port=None)
if with_couplers:
channels |= (
Channel(f"flux_coupler-{c}", port=instrument[f"flux_coupler-{c}"])
Channel(f"flux_coupler-{c}", port=instrument.ports(f"flux_coupler-{c}"))
for c in itertools.chain(range(0, 2), range(3, 5))
)
channels["readout"].attenuation = 0
Expand Down
40 changes: 9 additions & 31 deletions src/qibolab/instruments/abstract.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import tempfile
from abc import ABC, abstractmethod
from dataclasses import asdict, dataclass
from pathlib import Path
from typing import Optional

from qibolab.instruments.port import Port

InstrumentId = str
INSTRUMENTS_DATA_FOLDER = Path.home() / ".qibolab" / "instruments" / "data"


@dataclass
Expand All @@ -34,39 +31,23 @@ def __init__(self, name, address):
self.name: InstrumentId = name
self.address: str = address
self.is_connected: bool = False
self.signature: str = f"{type(self).__name__}@{address}"
self.settings: Optional[InstrumentSettings] = None
# create local storage folder
instruments_data_folder = INSTRUMENTS_DATA_FOLDER
instruments_data_folder.mkdir(parents=True, exist_ok=True)
# create temporary directory
self.tmp_folder = tempfile.TemporaryDirectory(dir=instruments_data_folder)
self.data_folder = Path(self.tmp_folder.name)

@property
def signature(self):
return f"{type(self).__name__}@{self.address}"

@abstractmethod
def connect(self):
"""Establish connection to the physical instrument."""
raise NotImplementedError

@abstractmethod
def setup(self, *args, **kwargs):
"""Upload settings to the physical instrument."""
raise NotImplementedError

@abstractmethod
def start(self):
"""Turn on the physical instrument."""
raise NotImplementedError

@abstractmethod
def stop(self):
"""Turn off the physical instrument."""
raise NotImplementedError

@abstractmethod
def disconnect(self):
"""Close connection to the physical instrument."""
raise NotImplementedError

@abstractmethod
def setup(self, *args, **kwargs):
"""Set instrument settings."""


class Controller(Instrument):
Expand All @@ -85,10 +66,7 @@ def sampling_rate(self):
"""Sampling rate of control electronics in giga samples per second
(GSps)."""

def __getitem__(self, port_name):
return self.ports(port_name)

def ports(self, port_name):
def ports(self, port_name, *args, **kwargs):
"""Get ports associated to this controller.
Args:
Expand Down
12 changes: 3 additions & 9 deletions src/qibolab/instruments/dummy.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,12 @@ def sampling_rate(self):
def connect(self):
log.info(f"Connecting to {self.name} instrument.")

def setup(self, *args, **kwargs):
log.info(f"Setting up {self.name} instrument.")

def start(self):
log.info(f"Starting {self.name} instrument.")

def stop(self):
log.info(f"Stopping {self.name} instrument.")

def disconnect(self):
log.info(f"Disconnecting {self.name} instrument.")

def setup(self, *args, **kwargs):
log.info(f"Setting up {self.name} instrument.")

def get_values(self, options, ro_pulse, shape):
if options.acquisition_type is AcquisitionType.DISCRIMINATION:
if options.averaging_mode is AveragingMode.SINGLESHOT:
Expand Down
Loading

0 comments on commit 47d1d55

Please sign in to comment.