iqm-pulse 9.14.0__tar.gz → 9.16.0__tar.gz

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.
Files changed (81) hide show
  1. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/CHANGELOG.rst +16 -0
  2. {iqm_pulse-9.14.0/src/iqm_pulse.egg-info → iqm_pulse-9.16.0}/PKG-INFO +1 -1
  3. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/builder.py +7 -6
  4. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gate_implementation.py +11 -15
  5. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/cz.py +3 -2
  6. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/measure.py +3 -4
  7. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/prx.py +27 -30
  8. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/rz.py +5 -5
  9. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/hd_drag.py +3 -3
  10. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/base.py +25 -1
  11. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/templates/playlist_inspection.jinja2 +1 -1
  12. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/scheduler.py +3 -3
  13. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0/src/iqm_pulse.egg-info}/PKG-INFO +1 -1
  14. iqm_pulse-9.16.0/version.txt +1 -0
  15. iqm_pulse-9.14.0/version.txt +0 -1
  16. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/LICENSE.txt +0 -0
  17. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/MANIFEST.in +0 -0
  18. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/README.rst +0 -0
  19. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/API.rst +0 -0
  20. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/Makefile +0 -0
  21. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/.gitignore +0 -0
  22. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/css/custom.css +0 -0
  23. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/images/favicon.ico +0 -0
  24. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/images/feedback_timing.svg +0 -0
  25. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/images/logo.png +0 -0
  26. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/images/playlist_breakdown.svg +0 -0
  27. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/images/pulse_timing.svg +0 -0
  28. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_static/images/readout_timing.svg +0 -0
  29. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_templates/autosummary-class-template.rst +0 -0
  30. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/_templates/autosummary-module-template.rst +0 -0
  31. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/changelog.rst +0 -0
  32. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/concepts.rst +0 -0
  33. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/conf.py +0 -0
  34. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/custom_gates.rst +0 -0
  35. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/index.rst +0 -0
  36. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/license.rst +0 -0
  37. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/pulse_timing.rst +0 -0
  38. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/references.bib +0 -0
  39. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/references.rst +0 -0
  40. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/docs/using_builder.rst +0 -0
  41. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/pyproject.toml +0 -0
  42. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/requirements/base.in +0 -0
  43. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/requirements/base.txt +0 -0
  44. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/setup.cfg +0 -0
  45. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/setup.py +0 -0
  46. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/__init__.py +0 -0
  47. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/base_utils.py +0 -0
  48. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/circuit_operations.py +0 -0
  49. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/__init__.py +0 -0
  50. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/barrier.py +0 -0
  51. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/conditional.py +0 -0
  52. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/default_gates.py +0 -0
  53. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/delay.py +0 -0
  54. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/enums.py +0 -0
  55. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/flux_multiplexer.py +0 -0
  56. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/move.py +0 -0
  57. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/reset.py +0 -0
  58. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/sx.py +0 -0
  59. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/gates/u.py +0 -0
  60. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/__init__.py +0 -0
  61. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/channel.py +0 -0
  62. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/fast_drag.py +0 -0
  63. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/instructions.py +0 -0
  64. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/playlist.py +0 -0
  65. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/schedule.py +0 -0
  66. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/__init__.py +0 -0
  67. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/templates/static/logo.png +0 -0
  68. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/templates/static/moment.min.js +0 -0
  69. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/templates/static/vis-timeline-graph2d.min.css +0 -0
  70. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/visualisation/templates/static/vis-timeline-graph2d.min.js +0 -0
  71. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/playlist/waveforms.py +0 -0
  72. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/quantum_ops.py +0 -0
  73. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/timebox.py +0 -0
  74. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/utils.py +0 -0
  75. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm/pulse/validation.py +0 -0
  76. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm_pulse.egg-info/SOURCES.txt +0 -0
  77. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm_pulse.egg-info/dependency_links.txt +0 -0
  78. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm_pulse.egg-info/requires.txt +0 -0
  79. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/src/iqm_pulse.egg-info/top_level.txt +0 -0
  80. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/tests/.pylintrc +0 -0
  81. {iqm_pulse-9.14.0 → iqm_pulse-9.16.0}/tests/__init__.py +0 -0
@@ -2,6 +2,22 @@
2
2
  Changelog
3
3
  =========
4
4
 
5
+ Version 9.16.0 (2025-07-01)
6
+ ===========================
7
+
8
+ Bug fixes
9
+ ---------
10
+
11
+ - Fix type errors raised by mypy.
12
+
13
+ Version 9.15.0 (2025-06-17)
14
+ ===========================
15
+
16
+ Bug fixes
17
+ ---------
18
+
19
+ - Convert ``numpy`` types to Python's built-in types so that playlist inspector HTML is rendered correctly. :mr:`1086`
20
+
5
21
  Version 9.14.0 (2025-06-13)
