iqm-pulse 10.1.0__tar.gz → 10.3.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.
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/CHANGELOG.rst +17 -0
- {iqm_pulse-10.1.0/src/iqm_pulse.egg-info → iqm_pulse-10.3.0}/PKG-INFO +1 -1
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/builder.py +1 -1
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/__init__.py +2 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/cz.py +308 -5
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/move.py +2 -2
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/waveforms.py +92 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0/src/iqm_pulse.egg-info}/PKG-INFO +1 -1
- iqm_pulse-10.3.0/version.txt +1 -0
- iqm_pulse-10.1.0/version.txt +0 -1
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/LICENSE.txt +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/MANIFEST.in +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/README.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/API.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/Makefile +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/.gitignore +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/css/custom.css +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/images/favicon.ico +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/images/feedback_timing.svg +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/images/logo.png +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/images/playlist_breakdown.svg +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/images/pulse_timing.svg +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_static/images/readout_timing.svg +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_templates/autosummary-class-template.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/_templates/autosummary-module-template.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/changelog.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/concepts.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/conf.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/custom_gates.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/index.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/license.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/pulse_timing.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/references.bib +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/references.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/docs/using_builder.rst +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/pyproject.toml +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/requirements/base.in +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/requirements/base.txt +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/setup.cfg +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/setup.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/__init__.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/base_utils.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/circuit_operations.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gate_implementation.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/barrier.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/conditional.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/default_gates.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/delay.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/enums.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/flux_multiplexer.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/measure.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/prx.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/reset.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/rz.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/sx.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/gates/u.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/__init__.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/channel.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/fast_drag.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/hd_drag.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/instructions.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/playlist.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/schedule.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/__init__.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/base.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/templates/playlist_inspection.jinja2 +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/templates/static/logo.png +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/templates/static/moment.min.js +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/templates/static/vis-timeline-graph2d.min.css +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/templates/static/vis-timeline-graph2d.min.js +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/py.typed +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/quantum_ops.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/scheduler.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/timebox.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/utils.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/validation.py +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm_pulse.egg-info/SOURCES.txt +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm_pulse.egg-info/dependency_links.txt +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm_pulse.egg-info/requires.txt +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm_pulse.egg-info/top_level.txt +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/tests/.pylintrc +0 -0
- {iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/tests/__init__.py +0 -0
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
Changelog
|
|
3
3
|
=========
|
|
4
4
|
|
|
5
|
+
Version 10.3.0 (2025-08-11)
|
|
6
|
+
===========================
|
|
7
|
+
|
|
8
|
+
Feature
|
|
9
|
+
-------
|
|
10
|
+
|
|
11
|
+
- Added ``FluxPulse_SmoothConstant_SmoothConstant `` which automatically splits pulses into three parts: rise, Constant, and fall.
|
|
12
|
+
- Changed Flux pulse argument ``parameter`` type to remove ignores all over the code.
|
|
13
|
+
|
|
14
|
+
Version 10.2.0 (2025-08-08)
|
|
15
|
+
===========================
|
|
16
|
+
|
|
17
|
+
Features
|
|
18
|
+
--------
|
|
19
|
+
|
|
20
|
+
- Modifies typing of CircuitOperation to use Locus directly. No other functional changes.
|
|
21
|
+
|
|
5
22
|
Version 10.1.0 (2025-07-18)
|
|
6
23
|
===========================
|
|
7
24
|
|
|
@@ -83,7 +83,7 @@ class CircuitOperation:
|
|
|
83
83
|
|
|
84
84
|
name: str
|
|
85
85
|
"""name of the quantum operation"""
|
|
86
|
-
locus:
|
|
86
|
+
locus: Locus
|
|
87
87
|
"""names of the information-bearing QPU components (qubits, computational resonators...) the operation acts on"""
|
|
88
88
|
args: dict[str, Any] = field(default_factory=dict)
|
|
89
89
|
"""arguments for the operation"""
|
|
@@ -42,6 +42,7 @@ from iqm.pulse.gates.cz import (
|
|
|
42
42
|
CZ_Slepian_ACStarkCRF,
|
|
43
43
|
CZ_Slepian_CRF,
|
|
44
44
|
CZ_TruncatedGaussianSmoothedSquare,
|
|
45
|
+
FluxPulse_SmoothConstant_SmoothConstant,
|
|
45
46
|
FluxPulseGate_CRF_CRF,
|
|
46
47
|
FluxPulseGate_TGSS_CRF,
|
|
47
48
|
)
|
|
@@ -98,6 +99,7 @@ _exposed_implementations: dict[str, type[GateImplementation]] = {
|
|
|
98
99
|
CZ_Slepian,
|
|
99
100
|
CZ_Slepian_CRF,
|
|
100
101
|
CZ_CRF,
|
|
102
|
+
FluxPulse_SmoothConstant_SmoothConstant,
|
|
101
103
|
CZ_TruncatedGaussianSmoothedSquare,
|
|
102
104
|
FluxPulseGate_TGSS_CRF,
|
|
103
105
|
FluxPulseGate_CRF_CRF,
|
|
@@ -22,6 +22,7 @@ It can be represented by the unitary matrix
|
|
|
22
22
|
from __future__ import annotations
|
|
23
23
|
|
|
24
24
|
from dataclasses import replace
|
|
25
|
+
import logging
|
|
25
26
|
from typing import TYPE_CHECKING
|
|
26
27
|
|
|
27
28
|
import numpy as np
|
|
@@ -32,14 +33,16 @@ from iqm.pulse.gate_implementation import GateImplementation, Locus, OILCalibrat
|
|
|
32
33
|
from iqm.pulse.playlist.instructions import Block, FluxPulse, Instruction, IQPulse, VirtualRZ
|
|
33
34
|
from iqm.pulse.playlist.schedule import Schedule
|
|
34
35
|
from iqm.pulse.playlist.waveforms import (
|
|
36
|
+
Constant,
|
|
37
|
+
CosineFallFlex,
|
|
35
38
|
CosineRiseFall,
|
|
39
|
+
CosineRiseFlex,
|
|
36
40
|
GaussianSmoothedSquare,
|
|
37
41
|
ModulatedCosineRiseFall,
|
|
38
42
|
Slepian,
|
|
39
43
|
TruncatedGaussianSmoothedSquare,
|
|
40
44
|
Waveform,
|
|
41
45
|
)
|
|
42
|
-
from iqm.pulse.timebox import TimeBox
|
|
43
46
|
from iqm.pulse.utils import phase_transformation
|
|
44
47
|
|
|
45
48
|
if TYPE_CHECKING: # pragma: no cover
|
|
@@ -79,9 +82,9 @@ class FluxPulseGate(GateImplementation):
|
|
|
79
82
|
"""Flux pulse Waveform to be played in the coupler flux AWG."""
|
|
80
83
|
qubit_wave: type[Waveform] | None
|
|
81
84
|
"""Flux pulse Waveform to be played in the qubit flux AWG."""
|
|
82
|
-
root_parameters: dict[str, Parameter | Setting] = {
|
|
85
|
+
root_parameters: dict[str, Parameter | Setting | dict] = {
|
|
83
86
|
"duration": Parameter("", "Gate duration", "s"),
|
|
84
|
-
"rz": {
|
|
87
|
+
"rz": {
|
|
85
88
|
"*": Parameter("", "Z rotation angle", "rad"), # wildcard parameter
|
|
86
89
|
},
|
|
87
90
|
}
|
|
@@ -261,9 +264,9 @@ class CouplerFluxPulseQubitACStarkPulseGate(GateImplementation):
|
|
|
261
264
|
qubit_drive_wave: type[Waveform] | None
|
|
262
265
|
"""Qubit drive pulse waveform to be played in the qubit drive AWG."""
|
|
263
266
|
|
|
264
|
-
root_parameters: dict[str, Parameter | Setting] = {
|
|
267
|
+
root_parameters: dict[str, Parameter | Setting | dict] = {
|
|
265
268
|
"duration": Parameter("", "Gate duration", "s"),
|
|
266
|
-
"rz": {
|
|
269
|
+
"rz": {
|
|
267
270
|
"*": Parameter("", "Z rotation angle", "rad"),
|
|
268
271
|
},
|
|
269
272
|
}
|
|
@@ -426,3 +429,303 @@ class CZ_CRF_ACStarkCRF(
|
|
|
426
429
|
CZ gate implemented using a cosine rise fall flux pulse for the coupler and a modulated
|
|
427
430
|
cosine rise fall (CRF) AC Stark pulse on one qubit.
|
|
428
431
|
"""
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def round_to_granularity(value: float, granularity: float, precision: float = 1e-15) -> float:
|
|
435
|
+
"""Round a value to the nearest multiple of granularity.
|
|
436
|
+
If the value is within a given precision of a multiple, round to that multiple.
|
|
437
|
+
Otherwise, round down to the nearest lower multiple.
|
|
438
|
+
|
|
439
|
+
Args:
|
|
440
|
+
value:
|
|
441
|
+
granularity: granularity
|
|
442
|
+
precision: rounding precision.
|
|
443
|
+
|
|
444
|
+
Returns:
|
|
445
|
+
value rounded to a granularity.
|
|
446
|
+
|
|
447
|
+
"""
|
|
448
|
+
return np.floor(value / granularity + precision) * granularity
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def split_flat_top_part_into_granular_parts(
|
|
452
|
+
duration: float, full_width: float, rise_time: float, granularity: float, precision: float = 1e-10
|
|
453
|
+
) -> tuple[float, float, float, float]:
|
|
454
|
+
"""To save waveform memory, a (long) flat-top pulse, which is defined by its duration, full_width and rise_time,
|
|
455
|
+
is divided into three consecutive parts (rise, flat, and fall),
|
|
456
|
+
all of which conform to the granularity of the device.
|
|
457
|
+
|
|
458
|
+
Args:
|
|
459
|
+
duration: pulse duration in seconds.
|
|
460
|
+
full_width: full width of the pulse.
|
|
461
|
+
rise_time: rise time of the pulse.
|
|
462
|
+
granularity: minimum allowed pulse duration.
|
|
463
|
+
precision: precision of rounding to granularity,
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
A tuple containing:
|
|
468
|
+
- flat part duration
|
|
469
|
+
- rise (or fall) part duration
|
|
470
|
+
- rise time
|
|
471
|
+
- flat part's non-granular leftover, which is transferred to the rise and fall parts
|
|
472
|
+
|
|
473
|
+
Raises:
|
|
474
|
+
ValueError: Error is raised if duration is not a multiple of granularity.
|
|
475
|
+
ValueError: Error is raised if pulse parameters do not obey duration >= full_width >= 2*rise_time.
|
|
476
|
+
|
|
477
|
+
"""
|
|
478
|
+
# Check if the number of samples is within 0.005 samples of an integer number, considered safe.
|
|
479
|
+
if not round(duration / granularity, ndigits=2).is_integer():
|
|
480
|
+
raise ValueError("Duration must be a multiple of granularity.")
|
|
481
|
+
|
|
482
|
+
if (duration >= full_width) & (full_width >= 2 * rise_time):
|
|
483
|
+
plateau_width = full_width - 2 * rise_time
|
|
484
|
+
|
|
485
|
+
plateau_width_granular = round_to_granularity(plateau_width, granularity)
|
|
486
|
+
rise_duration = (duration - plateau_width_granular) / 2
|
|
487
|
+
|
|
488
|
+
if np.abs(rise_duration - np.round(rise_duration / granularity) * granularity) > precision:
|
|
489
|
+
plateau_width_granular -= granularity
|
|
490
|
+
rise_duration = (duration - plateau_width_granular) / 2
|
|
491
|
+
|
|
492
|
+
flat_part = duration - 2 * rise_duration
|
|
493
|
+
plateau_leftover = (full_width - 2 * rise_time - flat_part) / 2
|
|
494
|
+
|
|
495
|
+
return plateau_width_granular, rise_duration, rise_time, plateau_leftover
|
|
496
|
+
else:
|
|
497
|
+
raise ValueError(
|
|
498
|
+
f"Current pulse parameters (duration {duration}, full_width {full_width}, rise_time {rise_time}) "
|
|
499
|
+
f"are impossible, please use duration >= full_width >= 2*rise_time."
|
|
500
|
+
)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
class FluxPulseGate_SmoothConstant(FluxPulseGate):
|
|
504
|
+
"""Flux pulse gate implementation realized as a 3-part pulse sequence,
|
|
505
|
+
consisting of |cosine rise|Constant|cosine fall|. Otherwise, works similar to FluxPulseGate.
|
|
506
|
+
|
|
507
|
+
Args:
|
|
508
|
+
flux_pulses: mapping from flux channel name to its flux pulse
|
|
509
|
+
rz: mapping from drive channel name to the virtual z rotation angle, in radians, that should be performed on it
|
|
510
|
+
|
|
511
|
+
"""
|
|
512
|
+
|
|
513
|
+
coupler_wave: Constant | None
|
|
514
|
+
"""Flux pulse Waveform to be played in the coupler flux AWG. Can be only Constant or None"""
|
|
515
|
+
qubit_wave: Constant | None
|
|
516
|
+
"""Flux pulse Waveform to be played in the qubit flux AWG. Can be only Constant or None"""
|
|
517
|
+
rise_wave: type[Waveform] = CosineRiseFlex
|
|
518
|
+
"""Waveform, rise part of the 3-pulse sequence to be played with qubit and coupler gates."""
|
|
519
|
+
fall_wave: type[Waveform] = CosineFallFlex
|
|
520
|
+
"""Waveform, fall part of the 3-pulse sequence to be played with qubit and coupler gates."""
|
|
521
|
+
|
|
522
|
+
root_parameters: dict[str, Parameter | Setting | dict] = {
|
|
523
|
+
"duration": Parameter("", "Gate duration", "s"),
|
|
524
|
+
"qubit": {
|
|
525
|
+
"rise_time": Parameter("", "Qubit pulse rise time", "s"),
|
|
526
|
+
"full_width": Parameter("", "Qubit pulse full width", "s"),
|
|
527
|
+
"amplitude": Parameter("", "Qubit pulse amplitude", ""),
|
|
528
|
+
},
|
|
529
|
+
"coupler": {
|
|
530
|
+
"rise_time": Parameter("", "Coupler pulse rise time", "s"),
|
|
531
|
+
"full_width": Parameter("", "Coupler pulse full width", "s"),
|
|
532
|
+
"amplitude": Parameter("", "Coupler pulse amplitude", ""),
|
|
533
|
+
},
|
|
534
|
+
"rz": {
|
|
535
|
+
"*": Parameter("", "Z rotation angle", "rad"),
|
|
536
|
+
},
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
def __init__(
|
|
540
|
+
self,
|
|
541
|
+
parent: QuantumOp,
|
|
542
|
+
name: str,
|
|
543
|
+
locus: Locus,
|
|
544
|
+
calibration_data: OILCalibrationData,
|
|
545
|
+
builder: ScheduleBuilder,
|
|
546
|
+
) -> None:
|
|
547
|
+
GateImplementation.__init__(self, parent, name, locus, calibration_data, builder)
|
|
548
|
+
duration = calibration_data["duration"]
|
|
549
|
+
|
|
550
|
+
flux_pulses = {}
|
|
551
|
+
rise_pulses = {}
|
|
552
|
+
fall_pulses = {}
|
|
553
|
+
|
|
554
|
+
def build_flux_pulse(waveform_class: type[Waveform], component_name: str, cal_node_name: str) -> None:
|
|
555
|
+
"""Uses a part of the gate calibration data to prepare a flux pulse for the given component."""
|
|
556
|
+
flux_channel = builder.get_flux_channel(component_name)
|
|
557
|
+
|
|
558
|
+
granularity = builder.channels[flux_channel].duration_to_seconds(
|
|
559
|
+
builder.channels[flux_channel].instruction_duration_min
|
|
560
|
+
)
|
|
561
|
+
|
|
562
|
+
data = calibration_data[cal_node_name]
|
|
563
|
+
calibration_data_constant = data.copy()
|
|
564
|
+
calibration_data_rise = data.copy()
|
|
565
|
+
|
|
566
|
+
plateau_width_granular, rise_duration, rise_time, plateau_leftover = (
|
|
567
|
+
split_flat_top_part_into_granular_parts(duration, data["full_width"], data["rise_time"], granularity)
|
|
568
|
+
)
|
|
569
|
+
calibration_data_rise["rise_time"] = rise_time
|
|
570
|
+
calibration_data_constant["duration"] = plateau_width_granular
|
|
571
|
+
calibration_data_rise["duration"] = rise_duration
|
|
572
|
+
calibration_data_rise["full_width"] = plateau_leftover + rise_time
|
|
573
|
+
|
|
574
|
+
if plateau_width_granular > 0:
|
|
575
|
+
params_for_flux_pulses = self.convert_calibration_data(
|
|
576
|
+
calibration_data=calibration_data_constant,
|
|
577
|
+
params=self.parameters[cal_node_name], # type: ignore[arg-type]
|
|
578
|
+
channel_props=builder.channels[flux_channel],
|
|
579
|
+
duration=plateau_width_granular,
|
|
580
|
+
)
|
|
581
|
+
else:
|
|
582
|
+
params_for_flux_pulses = {"n_samples": 0, "amplitude": calibration_data_constant["amplitude"]}
|
|
583
|
+
|
|
584
|
+
params_for_risefall = self.convert_calibration_data(
|
|
585
|
+
calibration_data=calibration_data_rise,
|
|
586
|
+
params=self.parameters[cal_node_name], # type: ignore[arg-type]
|
|
587
|
+
channel_props=builder.channels[flux_channel],
|
|
588
|
+
duration=rise_duration,
|
|
589
|
+
)
|
|
590
|
+
|
|
591
|
+
params_for_flux_pulses["n_samples"] = (
|
|
592
|
+
builder.channels[flux_channel].duration_to_int_samples(plateau_width_granular)
|
|
593
|
+
if plateau_width_granular > 0
|
|
594
|
+
else 0
|
|
595
|
+
)
|
|
596
|
+
|
|
597
|
+
params_for_risefall["n_samples"] = (
|
|
598
|
+
builder.channels[flux_channel].duration_to_int_samples(rise_duration) if rise_duration > 0 else 0
|
|
599
|
+
)
|
|
600
|
+
|
|
601
|
+
amplitude = params_for_flux_pulses.pop("amplitude")
|
|
602
|
+
params_for_risefall.pop("amplitude")
|
|
603
|
+
|
|
604
|
+
flux_pulses[flux_channel] = (
|
|
605
|
+
FluxPulse(
|
|
606
|
+
duration=params_for_flux_pulses["n_samples"],
|
|
607
|
+
wave=waveform_class(n_samples=params_for_flux_pulses["n_samples"]),
|
|
608
|
+
scale=amplitude,
|
|
609
|
+
)
|
|
610
|
+
if params_for_flux_pulses["n_samples"] > 0
|
|
611
|
+
else None
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
if params_for_risefall["n_samples"] > 0:
|
|
615
|
+
rise_pulses[flux_channel] = FluxPulse(
|
|
616
|
+
duration=params_for_risefall["n_samples"],
|
|
617
|
+
wave=self.rise_wave(**params_for_risefall),
|
|
618
|
+
scale=amplitude,
|
|
619
|
+
)
|
|
620
|
+
fall_pulses[flux_channel] = FluxPulse(
|
|
621
|
+
duration=params_for_risefall["n_samples"],
|
|
622
|
+
wave=self.fall_wave(**params_for_risefall),
|
|
623
|
+
scale=amplitude,
|
|
624
|
+
)
|
|
625
|
+
else:
|
|
626
|
+
rise_pulses[flux_channel] = None # type: ignore[assignment]
|
|
627
|
+
fall_pulses[flux_channel] = None # type: ignore[assignment]
|
|
628
|
+
|
|
629
|
+
if self.coupler_wave is not None:
|
|
630
|
+
build_flux_pulse(self.coupler_wave, builder.chip_topology.get_coupler_for(*locus), "coupler")
|
|
631
|
+
|
|
632
|
+
if self.qubit_wave is not None:
|
|
633
|
+
# the pulsed qubit is always the first one of the locus
|
|
634
|
+
build_flux_pulse(self.qubit_wave, locus[0], "qubit")
|
|
635
|
+
|
|
636
|
+
rz = calibration_data["rz"]
|
|
637
|
+
for c in locus:
|
|
638
|
+
if c not in rz:
|
|
639
|
+
raise ValueError(
|
|
640
|
+
f"{parent.name}.{name}: {locus}: Calibration is missing an RZ angle for locus component {c}."
|
|
641
|
+
)
|
|
642
|
+
rz_locus = {builder.get_drive_channel(c): angle for c, angle in rz.items() if c in locus}
|
|
643
|
+
rz_not_locus = tuple((builder.get_drive_channel(c), angle) for c, angle in rz.items() if c not in locus)
|
|
644
|
+
|
|
645
|
+
schedule: dict[str, list[Instruction]] = {
|
|
646
|
+
channel: [
|
|
647
|
+
VirtualRZ(
|
|
648
|
+
duration=builder.channels[channel].duration_to_int_samples(duration),
|
|
649
|
+
phase_increment=-angle,
|
|
650
|
+
)
|
|
651
|
+
]
|
|
652
|
+
for channel, angle in rz_locus.items()
|
|
653
|
+
}
|
|
654
|
+
vzs_inserted = False # insert the long-distance Vzs to the first flux pulse (whatever that is)
|
|
655
|
+
for channel, flux_pulse in flux_pulses.items():
|
|
656
|
+
if rz_not_locus and not vzs_inserted and flux_pulse:
|
|
657
|
+
schedule[channel] = [replace(flux_pulse, rzs=rz_not_locus)]
|
|
658
|
+
vzs_inserted = True
|
|
659
|
+
elif duration > 0:
|
|
660
|
+
schedule[channel] = [
|
|
661
|
+
v for v in [rise_pulses[channel], flux_pulse, fall_pulses[channel]] if v is not None
|
|
662
|
+
]
|
|
663
|
+
else:
|
|
664
|
+
schedule[channel] = []
|
|
665
|
+
affected_components = set(locus)
|
|
666
|
+
affected_components.add(builder.chip_topology.get_coupler_for(*locus))
|
|
667
|
+
self._affected_components = affected_components
|
|
668
|
+
self._schedule = Schedule(schedule if duration > 0 else {c: [Block(0)] for c in schedule}, duration=duration)
|
|
669
|
+
|
|
670
|
+
def __init_subclass__(
|
|
671
|
+
cls,
|
|
672
|
+
/,
|
|
673
|
+
coupler_wave: type[Waveform] | None = None,
|
|
674
|
+
qubit_wave: type[Waveform] | None = None,
|
|
675
|
+
rise_wave: type[Waveform] = CosineRiseFlex,
|
|
676
|
+
fall_wave: type[Waveform] = CosineFallFlex,
|
|
677
|
+
):
|
|
678
|
+
if coupler_wave is None and qubit_wave is None and hasattr(cls, "coupler_wave") and hasattr(cls, "qubit_wave"):
|
|
679
|
+
return
|
|
680
|
+
if coupler_wave and (coupler_wave != Constant):
|
|
681
|
+
logging.getLogger(__name__).warning(
|
|
682
|
+
"Forcing coupler wave to be Constant",
|
|
683
|
+
)
|
|
684
|
+
coupler_wave = Constant
|
|
685
|
+
if qubit_wave and (qubit_wave != Constant):
|
|
686
|
+
logging.getLogger(__name__).warning(
|
|
687
|
+
"Forcing qubit wave to be Constant",
|
|
688
|
+
)
|
|
689
|
+
qubit_wave = Constant
|
|
690
|
+
|
|
691
|
+
cls.coupler_wave = coupler_wave
|
|
692
|
+
cls.qubit_wave = qubit_wave
|
|
693
|
+
cls.symmetric = cls.qubit_wave is None
|
|
694
|
+
cls.fall_wave = fall_wave
|
|
695
|
+
cls.rise_wave = rise_wave
|
|
696
|
+
|
|
697
|
+
root_parameters = {k: v for k, v in cls.root_parameters.items() if k not in cls.excluded_parameters}
|
|
698
|
+
parameters = {}
|
|
699
|
+
if coupler_wave is not None:
|
|
700
|
+
parameters["coupler"] = (
|
|
701
|
+
get_waveform_parameters(rise_wave, label_prefix="Coupler flux pulse ")
|
|
702
|
+
| get_waveform_parameters(fall_wave, label_prefix="Coupler flux pulse ")
|
|
703
|
+
| get_waveform_parameters(coupler_wave, label_prefix="Coupler flux pulse ")
|
|
704
|
+
)
|
|
705
|
+
parameters["coupler"]["amplitude"] = Parameter("", "Coupler flux pulse amplitude", "")
|
|
706
|
+
parameters["coupler"]["rise_time"] = Parameter("", "Coupler flux pulse rise time", "s")
|
|
707
|
+
parameters["coupler"]["full_width"] = Parameter("", "Coupler flux pulse full width", "s")
|
|
708
|
+
|
|
709
|
+
if qubit_wave is not None:
|
|
710
|
+
parameters["qubit"] = (
|
|
711
|
+
get_waveform_parameters(rise_wave, label_prefix="Qubit flux pulse ")
|
|
712
|
+
| get_waveform_parameters(fall_wave, label_prefix="Qubit flux pulse ")
|
|
713
|
+
| get_waveform_parameters(qubit_wave, label_prefix="Qubit flux pulse ")
|
|
714
|
+
)
|
|
715
|
+
parameters["qubit"]["amplitude"] = Parameter("", "Qubit flux pulse amplitude", "")
|
|
716
|
+
parameters["qubit"]["rise_time"] = Parameter("", "Qubit flux pulse rise time", "s")
|
|
717
|
+
parameters["qubit"]["full_width"] = Parameter("", "Qubit flux pulse full width", "s")
|
|
718
|
+
|
|
719
|
+
cls.parameters = root_parameters | {k: v for k, v in parameters.items() if k not in cls.excluded_parameters}
|
|
720
|
+
|
|
721
|
+
|
|
722
|
+
class FluxPulse_SmoothConstant_qubit(FluxPulseGate_SmoothConstant, qubit_wave=Constant):
|
|
723
|
+
"""Constant flux pulse on qubit with smooth rise/fall"""
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
class FluxPulse_SmoothConstant_coupler(FluxPulseGate_SmoothConstant, coupler_wave=Constant):
|
|
727
|
+
"""Constant flux pulse on coupler with smooth rise/fall."""
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
class FluxPulse_SmoothConstant_SmoothConstant(FluxPulseGate_SmoothConstant, coupler_wave=Constant, qubit_wave=Constant):
|
|
731
|
+
"""Constant flux pulse on both qubit and coupler with smooth rise/fall."""
|
|
@@ -102,9 +102,9 @@ class MOVE_CustomWaveforms(FluxPulseGate):
|
|
|
102
102
|
The phases are calculated and applied on the qubits using :func:`.apply_move_gate_phase_corrections`.
|
|
103
103
|
"""
|
|
104
104
|
|
|
105
|
-
root_parameters: dict[str, Parameter | Setting] = {
|
|
105
|
+
root_parameters: dict[str, Parameter | Setting | dict] = {
|
|
106
106
|
"duration": Parameter("", "Gate duration", "s"),
|
|
107
|
-
"rz": {
|
|
107
|
+
"rz": {
|
|
108
108
|
"*": Parameter("", "Z rotation angle", "rad"), # wildcard parameter
|
|
109
109
|
},
|
|
110
110
|
"detuning": Parameter("", "Qubit - resonator detuning", "Hz"),
|
|
@@ -498,3 +498,95 @@ class CosineFall(Waveform):
|
|
|
498
498
|
|
|
499
499
|
def _sample(self, sample_coords: np.ndarray) -> np.ndarray:
|
|
500
500
|
return 0.5 - 0.5 * np.sin(np.pi * sample_coords)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
@dataclass(frozen=True)
|
|
504
|
+
class CosineRiseFlex(Waveform):
|
|
505
|
+
r"""Cosine Rise waveform with an extra duration buffer.
|
|
506
|
+
|
|
507
|
+
The waveform is a piecewise function: |buffer|cosine rise|flat plateau|, where:
|
|
508
|
+
- buffer is a 'leftover' constant signal with amplitude = 0, with duration of duration - full_width
|
|
509
|
+
- cosine rise is a cosine rise pulse with a duration of rise_time
|
|
510
|
+
- flat plateau is a constant signal with amplitude = 1, with duration of full_width - rise_time
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
rise_time: rise time of the waveform
|
|
514
|
+
full_width: combined duration of the cosine rise time and the flat plateau
|
|
515
|
+
|
|
516
|
+
Raises:
|
|
517
|
+
ValueError: Error is raised if full_width or rise_time is more than duration
|
|
518
|
+
|
|
519
|
+
"""
|
|
520
|
+
|
|
521
|
+
rise_time: float
|
|
522
|
+
full_width: float
|
|
523
|
+
|
|
524
|
+
def _sample(self, sample_coords: np.ndarray) -> np.ndarray:
|
|
525
|
+
flat_part_duration = np.abs(self.full_width) - np.abs(self.rise_time)
|
|
526
|
+
rise_time_duration = np.abs(self.rise_time)
|
|
527
|
+
dead_wait_time = 1 - np.abs(self.full_width)
|
|
528
|
+
|
|
529
|
+
if dead_wait_time >= 0:
|
|
530
|
+
return np.piecewise(
|
|
531
|
+
sample_coords,
|
|
532
|
+
[
|
|
533
|
+
sample_coords <= 0.5 - flat_part_duration - rise_time_duration,
|
|
534
|
+
sample_coords > 0.5 - flat_part_duration - rise_time_duration,
|
|
535
|
+
sample_coords >= 0.5 - flat_part_duration, # flat carry-over from the Constant
|
|
536
|
+
],
|
|
537
|
+
[
|
|
538
|
+
0,
|
|
539
|
+
lambda oc: 0.5 - 0.5 * np.cos(np.pi / rise_time_duration * (oc - dead_wait_time + 0.5)),
|
|
540
|
+
1,
|
|
541
|
+
],
|
|
542
|
+
)
|
|
543
|
+
elif (flat_part_duration + dead_wait_time > 0) and (1 - rise_time_duration >= 0):
|
|
544
|
+
raise ValueError("Full width is more than duration")
|
|
545
|
+
else:
|
|
546
|
+
raise ValueError("Rise time is more than duration")
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
@dataclass(frozen=True)
|
|
550
|
+
class CosineFallFlex(Waveform):
|
|
551
|
+
r"""Cosine fall waveform with an extra duration buffer.
|
|
552
|
+
|
|
553
|
+
The waveform is a piecewise function: |flat plateau|cosine fall|buffer|, where:
|
|
554
|
+
- buffer is a 'leftover' constant signal with amplitude = 0, generally with duration of duration - full_width
|
|
555
|
+
- cosine fall is a cosine fall pulse with a duration of rise_time
|
|
556
|
+
- flat plateau is a constant signal with amplitude = 1, generally with duration of full_width - rise_time
|
|
557
|
+
|
|
558
|
+
Args:
|
|
559
|
+
rise_time: rise time of the waveform
|
|
560
|
+
full_width: combined duration of the cosine fall time and the flat plateau
|
|
561
|
+
|
|
562
|
+
Raises:
|
|
563
|
+
ValueError: Error is raised if full_width or rise_time is more than duration
|
|
564
|
+
|
|
565
|
+
"""
|
|
566
|
+
|
|
567
|
+
rise_time: float
|
|
568
|
+
full_width: float
|
|
569
|
+
|
|
570
|
+
def _sample(self, sample_coords: np.ndarray) -> np.ndarray:
|
|
571
|
+
flat_part_duration = max(np.abs(self.full_width) - np.abs(self.rise_time), 0)
|
|
572
|
+
rise_time_duration = np.abs(self.rise_time)
|
|
573
|
+
dead_wait_time = 1 - flat_part_duration - rise_time_duration
|
|
574
|
+
|
|
575
|
+
if dead_wait_time >= 0:
|
|
576
|
+
return np.piecewise(
|
|
577
|
+
sample_coords,
|
|
578
|
+
[
|
|
579
|
+
sample_coords <= -0.5 + flat_part_duration, # flat corry-over from the Constant
|
|
580
|
+
sample_coords > -0.5 + flat_part_duration,
|
|
581
|
+
sample_coords >= -0.5 + flat_part_duration + rise_time_duration,
|
|
582
|
+
],
|
|
583
|
+
[
|
|
584
|
+
1,
|
|
585
|
+
lambda oc: 0.5 + 0.5 * np.cos(np.pi / rise_time_duration * (oc - flat_part_duration + 0.5)),
|
|
586
|
+
0,
|
|
587
|
+
],
|
|
588
|
+
)
|
|
589
|
+
elif (flat_part_duration + dead_wait_time > 0) and (1 - rise_time_duration >= 0):
|
|
590
|
+
raise ValueError("Full width is more than duration")
|
|
591
|
+
else:
|
|
592
|
+
raise ValueError("Rise time is more than duration")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
10.3.0
|
iqm_pulse-10.1.0/version.txt
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
10.1.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
|
|
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
|
|
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
|
|
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
|
{iqm_pulse-10.1.0 → iqm_pulse-10.3.0}/src/iqm/pulse/playlist/visualisation/templates/static/logo.png
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|