Skip to content

Releases: qua-platform/quam

v0.6.0

Choose a tag to compare

@github-actions github-actions released this 18 Jun 13:13
46a39c9

Highlights

Python 3.13 and 3.14 support

QUAM now supports Python 3.13 and 3.14, and the CI matrix runs against Python 3.10 through 3.14. Support for Python 3.9 has been dropped — the minimum supported version is now 3.10.

qualang-tools is no longer a dependency

qualang-tools has been removed as a runtime dependency. The waveform and integration-weight helper functions QUAM relied on are now vendored directly in quam/components/_waveform_tools.py, and scipy is now a direct
dependency. This trims QUAM's dependency footprint with no change in behavior.

Shaped pulses are moving to quam-builder

The standard shaped-pulse classes — GaussianPulse, DragGaussianPulse, DragCosinePulse, FlatTopGaussianPulse, FlatTopBlackmanPulse, BlackmanIntegralPulse, FlatTopCosinePulse, and FlatTopTanhPulse — are now
deprecated in quam. Their implementations have moved to quam-builder. They still work for now but will be removed in v1.0, so update your imports to the quam-builder versions when you get a chance.

lo_mode on MW-FEM input ports

MWFEMAnalogInputPort gains an lo_mode field ("auto" or "always_on", defaulting to None). Leaving it as None omits the field from the generated QUA config, so the QUA default LO mode applies; setting it explicitly
overrides that default in the QUA config.

Package versions recorded in saved configs

Saved QUAM JSON configs now include a __package_versions__ entry recording the installed versions of all packages used to build the config. This makes a saved state easier to reproduce or debug later, since you know exactly what
produced it.

Fix: saving without ~/.qualibrate

Saving or loading a QUAM state no longer raises an error when the ~/.qualibrate directory doesn't exist.


Full Changelog

Added

  • Added __package_versions__ to saved JSON configs, recording the installed versions of all packages used to build the config.
  • Added lo_mode field to MWFEMAnalogInputPort (Optional[Literal["auto", "always_on"]], defaults to None). When None, the field is omitted from the QUA config so the QUA default applies; when set, the value is passed
    through to the QUA config, allowing users to override the QOP default.
  • Added support for Python 3.13 and 3.14.

Changed

  • Removed qualang-tools as a runtime dependency. Waveform and integration-weight functions are now vendored in quam/components/_waveform_tools.py. Added scipy as a direct dependency.

Deprecated

  • DragGaussianPulse, DragCosinePulse, GaussianPulse, FlatTopGaussianPulse, FlatTopBlackmanPulse, BlackmanIntegralPulse, FlatTopCosinePulse, FlatTopTanhPulse — implementations moved to quam-builder. Will be removed
    in v1.0.

Removed

  • Removed support for Python 3.9.

Fixed

  • Saving / loading no longer raises an error if ~/.qualibrate doesn't exist.

GitHub Pull Requests

Full Changelog: v0.5.0...v0.6.0

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 27 Apr 10:17

Highlights

2 GS/s waveform support for OPX1000

Pulses now read the sampling rate directly from the channel's output port when generating waveforms, defaulting to 1 GHz for OPX+ and picking up 2 GS/s automatically for LF-FEM and MW-FEM. All the standard shaped pulses (GaussianPulse, DragGaussianPulse, DragCosinePulse, FlatTopGaussianPulse, FlatTopBlackmanPulse, BlackmanIntegralPulse, FlatTopCosinePulse, FlatTopTanhPulse) now generate the right number of samples for the hardware they're attached to. No code changes needed.

Port containers and new base classes

FEMPortsContainer and OPXPlusPortsContainer give you a single place to access all ports on a controller. Two matching base classes, BasicFEMQuam and BasicOPXPlusQuam, come with these containers already wired up so you don't have to set that up yourself. Error messages for bad port references in these containers are also improved.

Channels as quantum components

You can now use multiple inheritance to make a class that is both a Channel and a Qubit (or another quantum component). For example, class HybridChannel(SingleChannel, Qubit) is valid. This lets you attach macros and gate operations directly to a channel without needing a separate qubit wrapper, which is useful when your channels and qubits map one-to-one.

Voltage ramp methods

Channel.ramp(slope, duration) and Channel.ramp_to_zero(duration) are now available on all channels. They wrap the corresponding QUA commands.

Serialization now includes defaults

QUAM state files now include fields at their default values rather than omitting them. The saved JSON is more explicit and easier to read or hand-edit. You can control this per-project with quam.serialization.include_defaults. The config format has moved to v3, with an automatic migration on first use.

This is a breaking change. If your tooling expects the previous compact format, pass include_defaults=False to save() or set it in ~/.qualibrate/config.toml.

inferred_id on all QUAM components

QuamBase.inferred_id returns the component's explicit id field if set, or the attribute name or dict key it lives under in its parent. It's equivalent to self.parent.get_attr_name(self) but without having to remember that method exists.

skip_save field metadata

You can now mark a dataclass field with field(metadata={"skip_save": True}) to leave it out of JSON serialization while keeping it available at runtime. Useful for transient or derived fields that don't belong in the saved state.

Better error messages

Loading errors are a lot more useful now. If you have a typo in an attribute name, the error lists the valid options and suggests the closest match. Missing required attributes show what type was expected. Class-not-found errors from __class__ entries tell you which module and class failed to import. Every loading error from QuamRoot.load() also includes the path to the file being loaded.

Frequency inference errors on IQChannel and MWChannel now say which specific field is None or unresolved, rather than leaving you to figure it out.

Config version mismatches now produce one of two distinct errors: InvalidQuamConfigVersionError if your config is older than the package (run the migration), or GreaterThanSupportedQuamConfigVersionError if your package is older than the config (upgrade the package, or downgrade the config at ~/.qualibrate/config.toml). Previously these were hard to tell apart.

OctaveDownConverter calibration fix

OctaveDownConverter.apply_to_config now always writes IF_outputs to the QUA config when a channel is connected. Before this fix, omitting LO_frequency would produce a config missing the physical port wiring, and qm.calibrate_element() would fail silently with no useful error.

set_at_reference default changed

QuamBase.set_at_reference() now defaults to allow_non_reference=True. The old default (False) required an explicit keyword argument in almost every real use case. If you need the strict behavior, pass allow_non_reference=False explicitly.

This is a breaking change.

Channel-level port property deprecations

Several properties that exposed port configuration directly on channels (SingleChannel.opx_output_offset, filter_fir_taps, filter_iir_taps, DigitalOutputChannel.shareable, DigitalOutputChannel.inverted, and the I/Q offset variants) are deprecated. Set these on the Port object instead. Each deprecation warning now includes a code example. These properties will be removed in v0.6.0.


Full Changelog

Added

  • QuamBase.inferred_id property: returns the explicit id field value if set, otherwise returns the attribute name or key under which the component is stored in its parent. Equivalent to self.parent.get_attr_name(self). Resolves #53.
  • Added Channel.sampling_rate property that reads the sampling rate from the channel's output port, defaulting to 1 GHz. Overridden in SingleChannel, IQChannel, and MWChannel to read from their respective ports.
  • Added Pulse._get_sampling_rate() method for pulses to retrieve the sampling rate of their attached channel.
  • Updated GaussianPulse, DragGaussianPulse, DragCosinePulse, FlatTopGaussianPulse, FlatTopBlackmanPulse, BlackmanIntegralPulse, FlatTopCosinePulse, and FlatTopTanhPulse to use the channel's sampling rate when generating waveforms. This enables correct waveform generation at 2 GS/s (e.g., on OPX1000 with LF-FEM or MW-FEM).
  • Added OPXPlusAnalogOutputPort.sampling_rate class variable set to 1e9 Hz.
  • Added Channel.ramp(slope, duration) method for playing linear voltage ramps.
  • Added Channel.ramp_to_zero(duration) method for ramping channel output to zero.
  • Added FEMPortsContainer and OPXPlusPortsContainer for centralized port management.
  • Added BasicFEMQuam and BasicOPXPlusQuam classes with integrated port containers.
  • Added quam.serialization.include_defaults config field to control whether default values are included in serialized JSON (defaults to True).
  • Added v2→v3 config migration with automatic upgrade support for the new serialization settings.
  • Added support for channels as quantum components via multiple inheritance, enabling channel-level macros and operations (e.g., class HybridChannel(SingleChannel, Qubit)).
  • Added skip_save field metadata support to exclude specific dataclass fields from serialization while keeping them accessible at runtime. Use field(metadata={"skip_save": True}) to mark fields that should not be saved to JSON.

Changed

  • Improved error messages during QUAM state loading. Unexpected attributes now list all valid required and optional attributes and suggest close matches for typos. Missing required attributes now show the expected type and what was actually provided, with typo suggestions. Class-not-found errors from __class__ entries now report the failing module/class name and suggest close matches. All loading errors from QuamRoot.load() now include the source file path.
  • Improved error messages in OPXPlusPortsContainer and FEMPortsContainer: invalid port types now raise ValueError immediately, and malformed port reference strings raise ValueError with a descriptive message instead of a cryptic unpacking error.
  • Breaking Change: set_at_reference() method now defaults to allow_non_reference=True instead of False. Users requiring error-by-default can explicitly pass allow_non_reference=False.
  • Breaking Change: Default serialization behavior changed from excluding defaults to including them for more explicit state representation.
  • Config version bumped from v2 to v3.
  • Restructured config to use nested serialization subcategory under quam config section.
  • Priority chain for resolving include_defaults setting: (1) explicit parameter to save() or to_dict(), (2) JSONSerialiser instance value, (3) config setting quam.serialization.include_defaults, (4) fallback to True.
  • Enhanced deprecation warnings for channel-level port properties to include migration examples with code snippets.
  • Expanded documentation for channel-ports.md with comprehensive examples of port container usage.
  • Removed version field from qua config template.

Deprecated

  • SingleChannel.opx_output_offset — use Port.offset instead. Will be removed in v0.6.0.
  • SingleChannel.filter_fir_taps — use Port.feedforward_filter instead. Will be removed in v0.6.0.
  • SingleChannel.filter_iir_taps — use Port.feedback_filter instead. Will be removed in v0.6.0.
  • DigitalOutputChannel.shareable — use Port.shareable instead. Will be removed in v0.6.0.
  • DigitalOutputChannel.inverted — use Port.inverted instead. Will be removed in v0.6.0.
  • All channel-level port offset properties (opx_output_offset_I/Q, opx_input_offset, etc.) — use Port.offset instead. Will be removed in v0.6.0.

All deprecated properties now show migration guidance with code examples. See Port documentation for migration details.

Fixed

  • Added exponential_dc_gain and high_pass_filter fields to LFFEMAnalogOutputPort for QOP 3.5+ filter support; fixed validation so the two fields can coexist and exponential_dc_gain alone conflicts with feedback_filter.
  • Clarified in documentation how kwargs and attributes differ for method macros: kwargs are per-call overrides, attributes are persistent calibrated values that are saved with the QUAM state.
  • Improved error messages for inferred frequency properties (inferred_RF_frequency, inferred_intermediate_frequency, inferred_LO_frequency) in IQChannel and MWChannel: errors now clearly identify the specific field and whether it is None or an unresolved reference.
  • Fixed conf...
Read more

v0.5.0a3

v0.5.0a3 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 20 Jan 09:44

What's Changed

Full Changelog: v0.5.0a2...v0.5.0a3

v0.5.0a2

v0.5.0a2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 17 Nov 19:09

What's Changed

Full Changelog: v0.5.0a1...v0.5.0a2

v0.5.0a1

v0.5.0a1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 13 Nov 21:29

This is a prerelease version for the upcoming v0.5.0.
Currently there are no breaking changes, though minor breaking changes are planned related to serialization

What's Changed

  • Fix: Serialisation of QUA Config failing with digital marker by @nulinspiratie in #159
  • add documentation on method macros by @nulinspiratie in #161
  • Update outputPulseParameters to timeTaggingParameters by @matteo-at-ionq in #144
  • Adding 4 types of pulses: FlatTopBlackmanPulse, BlackmanIntegralPulse, FlatTopTanhPulse, FlatTopCosinePulse by @giladqm in #158
  • add cosine bipolar pulse by @paulQM in #165

New Contributors

Full Changelog: v0.4.2...v0.5.0a1

v0.4.2

Choose a tag to compare

@github-actions github-actions released this 01 Sep 19:26

This release introduces several new fixes and small additions. The main motivation for releasing this now is that there is some incompatibility with the newly released QUA v1.2.3, and this has been resolved in this release of QUAM.

Added

  • Added duration and fidelity as optional parameters to QuamMacro

Fixed

  • Fixed QuamBase.get_attr_name() failing when an attribute was a reference.
  • Fixed arbitrary waveforms on IQ/MW channels not converting Q component to list consistently
  • Changed default time_of_flight from 24 ns to 140 ns to fix error on newer qm-qua versions
    • 140 ns seems like a reasonable default for most channels
  • Fixed type annotation issue in QuamRoot.load() method causing linting errors for subclasses like BasicQuam
  • Fixed Pulse.waveform_function return type being wrong
  • Compatibility with qm-qua 1.2.3: Updated channel measure command to explicitly pass adc_stream
  • Removed all private imports from qm.qua
  • Fixed float-to-int coercion during component instantiation

Github Pull requests

New Contributors

Full Changelog: v0.4.1...v0.4.2

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 13 May 10:24

What's Changed

Full Changelog: v0.4.0...v0.4.1

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 09 Apr 19:39

This release introduces several major new features and changes

QuantumComponents (qubits and qubit pairs) and gate-level operations

This PR introduces the QuantumComponent class, which is the base class for qubits and qubit pairs.
The subclasses Qubit and QubitPair are used to represent qubits and qubit pairs, respectively.
These classes can contain implementations for gate-level operations, which we call macros.
This PR additionally introduces several components for gate-level operations, see the documentation for more details.

QUAM Config

An optional configuration file has been added to QUAM.
This file can be created by calling quam config --state-path {state_path}, where {state_path} is the path to the quam state file.
This path will be used as the default path when calling quam.save() without an explicit path.
The config file will be saved to ~/.qualibrate/config.toml, to be shared with QUAlibrate.

Improved serialisation

The JSONSerialiser has been upgraded in several ways:

  • Several parameters content_mapping, include_defaults, and state_path have been added to the JSONSerialiser.
    This allows these parameters to be set beforehand
  • The config state path is used as a default path.
  • The content_mapping structure has been changed. Instead of the keys being the file names, the keys are the component names and the values are the filenames.
    • Old method: content_mapping={"wiring.json": ["wiring", "network"]}
    • Equivalent new method: content_mapping={"wiring": "wiring.json", "network": "wiring.json"}
    • The old method is still valid, though raises a deprecation warning

Change all instances of QuAM to QUAM

Given the slightly confusing abbreviation QuAM, we decided to change it to QUAM.
This was done in both the code and the documentation.
Note that the class BasicQuAM was renamed to BasicQUAM, with a deprecation warning if the old name is used.

Full list of changes

Added

  • Add support for qubit-level components and gate implementations
    • Add QuantumComponent and subclasses Qubit and QubitPair.
      These introduce qubit-level objects to interfacce with circuit-level languages.
    • Add qubit-level macros (BaseMacro, QuamMacro, QubitMacro, QubitPairMacro, PulseMacro) that implementations for gate operations.
    • Add OperationsRegistry to register gate-level operations.
    • See documentation for details.
  • Add Channel.reset_if_phase() which matches the QUA command reset_if_phase(element)
  • Add the QUAM config, which can be called from the terminal command quam config.
    This enables adding a default QUAM state path
  • Add config entry raise_error_missing_reference to raise error if a reference is missing, rather than a warning
  • Add the following properties to the JSONSerialiser: content_mapping, include_defaults, and state_path.
  • Add quam.__version__

Changed

  • JSONSerialiser.content_mapping structure has been changed from dict {filename.json: [list of components]} to {component: filname.json}. The previous format is still supported although this raises a warning
  • Remove implicit support for content mapping structure `{filename.json: component} (note the lack of a list). This used to be supported even though it was never mentioned.
  • The default state path for a QuamRoot is now retrieved from the environment variable QUAM_STATE_PATH, and if this doesn't exist, from the quam config.
  • Add __class__ to serialisation (to_dict method), even if the target class matches the expected type
  • If a specific class can't be imported during instantiation, a warning will be raised and it will load the default class (specified by the type hint) instead
  • QuAM has been renamed to QUAM
    • Some root classes have been renamed to CamelCase (e.g. BasicQuAM -> BasicQuam)
  • Deprecate Quam component methodget_unreferenced_value in favor of naming get_raw_value

GitHub merged pull requests

New Contributors

Full Changelog: v0.3.10...v0.4.0

v0.3.10

Choose a tag to compare

@github-actions github-actions released this 25 Mar 10:28

The primary change is to add support for qm-qua 1.2.2

Changed

  • QuamBase.generate_config() now returns a DictQuaConfig instead of a Dict[str, Any]
    This provides type hints for the generated config.
  • Add MWFEMAnalogInputPort.gain_db to allow for setting the gain of the analog input port
  • Removed warning when multiple QuamRoot objects are instantiated
  • Added SingleChannel.exponential_filter in compliance with QOP 3.3.
  • Deprecated SingleChannel.filter_iir_taps in favor of SingleChannel.exponential_filter for the LF-FEM

Fixed

  • Fixed QuamBase.iterate_components() arg skip_elems having the wrongtype
  • Deprecated thread argument in favor of core in Channel when qm >= 1.2.2
  • Fixed MWFEMAnalogOutputPort.upconverters not being converted to a dict in the config
  • Fixed QUA type import errors due to qm-qua 1.2.2 changing type locations

GitHub merged pull requests

New Contributors

Full Changelog: v0.3.9...v0.3.10

v0.3.9

Choose a tag to compare

@github-actions github-actions released this 07 Feb 20:01

Added

  • Added QuamBase.set_at_reference to set a value at a reference
  • Added string_reference.get_parent_reference to get the parent reference of a string reference
  • Added FrequencyConverter.LO_frequency setter which updates the local oscillator frequency
  • Added optional relative_path to method QuamBase.get_reference()
  • Added support for multiple QuamRoot objects
  • Added QuamBase.get_root() to get the QuamRoot object of a component

Changed

  • Pulse.integration_weights now defaults to #./default_integration_weights, which returns [(1, pulse.length)]

Fixed

  • Fixed issues with parameters being references in a QuamRoot object
  • Fixed MWFEMAnalogOutputPort.upconverters not having the correct type
  • A warning is raised if a new QuamRoot instance is created while a previous one exists.
  • Fixed MWFEMAnalogOutputPort.upconverters not being converted to a dict in the config
  • Fixed: Improve error message when instantiating: list or dict expected but a different type is provided
  • MWChannel.upconverter_frequency and MWChannel.LO_frequency now correctly return the upconverter frequency from the opx_output port, supporting both upconverter_frequency and upconverters specifications.

GitHub Merged Pull Requests

Full Changelog: v0.3.8...v0.3.9