6
22
  ===========================
7
23
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-pulse
3
- Version: 9.14.0
3
+ Version: 9.16.0
4
4
  Summary: A Python-based project for providing interface and implementations for control pulses.
5
5
  Author-email: IQM Finland Oy <info@meetiqm.com>
6
6
  License: Apache License
@@ -758,8 +758,8 @@ class ScheduleBuilder:
758
758
  if priority_calibration:
759
759
  if op.name in priority_calibration:
760
760
  # 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, {}) # type: ignore
761
+ op_data = priority_calibration.get(op.name, {})
762
+ prio_data = op_data.get(new_impl_name, {}).get(new_locus, {})
763
763
  else:
764
764
  # if not assume just the data for this locus was given
765
765
  prio_data = priority_calibration
@@ -1116,10 +1116,11 @@ class ScheduleBuilder:
1116
1116
  ):
1117
1117
  # convert the locus durations to seconds (no probe channels have been used so far)
1118
1118
  scheduling_in_seconds = True
1119
- component_durations_seconds = {
1120
- component: self._channel_templates["other"].duration_to_seconds(duration) # type: ignore
1121
- for component, duration in component_durations.items()
1122
- }
1119
+ if self._channel_templates["other"] is not None:
1120
+ component_durations_seconds = {
1121
+ component: self._channel_templates["other"].duration_to_seconds(duration)
1122
+ for component, duration in component_durations.items()
1123
+ }
1123
1124
 
1124
1125
  child_components = self._get_neighborhood_hard_boundary(child, 0)
1125
1126
  neighborhood_components = self._get_neighborhood_hard_boundary(child, neighborhood)
@@ -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 ValueError(f"{wkey}: value {value} is neither a Parameter, Setting nor a dict.")
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
- if box := self.builder.composite_cache.get(self, default_cache_key):
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(
@@ -383,8 +383,9 @@ class CouplerFluxPulseQubitACStarkPulseGate(GateImplementation):
383
383
  """
384
384
  _, phase_increment = phase_transformation(0.0, phase_increment)
385
385
 
386
- wave_i = cls.qubit_drive_wave(phase=phase, **kwargs) # type: ignore
387
- wave_q = cls.qubit_drive_wave(phase=phase - np.pi / 2, **kwargs) # type: ignore
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,
@@ -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.
@@ -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 PRX_GateImplementation(GateImplementation):
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
- def _call(self, angle: float, phase: float = 0.0) -> TimeBox: # type: ignore[override]
98
- """Phased x rotation gate.
98
+ @abstractmethod
99
+ def _call(self, angle: float, phase: float) -> TimeBox:
100
+ """Phased X rotation gate.
99
101
 
100
102
  Args:
101
- angle: rotation angle (in radians)
102
- phase: phase angle (in radians)
103
+ angle: Rotation angle in radians.
104
+ phase: Phase angle in radians.
103
105
 
104
106
  Returns:
105
- boxed instruction schedule implementing the phased x rotation gate
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, PRX_GateImplementation):
180
- r"""ABC for PRX gates implemented using a single IQ pulse.
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: # type: ignore[override]
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
- """ABC for PRX gates implemented using a single IQ pulse and hot-swappable waveforms."""
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: ignore
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: ignore
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"""ABC for PRX gates implemented using SX gate, hot-swappable waveforms and phase manipulation.
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: ignore
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(PRX_GateImplementation):
451
- r"""ABC class for creating gates with an arbitrarily long Constant pulses with smooth rise and fall.
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): # type: ignore
621
- r"""ABC for PRX gates with modulated frequency, hot-swappable waveforms.
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"]
@@ -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) # type: ignore
222
- wave_q = cls.ac_stark_waveform(n_samples=n_samples, phase=phase - np.pi / 2, **kwargs) # type: ignore
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.
@@ -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
- suppressed_freq_arr = np.asarray(suppressed_freq_arr)
118
- n_coefs = len(suppressed_freq_arr) + 1
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 * suppressed_freq_arr[:, None]) ** (
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 | replace("array", "Array")}}
122
+ var schedules = {{jsonobj.playlists}}
123
123
  var waveforms = {{jsonobj.waveforms}}
124
124
  var segment_indices = {{segment_indices}}
125
125
 
@@ -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) # type: ignore
270
- return Block(duration=duration) # type: ignore
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)) # type: ignore
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iqm-pulse
3
- Version: 9.14.0
3
+ Version: 9.16.0
4
4
  Summary: A Python-based project for providing interface and implementations for control pulses.
5
5
  Author-email: IQM Finland Oy <info@meetiqm.com>
6
6
  License: Apache License
@@ -0,0 +1 @@
1
+ 9.16.0
@@ -1 +0,0 @@
1
- 9.14.0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes