iqm-pulse 9.14.0__py3-none-any.whl → 9.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iqm/pulse/builder.py +65 -78
- iqm/pulse/gate_implementation.py +11 -15
- iqm/pulse/gates/cz.py +3 -2
- iqm/pulse/gates/measure.py +3 -4
- iqm/pulse/gates/prx.py +27 -30
- iqm/pulse/gates/rz.py +5 -5
- iqm/pulse/playlist/hd_drag.py +3 -3
- iqm/pulse/playlist/visualisation/base.py +25 -1
- iqm/pulse/playlist/visualisation/templates/playlist_inspection.jinja2 +1 -1
- iqm/pulse/scheduler.py +3 -3
- {iqm_pulse-9.14.0.dist-info → iqm_pulse-9.17.0.dist-info}/METADATA +1 -1
- {iqm_pulse-9.14.0.dist-info → iqm_pulse-9.17.0.dist-info}/RECORD +15 -15
- {iqm_pulse-9.14.0.dist-info → iqm_pulse-9.17.0.dist-info}/LICENSE.txt +0 -0
- {iqm_pulse-9.14.0.dist-info → iqm_pulse-9.17.0.dist-info}/WHEEL +0 -0
- {iqm_pulse-9.14.0.dist-info → iqm_pulse-9.17.0.dist-info}/top_level.txt +0 -0
iqm/pulse/builder.py
CHANGED
|
@@ -18,7 +18,6 @@ from __future__ import annotations
|
|
|
18
18
|
from collections.abc import Iterable
|
|
19
19
|
import copy
|
|
20
20
|
from dataclasses import dataclass, field, replace
|
|
21
|
-
import functools
|
|
22
21
|
import itertools
|
|
23
22
|
import logging
|
|
24
23
|
from types import MethodType
|
|
@@ -63,7 +62,7 @@ from iqm.pulse.playlist.instructions import (
|
|
|
63
62
|
Wait,
|
|
64
63
|
)
|
|
65
64
|
from iqm.pulse.playlist.playlist import Playlist
|
|
66
|
-
from iqm.pulse.playlist.schedule import
|
|
65
|
+
from iqm.pulse.playlist.schedule import Schedule, Segment
|
|
67
66
|
from iqm.pulse.quantum_ops import QuantumOp, QuantumOpTable, validate_locus_calibration, validate_op_calibration
|
|
68
67
|
from iqm.pulse.scheduler import (
|
|
69
68
|
NONSOLID,
|
|
@@ -758,8 +757,8 @@ class ScheduleBuilder:
|
|
|
758
757
|
if priority_calibration:
|
|
759
758
|
if op.name in priority_calibration:
|
|
760
759
|
# first check if full OILCalibrationData structure was given
|
|
761
|
-
op_data = priority_calibration.get(op.name)
|
|
762
|
-
prio_data = op_data.get(new_impl_name, {}).get(new_locus, {})
|
|
760
|
+
op_data = priority_calibration.get(op.name, {})
|
|
761
|
+
prio_data = op_data.get(new_impl_name, {}).get(new_locus, {})
|
|
763
762
|
else:
|
|
764
763
|
# if not assume just the data for this locus was given
|
|
765
764
|
prio_data = priority_calibration
|
|
@@ -956,14 +955,8 @@ class ScheduleBuilder:
|
|
|
956
955
|
def _finish_schedule(self, schedule: Schedule) -> Schedule:
|
|
957
956
|
"""Finishes the instruction schedule.
|
|
958
957
|
|
|
959
|
-
* filters out zero-duration Blocks and Waits
|
|
960
|
-
* converts all spacer instructions used during scheduling to Waits
|
|
961
|
-
* merges consequent Waits
|
|
962
958
|
* removes channels that only have Waits in them
|
|
963
|
-
|
|
964
|
-
This should be the final step of the schedule building process, after this the
|
|
965
|
-
resulting Schedule can no longer be consistently extended with another (since
|
|
966
|
-
all the spacer instructions are gone).
|
|
959
|
+
* fuses long-distance Rz corrections to the correct drive pulses
|
|
967
960
|
|
|
968
961
|
Args:
|
|
969
962
|
schedule: schedule to finish
|
|
@@ -973,46 +966,15 @@ class ScheduleBuilder:
|
|
|
973
966
|
|
|
974
967
|
"""
|
|
975
968
|
has_long_distance_rzs = False
|
|
976
|
-
|
|
977
|
-
def segment_pass(inst: Instruction) -> Instruction:
|
|
978
|
-
"""Convert Blocks and Nothings to Waits. Also checks for FluxPulses that have long-distance VirtualZ
|
|
979
|
-
corrections in order to determine if these need handling (for performance reasons, we want to do this
|
|
980
|
-
step only on-demand).
|
|
981
|
-
"""
|
|
982
|
-
nonlocal has_long_distance_rzs
|
|
983
|
-
if isinstance(inst, NONSOLID) and not isinstance(inst, Wait):
|
|
984
|
-
return Wait(inst.duration)
|
|
985
|
-
if isinstance(inst, FluxPulse) and inst.rzs:
|
|
986
|
-
has_long_distance_rzs = True
|
|
987
|
-
return inst
|
|
988
|
-
|
|
989
|
-
def not_zero_block(inst: Instruction) -> bool:
|
|
990
|
-
"""Zero-duration Block instructions have a legitimate use (in barrier ops),
|
|
991
|
-
zero-duration Wait instructions are allowed for convenience.
|
|
992
|
-
Here we filter them out.
|
|
993
|
-
"""
|
|
994
|
-
return not (inst.duration < TOLERANCE and isinstance(inst, (Block, Wait)))
|
|
995
|
-
|
|
996
|
-
def merge_waits(result: list[Instruction], new: Instruction) -> list[Instruction]:
|
|
997
|
-
"""Merge consequent Wait instructions."""
|
|
998
|
-
if not result:
|
|
999
|
-
return [new] # first iteration
|
|
1000
|
-
last = result[-1]
|
|
1001
|
-
if isinstance(last, Wait) and isinstance(new, Wait):
|
|
1002
|
-
result[-1] = Wait(int(last.duration + new.duration)) # replace last with the combined wait
|
|
1003
|
-
else:
|
|
1004
|
-
result.append(new)
|
|
1005
|
-
return result
|
|
1006
|
-
|
|
1007
969
|
for channel in schedule.channels():
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
return
|
|
970
|
+
if "flux" in channel:
|
|
971
|
+
for inst in schedule[channel]:
|
|
972
|
+
if isinstance(inst, FluxPulse) and inst.rzs:
|
|
973
|
+
has_long_distance_rzs = True
|
|
974
|
+
break
|
|
975
|
+
if has_long_distance_rzs:
|
|
976
|
+
return self._fuse_long_distance_virtual_rzs(schedule)
|
|
977
|
+
return schedule.cleanup()
|
|
1016
978
|
|
|
1017
979
|
def _fuse_long_distance_virtual_rzs(self, schedule: Schedule) -> Schedule:
|
|
1018
980
|
"""Fuse long-distance (i.e. out-of-gate-locus) VirtualRZ corrections with the next drive pulse
|
|
@@ -1036,7 +998,11 @@ class ScheduleBuilder:
|
|
|
1036
998
|
for drive_channel, rz_angle in rzs.items():
|
|
1037
999
|
drive_sample_counter = 0
|
|
1038
1000
|
for drive_inst_idx, drive_inst in enumerate(schedule[drive_channel]):
|
|
1039
|
-
if
|
|
1001
|
+
if (
|
|
1002
|
+
not isinstance(drive_inst, Wait)
|
|
1003
|
+
and not isinstance(drive_inst, NONSOLID)
|
|
1004
|
+
and drive_sample_counter >= sample_counter
|
|
1005
|
+
):
|
|
1040
1006
|
fuse(
|
|
1041
1007
|
schedule_copy[drive_channel][drive_inst_idx],
|
|
1042
1008
|
drive_inst_idx,
|
|
@@ -1116,10 +1082,11 @@ class ScheduleBuilder:
|
|
|
1116
1082
|
):
|
|
1117
1083
|
# convert the locus durations to seconds (no probe channels have been used so far)
|
|
1118
1084
|
scheduling_in_seconds = True
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1085
|
+
if self._channel_templates["other"] is not None:
|
|
1086
|
+
component_durations_seconds = {
|
|
1087
|
+
component: self._channel_templates["other"].duration_to_seconds(duration)
|
|
1088
|
+
for component, duration in component_durations.items()
|
|
1089
|
+
}
|
|
1123
1090
|
|
|
1124
1091
|
child_components = self._get_neighborhood_hard_boundary(child, 0)
|
|
1125
1092
|
neighborhood_components = self._get_neighborhood_hard_boundary(child, neighborhood)
|
|
@@ -1344,38 +1311,58 @@ class ScheduleBuilder:
|
|
|
1344
1311
|
}
|
|
1345
1312
|
|
|
1346
1313
|
pl = Playlist()
|
|
1347
|
-
mapped_instructions: dict[int
|
|
1348
|
-
|
|
1314
|
+
mapped_instructions: dict[str, dict[int, Any]] = {}
|
|
1315
|
+
|
|
1316
|
+
def _append_to_schedule(sc_schedule: SC_Schedule, channel_name: str, instr: Instruction) -> None:
|
|
1317
|
+
"""Append ``instr`` to ``sc_schedule`` into the channel``channel_name``."""
|
|
1318
|
+
try:
|
|
1319
|
+
# Check if instr can be used as a dictionary key, and use it if possible.
|
|
1320
|
+
# 2 dataclasses can have the same hash if their fields are identical. We must
|
|
1321
|
+
# distinguish between different Waveform classes which may have identical fields,
|
|
1322
|
+
# so we use the instruction itself as a key, so that the class is checked too.
|
|
1323
|
+
instr_id = hash(instr)
|
|
1324
|
+
except TypeError:
|
|
1325
|
+
instr_id = instr.id
|
|
1326
|
+
if instr_id not in mapped_instructions.setdefault(channel_name, {}):
|
|
1327
|
+
mapped = _map_instruction(instr)
|
|
1328
|
+
idx = pl.channel_descriptions[channel_name].add_instruction(mapped)
|
|
1329
|
+
sc_schedule.instructions.setdefault(channel_name, []).append(idx)
|
|
1330
|
+
mapped_instructions[channel_name][instr_id] = idx
|
|
1331
|
+
else:
|
|
1332
|
+
sc_schedule.instructions.setdefault(channel_name, []).append(
|
|
1333
|
+
mapped_instructions[channel_name][instr_id]
|
|
1334
|
+
)
|
|
1335
|
+
|
|
1336
|
+
# add the schedules in the playlist
|
|
1337
|
+
|
|
1349
1338
|
# NOTE that there is no implicit right-alignment or equal duration for schedules, unlike in old-style playlists!
|
|
1350
1339
|
for schedule in schedules:
|
|
1351
|
-
if finish_schedules
|
|
1352
|
-
schedule = self._finish_schedule(schedule) # noqa: PLW2901
|
|
1340
|
+
finished_schedule = self._finish_schedule(schedule) if finish_schedules else schedule
|
|
1353
1341
|
sc_schedule = SC_Schedule()
|
|
1354
|
-
for channel_name, segment in
|
|
1342
|
+
for channel_name, segment in finished_schedule.items():
|
|
1355
1343
|
if (channel := channel_descriptions.get(channel_name)) is None:
|
|
1356
|
-
# ignore virtual channels in the schedule
|
|
1357
1344
|
continue
|
|
1358
1345
|
pl.add_channel(channel)
|
|
1346
|
+
prev_wait = None
|
|
1359
1347
|
for instruction in segment:
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
except TypeError:
|
|
1368
|
-
instr_id = instruction.id
|
|
1369
|
-
is_mapped = instr_id in mapped_instructions
|
|
1370
|
-
if is_mapped:
|
|
1371
|
-
sc_schedule.add_to_segment(channel, mapped_instructions[instr_id])
|
|
1348
|
+
# convert all NONSOLID instructions into Waits
|
|
1349
|
+
if finish_schedules and (isinstance(instruction, NONSOLID) or isinstance(instruction, Wait)):
|
|
1350
|
+
if instruction.duration > 0:
|
|
1351
|
+
if prev_wait: # if the previous instruction was a Wait, combine durations
|
|
1352
|
+
prev_wait = Wait(prev_wait.duration + instruction.duration)
|
|
1353
|
+
else:
|
|
1354
|
+
prev_wait = Wait(instruction.duration)
|
|
1372
1355
|
else:
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1356
|
+
if prev_wait: # if there's a prev_wait not yet added to schedule, place it before instruction
|
|
1357
|
+
instructions_to_add = [prev_wait, instruction]
|
|
1358
|
+
prev_wait = None
|
|
1359
|
+
else:
|
|
1360
|
+
instructions_to_add = [instruction]
|
|
1361
|
+
for instr in instructions_to_add:
|
|
1362
|
+
_append_to_schedule(sc_schedule, channel_name, instr)
|
|
1363
|
+
if prev_wait:
|
|
1364
|
+
_append_to_schedule(sc_schedule, channel_name, prev_wait)
|
|
1377
1365
|
pl.segments.append(sc_schedule)
|
|
1378
|
-
|
|
1379
1366
|
return pl
|
|
1380
1367
|
|
|
1381
1368
|
def _set_gate_implementation_shortcut(self, op_name: str) -> None:
|
iqm/pulse/gate_implementation.py
CHANGED
|
@@ -114,7 +114,7 @@ class GateImplementation(abc.ABC):
|
|
|
114
114
|
|
|
115
115
|
def __init__(
|
|
116
116
|
self, parent: QuantumOp, name: str, locus: Locus, calibration_data: OILCalibrationData, builder: ScheduleBuilder
|
|
117
|
-
):
|
|
117
|
+
) -> None:
|
|
118
118
|
self.parent = parent
|
|
119
119
|
self.name = name
|
|
120
120
|
self.locus = locus
|
|
@@ -247,12 +247,12 @@ class GateImplementation(abc.ABC):
|
|
|
247
247
|
return value
|
|
248
248
|
if unit == "s":
|
|
249
249
|
|
|
250
|
-
def conversion(val):
|
|
250
|
+
def conversion(val: Any) -> Any:
|
|
251
251
|
return val / dur if dur > 0 else 0.0
|
|
252
252
|
|
|
253
253
|
elif unit == "Hz":
|
|
254
254
|
|
|
255
|
-
def conversion(val):
|
|
255
|
+
def conversion(val: Any) -> Any:
|
|
256
256
|
return val * dur
|
|
257
257
|
|
|
258
258
|
if isinstance(value, Iterable):
|
|
@@ -303,10 +303,7 @@ class GateImplementation(abc.ABC):
|
|
|
303
303
|
def build_node(path: Iterable[str], dictionary: dict[str, Any]) -> SettingNode:
|
|
304
304
|
node = SettingNode(".".join(path), path=".".join(path))
|
|
305
305
|
for key, value in dictionary.items():
|
|
306
|
-
if "*" in key
|
|
307
|
-
wildcard_keys = [key.replace("*", q) for q in locus]
|
|
308
|
-
else:
|
|
309
|
-
wildcard_keys = [key]
|
|
306
|
+
wildcard_keys = [key.replace("*", q) for q in locus] if "*" in key else [key]
|
|
310
307
|
|
|
311
308
|
for wkey in wildcard_keys:
|
|
312
309
|
new_path = (*tuple(path), wkey)
|
|
@@ -321,7 +318,7 @@ class GateImplementation(abc.ABC):
|
|
|
321
318
|
value.parameter.model_copy(update={"name": name}), value.value, path=name
|
|
322
319
|
)
|
|
323
320
|
else:
|
|
324
|
-
raise
|
|
321
|
+
raise TypeError(f"{wkey}: value {value} is neither a Parameter, Setting nor a dict.")
|
|
325
322
|
return node
|
|
326
323
|
|
|
327
324
|
return build_node(path, cls.parameters)
|
|
@@ -394,7 +391,7 @@ class CustomIQWaveforms(GateImplementation):
|
|
|
394
391
|
|
|
395
392
|
def __init__(
|
|
396
393
|
self, parent: QuantumOp, name: str, locus: Locus, calibration_data: OILCalibrationData, builder: ScheduleBuilder
|
|
397
|
-
):
|
|
394
|
+
) -> None:
|
|
398
395
|
super().__init__(parent, name, locus, calibration_data, builder)
|
|
399
396
|
if getattr(self, "wave_i", None) is None or getattr(self, "wave_q", None) is None:
|
|
400
397
|
raise ValueError(
|
|
@@ -408,7 +405,7 @@ class CustomIQWaveforms(GateImplementation):
|
|
|
408
405
|
wave_i: type[Waveform] | None = None,
|
|
409
406
|
wave_q: type[Waveform] | None = None,
|
|
410
407
|
dependent_waves: bool | None = None,
|
|
411
|
-
):
|
|
408
|
+
) -> None:
|
|
412
409
|
"""Store the Waveform types used by this subclass, and their parameters.
|
|
413
410
|
|
|
414
411
|
NOTE: if ``MyGate`` is a subclass of ``CustomIQWaveforms``, with some defined i and q waves, further
|
|
@@ -579,7 +576,7 @@ class CompositeGate(GateImplementation):
|
|
|
579
576
|
locus: Locus,
|
|
580
577
|
calibration_data: OILCalibrationData,
|
|
581
578
|
builder: ScheduleBuilder,
|
|
582
|
-
):
|
|
579
|
+
) -> None:
|
|
583
580
|
super().__init__(parent, name, locus, calibration_data, builder)
|
|
584
581
|
custom_defaults = {
|
|
585
582
|
op: data.get("default_implementation") for op, data in calibration_data.items() if isinstance(data, dict)
|
|
@@ -596,9 +593,8 @@ class CompositeGate(GateImplementation):
|
|
|
596
593
|
key_is_hashable = True
|
|
597
594
|
except TypeError:
|
|
598
595
|
key_is_hashable = False
|
|
599
|
-
if key_is_hashable:
|
|
600
|
-
|
|
601
|
-
return box
|
|
596
|
+
if key_is_hashable and (box := self.builder.composite_cache.get(self, default_cache_key)):
|
|
597
|
+
return box
|
|
602
598
|
box = self._call(*args, **kwargs)
|
|
603
599
|
if key_is_hashable:
|
|
604
600
|
self.builder.composite_cache.set(self, default_cache_key, box)
|
|
@@ -660,7 +656,7 @@ class CompositeCache:
|
|
|
660
656
|
data.
|
|
661
657
|
"""
|
|
662
658
|
|
|
663
|
-
def __init__(self):
|
|
659
|
+
def __init__(self) -> None:
|
|
664
660
|
self._cache: dict[tuple[Any, ...], TimeBox] = {}
|
|
665
661
|
|
|
666
662
|
def set(
|
iqm/pulse/gates/cz.py
CHANGED
|
@@ -383,8 +383,9 @@ class CouplerFluxPulseQubitACStarkPulseGate(GateImplementation):
|
|
|
383
383
|
"""
|
|
384
384
|
_, phase_increment = phase_transformation(0.0, phase_increment)
|
|
385
385
|
|
|
386
|
-
|
|
387
|
-
|
|
386
|
+
if cls.qubit_drive_wave is not None:
|
|
387
|
+
wave_i = cls.qubit_drive_wave(phase=phase, **kwargs)
|
|
388
|
+
wave_q = cls.qubit_drive_wave(phase=phase - np.pi / 2, **kwargs)
|
|
388
389
|
return IQPulse(
|
|
389
390
|
kwargs["n_samples"],
|
|
390
391
|
wave_i=wave_i,
|
iqm/pulse/gates/measure.py
CHANGED
|
@@ -431,7 +431,7 @@ class Measure_Constant(Measure_CustomWaveforms, wave_i=Constant, wave_q=Constant
|
|
|
431
431
|
"""
|
|
432
432
|
|
|
433
433
|
|
|
434
|
-
class Measure_Constant_Qnd(Measure_CustomWaveforms, wave_i=Constant, wave_q=Constant):
|
|
434
|
+
class Measure_Constant_Qnd(Measure_CustomWaveforms, wave_i=Constant, wave_q=Constant): # type:ignore[call-arg]
|
|
435
435
|
"""Implementation of a single-qubit projective, non quantum demolition, dispersive
|
|
436
436
|
measurements in the Z basis.
|
|
437
437
|
|
|
@@ -824,10 +824,9 @@ class Shelved_Measure_CustomWaveforms(Measure_CustomWaveforms):
|
|
|
824
824
|
# implementation multiplexing. This is because the method has to return time boxes due to the `prx_12` pulses,
|
|
825
825
|
# instead of `MultiplexedProbeTimeBox`
|
|
826
826
|
# TODO: Enable mixed implementation multiplexing for shelved readout
|
|
827
|
-
def probe_timebox(
|
|
827
|
+
def probe_timebox( # type: ignore[override]
|
|
828
828
|
self, key: str = "", feedback_key: str = "", do_acquisition: bool = True, _skip_override: bool = False
|
|
829
829
|
) -> TimeBox:
|
|
830
|
-
# type: ignore[override]
|
|
831
830
|
if _skip_override:
|
|
832
831
|
return super().probe_timebox(key, feedback_key, do_acquisition)
|
|
833
832
|
multiplexed_timeboxes = super().probe_timebox(key, feedback_key)
|
|
@@ -847,7 +846,7 @@ class Shelved_Measure_CustomWaveforms(Measure_CustomWaveforms):
|
|
|
847
846
|
return shelved_measure_box
|
|
848
847
|
|
|
849
848
|
|
|
850
|
-
class Shelved_Measure_Constant(Shelved_Measure_CustomWaveforms, wave_i=Constant, wave_q=Constant):
|
|
849
|
+
class Shelved_Measure_Constant(Shelved_Measure_CustomWaveforms, wave_i=Constant, wave_q=Constant): # type:ignore[call-arg]
|
|
851
850
|
"""Implementation of a shelved readout.
|
|
852
851
|
|
|
853
852
|
A measure gate implemented as a constant waveform is surrounded by two `prx_12` gates.
|
iqm/pulse/gates/prx.py
CHANGED
|
@@ -26,6 +26,7 @@ It rotates the qubit state around an axis that lies in the XY plane of the Bloch
|
|
|
26
26
|
|
|
27
27
|
from __future__ import annotations
|
|
28
28
|
|
|
29
|
+
from abc import abstractmethod
|
|
29
30
|
import copy
|
|
30
31
|
from functools import lru_cache
|
|
31
32
|
from typing import TYPE_CHECKING
|
|
@@ -85,24 +86,25 @@ def get_unitary_prx(angle: float, phase: float) -> np.ndarray:
|
|
|
85
86
|
)
|
|
86
87
|
|
|
87
88
|
|
|
88
|
-
class
|
|
89
|
+
class PrxGateImplementation(GateImplementation):
|
|
89
90
|
"""ABC for different implementations of the PRX gate."""
|
|
90
91
|
|
|
91
92
|
def __init__(
|
|
92
93
|
self, parent: QuantumOp, name: str, locus: Locus, calibration_data: OILCalibrationData, builder: ScheduleBuilder
|
|
93
|
-
):
|
|
94
|
+
) -> None:
|
|
94
95
|
super().__init__(parent, name, locus, calibration_data, builder)
|
|
95
96
|
self._cliffords: dict[XYGate, TimeBox] = {}
|
|
96
97
|
|
|
97
|
-
|
|
98
|
-
|
|
98
|
+
@abstractmethod
|
|
99
|
+
def _call(self, angle: float, phase: float) -> TimeBox:
|
|
100
|
+
"""Phased X rotation gate.
|
|
99
101
|
|
|
100
102
|
Args:
|
|
101
|
-
angle:
|
|
102
|
-
phase:
|
|
103
|
+
angle: Rotation angle in radians.
|
|
104
|
+
phase: Phase angle in radians.
|
|
103
105
|
|
|
104
106
|
Returns:
|
|
105
|
-
|
|
107
|
+
Boxed instruction schedule implementing the phased X rotation gate.
|
|
106
108
|
|
|
107
109
|
"""
|
|
108
110
|
raise NotImplementedError
|
|
@@ -176,8 +178,8 @@ class PRX_GateImplementation(GateImplementation):
|
|
|
176
178
|
return SINGLE_COMPONENTS_WITH_DRIVE_LOCUS_MAPPING
|
|
177
179
|
|
|
178
180
|
|
|
179
|
-
class PRX_SinglePulse_GateImplementation(SinglePulseGate,
|
|
180
|
-
r"""
|
|
181
|
+
class PRX_SinglePulse_GateImplementation(SinglePulseGate, PrxGateImplementation):
|
|
182
|
+
r"""Base class for PRX gates implemented using a single IQ pulse.
|
|
181
183
|
|
|
182
184
|
This class implements phased x rotation gates on a specific qubit using an :class:`.IQPulse`
|
|
183
185
|
instance, derived from the pulse calibration data provided at construction by
|
|
@@ -195,7 +197,7 @@ class PRX_SinglePulse_GateImplementation(SinglePulseGate, PRX_GateImplementation
|
|
|
195
197
|
duration being zero, the gate implementation will apply a ``Block(0)`` instruction to the qubit's drive channel.
|
|
196
198
|
"""
|
|
197
199
|
|
|
198
|
-
def _call(self, angle: float, phase: float = 0.0) -> TimeBox:
|
|
200
|
+
def _call(self, angle: float, phase: float = 0.0) -> TimeBox:
|
|
199
201
|
scale, new_phase = _normalize_params(angle, phase)
|
|
200
202
|
pulse = self.pulse.copy(
|
|
201
203
|
scale_i=scale * self.pulse.scale_i,
|
|
@@ -216,7 +218,7 @@ class PRX_SinglePulse_GateImplementation(SinglePulseGate, PRX_GateImplementation
|
|
|
216
218
|
|
|
217
219
|
|
|
218
220
|
class PRX_CustomWaveforms(PRX_SinglePulse_GateImplementation, CustomIQWaveforms):
|
|
219
|
-
"""
|
|
221
|
+
"""Base class for PRX gates implemented using a single IQ pulse and hot-swappable waveforms."""
|
|
220
222
|
|
|
221
223
|
root_parameters: dict[str, Parameter | Setting] = {
|
|
222
224
|
"duration": Parameter("", "pi pulse duration", "s"),
|
|
@@ -251,14 +253,14 @@ class PRX_CustomWaveforms(PRX_SinglePulse_GateImplementation, CustomIQWaveforms)
|
|
|
251
253
|
)
|
|
252
254
|
|
|
253
255
|
|
|
254
|
-
class PRX_DRAGGaussian(PRX_CustomWaveforms, wave_i=TruncatedGaussian, wave_q=TruncatedGaussianD): # type:
|
|
256
|
+
class PRX_DRAGGaussian(PRX_CustomWaveforms, wave_i=TruncatedGaussian, wave_q=TruncatedGaussianD): # type:ignore[call-arg]
|
|
255
257
|
"""PRX gate, DRAG / TruncatedGaussian IQ pulse implementation.
|
|
256
258
|
|
|
257
259
|
See :class:`.PRX_CustomWaveforms`.
|
|
258
260
|
"""
|
|
259
261
|
|
|
260
262
|
|
|
261
|
-
class PRX_DRAGCosineRiseFall(PRX_CustomWaveforms, wave_i=CosineRiseFall, wave_q=CosineRiseFallD): # type:
|
|
263
|
+
class PRX_DRAGCosineRiseFall(PRX_CustomWaveforms, wave_i=CosineRiseFall, wave_q=CosineRiseFallD): # type:ignore[call-arg]
|
|
262
264
|
"""PRX gate, DRAG / CosineRiseFall IQ pulse implementation.
|
|
263
265
|
|
|
264
266
|
See :class:`.PRX_CustomWaveforms`.
|
|
@@ -273,7 +275,7 @@ class PRX_DRAGCosineRiseFall(PRX_CustomWaveforms, wave_i=CosineRiseFall, wave_q=
|
|
|
273
275
|
|
|
274
276
|
|
|
275
277
|
class PRX_CustomWaveformsSX(PRX_SinglePulse_GateImplementation, CustomIQWaveforms):
|
|
276
|
-
r"""
|
|
278
|
+
r"""Base class for PRX gates implemented using SX gate, hot-swappable waveforms and phase manipulation.
|
|
277
279
|
|
|
278
280
|
The schedule used to implement the PRX gate depends on the arguments:
|
|
279
281
|
1. If the rotation angle :math:`\theta = \pi/2`, the timebox will consist of just the SX IQ pulse, with phase.
|
|
@@ -373,15 +375,14 @@ class PRX_CustomWaveformsSX(PRX_SinglePulse_GateImplementation, CustomIQWaveform
|
|
|
373
375
|
)
|
|
374
376
|
|
|
375
377
|
|
|
376
|
-
class PRX_DRAGGaussianSX(PRX_CustomWaveformsSX, wave_i=TruncatedGaussian, wave_q=TruncatedGaussianD):
|
|
377
|
-
# type: ignore
|
|
378
|
+
class PRX_DRAGGaussianSX(PRX_CustomWaveformsSX, wave_i=TruncatedGaussian, wave_q=TruncatedGaussianD): # type:ignore[call-arg]
|
|
378
379
|
"""PRX gate, DRAG / Gaussian IQ pulse with VZ implementation.
|
|
379
380
|
|
|
380
381
|
See :class:`.PRX_CustomWaveformsVZ`.
|
|
381
382
|
"""
|
|
382
383
|
|
|
383
384
|
|
|
384
|
-
class PRX_DRAGCosineRiseFallSX(PRX_CustomWaveformsSX, wave_i=CosineRiseFall, wave_q=CosineRiseFallD): # type:
|
|
385
|
+
class PRX_DRAGCosineRiseFallSX(PRX_CustomWaveformsSX, wave_i=CosineRiseFall, wave_q=CosineRiseFallD): # type:ignore[call-arg]
|
|
385
386
|
"""PRX gate, DRAG / CosineRiseFall IQ pulse with VZ implementation.
|
|
386
387
|
|
|
387
388
|
See :class:`.PRX_CustomWaveformsVZ`.
|
|
@@ -395,32 +396,28 @@ class PRX_DRAGCosineRiseFallSX(PRX_CustomWaveformsSX, wave_i=CosineRiseFall, wav
|
|
|
395
396
|
return super()._get_pulse(**kwargs)
|
|
396
397
|
|
|
397
398
|
|
|
398
|
-
class PRX_FastDragSX(PRX_CustomWaveformsSX, wave_i=FastDragI, wave_q=FastDragQ):
|
|
399
|
-
# type: ignore
|
|
399
|
+
class PRX_FastDragSX(PRX_CustomWaveformsSX, wave_i=FastDragI, wave_q=FastDragQ): # type:ignore[call-arg]
|
|
400
400
|
"""PRX gate, FAST DRAG IQ pulse with VZ-based SX-implementation.
|
|
401
401
|
|
|
402
402
|
See :class:`.PRX_CustomWaveformsSX`.
|
|
403
403
|
"""
|
|
404
404
|
|
|
405
405
|
|
|
406
|
-
class PRX_FastDrag(PRX_CustomWaveforms, wave_i=FastDragI, wave_q=FastDragQ):
|
|
407
|
-
# type: ignore
|
|
406
|
+
class PRX_FastDrag(PRX_CustomWaveforms, wave_i=FastDragI, wave_q=FastDragQ): # type:ignore[call-arg]
|
|
408
407
|
"""PRX gate, FAST DRAG IQ pulse based on amplitude scaling.
|
|
409
408
|
|
|
410
409
|
See :class:`.PRX_CustomWaveforms`.
|
|
411
410
|
"""
|
|
412
411
|
|
|
413
412
|
|
|
414
|
-
class PRX_HdDragSX(PRX_CustomWaveformsSX, wave_i=HdDragI, wave_q=HdDragQ):
|
|
415
|
-
# type: ignore
|
|
413
|
+
class PRX_HdDragSX(PRX_CustomWaveformsSX, wave_i=HdDragI, wave_q=HdDragQ): # type:ignore[call-arg]
|
|
416
414
|
"""PRX gate, HD DRAG IQ pulse with VZ-based SX-implementation.
|
|
417
415
|
|
|
418
416
|
See :class:`.PRX_CustomWaveformsSX`.
|
|
419
417
|
"""
|
|
420
418
|
|
|
421
419
|
|
|
422
|
-
class PRX_HdDrag(PRX_CustomWaveforms, wave_i=HdDragI, wave_q=HdDragQ):
|
|
423
|
-
# type: ignore
|
|
420
|
+
class PRX_HdDrag(PRX_CustomWaveforms, wave_i=HdDragI, wave_q=HdDragQ): # type:ignore[call-arg]
|
|
424
421
|
"""PRX gate, HD DRAG IQ pulse based on amplitude scaling
|
|
425
422
|
|
|
426
423
|
See :class:`.PRX_CustomWaveforms`.
|
|
@@ -447,8 +444,8 @@ def _normalize_params(angle: float, phase: float) -> tuple[float, float]:
|
|
|
447
444
|
return angle / half_turn, normalize_angle(phase)
|
|
448
445
|
|
|
449
446
|
|
|
450
|
-
class ABC_Constant_smooth(
|
|
451
|
-
r"""
|
|
447
|
+
class ABC_Constant_smooth(PrxGateImplementation):
|
|
448
|
+
r"""Base class for creating gates with an arbitrarily long Constant pulses with smooth rise and fall.
|
|
452
449
|
This pulse creates a :'Segment' consisting of three instructions : [rise_waveform, main_waveform, fall_waveform].
|
|
453
450
|
This class is created so that one can use middle waveform as a constant, thus enabling to use arbitrarily
|
|
454
451
|
long pulses, not limited by the awg memory.
|
|
@@ -617,8 +614,8 @@ class Constant_PRX_with_smooth_rise_fall(
|
|
|
617
614
|
"""
|
|
618
615
|
|
|
619
616
|
|
|
620
|
-
class PRX_ModulatedCustomWaveForms(PRX_CustomWaveforms):
|
|
621
|
-
r"""
|
|
617
|
+
class PRX_ModulatedCustomWaveForms(PRX_CustomWaveforms):
|
|
618
|
+
r"""Base class for PRX gates with modulated frequency, hot-swappable waveforms.
|
|
622
619
|
|
|
623
620
|
The class takes baseband I and Q waveform as input, and modulates them with frequency in the root_parameters.
|
|
624
621
|
The final pulse shape after modulation is:
|
|
@@ -660,7 +657,7 @@ class PRX_ModulatedCustomWaveForms(PRX_CustomWaveforms): # type: ignore
|
|
|
660
657
|
)
|
|
661
658
|
|
|
662
659
|
|
|
663
|
-
class PRX_ModulatedDRAGCosineRiseFall(PRX_ModulatedCustomWaveForms, wave_i=CosineRiseFall, wave_q=CosineRiseFallD):
|
|
660
|
+
class PRX_ModulatedDRAGCosineRiseFall(PRX_ModulatedCustomWaveForms, wave_i=CosineRiseFall, wave_q=CosineRiseFallD): # type:ignore[call-arg]
|
|
664
661
|
"""Modulated PRX pulse with cosine rise fall waveform"""
|
|
665
662
|
|
|
666
663
|
excluded_parameters = ["rise_time"]
|
iqm/pulse/gates/rz.py
CHANGED
|
@@ -218,8 +218,8 @@ class RZ_ACStarkShift(GateImplementation):
|
|
|
218
218
|
"""
|
|
219
219
|
_, phase_increment = phase_transformation(0, phase_increment)
|
|
220
220
|
|
|
221
|
-
wave_i = cls.ac_stark_waveform(n_samples=n_samples, phase=phase, **kwargs)
|
|
222
|
-
wave_q = cls.ac_stark_waveform(n_samples=n_samples, phase=phase - np.pi / 2, **kwargs)
|
|
221
|
+
wave_i = cls.ac_stark_waveform(n_samples=n_samples, phase=phase, **kwargs)
|
|
222
|
+
wave_q = cls.ac_stark_waveform(n_samples=n_samples, phase=phase - np.pi / 2, **kwargs)
|
|
223
223
|
return IQPulse(
|
|
224
224
|
n_samples,
|
|
225
225
|
wave_i=wave_i,
|
|
@@ -236,9 +236,9 @@ class RZ_ACStarkShift_CosineRiseFall(RZ_ACStarkShift, ac_stark_waveform=Modulate
|
|
|
236
236
|
|
|
237
237
|
class RZ_ACStarkShift_smoothConstant(
|
|
238
238
|
Constant_PRX_with_smooth_rise_fall,
|
|
239
|
-
rise_waveform=CosineRise,
|
|
240
|
-
main_waveform=Constant,
|
|
241
|
-
fall_waveform=CosineFall,
|
|
239
|
+
rise_waveform=CosineRise, # type:ignore[call-arg]
|
|
240
|
+
main_waveform=Constant, # type:ignore[call-arg]
|
|
241
|
+
fall_waveform=CosineFall, # type:ignore[call-arg]
|
|
242
242
|
):
|
|
243
243
|
"""Constant AC stark pulse with cosine rise and fall padding.
|
|
244
244
|
Implemented as a 3-instruction Schedule.
|
iqm/pulse/playlist/hd_drag.py
CHANGED
|
@@ -114,11 +114,11 @@ def solve_hd_drag_coefficients_from_suppressed_frequencies(
|
|
|
114
114
|
|
|
115
115
|
"""
|
|
116
116
|
# The beta coefficients can be solved from a matrix equation A*beta = b according to Eq. (B5). Let's build A
|
|
117
|
-
|
|
118
|
-
n_coefs = len(
|
|
117
|
+
suppressed_freqs = np.asarray(suppressed_freq_arr)
|
|
118
|
+
n_coefs = len(suppressed_freqs) + 1
|
|
119
119
|
a_mat = np.zeros((n_coefs, n_coefs))
|
|
120
120
|
a_mat[0, 0] = 1
|
|
121
|
-
a_mat[1:, :] = (-1) ** np.arange(n_coefs)[None] * (pulse_duration *
|
|
121
|
+
a_mat[1:, :] = (-1) ** np.arange(n_coefs)[None] * (pulse_duration * suppressed_freqs[:, None]) ** (
|
|
122
122
|
2 * np.arange(n_coefs)[None]
|
|
123
123
|
)
|
|
124
124
|
b_arr = np.zeros((n_coefs,))
|
|
@@ -22,6 +22,7 @@ import html
|
|
|
22
22
|
import io
|
|
23
23
|
import json
|
|
24
24
|
from pathlib import Path
|
|
25
|
+
from typing import Any
|
|
25
26
|
|
|
26
27
|
from iqm.models.playlist.waveforms import Waveform
|
|
27
28
|
from jinja2 import Environment, FileSystemLoader
|
|
@@ -30,6 +31,29 @@ import numpy as np
|
|
|
30
31
|
from iqm.pulse.playlist.playlist import Playlist
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
def _numpy_to_builtin_types(data: list[tuple[str, Any]]):
|
|
35
|
+
"""Convert selected ``numpy`` types to Python's built-in types.
|
|
36
|
+
|
|
37
|
+
This helper function is to be used for converting dataclasses into
|
|
38
|
+
dictionaries with ``asdict``.
|
|
39
|
+
|
|
40
|
+
For example, ``Playlist`` dataclasses can get converted to dictionaries to
|
|
41
|
+
be rendered as HTML/JavaScript in "playlist inspector". If such classes
|
|
42
|
+
were to contain ``numpy`` types they could not be handled by JavaScript.
|
|
43
|
+
"""
|
|
44
|
+
converted_data = {}
|
|
45
|
+
|
|
46
|
+
for key, value in data:
|
|
47
|
+
if isinstance(value, np.float64):
|
|
48
|
+
converted_data[key] = float(value)
|
|
49
|
+
elif isinstance(value, np.ndarray):
|
|
50
|
+
converted_data[key] = value.tolist()
|
|
51
|
+
else:
|
|
52
|
+
converted_data[key] = value
|
|
53
|
+
|
|
54
|
+
return converted_data
|
|
55
|
+
|
|
56
|
+
|
|
33
57
|
def _get_waveform(wave: Waveform, scale: float, wave_q: Waveform | None = None, scale_q: float | None = None) -> str:
|
|
34
58
|
import matplotlib.pyplot as plt
|
|
35
59
|
|
|
@@ -74,7 +98,7 @@ def _playlist_as_a_dict(playlist: Playlist, segment_indices: Sequence[int]) -> d
|
|
|
74
98
|
instruction = channel_desc.instruction_table[instruction_idx]
|
|
75
99
|
instruction_dict = {}
|
|
76
100
|
instruction_dict["name"] = instruction.operation.__class__.__name__
|
|
77
|
-
params = asdict(instruction.operation)
|
|
101
|
+
params = asdict(instruction.operation, dict_factory=_numpy_to_builtin_types)
|
|
78
102
|
if instruction.operation.__class__.__name__ == "RealPulse":
|
|
79
103
|
instruction_dict["wave_img_idx"] = instruction_idx
|
|
80
104
|
if str(instruction_idx) not in waveform_dict[channel]:
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
var fullscreen_state = false;
|
|
120
120
|
|
|
121
121
|
// The schedules to render
|
|
122
|
-
var schedules = {{jsonobj.playlists
|
|
122
|
+
var schedules = {{jsonobj.playlists}}
|
|
123
123
|
var waveforms = {{jsonobj.waveforms}}
|
|
124
124
|
var segment_indices = {{segment_indices}}
|
|
125
125
|
|
iqm/pulse/scheduler.py
CHANGED
|
@@ -266,8 +266,8 @@ def extend_schedule_new( # noqa: PLR0915
|
|
|
266
266
|
_ = channels[ch].duration_to_int_samples(duration, message=f"{ch}: {iA} + {iB}: overlap duration")
|
|
267
267
|
|
|
268
268
|
if isinstance(iA, Nothing) and isinstance(iB, Nothing):
|
|
269
|
-
return Nothing(duration=duration)
|
|
270
|
-
return Block(duration=duration)
|
|
269
|
+
return Nothing(duration=duration)
|
|
270
|
+
return Block(duration=duration)
|
|
271
271
|
|
|
272
272
|
def find_start_time() -> float:
|
|
273
273
|
"""Find the earliest possible start time for schedule B."""
|
|
@@ -297,7 +297,7 @@ def extend_schedule_new( # noqa: PLR0915
|
|
|
297
297
|
if distance >= -TOL:
|
|
298
298
|
if distance > TOL:
|
|
299
299
|
# gap, add a Nothing between A and B
|
|
300
|
-
segment_A._instructions.append(Nothing(duration=distance))
|
|
300
|
+
segment_A._instructions.append(Nothing(duration=distance))
|
|
301
301
|
# add B
|
|
302
302
|
segment_A._instructions.extend(pointer_B.tail())
|
|
303
303
|
else:
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
iqm/pulse/__init__.py,sha256=FxgHlv3bF8bQCREwOJ1yu_nsrfJq0g0HdovvT1wUnCI,881
|
|
2
2
|
iqm/pulse/base_utils.py,sha256=tLbmnWGmHsjcA8QFCiqvHfgSJJNWS4AVTcD2y4M2ipU,2641
|
|
3
|
-
iqm/pulse/builder.py,sha256=
|
|
3
|
+
iqm/pulse/builder.py,sha256=34y0-5CF4Izo4s7BsVYXOVePuf5SomxZiMdM7Je59PY,66940
|
|
4
4
|
iqm/pulse/circuit_operations.py,sha256=LhOcgSXVYUr6-JzI38uy3r14Bnra9Yu-Zlubg2l_MUA,22665
|
|
5
|
-
iqm/pulse/gate_implementation.py,sha256=
|
|
5
|
+
iqm/pulse/gate_implementation.py,sha256=1sJ6Vy4DcQBswY5WUOkHKbIkMS3NSCEhovxG9QsdkU4,33898
|
|
6
6
|
iqm/pulse/quantum_ops.py,sha256=VxWOV_XD61JjQl0ugKhgY0TSOhg3CRwcrpLvpzIAcIQ,14732
|
|
7
|
-
iqm/pulse/scheduler.py,sha256=
|
|
7
|
+
iqm/pulse/scheduler.py,sha256=Y5WL8TwAEzoSnboie8scv9skC5YBmdXKAJ4KTnYn0xU,22690
|
|
8
8
|
iqm/pulse/timebox.py,sha256=w3R6VafBXx_cGWrcvI_6x1e6JII_9v1vxQoRSGIjtXE,16591
|
|
9
9
|
iqm/pulse/utils.py,sha256=HyTkMD0er_rZnvDZWM1WscOFxaxGMyRAW_Aw36b0Hdc,7998
|
|
10
10
|
iqm/pulse/validation.py,sha256=-tZWrW201t4nbTQWeZ8M9DixzoN8B0Q63IP57BfDAz0,10733
|
|
11
11
|
iqm/pulse/gates/__init__.py,sha256=UI6kx0MrXw4Fqz8OFkVo8rZirNbSfT1dlWpnnG8ELwQ,12986
|
|
12
12
|
iqm/pulse/gates/barrier.py,sha256=WhYV70lf4lh4Wa9UZuMk2lp9JbUQIu8lzewRC2P7pNE,2546
|
|
13
13
|
iqm/pulse/gates/conditional.py,sha256=3tW5kVt2M2xaTJxaixTErU5DTe91F0uE9BN9kopBEkQ,6242
|
|
14
|
-
iqm/pulse/gates/cz.py,sha256=
|
|
14
|
+
iqm/pulse/gates/cz.py,sha256=HAKdR7puauiOIPikW5proQXf_oWauivrPuX1e632h9k,20162
|
|
15
15
|
iqm/pulse/gates/default_gates.py,sha256=choy57ODXqXvpqY7rFMsZDHqxbDaIosu5Zy70sVbRL8,9516
|
|
16
16
|
iqm/pulse/gates/delay.py,sha256=nST9dY2JFp_mpKhiSfsYa5yL4hFKcNJSAyCzXjhauQg,3767
|
|
17
17
|
iqm/pulse/gates/enums.py,sha256=ATwb6vZYpfgQ1gQyFPW53JyIKrdAP3FPHm6jV-t9OAk,2532
|
|
18
18
|
iqm/pulse/gates/flux_multiplexer.py,sha256=5psam8_3z796z2nL-A2RKzDGTRDE-7GJ4F0aYCgaPUY,9691
|
|
19
|
-
iqm/pulse/gates/measure.py,sha256=
|
|
19
|
+
iqm/pulse/gates/measure.py,sha256=sLr3j7P4C1VAODuUZRWg5tDkPjI0CGFBtQ_mendAHbA,43935
|
|
20
20
|
iqm/pulse/gates/move.py,sha256=yKY-Et4YJV0KmcDwN0yE3oHgDtLL-Xfgy1G_InsJN0U,17182
|
|
21
|
-
iqm/pulse/gates/prx.py,sha256=
|
|
21
|
+
iqm/pulse/gates/prx.py,sha256=yd87JbHU1y40EOzgA1m4m-y8BX6XkHij_uw7o0t-B1s,24596
|
|
22
22
|
iqm/pulse/gates/reset.py,sha256=vYbzaA0pg3r5Oh6Edpu6NPlYoq1M7_tEWnf-7SHig4o,7589
|
|
23
|
-
iqm/pulse/gates/rz.py,sha256=
|
|
23
|
+
iqm/pulse/gates/rz.py,sha256=GWOlaHITJojQruu4R8-jIBez0OgFg4olarZkkxIRwRg,9459
|
|
24
24
|
iqm/pulse/gates/sx.py,sha256=V8e94LHRLkXLjSSeuKxZQbhwgGDAWdQxsfhbYi4gtp8,1673
|
|
25
25
|
iqm/pulse/gates/u.py,sha256=2kmbTYprrkVP4EbwGXNZcT5lzInjjOAvq8vk0lw57YY,5256
|
|
26
26
|
iqm/pulse/playlist/__init__.py,sha256=XW-7Po_vCzhkk1Js06K8P-5srPpBuPHkqpc1yhL_Zx4,997
|
|
27
27
|
iqm/pulse/playlist/channel.py,sha256=RAkGyjTU66MiF-ccf06FFZAXpUykWEltbfNXw4xJpYc,17164
|
|
28
28
|
iqm/pulse/playlist/fast_drag.py,sha256=80Knv0Q9IaGiVdc0TrHlxNi1zJtTUZvWIVO38reYcA0,19600
|
|
29
|
-
iqm/pulse/playlist/hd_drag.py,sha256=
|
|
29
|
+
iqm/pulse/playlist/hd_drag.py,sha256=JYRy3aPu0LD9y0H3UncOiWI39eV9-TARvgLonNUsaO0,13562
|
|
30
30
|
iqm/pulse/playlist/instructions.py,sha256=K4c8TwC9FBbD_kdPD2OpjG1OZsDJALlwJon4SD9etk8,9845
|
|
31
31
|
iqm/pulse/playlist/playlist.py,sha256=7MIX4iRfh2Nit8AnpNyqv5A5ZmK7JR-v201DXVL6kUk,685
|
|
32
32
|
iqm/pulse/playlist/schedule.py,sha256=VYrVyPlB04Rm8iOYBXu2uOpsLBqczJRx3L2VU53CxVU,17989
|
|
33
33
|
iqm/pulse/playlist/waveforms.py,sha256=Xa7P3V0rRIn7sQIoLKqXaWwtAbyQWjdVGW6bKOGNcOQ,17898
|
|
34
34
|
iqm/pulse/playlist/visualisation/__init__.py,sha256=wCNfJHIR_bqG3ZBlgm55v90Rih7VCpfctoIMfwRMgjk,567
|
|
35
|
-
iqm/pulse/playlist/visualisation/base.py,sha256=
|
|
36
|
-
iqm/pulse/playlist/visualisation/templates/playlist_inspection.jinja2,sha256=
|
|
35
|
+
iqm/pulse/playlist/visualisation/base.py,sha256=5RkwfZw-5bMVsZSTx6gbw1DAEz2B9HA5kuAKuzUQoME,8734
|
|
36
|
+
iqm/pulse/playlist/visualisation/templates/playlist_inspection.jinja2,sha256=4XPmpISH5LLOf3YjmK3OKfvkAWj4TlzD2K4ClFTvZhI,11511
|
|
37
37
|
iqm/pulse/playlist/visualisation/templates/static/logo.png,sha256=rbfQZ6_UEaztpY2uoYBuVypEwQVQTFB61oHzDzNRFJ0,94565
|
|
38
38
|
iqm/pulse/playlist/visualisation/templates/static/moment.min.js,sha256=4iQZ6BVL4qNKlQ27TExEhBN1HFPvAvAMbFavKKosSWQ,53324
|
|
39
39
|
iqm/pulse/playlist/visualisation/templates/static/vis-timeline-graph2d.min.css,sha256=svzNasPg1yR5gvEaRei2jg-n4Pc3sVyMUWeS6xRAh6U,19837
|
|
40
40
|
iqm/pulse/playlist/visualisation/templates/static/vis-timeline-graph2d.min.js,sha256=OqCqCyA6JnxPz3PGXq_P_9VuSqWptgNt5Ev3T-xjefQ,570288
|
|
41
|
-
iqm_pulse-9.
|
|
42
|
-
iqm_pulse-9.
|
|
43
|
-
iqm_pulse-9.
|
|
44
|
-
iqm_pulse-9.
|
|
45
|
-
iqm_pulse-9.
|
|
41
|
+
iqm_pulse-9.17.0.dist-info/LICENSE.txt,sha256=R6Q7eUrLyoCQgWYorQ8WJmVmWKYU3dxA3jYUp0wwQAw,11332
|
|
42
|
+
iqm_pulse-9.17.0.dist-info/METADATA,sha256=1PDOhj5fzQhuYt0aZaxhzyKBGHBVlOQXCNghiRUJMZw,14524
|
|
43
|
+
iqm_pulse-9.17.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
|
44
|
+
iqm_pulse-9.17.0.dist-info/top_level.txt,sha256=NB4XRfyDS6_wG9gMsyX-9LTU7kWnTQxNvkbzIxGv3-c,4
|
|
45
|
+
iqm_pulse-9.17.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|