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

Unrolling bounds as instrument settings #832

Merged
merged 4 commits into from
Mar 20, 2024
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
7 changes: 7 additions & 0 deletions src/qibolab/dummy/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
]
},
"instruments": {
"dummy": {
"bounds": {
"waveforms": 0,
"readout": 0,
"instructions": 0
}
},
"twpa_pump": {
"power": 10,
"frequency": 1000000000.0
Expand Down
13 changes: 10 additions & 3 deletions src/qibolab/instruments/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,19 @@ class Controller(Instrument):
PortType = Port
"""Class used by the instrument to instantiate ports."""

BOUNDS: Bounds = Bounds(0, 0, 0)
"""Estimated limitations of the device memory."""

def __init__(self, name, address):
super().__init__(name, address)
self._ports = {}
self.bounds: Bounds = Bounds(0, 0, 0)
"""Estimated limitations of the device memory."""

def setup(self, bounds):
"""Set unrolling batch bounds."""
self.bounds = Bounds(**bounds)

def dump(self):
"""Dump unrolling batch bounds."""
return {"bounds": asdict(self.bounds)}

@property
@abstractmethod
Expand Down
27 changes: 7 additions & 20 deletions src/qibolab/instruments/qblox/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@
from qibolab.sweeper import Parameter, Sweeper, SweeperType
from qibolab.unrolling import Bounds

MAX_DURATION = int(4e4) # Translate SEQUENCER_MEMORY = 2**17 into pulse duration
"""Maximum duration of the control pulses [1q 40ns] [Rough estimate]."""
MAX_READOUT = int(1e6)
"""Maximum number of readout pulses [Not estimated]."""
MAX_INSTRUCTIONS = int(1e6)
"""Maximum instructions size [Not estimated]."""

SEQUENCER_MEMORY = 2**17


Expand All @@ -34,12 +27,6 @@ class QbloxController(Controller):
modules (dict): A dictionay with the qblox modules connected to the experiment.
"""

BOUNDS = Bounds(
waveforms=MAX_DURATION,
readout=MAX_READOUT,
instructions=MAX_READOUT,
)

def __init__(
self, name, address: str, modules, internal_reference_clock: bool = True
):
Expand All @@ -49,6 +36,13 @@ def __init__(
self.cluster: QbloxCluster = None
self.modules: dict = modules
self._reference_clock = "internal" if internal_reference_clock else "external"
self.bounds = Bounds(
waveforms=int(
4e4
), # Translate SEQUENCER_MEMORY = 2**17 into pulse duration
readout=int(1e6),
instructions=int(1e6),
)
signal.signal(signal.SIGTERM, self._termination_handler)

@property
Expand Down Expand Up @@ -84,13 +78,6 @@ def disconnect(self):
self.cluster.close()
self.is_connected = False

def setup(self):
"""Empty method to comply with Instrument interface.

Setup of the modules happens in the platform ``create`` method
using :meth:`qibolab.serialize.load_instrument_settings`.
"""

def _termination_handler(self, signum, frame):
"""Calls all modules to stop if the program receives a termination
signal."""
Expand Down
24 changes: 8 additions & 16 deletions src/qibolab/instruments/qm/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,6 @@
"""Offset to be added to Octave addresses, because they must be 11xxx, where
xxx are the last three digits of the Octave IP address."""

MAX_DURATION = int(4e4)
"""Maximum duration of the control pulses [1q 40ns] [Rough estimate]."""
MAX_READOUT = int(30)
"""Maximum number of readout pulses [Not estimated]."""
MAX_INSTRUCTIONS = int(1e6)
"""Maximum instructions size [Not estimated]."""


def declare_octaves(octaves, host, calibration_path=None):
"""Initiate Octave configuration and add octaves info.
Expand Down Expand Up @@ -126,16 +119,12 @@ class QMController(Controller):
"""Dictionary containing the :class:`qibolab.instruments.qm.devices.Octave`
instruments being used."""

BOUNDS = Bounds(
waveforms=MAX_DURATION,
readout=MAX_READOUT,
instructions=MAX_INSTRUCTIONS,
)

time_of_flight: int = 0
"""Time of flight used for hardware signal integration."""
smearing: int = 0
"""Smearing used for hardware signal integration."""
bounds: Bounds = Bounds(0, 0, 0)
"""Maximum bounds used for batching in sequence unrolling."""
calibration_path: Optional[str] = None
"""Path to the JSON file that contains the mixer calibration."""
script_file_name: Optional[str] = None
Expand Down Expand Up @@ -170,6 +159,12 @@ class QMController(Controller):

def __post_init__(self):
super().__init__(self.name, self.address)
# redefine bounds because abstract instrument overwrites them
self.bounds = Bounds(
waveforms=int(4e4),
readout=30,
instructions=int(1e6),
)
# convert lists to dicts
if not isinstance(self.opxs, dict):
self.opxs = {instr.name: instr for instr in self.opxs}
Expand Down Expand Up @@ -223,9 +218,6 @@ def connect(self):
)
self.is_connected = True

def setup(self):
"""Deprecated method."""

def disconnect(self):
"""Disconnect from QM manager."""
if self.manager is not None:
Expand Down
3 changes: 0 additions & 3 deletions src/qibolab/instruments/rfsoc/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,6 @@ def connect(self):
def disconnect(self):
"""Empty method to comply with Instrument interface."""

def setup(self):
"""Empty deprecated method."""

def _execute_pulse_sequence(
self,
sequence: PulseSequence,
Expand Down
23 changes: 6 additions & 17 deletions src/qibolab/instruments/zhinst.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,6 @@
SWEEPER_START = {"start"}


MAX_DURATION = int(4e4)
"""Maximum duration of the control pulses [1q 40ns] [Rough estimate]."""
MAX_READOUT = 250
"""Maximum number of readout pulses [Not estimated]."""
MAX_INSTRUCTIONS = int(1e6)
"""Maximum instructions size [Not estimated]."""


def select_pulse(pulse, pulse_type):
"""Pulse translation."""

Expand Down Expand Up @@ -298,12 +290,6 @@ class Zurich(Controller):

PortType = ZhPort

BOUNDS = Bounds(
waveforms=MAX_DURATION,
readout=MAX_READOUT,
instructions=MAX_INSTRUCTIONS,
)

def __init__(
self, name, device_setup, use_emulation=False, time_of_flight=0.0, smearing=0.0
):
Expand Down Expand Up @@ -337,6 +323,12 @@ def __init__(
self.results = None
"Zurich experiment definitions"

self.bounds = Bounds(
waveforms=int(4e4),
readout=250,
instructions=int(1e6),
Comment on lines +326 to +329
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do these numbers come from. I believe ZI limitations are much larger than these numbers.

Additionally, different ZI instruments have different limitations. Our Zurich class does not represent a single instrument, but a collection of ZI instruments. So the concept of bounds is not straightforwardly applicable to this class. The best we can do for now is for each property take the minimum across all possible ZI instruments.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In principle, we should be able to serialize the configuration for every instrument in the platform. They should just live in nested sections.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for name, instrument in instruments.items():

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ran some quick experiments until they crashed for the waveforms and readouts, I don't claim them to be the best but I needed something for the code. They should get updated with the feedback from people running stuff I hope.

)

self.acquisition_type = None
"To store if the AcquisitionType.SPECTROSCOPY needs to be enabled by parsing the sequence"

Expand Down Expand Up @@ -371,9 +363,6 @@ def disconnect(self):
self.device = self.session.disconnect()
self.is_connected = False

def setup(self, *args, **kwargs):
"""Empty method to comply with Instrument interface."""

def calibration_step(self, qubits, couplers, options):
"""Zurich general pre experiment calibration definitions.

Expand Down
2 changes: 1 addition & 1 deletion src/qibolab/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ def execute_pulse_sequences(
}

results = defaultdict(list)
bounds = kwargs.get("bounds", self._controller.BOUNDS)
bounds = kwargs.get("bounds", self._controller.bounds)
for b in batch(sequences, bounds):
sequence, readouts = unroll_sequences(b, options.relaxation_time)
result = self._execute(sequence, options, **kwargs)
Expand Down
13 changes: 7 additions & 6 deletions src/qibolab/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,19 @@ def dump_instruments(instruments: InstrumentMap) -> dict:
data = {}
for name, instrument in instruments.items():
try:
# TODO: Migrate all instruments to this approach
# (I think it is also useful for qblox)
settings = instrument.dump()
if len(settings) > 0:
data[name] = settings
except AttributeError:
Comment on lines +182 to +185
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anyone still missing .dump(), but with .settings?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I believe the qblox modules, not the controller itself but QrmRf, QcmRf, etc. And in the platforms we need to pass settings to each module seperately.

settings = instrument.settings
if settings is not None:
if isinstance(settings, dict):
data[name] = settings
else:
data[name] = settings.dump()
except AttributeError:
# TODO: Migrate all instruments to this approach
# (I think it is also useful for qblox)
settings = instrument.dump()
if len(settings) > 0:
data[name] = settings

return data


Expand Down
7 changes: 7 additions & 0 deletions tests/dummy_qrc/qblox/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
]
],
"instruments": {
"qblox_controller": {
"bounds": {
"instructions": 1000000,
"readout": 250,
"waveforms": 40000
}
},
"twpa_pump": {
"frequency": 6535900000,
"power": 4
Expand Down
7 changes: 7 additions & 0 deletions tests/dummy_qrc/qm/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
]
],
"instruments": {
"qm": {
"bounds": {
"waveforms" : 10000,
"readout": 30,
"instructions": 1000000
}
},
"con1": {
"i1": {"gain": 0},
"i2": {"gain": 0}
Expand Down
7 changes: 7 additions & 0 deletions tests/dummy_qrc/qm_octave/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
]
],
"instruments": {
"qm": {
"bounds": {
"waveforms" : 10000,
"readout": 30,
"instructions": 1000000
}
},
"con1": {
"i1": {
"gain": 0
Expand Down
7 changes: 7 additions & 0 deletions tests/dummy_qrc/rfsoc/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
"relaxation_time": 100000
},
"instruments": {
"tii_rfsoc4x2": {
"bounds": {
"waveforms": 0,
"readout": 0,
"instructions": 0
}
},
"twpa_a": {
"frequency": 6200000000,
"power": -1
Expand Down
7 changes: 7 additions & 0 deletions tests/dummy_qrc/zurich/parameters.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
"relaxation_time": 300000
},
"instruments": {
"EL_ZURO": {
"bounds": {
"instructions": 1000000,
"readout": 250,
"waveforms": 40000
}
},
"lo_readout": {
"frequency": 5500000000
},
Expand Down
2 changes: 1 addition & 1 deletion tests/test_instruments_zhinst.py
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ def test_batching(dummy_qrc):
sequence.add(platform.create_MZ_pulse(0, start=measurement_start))
sequence.add(platform.create_MZ_pulse(1, start=measurement_start))

batches = list(batch(600 * [sequence], instrument.BOUNDS))
batches = list(batch(600 * [sequence], instrument.bounds))
# These sequences get limited by the number of measuraments (600/250/2)
assert len(batches) == 5
assert len(batches[0]) == 125
Expand Down
Loading