From eebb1fbf47d8cecc451d68ecee240bd965ed654e Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Fri, 19 Apr 2024 21:13:24 +0200 Subject: [PATCH 01/27] minor title changes --- docs/quam-references.md | 4 ++-- mkdocs.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/quam-references.md b/docs/quam-references.md index 162e1ca9..105e5976 100644 --- a/docs/quam-references.md +++ b/docs/quam-references.md @@ -1,6 +1,6 @@ -# Component referencing +# Referencing between components -## QuAM tree-structure +## QuAM tree structure QuAM follows a tree structure, meaning that each QuAM component can have a parent component and it can have children. The top-level object is always an instance of QuAMRoot, e.g. diff --git a/mkdocs.yml b/mkdocs.yml index 7b04fd0e..1a911621 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -17,7 +17,7 @@ nav: - index.md - getting-started.md - demonstration.md - - "Features": + - "QuAM features": - quam-references.md - "QuAM components": - "components/channels.md" From 3b8c8dcc73b6e250b4d248c39c4562f30e35133b Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Mon, 22 Apr 2024 13:51:28 +0200 Subject: [PATCH 02/27] doc: QM styling --- docs/assets/qm_logo_white.svg | 197 ++++++++++++++++++++++++++++++++++ docs/stylesheets/extra.css | 92 ++++++++++++++++ mkdocs.yml | 36 ++++++- 3 files changed, 321 insertions(+), 4 deletions(-) create mode 100644 docs/assets/qm_logo_white.svg create mode 100644 docs/stylesheets/extra.css diff --git a/docs/assets/qm_logo_white.svg b/docs/assets/qm_logo_white.svg new file mode 100644 index 00000000..f1b10556 --- /dev/null +++ b/docs/assets/qm_logo_white.svg @@ -0,0 +1,197 @@ + + + + + + image/svg+xml + + 2019-03-QUA-4284-I-Logo_R1 + + + + + + + + + + + + + + + + + + + + + + + + + + + 2019-03-QUA-4284-I-Logo_R1 + + + + + + + + + diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 00000000..4d932ade --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,92 @@ + +[data-md-color-scheme="entropy-bright"] { + --md-primary-fg-color: #404044; + --md-accent-fg-color: #3082CF; + --md-typeset-a-color: #3082CF; + --md-footer-bg-color: #404044; + --md-default-bg-color:#E5E5E5; + --md-tabs-color: #464647; +} +[data-md-color-scheme="entropy-high-contrast"] { + --md-primary-fg-color: #404044; + --md-accent-fg-color: #3082CF; + --md-typeset-a-color: #3082CF; + --md-footer-bg-color: #404044; + --md-default-bg-color:#ffffff; + --md-tabs-color: #464647; + --md-typeset-color: black; +} + +[data-md-color-scheme="entropy-dark"] { + --md-primary-fg-color: #404044; + --md-accent-fg-color: #3082CF; + --md-typeset-a-color: #3082CF; + --md-typeset-color: #C6CDD6; + --md-footer-bg-color: #404044; + --md-default-bg-color:#2B2C32; + --md-code-bg-color:#323339; + --md-default-fg-color:#F6F9FA; + --md-default-fg-color--light: rgba(255,255,255,.54); + --md-default-fg-color--lighter: rgba(255,255,255,.32); + --md-typeset-kbd-color: #323339; + --md-typeset-kbd-accent-color: #2B2C32; + --md-code-fg-color: #F6F9FA; + --md-code-hl-name-color: #C6CDD6; + --md-code-hl-operator-color: #F6F9FA; + --md-code-hl-punctuation-color: #F6F9FA; + --md-code-hl-color: rgba(115, 115, 51, 0.54); + --md-code-hl-comment-color: rgba(255,255,255,.32); + --md-default-fg-color--light: rgba(255,255,255,.54); + --md-default-fg-color--lighter: rgba(255,255,255,.32); + --md-typeset-table-color: rgba(255,255,255,.32); + --md-code-hl-string-color: #00D59A; + --md-code-hl-number-color: #FF2463; + --md-code-hl-keyword-color: #6593ea; + --md-code-hl-constant-color: #6593ea; + --md-code-hl-function-color: #FFDB2C; + --md-tabs-color: #212123; +} +.md-annotation__index::after{ + background-color:#3082CF; + --md-default-fg-color--lightest: #0fafcbb3; +} +.md-header__topic:first-child { + font-weight: 700; +} +.md-nav__item .md-nav__link--active { + --md-typeset-a-color: #3082CF; +} +/* Indentation. */ +div.doc-contents:not(.first) { + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); +} + +/* Mark external links as such. */ +a.autorefs-external::after { + /* https://primer.style/octicons/arrow-up-right-24 */ + background-image: url('data:image/svg+xml,'); + content: ' '; + + display: inline-block; + position: relative; + top: 0.1em; + margin-left: 0.2em; + margin-right: 0.1em; + + height: 1em; + width: 1em; + border-radius: 100%; + background-color: var(--md-typeset-a-color); +} +a.autorefs-external:hover::after { + background-color: var(--md-accent-fg-color); +} +.md-header{ + background-color:rgba(30,30,32,0.8); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); +} +.md-tabs{ + background-color: var(--md-tabs-color); +} \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 1a911621..90a75c18 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,11 +1,36 @@ -site_name: QuAM (Quantum Abstract Machine) Documentation +site_name: The Quantum Abstract Machine - QuAM Documentation +# site_url: +site_author: QM. Technologies Ltd. +# site_description: + +copyright: Copyright © 2024 Q.M Technologies Ltd. theme: name: material + logo: assets/qm_logo_white.svg + font: + text: Roboto + code: Roboto Mono + favicon: assets/qm_logo_white.svg + palette: + - scheme: entropy-bright + toggle: + icon: material/brightness-7 + name: Switch to high contrast mode + - scheme: entropy-high-contrast + toggle: + icon: material/brightness-6 + name: Switch to dark mode + - scheme: entropy-dark + toggle: + icon: material/brightness-5 + name: Switch to light mode + features: - - navigation.tabs - - navigation.sections - - toc.integrate + # - navigation.tabs # Add tabs to the top of the page + # - navigation.sections # Expand sections in the navigation + - navigation.top # Add "back to top" button when scrolling back up + - toc.integrate # Invlude TOC in left sidebar instead of separate right - search.suggest - search.highlight - content.tabs.link @@ -13,6 +38,9 @@ theme: - content.code.copy language: en +extra_css: + - stylesheets/extra.css + nav: - index.md - getting-started.md From f8a7318022acb868a37531913d1a4435653a5344 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Mon, 22 Apr 2024 15:01:43 +0200 Subject: [PATCH 03/27] adding channels documentation --- docs/components/channels.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/components/channels.md b/docs/components/channels.md index 61bb7a16..a8aa7391 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -1,4 +1,30 @@ # Channels +In the QuAM library, channels are a fundamental concept that represent the physical connections to the quantum hardware. They are defined in the `quam.components.channels` module. + +There are two types of channels: Analog and Digital. + +## Analog channels +Analog channels are the primary means of communication with the quantum hardware. They can be used to send various types of signals, such as microwave or RF signals, to control the quantum system. Each [Channel][quam.components.channels.Channel] corresponds to an element in QUA. + +We distinguish between the following output channels: + +- [SingleChannel][quam.components.channels.SingleChannel] - A single OPX output channel +- [IQChannel][quam.components.IQChannel] - An OPX IQ output channel +- [InOutSingleChannel][quam.components.channels.InOutSingleChannel] - An OPX output channel + OPX input channel +- [InOutIQChannel][quam.components.channels.InOutIQChannel] - + + +Digital channels, on the other hand, are used for sending digital signals to the hardware. These signals are typically used for synchronization and triggering purposes. Digital channels can be attached to any analog channel through the Channel.digital_outputs attribute. + +In addition to these, QuAM also supports digital-only channels. These are channels that use digital ports without any analog ports. This can be useful in scenarios where only digital signals are needed. + +Once a DigitalOutputChannel is added to a Channel, digital waveforms can be played on it. This is done by attaching a digital waveform to a Pulse through the Pulse.digital_marker attribute. + +In summary, channels in QuAM provide a flexible and powerful way to control and interact with quantum hardware. + +## Analog channels + + ## Digital channels QuAM supports digital output channels (output from the OPX perspective) through the component [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel]. From 6f252ee6c7df5a5638ed1376a470ba5035f27b2d Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 23 Apr 2024 08:37:19 +0200 Subject: [PATCH 04/27] doc: more info on channels --- docs/components/channels.md | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/docs/components/channels.md b/docs/components/channels.md index a8aa7391..b59a3fb0 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -6,24 +6,42 @@ There are two types of channels: Analog and Digital. ## Analog channels Analog channels are the primary means of communication with the quantum hardware. They can be used to send various types of signals, such as microwave or RF signals, to control the quantum system. Each [Channel][quam.components.channels.Channel] corresponds to an element in QUA. -We distinguish between the following output channels: +### Analog channel types +We distinguish between the following analog channel types - [SingleChannel][quam.components.channels.SingleChannel] - A single OPX output channel -- [IQChannel][quam.components.IQChannel] - An OPX IQ output channel -- [InOutSingleChannel][quam.components.channels.InOutSingleChannel] - An OPX output channel + OPX input channel -- [InOutIQChannel][quam.components.channels.InOutIQChannel] - +- [IQChannel][quam.components.IQChannel] - An IQ OPX output channel +- [InOutSingleChannel][quam.components.channels.InOutSingleChannel] - A single OPX output + input channel +- [InOutIQChannel][quam.components.channels.InOutIQChannel] - An IQ OPX output + input channel +Note in QuAM,the terms output / input are in all cases from the OPX hardware's perspective. -Digital channels, on the other hand, are used for sending digital signals to the hardware. These signals are typically used for synchronization and triggering purposes. Digital channels can be attached to any analog channel through the Channel.digital_outputs attribute. +These channel combinations covermost use cases, though there are exceptions (input-only channels and single-output, IQ-input channels) which will be implemented in a subsequent QuAM release. -In addition to these, QuAM also supports digital-only channels. These are channels that use digital ports without any analog ports. This can be useful in scenarios where only digital signals are needed. +### Analog channel ports +A [SingleChannel][quam.components.channels.SingleChannel] is always attached to a single OPX output port, and similarly an [IQChannel][quam.components.channels.IQChannel] has an associated pair of IQ ports: -Once a DigitalOutputChannel is added to a Channel, digital waveforms can be played on it. This is done by attaching a digital waveform to a Pulse through the Pulse.digital_marker attribute. +```python +from quam.components import SingleChannel, IQChannel + +single_channel = SingleChannel( + opx_output=("con1", 1), + ... +) +IQ_channel = IQChannel( + opx_output_I=("con1", 2), + opx_output_Q=("con1", 3), + ... +) +``` + +Although each channel is always attached to a single or pair of OPX ports, the converse is not necessarily true: multiple channels can be attached to the same output port(s). + +### DC offset -In summary, channels in QuAM provide a flexible and powerful way to control and interact with quantum hardware. -## Analog channels +### Frequency converters ## Digital channels From da45f374ebd8bb694ca807217807962a25e4e293 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 23 Apr 2024 11:28:31 +0200 Subject: [PATCH 05/27] doc: discussing pulses + channels --- docs/components/channels.md | 75 +++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/docs/components/channels.md b/docs/components/channels.md index b59a3fb0..7386a54f 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -1,48 +1,83 @@ # Channels + In the QuAM library, channels are a fundamental concept that represent the physical connections to the quantum hardware. They are defined in the `quam.components.channels` module. -There are two types of channels: Analog and Digital. +We distinguish between the following channel types: + +**1. Analog output channels** + +- [SingleChannel][quam.components.channels.SingleChannel]: Represents a single OPX output channel. +- [IQChannel][quam.components.IQChannel]: Represents an IQ OPX output channel. + +**2. Analog output + input channels** + +- [InOutSingleChannel][quam.components.channels.InOutSingleChannel]: Represents a single OPX output + input channel. +- [InOutIQChannel][quam.components.channels.InOutIQChannel]: Represents an IQ OPX output + input channel. + +**3. Digital channels** -## Analog channels -Analog channels are the primary means of communication with the quantum hardware. They can be used to send various types of signals, such as microwave or RF signals, to control the quantum system. Each [Channel][quam.components.channels.Channel] corresponds to an element in QUA. +- [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel]: Represents a digital output channel. -### Analog channel types -We distinguish between the following analog channel types +Each analog [Channel][quam.components.channels.Channel] corresponds to an element in QUA, whereas the digital channel is part of an analog channel. -- [SingleChannel][quam.components.channels.SingleChannel] - A single OPX output channel -- [IQChannel][quam.components.IQChannel] - An IQ OPX output channel -- [InOutSingleChannel][quam.components.channels.InOutSingleChannel] - A single OPX output + input channel -- [InOutIQChannel][quam.components.channels.InOutIQChannel] - An IQ OPX output + input channel +Note that in QuAM, the terms "output" and "input" are always from the perspective of the OPX hardware. -Note in QuAM,the terms output / input are in all cases from the OPX hardware's perspective. +These channel combinations cover most use cases, although there are exceptions (input-only channels and single-output, IQ-input channels) which will be implemented in a subsequent QuAM release. If you need such channels, please create a [Github issue](https://github.com/qua-platform/quam/issues). -These channel combinations covermost use cases, though there are exceptions (input-only channels and single-output, IQ-input channels) which will be implemented in a subsequent QuAM release. +## Analog output channels + +Analog output channels are the primary means of controlling the quantum hardware. They can be used to send various types of signals, such as microwave or RF signals, to control the quantum system. The two types of analog output channels are the [SingleChannel][quam.components.channels.SingleChannel] and the [IQChannel][quam.components.channels.IQChannel]. ### Analog channel ports + A [SingleChannel][quam.components.channels.SingleChannel] is always attached to a single OPX output port, and similarly an [IQChannel][quam.components.channels.IQChannel] has an associated pair of IQ ports: + +### DC offset +Each analog channel can have a specified DC offset that remains for the duration of the QUA program. +This can be set through `SingleChannel.opx_output_offset` for the `SingleChannel`, and through `IQChannel.opx_output_offset_I` and `IQChannel.opx_output_offset_Q` for the `IQChannel`. + +Note that if multiple channels are attached to the same OPX output port(s), they may not have different output offsets. +This raises a warning and chooses the DC offset of the last channel. + +### Frequency converters +The `IQChannel` is usually connected to a mixer to upconvert the signal using a local oscillator. +This frequency upconversion is represented in QuAM by a [FrequencyConverter][quam.components.hardware.FrequencyConverter] + ```python -from quam.components import SingleChannel, IQChannel +from quam.components.hardware import FrequencyConverter, LocalOscillator, Mixer -single_channel = SingleChannel( - opx_output=("con1", 1), - ... -) IQ_channel = IQChannel( opx_output_I=("con1", 2), opx_output_Q=("con1", 3), - ... + frequency_converter=FrequencyConverter( + local_oscillator=LocalOscillator(frequency=6e9, power=10), + mixer=Mixer(), + ) ) ``` -Although each channel is always attached to a single or pair of OPX ports, the converse is not necessarily true: multiple channels can be attached to the same output port(s). +Integrated frequency conversion systems such as [QM's Octave](https://docs.quantum-machines.co/1.1.7/qm-qua-sdk/docs/Hardware/octave/) usually have additional features such as auto-calibration. +For this reason they have a specialized frequency converter such as the [OctaveUpConverter][quam.components.octave.OctaveUpConverter]. +See the [octave][] documentation for details. -### DC offset +### Adding pulses to channels +QuAM has a range of standard pulses in [quam.components.pulses][quam.components.pulses]. +These pulses can be registered as part of the analog channel via `Channel.operations` such that the channel can output the associated pulse waveforms: +```python +from quam.components import pulses +channel.operations["X180"] = pulses.SquarePulse( + amplitude=0.1, # Volt + length=16, # nanoseconds +) +``` +### Playing pulses on a channel -### Frequency converters +## Analog output + input channels +### Readout pulses ## Digital channels QuAM supports digital output channels (output from the OPX perspective) through the component [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel]. From 51b6e8907a718f7cac74c72f0d91d75520d4b8e8 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 23 Apr 2024 11:41:34 +0200 Subject: [PATCH 06/27] doc: finished analog output channels --- docs/components/channels.md | 52 ++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/docs/components/channels.md b/docs/components/channels.md index 7386a54f..eb4c757d 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -24,14 +24,30 @@ Note that in QuAM, the terms "output" and "input" are always from the perspectiv These channel combinations cover most use cases, although there are exceptions (input-only channels and single-output, IQ-input channels) which will be implemented in a subsequent QuAM release. If you need such channels, please create a [Github issue](https://github.com/qua-platform/quam/issues). + ## Analog output channels Analog output channels are the primary means of controlling the quantum hardware. They can be used to send various types of signals, such as microwave or RF signals, to control the quantum system. The two types of analog output channels are the [SingleChannel][quam.components.channels.SingleChannel] and the [IQChannel][quam.components.channels.IQChannel]. + ### Analog channel ports A [SingleChannel][quam.components.channels.SingleChannel] is always attached to a single OPX output port, and similarly an [IQChannel][quam.components.channels.IQChannel] has an associated pair of IQ ports: +```python +from quam.components import SingleChannel, IQChannel + +single_channel = SingleChannel( + opx_output=("con1", 1), + ... +) +IQ_channel = IQChannel( + opx_output_I=("con1", 2), + opx_output_Q=("con1", 3), + ... +) +``` + ### DC offset Each analog channel can have a specified DC offset that remains for the duration of the QUA program. @@ -40,6 +56,18 @@ This can be set through `SingleChannel.opx_output_offset` for the `SingleChannel Note that if multiple channels are attached to the same OPX output port(s), they may not have different output offsets. This raises a warning and chooses the DC offset of the last channel. +The DC offset can also be modified while a QUA program is running: +```python +from qm.qua import program + +with program() as prog: + single_channel.set_dc_offset(offset=0.1) + IQ_channel.set_dc_offset(offset=0.25, element_input="I") # Set offset of port I +``` +The offsets can also be QUA variables. +[Channel.set_dc_offset()][quam.components.channels.SingleChannel.set_dc_offset] is a light wrapper around `qm.qua.set_dc_offset` to attach it to the channel. + + ### Frequency converters The `IQChannel` is usually connected to a mixer to upconvert the signal using a local oscillator. This frequency upconversion is represented in QuAM by a [FrequencyConverter][quam.components.hardware.FrequencyConverter] @@ -50,6 +78,7 @@ from quam.components.hardware import FrequencyConverter, LocalOscillator, Mixer IQ_channel = IQChannel( opx_output_I=("con1", 2), opx_output_Q=("con1", 3), + intermediate_frequency=100e6, # Hz frequency_converter=FrequencyConverter( local_oscillator=LocalOscillator(frequency=6e9, power=10), mixer=Mixer(), @@ -61,24 +90,38 @@ Integrated frequency conversion systems such as [QM's Octave](https://docs.quant For this reason they have a specialized frequency converter such as the [OctaveUpConverter][quam.components.octave.OctaveUpConverter]. See the [octave][] documentation for details. + ### Adding pulses to channels -QuAM has a range of standard pulses in [quam.components.pulses][quam.components.pulses]. +QuAM has a range of standard [Pulse][quam.components.pulses.Pulse] components in [quam.components.pulses][quam.components.pulses]. These pulses can be registered as part of the analog channel via `Channel.operations` such that the channel can output the associated pulse waveforms: ```python from quam.components import pulses channel.operations["X180"] = pulses.SquarePulse( - amplitude=0.1, # Volt - length=16, # nanoseconds + amplitude=0.1, # V + length=16, # ns ) ``` +Details on pulses in quam can be found at [pulses][] + + ### Playing pulses on a channel +Once a pulse has been registered in a channel, it can be played within a QUA program: + +```python +with program() as prog: + channel.play("X180") +``` +[Channel.play()][quam.components.channels.Channel.play] is a light wrapper around [qm.qua.play()](https://docs.quantum-machines.co/latest/qm-qua-sdk/docs/Introduction/qua_overview/?h=play#play-statement) to attach it to the channel. + ## Analog output + input channels + ### Readout pulses + ## Digital channels QuAM supports digital output channels (output from the OPX perspective) through the component [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel]. These can be added to any analog channel through the attribute `Channel.digital_outputs`. As an example: @@ -104,6 +147,7 @@ analog_channel.digital_outputs = { ``` In this case, any digital pulses will be played to all digital channels. + ### Digital-only channel It is also possible to create a digital-only channel, i.e. using digital ports without any analog ports. ```python @@ -114,6 +158,7 @@ channel = Channel( ) ``` + ## Digital pulses Once a [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel] is added to a [Channel][quam.components.channels.Channel], digital waveforms can be played on it. This is done by attaching a digital waveform to a [Pulse][quam.components.pulses.Pulse] through the attribute `Pulse.digital_marker`: @@ -128,6 +173,7 @@ pulse = pulses.SquarePulse( ``` In the example above, the square pulse will also output digital waveform: "high" for 20 ns ⇨ "low" for 20 ns ⇨ "high" for 40 ns. This digital waveform will be played on all digital channels that are attached to the analog channel. + ### Digital-only pulses A digital pulse can also be played without a corresponding analog pulse. This can be done by directly using the base [pulses.Pulse][quam.components.pulses.Pulse] class: From 1b066484f3bfd2a6462889ca63fcdea43edbd6ac Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 23 Apr 2024 11:58:56 +0200 Subject: [PATCH 07/27] doc: channels.md done! --- docs/components/channels.md | 49 +++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/docs/components/channels.md b/docs/components/channels.md index eb4c757d..31329007 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -1,8 +1,8 @@ # Channels -In the QuAM library, channels are a fundamental concept that represent the physical connections to the quantum hardware. They are defined in the `quam.components.channels` module. +In the QuAM library, channels are a fundamental concept that represent the physical connections to the quantum hardware. They are defined in the [quam.components.channels][quam.components.channels] module. -We distinguish between the following channel types: +We distinguish between the following channel types, where the terms "output" and "input" are always from the perspective of the OPX hardware: **1. Analog output channels** @@ -20,8 +20,6 @@ We distinguish between the following channel types: Each analog [Channel][quam.components.channels.Channel] corresponds to an element in QUA, whereas the digital channel is part of an analog channel. -Note that in QuAM, the terms "output" and "input" are always from the perspective of the OPX hardware. - These channel combinations cover most use cases, although there are exceptions (input-only channels and single-output, IQ-input channels) which will be implemented in a subsequent QuAM release. If you need such channels, please create a [Github issue](https://github.com/qua-platform/quam/issues). @@ -91,7 +89,7 @@ For this reason they have a specialized frequency converter such as the [OctaveU See the [octave][] documentation for details. -### Adding pulses to channels +### Analog output pulses QuAM has a range of standard [Pulse][quam.components.pulses.Pulse] components in [quam.components.pulses][quam.components.pulses]. These pulses can be registered as part of the analog channel via `Channel.operations` such that the channel can output the associated pulse waveforms: @@ -103,10 +101,7 @@ channel.operations["X180"] = pulses.SquarePulse( length=16, # ns ) ``` -Details on pulses in quam can be found at [pulses][] - -### Playing pulses on a channel Once a pulse has been registered in a channel, it can be played within a QUA program: ```python @@ -115,11 +110,49 @@ with program() as prog: ``` [Channel.play()][quam.components.channels.Channel.play] is a light wrapper around [qm.qua.play()](https://docs.quantum-machines.co/latest/qm-qua-sdk/docs/Introduction/qua_overview/?h=play#play-statement) to attach it to the channel. +Details on pulses in quam can be found at [pulses][]. ## Analog output + input channels +Aside from sending signals to the quantum hardware, data is usually also received back, and subsequently read out through the hardware's input ports. +In QuAM, this is represented using the [InOutSingleChannel][quam.components.channels.InOutSingleChannel] and the [InOutIQChannel][quam.components.channels.InOutIQChannel]. +These channels don't only have associated output port(s) but also input port(s): + +```python +from quam.components import InOutSingleChannel, InOutIQChannel + +single_io_channel = InOutSingleChannel( + opx_output=("con1", 1), + opx_input=("con1", 1) + ... +) +IQ_io_channel = InOutIQChannel( + opx_output_I=("con1", 2), + opx_output_Q=("con1", 3), + opx_input_I=("con1", 1), + opx_input_Q=("con1", 2) + ... +) +``` + +These are extensions of the [SingleChannel][quam.components.channels.SingleChannel] and the [IQChannel][quam.components.channels.IQChannel] that add relevant features for readout. + +Both the [InOutSingleChannel][quam.components.channels.InOutSingleChannel] and the [InOutIQChannel][quam.components.channels.InOutIQChannel] combine output + input as in most cases a signal is also sent to probe the quantum hardware. +Support for input-only analog channels is planned for a future release. ### Readout pulses +Channels that have input ports can also have readout pulses: + +```python +from quam.components import pulses +io_channel.operations["readout"] = pulses.SquareReadoutPulse( + length=16, # ns + amplitude=0.1, # V + integration_weights_angle=0.0, # rad, optional rotation of readout signal +) +``` +As can be seen, the readout pulse (in this case [SquareReadoutPulse][quam.components.pulses.SquareReadoutPulse]) is similar to the regular pulses, but with additional parameters for readout. +Specifically, it contains the attributes `integration_weights_angle` and `integration_weights` to specify how the readout signal should be integrated. ## Digital channels From e4fab5d5bc0b5474ed3244b436cab29b547faab6 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Wed, 24 Apr 2024 15:58:00 +0200 Subject: [PATCH 08/27] added info on pulses --- docs/components/channels.md | 2 +- docs/components/pulses.md | 81 +++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 docs/components/pulses.md diff --git a/docs/components/channels.md b/docs/components/channels.md index 31329007..74726e81 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -89,7 +89,7 @@ For this reason they have a specialized frequency converter such as the [OctaveU See the [octave][] documentation for details. -### Analog output pulses +### Analog pulses QuAM has a range of standard [Pulse][quam.components.pulses.Pulse] components in [quam.components.pulses][quam.components.pulses]. These pulses can be registered as part of the analog channel via `Channel.operations` such that the channel can output the associated pulse waveforms: diff --git a/docs/components/pulses.md b/docs/components/pulses.md new file mode 100644 index 00000000..d546c9b9 --- /dev/null +++ b/docs/components/pulses.md @@ -0,0 +1,81 @@ +# Pulses +In the QuAM framework, pulses are the fundamental building blocks for crafting signals that interact with quantum processors. +These parametrized representations of waveforms, emitted from the OPX analog outputs, allow precise control over the shape and timing of signals. +For instance, a square pulse, defined by its amplitude and duration, can be used to initialize a quantum state or implement a gate operation. +This section explains how pulses are used in QuAM to facilitate quantum computing experiments. + +All pulses in QuAM are instances of the [Pulse][quam.components.pulses.Pulse] class. The QuAM library includes several predefined pulse types, such as: + +- **[SquarePulse][quam.components.pulses.SquarePulse]**: Typically used for simple quantum operations like flips or resets, characterized by a constant amplitude throughout its duration. +- **[GaussianPulse][quam.components.pulses.GaussianPulse]**: Ideal for minimizing spectral leakage due to its smooth rise and fall, commonly used in operations requiring high fidelity. +- **[DragPulse][quam.components.pulses.DragPulse]**: Designed to correct phase errors in quantum gates, enhancing the accuracy of operations involving superconducting qubits. + +The full list of predefined pulses can be found in the [pulses][quam.components.pulses] module. +Users can also define custom pulses by subclassing the `Pulse` class. This flexibility allows the creation of tailored waveforms that suit specific experimental requirements. + +All pulses in QuAM are instances of the [Pulse][quam.components.pulses.Pulse] class. +The QuAM library contains a set of common pulse types in the [pulses][quam.components.pulses] module. +Typical examples are [SquarePulse][quam.components.pulses.SquarePulse], [GaussianPulse][quam.components.pulses.GaussianPulse], and [DragPulse][quam.components.pulses.DragPulse]. +Users can supplement these common pulses with their own custom pulses by subclassing the [Pulse][quam.components.pulses.Pulse] class (see [Custom QuAM components][custom-components] for details). + + + + + +## Usage +To implement pulses in a QuAM program, you first need to register them to a specific channel. Here's how to set up a channel and register a square pulse for an operation labeled "X180": + +```python +from quam.components import pulses, SingleChannel + +# Create a channel associated with the first output on connector 1 +channel = SingleChannel(opx_output=("con1", 1)) + +# Register a square pulse with a duration of 1000 units and amplitude of 0.5 +channel.operations["X180"] = pulses.SquarePulse(duration=1000, amplitude=0.5)``` +``` + +After registering a pulse, you can utilize it in a QuAM program. Below is a simple example where the "X180" pulse is played: + +```python +from qm.qua import program + +# Start a new QuAM program +with program() as prog: + # Play the "X180" pulse on the previously defined channel + channel.play("X180") +``` + + +## Comparing QuAM and QUA Configurations + +The handling of pulses in QuAM and QUA presents fundamental differences in design philosophy and implementation, which can impact both usability and functionality. Understanding these differences is key for users who are transitioning to QuAM. Here's a comparison of how pulses are configured in each system: + +### QUA Configuration + +In the QUA configuration, pulses are decomposed into multiple components, such as `"waveforms"` and `"integration_weights"`. These components are defined separately and referenced by name within the "pulses" section of the configuration: + +- **Decomposition**: Each pulse is linked to a specific waveform and optionally, integration weights. This modular approach can be flexible but may lead to fragmented configuration, where information about a single pulse is scattered across multiple sections. +- **Pulse Mapping**: The elements (channels) use a `pulse_mapping` to link a label (e.g., "X180") to a specific pulse setup. This system allows multiple channels to share a pulse, enhancing reusability but potentially complicating pulse modifications. +- **External Functions**: Typically, the lack of a parametrized representation means that external functions are often required to populate waveform parameters, which can add complexity to pulse configuration and maintenance. + +### QuAM Configuration + +Conversely, QuAM adopts a parametrized approach that encapsulates all pulse characteristics within a single class, aiming to simplify pulse definition and manipulation: + +- **Parametrized Representation**: Pulses in QuAM are instances of a parametrized class, where the type of pulse and its parameters (such as length and amplitude) are directly defined by the user. This simplifies the initial setup and modification of pulse configurations. +- **Waveform Generation**: These parameters are used to generate the waveform dynamically using the method `[Pulse.generate_waveform()][quam.components.pulses.Pulse.generate_waveform]`. This approach integrates waveform generation within the pulse definition, streamlining the configuration process. +- **Integrated Configuration**: The resulting pulse definition includes not only the waveform but also the mapping and any optional integration weights, all encapsulated within a single entity. This integration simplifies the management and updating of pulses within the QuAM system. +- **No built-in waveform reuse**: QuAM does not currently support sharing waveforms across pulses, as each pulse is defined independently. This can have implications for memory usage on the OPX. Reusing waveforms in QuAM is planned in a future release. + +### Conclusion + +Understanding the relationship between QuAM and QUA helps users navigate the choices available to them, balancing ease of use with the power and flexibility offered by direct QUA scripting. +By considering these aspects, users can better choose or adapt their system according to their specific needs and technical preferences. \ No newline at end of file From b745c69c8dafb3d4d81c559a8946ec8d94a06ab8 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Wed, 24 Apr 2024 16:41:49 +0200 Subject: [PATCH 09/27] doc: Finished-ish pulses --- docs/components/pulses.md | 85 ++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 15 deletions(-) diff --git a/docs/components/pulses.md b/docs/components/pulses.md index d546c9b9..b8dc2b0c 100644 --- a/docs/components/pulses.md +++ b/docs/components/pulses.md @@ -17,16 +17,6 @@ All pulses in QuAM are instances of the [Pulse][quam.components.pulses.Pulse] cl The QuAM library contains a set of common pulse types in the [pulses][quam.components.pulses] module. Typical examples are [SquarePulse][quam.components.pulses.SquarePulse], [GaussianPulse][quam.components.pulses.GaussianPulse], and [DragPulse][quam.components.pulses.DragPulse]. Users can supplement these common pulses with their own custom pulses by subclassing the [Pulse][quam.components.pulses.Pulse] class (see [Custom QuAM components][custom-components] for details). - - - ## Usage @@ -53,18 +43,84 @@ with program() as prog: channel.play("X180") ``` +## Readout pulses +In addition to control pulses, QuAM also supports readout pulses, which are used to measure the state of a quantum system. +These pulses should be attached to an input channel, either [InOutIQChannel][quam.components.channels.InOutIQChannel] or [InOutSingleChannel][quam.components.channels.InOutSingleChannel]. + +Here's an example of how to define a readout pulse for a channel: + +```python +readout_channel.operations["readout"] = pulses.SquareReadoutPulse( + length=1000, + amplitude=0.1 + integration_weights=[(1, 500)] +) +``` + +Once a readout pulse is defined, it can be used in a QuAM program to measure the state of the quantum system: + +```python +with program() as prog: + # Measure the state of the quantum system using the "readout" pulse + qua_result = readout_channel.measure("readout") +``` + +## Creating custom pulses +To create custom pulses in QuAM, you can extend the functionality of the Pulse class by subclassing it and defining your own waveform generation logic. This allows for precise control over the pulse characteristics. + +### Example: Creating a Triangular Pulse +To illustrate, let's create a triangular pulse. This involves subclassing the Pulse class from the QuAM library and defining specific parameters and the waveform function. + +```python +import numpy as np +from quam.core import quam_dataclass +from quam.components import pulses + +@quam_dataclass +class TriangularPulse(pulses.Pulse): + # Define the starting and stopping amplitudes for the triangular pulse + amplitude_start: float + amplitude_stop: float + + def waveform_function(self) -> np.ndarray: + # This function generates a linearly spaced array to form a triangular waveform + return np.linspace(self.amplitude_start, self.amplitude_stop, self.length) +``` +Ensure this code is saved in a properly structured Python module within your project so that it can be imported as needed. For details on organizing custom components, refer to the [Custom Components][custom-components] section of the QuAM documentation + +### Extending to readout pulses +To create a readout pulse derived from a control pulse, subclass both the specific control pulse and the [ReadoutPulse][quam.components.pulses.ReadoutPulse] class. Below is an example of how to adapt the Triangular Pulse into a readout pulse. + +```python +@quam_dataclass +class TriangularReadoutPulse(pulses.ReadoutPulse, TriangularPulse): + """Extend TriangularPulse to include readout-specific functionality.""" + # No additional fields needed; inherits all from TriangularPulse and ReadoutPulse + pass +``` +Readout pulses utilize additional parameters for integration weights which are crucial for signal processing: + +- **`ReadoutPulse.integration_weights`**: A list of floats or tuples specifying the weights over time. +- **`ReadoutPulse.integration_weights_angle`**: The angle (in radians) applied to the integration weights. + +These two parameters are used to calculate the readout pulse's integration weights (`sine`, `-sine` and `cosine`), which are essential for signal processing in readout operations. + +These parameters are typically used to manage the integration weights (`sine`, `-sine`, and `cosine`) for the readout operations. By default, these weights assume a fixed angle. If variable angles are needed, subclass the BaseReadoutPulse class and override the integration_weights_function() to customize this behavior. + +This approach ensures your custom pulse configurations are both flexible and compatible with the broader QuAM framework. + -## Comparing QuAM and QUA Configurations +## Pulses in QuAM and QUA The handling of pulses in QuAM and QUA presents fundamental differences in design philosophy and implementation, which can impact both usability and functionality. Understanding these differences is key for users who are transitioning to QuAM. Here's a comparison of how pulses are configured in each system: ### QUA Configuration -In the QUA configuration, pulses are decomposed into multiple components, such as `"waveforms"` and `"integration_weights"`. These components are defined separately and referenced by name within the "pulses" section of the configuration: +In the QUA configuration, pulses are decomposed into multiple components, such as `"waveforms"` and `"integration_weights"`. These components are defined separately and referenced by name within the `"pulses"` section of the configuration: -- **Decomposition**: Each pulse is linked to a specific waveform and optionally, integration weights. This modular approach can be flexible but may lead to fragmented configuration, where information about a single pulse is scattered across multiple sections. +- **Decomposition**: Each pulse is linked to a specific waveform and optionally, integration weights. This modular approach is more memory-efficient but may lead to fragmented configuration, where information about a single pulse is scattered across multiple sections. - **Pulse Mapping**: The elements (channels) use a `pulse_mapping` to link a label (e.g., "X180") to a specific pulse setup. This system allows multiple channels to share a pulse, enhancing reusability but potentially complicating pulse modifications. -- **External Functions**: Typically, the lack of a parametrized representation means that external functions are often required to populate waveform parameters, which can add complexity to pulse configuration and maintenance. +- **External Functions**: Typically, the lack of a parametrized representation means that external functions are often required to populate waveform entries. ### QuAM Configuration @@ -72,7 +128,6 @@ Conversely, QuAM adopts a parametrized approach that encapsulates all pulse char - **Parametrized Representation**: Pulses in QuAM are instances of a parametrized class, where the type of pulse and its parameters (such as length and amplitude) are directly defined by the user. This simplifies the initial setup and modification of pulse configurations. - **Waveform Generation**: These parameters are used to generate the waveform dynamically using the method `[Pulse.generate_waveform()][quam.components.pulses.Pulse.generate_waveform]`. This approach integrates waveform generation within the pulse definition, streamlining the configuration process. -- **Integrated Configuration**: The resulting pulse definition includes not only the waveform but also the mapping and any optional integration weights, all encapsulated within a single entity. This integration simplifies the management and updating of pulses within the QuAM system. - **No built-in waveform reuse**: QuAM does not currently support sharing waveforms across pulses, as each pulse is defined independently. This can have implications for memory usage on the OPX. Reusing waveforms in QuAM is planned in a future release. ### Conclusion From 540732392b84f49318090ff34f489eb6f596a355 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 25 Apr 2024 07:49:47 +0200 Subject: [PATCH 10/27] doc: rename titel --- docs/custom-components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/custom-components.md b/docs/custom-components.md index 63acd510..761fce25 100644 --- a/docs/custom-components.md +++ b/docs/custom-components.md @@ -1,4 +1,4 @@ -# Custom components +# Custom QuAM components To create custom QuAM components, their classes should be defined in a Python module that can be accessed from Python. The reason for this is that otherwise QuAM cannot load QuAM from a JSON file as it cannot determine where the classes are defined. From 66e24de863f85f06f7e1293962bb014e87fef5ac Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 25 Apr 2024 19:47:06 +0200 Subject: [PATCH 11/27] working on migration document --- docs/migrating-to-quam.md | 171 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 docs/migrating-to-quam.md diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md new file mode 100644 index 00000000..2434b6d8 --- /dev/null +++ b/docs/migrating-to-quam.md @@ -0,0 +1,171 @@ +# Migrating to QuAM + +QuAM serves as an abstraction framework over the QUA programming language. +For users already familiar with QUA, transitioning to QuAM is straightforward. +In this guide, we outline the steps to migrate your existing QUA code to QuAM. + +Assuming you already have a QUA configuration, the migration process involves two steps: + +1. Migrate the **QUA configuration** to QuAM Use the standard QuAM components. +2. Create **high-level QuAM components** (e.g. qubit) that encapsulate the low-level components and build abstraction layers. + The second step is optional but can significantly help in organizing and simplifying your codebase. + +## Migrate QUA Configuration to QuAM + +### Create a root QuAM object +The QuAM structure needs a top-level [QuamRoot][quam.core.QuamRoot] which has features such as saving/loading QuAM. +Typically one would subclass [QuamRoot][quam.core.QuamRoot] and add the necessary components as fields. +However, as a basic example, we can use the [BasicQuAM][quam.components.BasicQuAM] class, which contains the fields necessary for the migration. +We call this object the `machine`. + +```python +from quam.components import BasicQuAM + +machine = BasicQuAM() +machine.print_summary() +``` + + +Next we populate the root-level `machine` object with QuAM components + +### Adding Octaves +If you have one or more Octave components, you can add them to the QUA configuration: +```python +from quam.components import Octave, OctaveUpConverter, OctaveDownConverter, Channel + +machine.octaves["octave1"] = Octave(name="octave1", ip="127.0.0.1", port=80) + +# Initialize all frequency converters in the default wiring configuration +machine.octave.initialize_frequency_converters() +``` +The [Octave documentation][octave] provides more details on the Octave configuration. + +### Convert "elements" to Channels +The QUA configuration has a section labelled `"elements"`, which corresponds to a pulse processor that can either send or receive signals. +Each element has a direct mapping to one of the [quam.components.channels][] in QuAM, though the channel type depends on the element. + +Here we show how to convert different types of elements to QuAM channels. +We don't cover all possible properties, details for this can be found in the [Channels documentation][channels] and the relevant API documentation for each channel type. +We also delay the discussion on the `"operations"` field for the next section on pulses. + +#### Single analog output channel +In the simplest case, a single output channel is defined in the QUA configuration. + + + + + + + +
+ ```json title='qua_configuration["elements"]' + "qubit_z": { + "singleInput": {"port": ("con1", 1)}, + "operations": {...} + } + ``` + + ```python title="QuAM" + from quam.components import SingleChannel + + machine.channels["qubit_z"] = IQChannel( + opx_output=("con1", 1), + ) + ``` +
+ +The corresponding QuAM component is the [SingleChannel][quam.components.SingleChannel]. + +#### IQ analog output channel + +In the case where the IQ channel is not connected to an + + + + + + +
+ ```json title='qua_configuration["elements"]' + "qubit_xy": { + "intermediate_frequency": 100e6, + "mixInputs": { + "I": ("con1", 1), + "Q": ("con1", 2), + "lo_frequency": 5e9, + "mixer": "mixer_qubit", + }, + "operations": {...} + }, + ``` + + ```python title="QuAM" + from quam.components import IQChannel + channels["qubit_XY"] = IQChannel( + opx_output_I=("con1", 1), + opx_output_Q=("con1", 2), + frequency_converter_up=FrequencyConverter( + local_oscillator=LocalOscillator(frequency=5e9), + mixer=Mixer() + ) + ) + ``` +
+ + + + +If an Octave is used for upconversion, the IQChannel should be connected to the OctaveUpConverter. + + + + + + +
+ ```json title='qua_configuration["elements"]' + "qubit_xy": { + "intermediate_frequency": 100e6, + "RF_inputs": {"port": ["octave1", 1]}, + "operations": {...} + }, + ``` + + ```python + from quam.components import IQChannel + + RF_output = machine.octaves["octave1"].RF_outputs[1] + channel = machine.channels["qubit_xy"] = IQChannel( + opx_output_I=("con1", 1), + opx_output_Q=("con1", 2), + frequency_converter_up=RF_output.get_reference() + ) + RF_output.channel = channel.get_reference() + ``` +
+ + + + +Detailed instructions can be found at the [Octave documentation][octave]. + +#### Single analog output + input channel +In the case where the channel is both an input and output channel, the [InOutSingleChannel][quam.components.InOutSingleChannel] should be used. + +```json title='qua_configuration["elements"] - Single input/output channel' +"qubit_readout": { + "singleInput": { + "port": ("con1", 1), + }, + "operations": {...} +} +``` +The corresponding QuAM component is the [SingleChannel][quam.components.SingleChannel]. + +```python +from quam.components import SingleChannel + +machine.channels["qubit_z"] = IQChannel( + opx_output=("con1", 1), +) +``` \ No newline at end of file From ef689b798eead4c4ac93fb93dde32bd98209cdc5 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 25 Apr 2024 19:55:02 +0200 Subject: [PATCH 12/27] Capitalization of titles --- docs/components/channels.md | 22 +-- docs/components/octave.md | 217 +++++++++++------------------- docs/components/pulses.md | 8 +- docs/custom-components.md | 8 +- docs/demonstration.md | 6 +- docs/examples/QuAM features.ipynb | 12 +- docs/getting-started.md | 4 +- docs/index.md | 2 +- docs/migrating-to-quam.md | 8 +- docs/quam-references.md | 16 +-- docs/stylesheets/extra.css | 145 +++++++++++--------- mkdocs.yml | 2 + 12 files changed, 205 insertions(+), 245 deletions(-) diff --git a/docs/components/channels.md b/docs/components/channels.md index 74726e81..d13a376c 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -23,12 +23,12 @@ Each analog [Channel][quam.components.channels.Channel] corresponds to an elemen These channel combinations cover most use cases, although there are exceptions (input-only channels and single-output, IQ-input channels) which will be implemented in a subsequent QuAM release. If you need such channels, please create a [Github issue](https://github.com/qua-platform/quam/issues). -## Analog output channels +## Analog Output Channels Analog output channels are the primary means of controlling the quantum hardware. They can be used to send various types of signals, such as microwave or RF signals, to control the quantum system. The two types of analog output channels are the [SingleChannel][quam.components.channels.SingleChannel] and the [IQChannel][quam.components.channels.IQChannel]. -### Analog channel ports +### Analog Channel Ports A [SingleChannel][quam.components.channels.SingleChannel] is always attached to a single OPX output port, and similarly an [IQChannel][quam.components.channels.IQChannel] has an associated pair of IQ ports: @@ -47,7 +47,7 @@ IQ_channel = IQChannel( ``` -### DC offset +### DC Offset Each analog channel can have a specified DC offset that remains for the duration of the QUA program. This can be set through `SingleChannel.opx_output_offset` for the `SingleChannel`, and through `IQChannel.opx_output_offset_I` and `IQChannel.opx_output_offset_Q` for the `IQChannel`. @@ -66,7 +66,7 @@ The offsets can also be QUA variables. [Channel.set_dc_offset()][quam.components.channels.SingleChannel.set_dc_offset] is a light wrapper around `qm.qua.set_dc_offset` to attach it to the channel. -### Frequency converters +### Frequency Converters The `IQChannel` is usually connected to a mixer to upconvert the signal using a local oscillator. This frequency upconversion is represented in QuAM by a [FrequencyConverter][quam.components.hardware.FrequencyConverter] @@ -89,7 +89,7 @@ For this reason they have a specialized frequency converter such as the [OctaveU See the [octave][] documentation for details. -### Analog pulses +### Analog Pulses QuAM has a range of standard [Pulse][quam.components.pulses.Pulse] components in [quam.components.pulses][quam.components.pulses]. These pulses can be registered as part of the analog channel via `Channel.operations` such that the channel can output the associated pulse waveforms: @@ -112,7 +112,7 @@ with program() as prog: Details on pulses in quam can be found at [pulses][]. -## Analog output + input channels +## Analog Output + Input Channels Aside from sending signals to the quantum hardware, data is usually also received back, and subsequently read out through the hardware's input ports. In QuAM, this is represented using the [InOutSingleChannel][quam.components.channels.InOutSingleChannel] and the [InOutIQChannel][quam.components.channels.InOutIQChannel]. These channels don't only have associated output port(s) but also input port(s): @@ -140,7 +140,7 @@ Both the [InOutSingleChannel][quam.components.channels.InOutSingleChannel] and t Support for input-only analog channels is planned for a future release. -### Readout pulses +### Readout Pulses Channels that have input ports can also have readout pulses: ```python @@ -155,7 +155,7 @@ As can be seen, the readout pulse (in this case [SquareReadoutPulse][quam.compon Specifically, it contains the attributes `integration_weights_angle` and `integration_weights` to specify how the readout signal should be integrated. -## Digital channels +## Digital Channels QuAM supports digital output channels (output from the OPX perspective) through the component [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel]. These can be added to any analog channel through the attribute `Channel.digital_outputs`. As an example: @@ -181,7 +181,7 @@ analog_channel.digital_outputs = { In this case, any digital pulses will be played to all digital channels. -### Digital-only channel +### Digital-only Channel It is also possible to create a digital-only channel, i.e. using digital ports without any analog ports. ```python from quam.components import Channel, DigitalOutputChannel @@ -192,7 +192,7 @@ channel = Channel( ``` -## Digital pulses +## Digital Pulses Once a [DigitalOutputChannel][quam.components.channels.DigitalOutputChannel] is added to a [Channel][quam.components.channels.Channel], digital waveforms can be played on it. This is done by attaching a digital waveform to a [Pulse][quam.components.pulses.Pulse] through the attribute `Pulse.digital_marker`: ```python @@ -207,7 +207,7 @@ pulse = pulses.SquarePulse( In the example above, the square pulse will also output digital waveform: "high" for 20 ns ⇨ "low" for 20 ns ⇨ "high" for 40 ns. This digital waveform will be played on all digital channels that are attached to the analog channel. -### Digital-only pulses +### Digital-only Pulses A digital pulse can also be played without a corresponding analog pulse. This can be done by directly using the base [pulses.Pulse][quam.components.pulses.Pulse] class: ```python diff --git a/docs/components/octave.md b/docs/components/octave.md index c93e60a9..1514c6a9 100644 --- a/docs/components/octave.md +++ b/docs/components/octave.md @@ -7,7 +7,7 @@ Below we describe the three steps needed to configuring an Octave in QuAM: 2. Adding frequency converters 3. Attaching channels -## :zero: Creating the root QuAM machine +## :zero: Creating the Root QuAM Machine Before we get started, we need a top-level QuAM class that matches our components: ```python @@ -30,11 +30,7 @@ This will be used later to generate our QUA configuration Below we show how an Octave is instantiated using some example arguments: ```python -octave = Octave( - name="octave1", - ip="127.0.0.1", - port=80, -) +octave = Octave(name="octave1", ip="127.0.0.1", port=80) machine.octave = octave ``` @@ -49,7 +45,7 @@ qmm = QuantumMachinesManager(host={opx_host}, port={opx_port}, octave=octave_con At this point the channel connectivity of the Octave hasn't yet been configured. We can do so by adding frequency converters. -## :two: Adding frequency converters +## :two: Adding Frequency Converters A frequency converter is a grouping of the components needed to upconvert or downconvert a signal. These typically consist of a local oscillator, mixer, as well as IF, LO, and RF ports. For the Octave we have two types of frequency converters: @@ -142,7 +138,7 @@ It is important to specify the `LO_frequency` of the frequency converters that a At this point, our `Octave` does not yet contain any information on which OPX output / input is connected to each `OctaveUpconverter` / `OctaveDownConverter`. This is done in the third stage -## :three: Attaching channels +## :three: Attaching Channels Once the frequency converters have been setup, it is time to attach the ones that are in use to corresponding channels in QuAM. In the example below, we connect an `IQChannel` to the `OctaveUpconverter` at `octave.RF_outputs[1]` ```python @@ -173,7 +169,7 @@ octave.RF_outputs[2].LO_frequency = 2e9 octave.RF_inputs[2].LO_frequency = 2e9 ``` -## Generating the config +## Generating the Config Once everything is setup, we can generate the QUA configuration ```python @@ -183,142 +179,93 @@ qua_config = machine.generate_config() /// details | qua_config ```json { - "version": 1, - "controllers": { - "con1": { - "analog_outputs": { - "1": { - "offset": 0.0 - }, - "2": { - "offset": 0.0 - }, - "3": { - "offset": 0.0 - }, - "4": { - "offset": 0.0 + "version": 1, + "controllers": { + "con1": { + "analog_outputs": { + "1": {"offset": 0.0}, + "2": {"offset": 0.0}, + "3": {"offset": 0.0}, + "4": {"offset": 0.0}, + }, + "digital_outputs": {}, + "analog_inputs": {"1": {"offset": 0.0}, "2": {"offset": 0.0}}, } - }, - "digital_outputs": {}, - "analog_inputs": { - "1": { - "offset": 0.0 + }, + "elements": { + "IQ1": { + "operations": {}, + "intermediate_frequency": 0.0, + "RF_inputs": {"port": ["octave1", 1]}, }, - "2": { - "offset": 0.0 + "IQ2": { + "operations": {}, + "intermediate_frequency": 0.0, + "RF_inputs": {"port": ["octave1", 2]}, + "smearing": 0, + "time_of_flight": 24, + "RF_outputs": {"port": ["octave1", 1]}, + }, + }, + "pulses": { + "const_pulse": { + "operation": "control", + "length": 1000, + "waveforms": {"I": "const_wf", "Q": "zero_wf"}, } - } - } - }, - "elements": { - "IQ1": { - "operations": {}, - "intermediate_frequency": 0.0, - "RF_outputs": { - "port": [ - "octave1", - 1 - ] - } }, - "IQ2": { - "operations": {}, - "intermediate_frequency": 0.0, - "RF_outputs": { - "port": [ - "octave1", - 2 - ] - }, - "smearing": 0, - "time_of_flight": 24, - "RF_inputs": { - "port": [ - "octave1", - 1 - ] - } - } - }, - "pulses": { - "const_pulse": { - "operation": "control", - "length": 1000, - "waveforms": { - "I": "const_wf", - "Q": "zero_wf" - } - } - }, - "waveforms": { - "zero_wf": { - "type": "constant", - "sample": 0.0 + "waveforms": { + "zero_wf": {"type": "constant", "sample": 0.0}, + "const_wf": {"type": "constant", "sample": 0.1}, }, - "const_wf": { - "type": "constant", - "sample": 0.1 - } - }, - "digital_waveforms": { - "ON": { - "samples": [ - [ - 1, - 0 - ] - ] - } - }, - "integration_weights": {}, - "mixers": {}, - "oscillators": {}, - "octaves": { - "octave1": { - "RF_outputs": { - "1": { - "LO_frequency": 2000000000.0, - "LO_source": "internal", - "gain": 0, - "output_mode": "always_off", - "input_attenuators": "off", - "I_connection": [ - "con1", - 1 - ], - "Q_connection": [ - "con1", - 2 - ] - }, - "2": { - "LO_frequency": 2000000000.0, - "LO_source": "internal", - "gain": 0, - "output_mode": "always_off", - "input_attenuators": "off", - "I_connection": [ - "con1", - 3 - ], - "Q_connection": [ - "con1", - 4 - ] + "digital_waveforms": {"ON": {"samples": [[1, 0]]}}, + "integration_weights": {}, + "mixers": {}, + "oscillators": {}, + "octaves": { + "octave1": { + "RF_outputs": { + "1": { + "LO_frequency": 2000000000.0, + "LO_source": "internal", + "gain": 0, + "output_mode": "always_off", + "input_attenuators": "off", + "I_connection": ["con1", 1], + "Q_connection": ["con1", 2], + }, + "2": { + "LO_frequency": 2000000000.0, + "LO_source": "internal", + "gain": 0, + "output_mode": "always_off", + "input_attenuators": "off", + "I_connection": ["con1", 3], + "Q_connection": ["con1", 4], + }, + }, + "IF_outputs": { + "IF_out1": {"port": ["con1", 1], "name": "out1"}, + "IF_out2": {"port": ["con1", 2], "name": "out2"}, + }, + "RF_inputs": { + "1": { + "RF_source": "RF_in", + "LO_frequency": 2000000000.0, + "LO_source": "internal", + "IF_mode_I": "direct", + "IF_mode_Q": "direct", + } + }, + "loopbacks": [], } - }, - "IF_outputs": {}, - "RF_inputs": {}, - "loopbacks": [] - } - } + }, } ``` /// -## Combined example +## Combined Example ```python from typing import Dict from dataclasses import field @@ -367,7 +314,7 @@ machine.channels["IQ2"] = InOutIQChannel( octave.RF_outputs[2].channel = machine.channels["IQ2"].get_reference() octave.RF_inputs[1].channel = machine.channels["IQ2"].get_reference() octave.RF_outputs[2].LO_frequency = 2e9 -octave.RF_inputs[2].LO_frequency = 2e9 +octave.RF_inputs[1].LO_frequency = 2e9 qua_config = machine.generate_config() diff --git a/docs/components/pulses.md b/docs/components/pulses.md index b8dc2b0c..be90d6b0 100644 --- a/docs/components/pulses.md +++ b/docs/components/pulses.md @@ -43,7 +43,7 @@ with program() as prog: channel.play("X180") ``` -## Readout pulses +## Readout Pulses In addition to control pulses, QuAM also supports readout pulses, which are used to measure the state of a quantum system. These pulses should be attached to an input channel, either [InOutIQChannel][quam.components.channels.InOutIQChannel] or [InOutSingleChannel][quam.components.channels.InOutSingleChannel]. @@ -65,7 +65,7 @@ with program() as prog: qua_result = readout_channel.measure("readout") ``` -## Creating custom pulses +## Creating Custom Pulses To create custom pulses in QuAM, you can extend the functionality of the Pulse class by subclassing it and defining your own waveform generation logic. This allows for precise control over the pulse characteristics. ### Example: Creating a Triangular Pulse @@ -88,7 +88,7 @@ class TriangularPulse(pulses.Pulse): ``` Ensure this code is saved in a properly structured Python module within your project so that it can be imported as needed. For details on organizing custom components, refer to the [Custom Components][custom-components] section of the QuAM documentation -### Extending to readout pulses +### Extending to Readout Pulses To create a readout pulse derived from a control pulse, subclass both the specific control pulse and the [ReadoutPulse][quam.components.pulses.ReadoutPulse] class. Below is an example of how to adapt the Triangular Pulse into a readout pulse. ```python @@ -119,7 +119,7 @@ The handling of pulses in QuAM and QUA presents fundamental differences in desig In the QUA configuration, pulses are decomposed into multiple components, such as `"waveforms"` and `"integration_weights"`. These components are defined separately and referenced by name within the `"pulses"` section of the configuration: - **Decomposition**: Each pulse is linked to a specific waveform and optionally, integration weights. This modular approach is more memory-efficient but may lead to fragmented configuration, where information about a single pulse is scattered across multiple sections. -- **Pulse Mapping**: The elements (channels) use a `pulse_mapping` to link a label (e.g., "X180") to a specific pulse setup. This system allows multiple channels to share a pulse, enhancing reusability but potentially complicating pulse modifications. +- **Pulse Mapping**: The elements (channels) use an `operations` mapping to link a label (e.g., "X180") to a specific pulse setup. This system allows multiple channels to share a pulse, enhancing reusability but potentially complicating pulse modifications. - **External Functions**: Typically, the lack of a parametrized representation means that external functions are often required to populate waveform entries. ### QuAM Configuration diff --git a/docs/custom-components.md b/docs/custom-components.md index 761fce25..3dfb8832 100644 --- a/docs/custom-components.md +++ b/docs/custom-components.md @@ -1,11 +1,11 @@ -# Custom QuAM components +# Custom QuAM Components To create custom QuAM components, their classes should be defined in a Python module that can be accessed from Python. The reason for this is that otherwise QuAM cannot load QuAM from a JSON file as it cannot determine where the classes are defined. If you already have a Python module that you use for your own QUA code, it is recommended to add QuAM components to that module. If you don't already have such a module, please follow the guide below. -## Creating a custom Python module +## Creating a Custom Python Module Here we describe how to create a minimal Python module that can be used for your custom QuAM components. In this example, we will give the top-level folder the name `my-quam` and the Python module will be called `my_quam` (note the underscore instead of dash). First create the following folder structure @@ -49,7 +49,7 @@ from my_quam.components import * ``` All the custom QuAM components should be placed as Python files in `my-quam/my_quam/components`. -## Creating a custom QuAM component +## Creating a Custom QuAM Component Once a designated Python module has been chosen / created, it can be populated with a custom component. We will assume that the newly-created Python module `my_quam` is used. In this example, we will make a basic QuAM component representing a DC gate, with two properties: `name` and `dc_voltage`: @@ -113,7 +113,7 @@ An additional benefit is that `kw_only=True` is automatically passed along. From Python 3.10 onwards, `@quam_dataclass` is equivalent to `@dataclass(kw_only=True, eq=False)` /// -## QuAM component subclassing +## QuAM Component Subclassing QuAM components can also be subclassed to add functionalities to the parent class. For example, we now want to combine a DC and AC gate together, where the AC part corresponds to an OPX channel. To do this, we create a class called `AcDcGate` that inherits from both `DcGate` and [quam.components.channels.SingleChannel][]: diff --git a/docs/demonstration.md b/docs/demonstration.md index fe99cf32..9e42bccb 100644 --- a/docs/demonstration.md +++ b/docs/demonstration.md @@ -1,4 +1,4 @@ -# QuAM demonstration +# QuAM Demonstration In this demonstration we will create a basic superconducting setup using standard components. Note that QuAM is not specific to superconducting setups but is meant to serve any quantum platform. @@ -195,7 +195,7 @@ QuAM: /// -## Saving and loading QuAM +## Saving and Loading QuAM Now that we have defined our QuAM structure, we can save its contents to a JSON file: @@ -325,7 +325,7 @@ This JSON file is a serialised representation of QuAM. As a result, QuAM can als loaded_machine = QuAM.load("state.json") ``` -## Generating the QUA configuration +## Generating the QUA Configuration We can also generate the QUA config from QuAM. This recursively calls `QuamComponent.apply_to_config()` on all QuAM components. diff --git a/docs/examples/QuAM features.ipynb b/docs/examples/QuAM features.ipynb index 348a6421..486c80f9 100644 --- a/docs/examples/QuAM features.ipynb +++ b/docs/examples/QuAM features.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# QuAM demonstration" + "# QuAM Demonstration" ] }, { @@ -28,7 +28,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Creating QuAM from scratch" + "## Creating QuAM from Scratch" ] }, { @@ -129,7 +129,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Saving and loading quam" + "## Saving and Loading QuAM" ] }, { @@ -175,7 +175,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Generating QUA config" + "## Generating QUA Configuration" ] }, { @@ -219,7 +219,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Quam using references" + "## QuAM Using References" ] }, { @@ -332,7 +332,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Separating QuAM into multiple files" + "## Separating QuAM into Multiple Files" ] }, { diff --git a/docs/getting-started.md b/docs/getting-started.md index b2e1326f..465db99c 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -1,4 +1,4 @@ -# Getting started +# Getting Started ## :one: Pre-requisites @@ -81,7 +81,7 @@ pip install ./quam If this raises a similar error, it likely means that Python cannot be found. Please check that you have Python installed. If you've set up a virtual environment, please ensure that it has been activated (see `Pre-requisites`). /// -## :three: Next steps +## :three: Next Steps QuAM comes with a range of standard QuAM components that can kick-start experimental setups. An example of these components are used can be found at the [QuAM demonstration](demonstration.md). diff --git a/docs/index.md b/docs/index.md index 2872ed6d..f90d448b 100644 --- a/docs/index.md +++ b/docs/index.md @@ -5,7 +5,7 @@ QuAM is a software framework that provides an abstraction layer for the [QUA pro Whereas QUA, and especially the QUA configuration, approaches quantum control from a generic hardware perspective, QuAM allows the user to interact with the Quantum Orchestration Platform from the physicist's perspective. It does so by providing a framework that allows the creation of abstraction layers, such that instead of channels and waveforms, users can interact with qubits and qubit operations. -## Key features +## Key Features - Standard set of QuAM components (e.g. Mixer, IQChannel) that allow you to digitally represent your quantum setup. - Automated generation of the QUA configuration from QuAM components - Framework for easily extending QuAM with custom classes. diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md index 2434b6d8..6a722e4b 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -12,7 +12,7 @@ Assuming you already have a QUA configuration, the migration process involves tw ## Migrate QUA Configuration to QuAM -### Create a root QuAM object +### Create a Root QuAM Object The QuAM structure needs a top-level [QuamRoot][quam.core.QuamRoot] which has features such as saving/loading QuAM. Typically one would subclass [QuamRoot][quam.core.QuamRoot] and add the necessary components as fields. However, as a basic example, we can use the [BasicQuAM][quam.components.BasicQuAM] class, which contains the fields necessary for the migration. @@ -48,7 +48,7 @@ Here we show how to convert different types of elements to QuAM channels. We don't cover all possible properties, details for this can be found in the [Channels documentation][channels] and the relevant API documentation for each channel type. We also delay the discussion on the `"operations"` field for the next section on pulses. -#### Single analog output channel +#### Single Analog Output Channel In the simplest case, a single output channel is defined in the QUA configuration. @@ -76,7 +76,7 @@ In the simplest case, a single output channel is defined in the QUA configuratio The corresponding QuAM component is the [SingleChannel][quam.components.SingleChannel]. -#### IQ analog output channel +#### IQ Analog Output Channel In the case where the IQ channel is not connected to an @@ -149,7 +149,7 @@ If an Octave is used for upconversion, the IQChannel should be connected to the Detailed instructions can be found at the [Octave documentation][octave]. -#### Single analog output + input channel +#### Single Analog Output + Input Channel In the case where the channel is both an input and output channel, the [InOutSingleChannel][quam.components.InOutSingleChannel] should be used. ```json title='qua_configuration["elements"] - Single input/output channel' diff --git a/docs/quam-references.md b/docs/quam-references.md index 105e5976..5b27a6e0 100644 --- a/docs/quam-references.md +++ b/docs/quam-references.md @@ -1,6 +1,6 @@ -# Referencing between components +# Referencing Between Components -## QuAM tree structure +## QuAM Tree Structure QuAM follows a tree structure, meaning that each QuAM component can have a parent component and it can have children. The top-level object is always an instance of QuAMRoot, e.g. @@ -25,7 +25,7 @@ assert qubit.parent == machine However, situations often arise where a component needs access to another part of QuAM that is not directly one of its children. To accomodate this, we introduce the concept of references. -## QuAM references +## QuAM References A reference in QuAM is a way for a component's attribute to be a reference to another part of QuAM. An example is shown here ```python @@ -42,7 +42,7 @@ As can be seen, the Quam component attribute `component.b` was set to a referenc Quam references follow the JSON pointer syntax (For a description see https://datatracker.ietf.org/doc/html/rfc6901), but further allow for relative references, i.e. references w.r.t the current Quam component. We will next describe the three types of references. -### Absolute references +### Absolute References Absolute references always start with `"#/"`, e.g. `"#/absolute/path/to/value`. They are references from the top-level QuAM object which inherits from `QuamRoot` For example: @@ -53,7 +53,7 @@ machine.qubit = Transmon(frequency="#/frequency") print(machine.qubit.frequency) # Prints 6e9 ``` -### Relative references +### Relative References Relative references start with `"#./"`, e.g. `"#./relative/path/to/value` These are references with respect to the current QuAM component. An example was given above, and is reiterated here: @@ -69,7 +69,7 @@ component.b = "#./a" print(component.b) # Prints 42 ``` -### Relative parent references +### Relative Parent References Relative parent references start with `"#../"`, e.g. `"#../relative/path/from/parent/to/value` These are references with respect to the parent of the current QuAM component. Note that the parent @@ -86,9 +86,9 @@ component.b = "#./a" print(component.b) # Prints 42 ``` -## Additional notes on references +## Additional Notes on References -### Directly overwriting references is not allowed +### Directly Overwriting References is not Allowed Since Quam references behave like regular attributes, the user might accidentally overwrite a reference without realizing it. To prohibit this, it is not possible to directly overwrite a reference: ```python diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 4d932ade..a9948a17 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,92 +1,103 @@ - [data-md-color-scheme="entropy-bright"] { - --md-primary-fg-color: #404044; - --md-accent-fg-color: #3082CF; - --md-typeset-a-color: #3082CF; - --md-footer-bg-color: #404044; - --md-default-bg-color:#E5E5E5; - --md-tabs-color: #464647; + --md-primary-fg-color: #404044; + --md-accent-fg-color: #3082CF; + --md-typeset-a-color: #3082CF; + --md-footer-bg-color: #404044; + --md-default-bg-color: #E5E5E5; + --md-tabs-color: #464647; } + [data-md-color-scheme="entropy-high-contrast"] { - --md-primary-fg-color: #404044; - --md-accent-fg-color: #3082CF; - --md-typeset-a-color: #3082CF; - --md-footer-bg-color: #404044; - --md-default-bg-color:#ffffff; - --md-tabs-color: #464647; - --md-typeset-color: black; + --md-primary-fg-color: #404044; + --md-accent-fg-color: #3082CF; + --md-typeset-a-color: #3082CF; + --md-footer-bg-color: #404044; + --md-default-bg-color: #ffffff; + --md-tabs-color: #464647; + --md-typeset-color: black; } [data-md-color-scheme="entropy-dark"] { - --md-primary-fg-color: #404044; - --md-accent-fg-color: #3082CF; - --md-typeset-a-color: #3082CF; - --md-typeset-color: #C6CDD6; - --md-footer-bg-color: #404044; - --md-default-bg-color:#2B2C32; - --md-code-bg-color:#323339; - --md-default-fg-color:#F6F9FA; - --md-default-fg-color--light: rgba(255,255,255,.54); - --md-default-fg-color--lighter: rgba(255,255,255,.32); - --md-typeset-kbd-color: #323339; - --md-typeset-kbd-accent-color: #2B2C32; - --md-code-fg-color: #F6F9FA; - --md-code-hl-name-color: #C6CDD6; - --md-code-hl-operator-color: #F6F9FA; - --md-code-hl-punctuation-color: #F6F9FA; - --md-code-hl-color: rgba(115, 115, 51, 0.54); - --md-code-hl-comment-color: rgba(255,255,255,.32); - --md-default-fg-color--light: rgba(255,255,255,.54); - --md-default-fg-color--lighter: rgba(255,255,255,.32); - --md-typeset-table-color: rgba(255,255,255,.32); - --md-code-hl-string-color: #00D59A; - --md-code-hl-number-color: #FF2463; - --md-code-hl-keyword-color: #6593ea; - --md-code-hl-constant-color: #6593ea; - --md-code-hl-function-color: #FFDB2C; - --md-tabs-color: #212123; + --md-primary-fg-color: #404044; + --md-accent-fg-color: #3082CF; + --md-typeset-a-color: #3082CF; + --md-typeset-color: #C6CDD6; + --md-footer-bg-color: #404044; + --md-default-bg-color: #2B2C32; + --md-code-bg-color: #323339; + --md-default-fg-color: #F6F9FA; + --md-default-fg-color--light: rgba(255, 255, 255, .54); + --md-default-fg-color--lighter: rgba(255, 255, 255, .32); + --md-typeset-kbd-color: #323339; + --md-typeset-kbd-accent-color: #2B2C32; + --md-code-fg-color: #F6F9FA; + --md-code-hl-name-color: #C6CDD6; + --md-code-hl-operator-color: #F6F9FA; + --md-code-hl-punctuation-color: #F6F9FA; + --md-code-hl-color: rgba(115, 115, 51, 0.54); + --md-code-hl-comment-color: rgba(255, 255, 255, .32); + --md-default-fg-color--light: rgba(255, 255, 255, .54); + --md-default-fg-color--lighter: rgba(255, 255, 255, .32); + --md-typeset-table-color: rgba(255, 255, 255, .32); + --md-code-hl-string-color: #00D59A; + --md-code-hl-number-color: #FF2463; + --md-code-hl-keyword-color: #6593ea; + --md-code-hl-constant-color: #6593ea; + --md-code-hl-function-color: #FFDB2C; + --md-tabs-color: #212123; } -.md-annotation__index::after{ - background-color:#3082CF; - --md-default-fg-color--lightest: #0fafcbb3; + +.md-annotation__index::after { + background-color: #3082CF; + --md-default-fg-color--lightest: #0fafcbb3; } + .md-header__topic:first-child { - font-weight: 700; + font-weight: 700; } + .md-nav__item .md-nav__link--active { - --md-typeset-a-color: #3082CF; + --md-typeset-a-color: #3082CF; } + /* Indentation. */ div.doc-contents:not(.first) { - padding-left: 25px; - border-left: .05rem solid var(--md-typeset-table-color); + padding-left: 25px; + border-left: .05rem solid var(--md-typeset-table-color); } /* Mark external links as such. */ a.autorefs-external::after { - /* https://primer.style/octicons/arrow-up-right-24 */ - background-image: url('data:image/svg+xml,'); - content: ' '; + /* https://primer.style/octicons/arrow-up-right-24 */ + background-image: url('data:image/svg+xml,'); + content: ' '; - display: inline-block; - position: relative; - top: 0.1em; - margin-left: 0.2em; - margin-right: 0.1em; + display: inline-block; + position: relative; + top: 0.1em; + margin-left: 0.2em; + margin-right: 0.1em; - height: 1em; - width: 1em; - border-radius: 100%; - background-color: var(--md-typeset-a-color); + height: 1em; + width: 1em; + border-radius: 100%; + background-color: var(--md-typeset-a-color); } + a.autorefs-external:hover::after { - background-color: var(--md-accent-fg-color); + background-color: var(--md-accent-fg-color); } -.md-header{ - background-color:rgba(30,30,32,0.8); - backdrop-filter: saturate(180%) blur(20px); - -webkit-backdrop-filter: saturate(180%) blur(20px); + +.md-header { + background-color: rgba(30, 30, 32, 0.8); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); } -.md-tabs{ - background-color: var(--md-tabs-color); + +.md-tabs { + background-color: var(--md-tabs-color); +} + +.md-typeset table:not([class]) { + font-size: 0.85rem; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 90a75c18..c077c589 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -44,11 +44,13 @@ extra_css: nav: - index.md - getting-started.md + - migrating-to-quam.md - demonstration.md - "QuAM features": - quam-references.md - "QuAM components": - "components/channels.md" + - "components/pulses.md" - "components/octave.md" - custom-components.md From cbda49048e88f82eed774701266154322a6dc98f Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 25 Apr 2024 20:19:57 +0200 Subject: [PATCH 13/27] using flex rows --- docs/migrating-to-quam.md | 130 ++++++++++++++++++++++++------------- docs/stylesheets/extra.css | 22 +++++++ mkdocs.yml | 4 +- 3 files changed, 109 insertions(+), 47 deletions(-) diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md index 6a722e4b..2244667b 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -51,18 +51,17 @@ We also delay the discussion on the `"operations"` field for the next section on #### Single Analog Output Channel In the simplest case, a single output channel is defined in the QUA configuration. -
- - - - - -
+ +
+
```json title='qua_configuration["elements"]' "qubit_z": { "singleInput": {"port": ("con1", 1)}, "operations": {...} } ``` -
+ +
```python title="QuAM" from quam.components import SingleChannel @@ -70,9 +69,8 @@ In the simplest case, a single output channel is defined in the QUA configuratio opx_output=("con1", 1), ) ``` -
+ + The corresponding QuAM component is the [SingleChannel][quam.components.SingleChannel]. @@ -80,9 +78,9 @@ The corresponding QuAM component is the [SingleChannel][quam.components.SingleCh In the case where the IQ channel is not connected to an - - - - - -
+ +
+
```json title='qua_configuration["elements"]' "qubit_xy": { "intermediate_frequency": 100e6, @@ -95,11 +93,11 @@ In the case where the IQ channel is not connected to an "operations": {...} }, ``` -
+ +
```python title="QuAM" from quam.components import IQChannel + channels["qubit_XY"] = IQChannel( opx_output_I=("con1", 1), opx_output_Q=("con1", 2), @@ -109,17 +107,15 @@ In the case where the IQ channel is not connected to an ) ) ``` -
- - + + If an Octave is used for upconversion, the IQChannel should be connected to the OctaveUpConverter. - - - - - -
+ +
+
```json title='qua_configuration["elements"]' "qubit_xy": { "intermediate_frequency": 100e6, @@ -127,24 +123,23 @@ If an Octave is used for upconversion, the IQChannel should be connected to the "operations": {...} }, ``` -
- ```python + +
+ ```python title="QuAM" from quam.components import IQChannel + # Note the output/input is switched w.r.t. the QUA configuration RF_output = machine.octaves["octave1"].RF_outputs[1] - channel = machine.channels["qubit_xy"] = IQChannel( + + machine.channels["qubit_xy"] = channel = IQChannel( opx_output_I=("con1", 1), opx_output_Q=("con1", 2), frequency_converter_up=RF_output.get_reference() ) RF_output.channel = channel.get_reference() ``` -
- - + + Detailed instructions can be found at the [Octave documentation][octave]. @@ -152,20 +147,65 @@ Detailed instructions can be found at the [Octave documentation][octave]. #### Single Analog Output + Input Channel In the case where the channel is both an input and output channel, the [InOutSingleChannel][quam.components.InOutSingleChannel] should be used. -```json title='qua_configuration["elements"] - Single input/output channel' -"qubit_readout": { - "singleInput": { - "port": ("con1", 1), + +
+
+ ```json title='qua_configuration["elements"]' + "qubit_readout": { + "singleInput": { + "port": ("con1", 1), + }, + "outputs": {"out1": ("con1", 2)}, + "operations": {...} + } + ``` +
+
+ ```python title="QuAM" + from quam.components import InOutSingleChannel + + machine.channels["readout_resonator"] = InOutSingleChannel( + opx_output=("con1", 1), + opx_input=("con1", 2), + ) + ``` +
+
+ +#### IQ Analog Output + Input Channel +In the case where the channel is both an input and output channel with IQ (de)modulation, the [InOutIQChannel][quam.components.InOutIQChannel] should be used. + + +
+
+ ```json title='qua_configuration["elements"]' + "qubit_xy": { + "intermediate_frequency": 100e6, + "RF_inputs": {"port": ["octave1", 1]}, + "RF_outputs": {"port": ["octave1", 1]}, + "operations": {...} }, - "operations": {...} -} -``` -The corresponding QuAM component is the [SingleChannel][quam.components.SingleChannel]. + ``` +
+
+ ```python title="QuAM" + from quam.components import IQChannel + + # Note the output/input is switched w.r.t. the QUA configuration + RF_output = machine.octaves["octave1"].RF_outputs[1] + RF_input = machine.octaves["octave1"].RF_inputs[2] + + machine.channels["qubit_xy"] = channel = IQChannel( + opx_output_I=("con1", 1), + opx_output_Q=("con1", 2), + opx_input_I=("con1", 1), + opx_input_Q=("con1", 2), + frequency_converter_up=RF_output.get_reference() + frequency_converter_down=RF_input.get_reference() + ) + RF_output.channel = channel.get_reference() + ``` +
+
-```python -from quam.components import SingleChannel -machine.channels["qubit_z"] = IQChannel( - opx_output=("con1", 1), -) -``` \ No newline at end of file diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index a9948a17..7f12c14d 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -100,4 +100,26 @@ a.autorefs-external:hover::after { .md-typeset table:not([class]) { font-size: 0.85rem; +} + + +.code-flex-container { + display: flex; + justify-content: space-between; + /* This will space out the flex items evenly */ + align-items: left; + /* This will align items vertically in the center */ + flex-wrap: wrap; + /* Allows items to wrap onto the next line */ +} + +.code-flex-item { + min-width: 500px; + width: 50%; + /* Each item takes up half of the container's width */ + text-align: left; + /* Centers the text inside the flex items */ + padding: 10px; + /* Optional: adds some padding inside each flex item */ + padding-top: 0px; } \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index c077c589..6de82291 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -46,9 +46,9 @@ nav: - getting-started.md - migrating-to-quam.md - demonstration.md - - "QuAM features": + - "QuAM Features": - quam-references.md - - "QuAM components": + - "QuAM Components": - "components/channels.md" - "components/pulses.md" - "components/octave.md" From 86bdb8f65820cdf086a7a1019f27ce817eff9c74 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Sun, 28 Apr 2024 13:55:21 +0200 Subject: [PATCH 14/27] rewriting quam migration --- docs/migrating-to-quam.md | 43 +++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md index 2244667b..36c1bed5 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -1,22 +1,20 @@ # Migrating to QuAM -QuAM serves as an abstraction framework over the QUA programming language. -For users already familiar with QUA, transitioning to QuAM is straightforward. -In this guide, we outline the steps to migrate your existing QUA code to QuAM. +QuAM, the Quantum Abstract Machine, serves as a powerful abstraction framework built over the QUA programming language. This guide aims to facilitate a smooth transition for developers from QUA to QuAM by detailing the necessary steps and modifications. -Assuming you already have a QUA configuration, the migration process involves two steps: +## Overview of Migration Process -1. Migrate the **QUA configuration** to QuAM Use the standard QuAM components. -2. Create **high-level QuAM components** (e.g. qubit) that encapsulate the low-level components and build abstraction layers. - The second step is optional but can significantly help in organizing and simplifying your codebase. +The migration from QUA to QuAM involves two primary stages: -## Migrate QUA Configuration to QuAM +1. **Conversion of the QUA Configuration to QuAM Components:** This step involves translating your existing QUA configurations into QuAM's component-based structure, starting from the root object down to individual channels and pulses. -### Create a Root QuAM Object -The QuAM structure needs a top-level [QuamRoot][quam.core.QuamRoot] which has features such as saving/loading QuAM. -Typically one would subclass [QuamRoot][quam.core.QuamRoot] and add the necessary components as fields. -However, as a basic example, we can use the [BasicQuAM][quam.components.BasicQuAM] class, which contains the fields necessary for the migration. -We call this object the `machine`. +2. **Creation of High-Level QuAM Components:** While optional, defining high-level components such as qubits can significantly enhance the manageability and scalability of your quantum programs by abstracting complex configurations. + +## Step 1: Convert QUA Configuration to QuAM + +### 1. Create a Root QuAM Object + +Begin by establishing a `QuamRoot` object, which serves as the top-level container for all other QuAM components. For simplicity, you can use the pre-defined `BasicQuAM` class: ```python from quam.components import BasicQuAM @@ -35,10 +33,10 @@ from quam.components import Octave, OctaveUpConverter, OctaveDownConverter, Chan machine.octaves["octave1"] = Octave(name="octave1", ip="127.0.0.1", port=80) -# Initialize all frequency converters in the default wiring configuration +# Initialize all frequency converters using the default connectivity to the OPX machine.octave.initialize_frequency_converters() ``` -The [Octave documentation][octave] provides more details on the Octave configuration. +Refer to the [Octave documentation][octave] for further configuration details ### Convert "elements" to Channels The QUA configuration has a section labelled `"elements"`, which corresponds to a pulse processor that can either send or receive signals. @@ -164,7 +162,7 @@ In the case where the channel is both an input and output channel, the [InOutSin ```python title="QuAM" from quam.components import InOutSingleChannel - machine.channels["readout_resonator"] = InOutSingleChannel( + machine.channels["qubit_readout"] = InOutSingleChannel( opx_output=("con1", 1), opx_input=("con1", 2), ) @@ -179,7 +177,7 @@ In the case where the channel is both an input and output channel with IQ (de)mo
```json title='qua_configuration["elements"]' - "qubit_xy": { + "readout_resonator": { "intermediate_frequency": 100e6, "RF_inputs": {"port": ["octave1", 1]}, "RF_outputs": {"port": ["octave1", 1]}, @@ -195,7 +193,7 @@ In the case where the channel is both an input and output channel with IQ (de)mo RF_output = machine.octaves["octave1"].RF_outputs[1] RF_input = machine.octaves["octave1"].RF_inputs[2] - machine.channels["qubit_xy"] = channel = IQChannel( + machine.channels["readout_resonator"] = channel = IQChannel( opx_output_I=("con1", 1), opx_output_Q=("con1", 2), opx_input_I=("con1", 1), @@ -209,3 +207,12 @@ In the case where the channel is both an input and output channel with IQ (de)mo
+## Step 2: Create High-Level QuAM Components (Optional) +This step involves defining more abstract components such as qubits, which can simplify the interaction with the lower-level hardware details: + +See [Custom components][custom-components] for more information on creating custom QuAM components. + +## Conclusion + +By following these steps, you should be able to transition your existing QUA codebase to the more flexible and powerful QuAM framework efficiently. +Remember, the key to a successful migration is understanding the mapping of QUA elements to QuAM components and taking advantage of QuAM's modular design to enhance your quantum programming capabilities. \ No newline at end of file From a77a687874c0f2eb290d3be6b3af40bf5234de92 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 30 Apr 2024 09:43:46 +0200 Subject: [PATCH 15/27] docs: added section on converting pulses --- docs/components/octave.md | 2 +- docs/migrating-to-quam.md | 130 ++++++++++++++++++++++++++++---------- 2 files changed, 98 insertions(+), 34 deletions(-) diff --git a/docs/components/octave.md b/docs/components/octave.md index 1514c6a9..b0bc26a3 100644 --- a/docs/components/octave.md +++ b/docs/components/octave.md @@ -51,7 +51,7 @@ These typically consist of a local oscillator, mixer, as well as IF, LO, and RF For the Octave we have two types of frequency converters: - [OctaveUpConverter][quam.components.octave.OctaveUpConverter]: Used to upconvert a pair of IF signals to an RF signal -- [OctaveDownCovnerter][quam.components.octave.OctaveDownConverter]: Used to downconvert an RF signal to a pair of IF signals +- [OctaveDownConverter][quam.components.octave.OctaveDownConverter]: Used to downconvert an RF signal to a pair of IF signals We can add all relevant frequency converters as follows: diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md index 36c1bed5..01426304 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -4,15 +4,15 @@ QuAM, the Quantum Abstract Machine, serves as a powerful abstraction framework b ## Overview of Migration Process -The migration from QUA to QuAM involves two primary stages: +The migration from QUA to QuAM involves five steps: 1. **Conversion of the QUA Configuration to QuAM Components:** This step involves translating your existing QUA configurations into QuAM's component-based structure, starting from the root object down to individual channels and pulses. 2. **Creation of High-Level QuAM Components:** While optional, defining high-level components such as qubits can significantly enhance the manageability and scalability of your quantum programs by abstracting complex configurations. -## Step 1: Convert QUA Configuration to QuAM + -### 1. Create a Root QuAM Object +## 1: Create a Root QuAM Object Begin by establishing a `QuamRoot` object, which serves as the top-level container for all other QuAM components. For simplicity, you can use the pre-defined `BasicQuAM` class: @@ -20,16 +20,16 @@ Begin by establishing a `QuamRoot` object, which serves as the top-level contain from quam.components import BasicQuAM machine = BasicQuAM() -machine.print_summary() +machine.print_summary() # outputs the current QuAM state ``` Next we populate the root-level `machine` object with QuAM components -### Adding Octaves +## 2: Adding Octaves If you have one or more Octave components, you can add them to the QUA configuration: ```python -from quam.components import Octave, OctaveUpConverter, OctaveDownConverter, Channel +from quam.components import Octave machine.octaves["octave1"] = Octave(name="octave1", ip="127.0.0.1", port=80) @@ -38,17 +38,16 @@ machine.octave.initialize_frequency_converters() ``` Refer to the [Octave documentation][octave] for further configuration details -### Convert "elements" to Channels -The QUA configuration has a section labelled `"elements"`, which corresponds to a pulse processor that can either send or receive signals. +## 3: Convert "elements" to Channels +The QUA configuration has a section labelled `"elements"`, which corresponds to a pulse processor that can send and/or receive signals. Each element has a direct mapping to one of the [quam.components.channels][] in QuAM, though the channel type depends on the element. -Here we show how to convert different types of elements to QuAM channels. -We don't cover all possible properties, details for this can be found in the [Channels documentation][channels] and the relevant API documentation for each channel type. -We also delay the discussion on the `"operations"` field for the next section on pulses. - -#### Single Analog Output Channel -In the simplest case, a single output channel is defined in the QUA configuration. +Here we show how to convert different types of elements to QuAM channels. +We don't cover all possible properties; details for this can be found in the [Channels documentation][channels] and the relevant API documentation for each channel type. +We also postpone the discussion on the `"operations"` field for the next section on pulses. +### Single Analog Output Channel +For straightforward configurations with only a single output port, use the [SingleChannel][quam.components.SingleChannel] in QuAM. This example demonstrates the conversion of a single output setup in QUA to a SingleChannel in QuAM:
@@ -63,19 +62,17 @@ In the simplest case, a single output channel is defined in the QUA configuratio ```python title="QuAM" from quam.components import SingleChannel - machine.channels["qubit_z"] = IQChannel( + machine.channels["qubit_z"] = SingleChannel( opx_output=("con1", 1), ) ```
-The corresponding QuAM component is the [SingleChannel][quam.components.SingleChannel]. - -#### IQ Analog Output Channel -In the case where the IQ channel is not connected to an +### IQ Analog Output Channel +When dealing with IQ modulation, the IQChannel provides the necessary framework. Below are examples of converting an element with IQ outputs and a frequency upconverter:
@@ -94,7 +91,7 @@ In the case where the IQ channel is not connected to an
```python title="QuAM" - from quam.components import IQChannel + from quam.components import IQChannel, FrequencyConverter, LocalOscillator, Mixer channels["qubit_XY"] = IQChannel( opx_output_I=("con1", 1), @@ -108,9 +105,7 @@ In the case where the IQ channel is not connected to an
- -If an Octave is used for upconversion, the IQChannel should be connected to the OctaveUpConverter. - +If an Octave is used for upconversion, the [IQChannel][quam.components.IQChannel] should be connected to the [OctaveUpConverter][quam.components.octave.OctaveUpConverter].
@@ -139,12 +134,11 @@ If an Octave is used for upconversion, the IQChannel should be connected to the
- Detailed instructions can be found at the [Octave documentation][octave]. -#### Single Analog Output + Input Channel -In the case where the channel is both an input and output channel, the [InOutSingleChannel][quam.components.InOutSingleChannel] should be used. +### Single Analog Output + Input Channel +For elements that function as both input and output channels, use [InOutSingleChannel][quam.components.InOutSingleChannel]. This setup allows for efficient bidirectional communication:
@@ -170,9 +164,8 @@ In the case where the channel is both an input and output channel, the [InOutSin
-#### IQ Analog Output + Input Channel -In the case where the channel is both an input and output channel with IQ (de)modulation, the [InOutIQChannel][quam.components.InOutIQChannel] should be used. - +### IQ Analog Output + Input Channel +For complex setups involving both IQ modulation and bidirectional communication, the [InOutIQChannel][quam.components.InOutIQChannel] is the appropriate choice:
@@ -206,13 +199,84 @@ In the case where the channel is both an input and output channel with IQ (de)mo
+## 4: Converting Pulses + +After converting elements into channels, the next step is to configure the pulses. Pulses in QUA are defined across several fields within the configuration, each contributing to how the pulse is shaped and controlled. In QuAM, these properties are consolidated, allowing for a more streamlined and parameterized approach to pulse definition. + +### Overview of QUA Pulse Configuration + +In the QUA configuration, pulses are defined through the following components: + +- **"waveforms"**: These are the actual waveform shapes labeled for reference within pulses. +- **"digital_waveforms"**: Digital signals that can be paired with analog waveforms to control pulse execution. +- **"integration_weights"**: Used for defining how signals are integrated during readout. +- **"pulses"**: This is a collection of pulse definitions, specifying labels, duration, and type of operation (`"control"` or `"measurement"`). Pulses may reference waveforms, digital waveforms, and integration weights specified in the other fields. +- **`element["operations"]`**: Maps operation names to specific pulses defined in the `"pulses"` collection, linking them to the relevant channel. + +### QuAM Pulse Configuration + +In QuAM, pulse properties are grouped and parameterized by pulse type, simplifying the configuration process. Here is how you would convert a typical pulse setup from QUA to QuAM: + +#### Example: Converting a Constant Voltage Pulse + +Consider a QUA pulse configured to deliver a constant voltage. In QuAM, this corresponds to the [SquarePulse][quam.components.pulses.SquarePulse] component, which is designed for straightforward amplitude modulation. + +**QUA Configuration:** + +```json +{ + "elements": { + "qubit_xy": { + "intermediate_frequency": 100e6, + "mixInputs": { + "I": ["con1", 1], + "Q": ["con1", 2], + "lo_frequency": 5e9, + "mixer": "mixer_qubit" + }, + "operations": { + "const_pulse": "const_pulse" + } + } + }, + "pulses": { + "const_pulse": { + "operation": "control", + "length": 1000, + "waveforms": {"I": "const_wf", "Q": "zero_wf"} + } + }, + "waveforms": { + "const_wf": {"type": "constant", "sample": 0.5}, + "zero_wf": {"type": "constant", "sample": 0.0} + } +} +``` + +**QuAM Conversion:** + +```python +from quam.components import pulses + +# Assuming qubit_xy is configured as an IQChannel +qubit_xy.operations["const_pulse"] = pulses.SquarePulse( + length=1000, + amplitude=0.5, + axis_angle=0 # Phase angle on the IQ plane +) +``` + +This example highlights the transformation of a basic pulse from QUA into a QuAM `SquarePulse`, demonstrating the streamlined approach QuAM offers for pulse configuration. + +For comprehensive details on configuring different types of pulses in QuAM, refer to the [Pulses Documentation][pulses]. + -## Step 2: Create High-Level QuAM Components (Optional) -This step involves defining more abstract components such as qubits, which can simplify the interaction with the lower-level hardware details: +## 5: Create High-Level QuAM Components (Optional) +After converting the QUA configuration +This step involves defining more abstract components, which can simplify the interaction with the lower-level hardware details. See [Custom components][custom-components] for more information on creating custom QuAM components. ## Conclusion -By following these steps, you should be able to transition your existing QUA codebase to the more flexible and powerful QuAM framework efficiently. -Remember, the key to a successful migration is understanding the mapping of QUA elements to QuAM components and taking advantage of QuAM's modular design to enhance your quantum programming capabilities. \ No newline at end of file +Following these steps will guide you through transitioning your existing QUA codebase to QuAM. The primary goal of this migration is to harness QuAM's abstraction capabilities to organize and manage the underlying quantum-computing elements. QuAM provides a structured way to encapsulate the complexity of your configurations, which can facilitate maintenance and scalability. By understanding the mapping of QUA elements to QuAM components, you can effectively utilize this abstraction layer to enhance the organization of your quantum programs. From 25f383571a06912c45f4a121dfe9291846935310 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 30 Apr 2024 11:45:08 +0200 Subject: [PATCH 16/27] finished version on migration --- docs/migrating-to-quam.md | 45 +++++++++++++++++++++++++++++++++++---- mkdocs.yml | 6 +++--- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md index 01426304..1c8bff54 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -211,7 +211,7 @@ In the QUA configuration, pulses are defined through the following components: - **"digital_waveforms"**: Digital signals that can be paired with analog waveforms to control pulse execution. - **"integration_weights"**: Used for defining how signals are integrated during readout. - **"pulses"**: This is a collection of pulse definitions, specifying labels, duration, and type of operation (`"control"` or `"measurement"`). Pulses may reference waveforms, digital waveforms, and integration weights specified in the other fields. -- **`element["operations"]`**: Maps operation names to specific pulses defined in the `"pulses"` collection, linking them to the relevant channel. +- **element["operations"]**: Maps operation names to specific pulses defined in the `"pulses"` collection, linking them to the relevant channel. ### QuAM Pulse Configuration @@ -271,9 +271,46 @@ This example highlights the transformation of a basic pulse from QUA into a QuAM For comprehensive details on configuring different types of pulses in QuAM, refer to the [Pulses Documentation][pulses]. -## 5: Create High-Level QuAM Components (Optional) -After converting the QUA configuration -This step involves defining more abstract components, which can simplify the interaction with the lower-level hardware details. +## 5: Generating the QUA configuration +Once the QUA configuration has been converted to QuAM, QuAM can in turn be used to generate the QUA configuration: + +```python +qua_config = machine.generate_config() +``` + +This `qua_config` can then be used to create a `QuantumMachine` object, which can be used to run quantum programs on the OPX. + +## 6: Create High-Level QuAM Components (Optional) +After converting the QUA configuration to the corresponding QuAM components, an optional next step is to group similar components into higher-level abstractions. +As an example, in the code above we had multiple channels belonging to the same qubit (`qubit_xy`, `qubit_z`, `qubit_readout`). +We can group these channels into a single `Qubit` object to simplify the management of the qubit's configuration: + +```python +from quam.core import QuamComponent, quam_dataclass +from quam.components import SingleChannel, IQChannel, InOutSingleChannel + +@quam_dataclass +class Qubit(QuamComponent): + xy: IQChannel + z: SingleChannel + readout: InOutSingleChannel + +qubit = Qubit(xy=qubit_xy, z=qubit_z, readout=qubit_readout) +``` + +This `Qubit` object can then be used to access the individual channels and their associated pulses, simplifying the management of the qubit's configuration. + +Note that the root-level QuAM object also needs to be customized to support the new `Qubit` object: +```python +from typing import Dict +from quam.core import QuamRoot + +@quam_dataclass +class QuAM(QuamRoot): + qubits: Dict[str, Qubit] + +machine = QuAM(qubits={"qubit1": qubit}) +``` See [Custom components][custom-components] for more information on creating custom QuAM components. diff --git a/mkdocs.yml b/mkdocs.yml index 6de82291..77e9c28c 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -44,15 +44,15 @@ extra_css: nav: - index.md - getting-started.md - - migrating-to-quam.md - demonstration.md - - "QuAM Features": - - quam-references.md - "QuAM Components": - "components/channels.md" - "components/pulses.md" - "components/octave.md" - custom-components.md + - "QuAM Features": + - quam-references.md + - migrating-to-quam.md plugins: # - mkdocs-jupyter: From 02a80e17da520deb3a2d8fa9f72116c8961f2b46 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 30 Apr 2024 11:51:29 +0200 Subject: [PATCH 17/27] docs: rewrote overview section --- docs/migrating-to-quam.md | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/migrating-to-quam.md b/docs/migrating-to-quam.md index 1c8bff54..2fa5b729 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -4,13 +4,21 @@ QuAM, the Quantum Abstract Machine, serves as a powerful abstraction framework b ## Overview of Migration Process -The migration from QUA to QuAM involves five steps: +Migrating from QUA to QuAM involves a structured, five-step process that methodically transitions your existing quantum programming framework. Here's a brief overview of each step: -1. **Conversion of the QUA Configuration to QuAM Components:** This step involves translating your existing QUA configurations into QuAM's component-based structure, starting from the root object down to individual channels and pulses. +1. **Create a Root QuAM Object:** Start by establishing a foundational `QuamRoot` object that serves as the top-level container for all other QuAM components. This is where you'll begin building your new QuAM configuration. -2. **Creation of High-Level QuAM Components:** While optional, defining high-level components such as qubits can significantly enhance the manageability and scalability of your quantum programs by abstracting complex configurations. +2. **Add Octaves:** If your original QUA setup includes Octave components, this step involves integrating these components into the QuAM configuration, utilizing existing connectivity settings. - +3. **Convert "elements" to Channels:** Each element in the QUA configuration that handles signal processing is mapped to a corresponding channel type in QuAM. This critical step ensures that the functional properties of your setup are preserved and adapted to the new architecture. + +4. **Convert Pulses:** After setting up the channels, the next step is to configure the pulses. This involves translating QUA pulse specifications into QuAM's consolidated and parameterized pulse framework. + +5. **Generate the QUA configuration:** Once the QuAM structure has been created and populated, you can generate the QUA configuration using the QuAM object. This configuration can then be used to run quantum programs on the OPX. + +5. **Create High-Level QuAM Components (Optional):** This final step is about abstracting complex configurations into high-level components like qubits, which can simplify the management and scalability of your quantum programs. + +Each of these steps is designed to ensure a seamless transition to QuAM, leveraging its robust abstraction capabilities to manage and organize your quantum computing elements more effectively. ## 1: Create a Root QuAM Object @@ -26,7 +34,7 @@ machine.print_summary() # outputs the current QuAM state Next we populate the root-level `machine` object with QuAM components -## 2: Adding Octaves +## 2: Add Octaves If you have one or more Octave components, you can add them to the QUA configuration: ```python from quam.components import Octave @@ -199,7 +207,7 @@ For complex setups involving both IQ modulation and bidirectional communication,
-## 4: Converting Pulses +## 4: Convert Pulses After converting elements into channels, the next step is to configure the pulses. Pulses in QUA are defined across several fields within the configuration, each contributing to how the pulse is shaped and controlled. In QuAM, these properties are consolidated, allowing for a more streamlined and parameterized approach to pulse definition. @@ -271,7 +279,7 @@ This example highlights the transformation of a basic pulse from QUA into a QuAM For comprehensive details on configuring different types of pulses in QuAM, refer to the [Pulses Documentation][pulses]. -## 5: Generating the QUA configuration +## 5: Generate the QUA configuration Once the QUA configuration has been converted to QuAM, QuAM can in turn be used to generate the QUA configuration: ```python From 700e9b5b11fb5caab9ac3f1af85104548061ed60 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 30 Apr 2024 14:09:15 +0200 Subject: [PATCH 18/27] docs: added index pages --- docs/{ => components}/custom-components.md | 7 ++-- docs/components/index.md | 25 +++++++++++++ docs/features/index.md | 10 ++++++ docs/{ => features}/quam-references.md | 0 docs/index.md | 38 ++++++++++++++------ docs/{getting-started.md => installation.md} | 2 +- mkdocs.yml | 8 +++-- 7 files changed, 72 insertions(+), 18 deletions(-) rename docs/{ => components}/custom-components.md (93%) create mode 100644 docs/components/index.md create mode 100644 docs/features/index.md rename docs/{ => features}/quam-references.md (100%) rename docs/{getting-started.md => installation.md} (99%) diff --git a/docs/custom-components.md b/docs/components/custom-components.md similarity index 93% rename from docs/custom-components.md rename to docs/components/custom-components.md index 3dfb8832..d75f4b7e 100644 --- a/docs/custom-components.md +++ b/docs/components/custom-components.md @@ -71,7 +71,7 @@ dc_gate = DcGate(id="plunger_gate", dc_voltage=0.43) A few notes about the above: -- Each QuamComponent inherits from [quam.core.quam_classes.QuamComponent][]. +- Each QuamComponent inherits from [QuamComponent][quam.core.quam_classes.QuamComponent]. - QuAM components are decorated with `@quam_dataclass`, which is a variant of the Python [@dataclass](https://docs.python.org/3/library/dataclasses.html). /// details | Reason for `@quam_dataclass` instead of `@dataclass` @@ -116,7 +116,7 @@ From Python 3.10 onwards, `@quam_dataclass` is equivalent to `@dataclass(kw_only ## QuAM Component Subclassing QuAM components can also be subclassed to add functionalities to the parent class. For example, we now want to combine a DC and AC gate together, where the AC part corresponds to an OPX channel. -To do this, we create a class called `AcDcGate` that inherits from both `DcGate` and [quam.components.channels.SingleChannel][]: +To do this, we create a class called `AcDcGate` that inherits from both `DcGate` and [SingleChannel][quam.components.channels.SingleChannel]: ```python from quam.components import SingleChannel @@ -124,6 +124,7 @@ from quam.components import SingleChannel @quam_dataclass class AcDcGate(DcGate, SingleChannel): + pass ``` It can be instantiated using @@ -131,4 +132,4 @@ It can be instantiated using ac_dc_gate = AcDcGate(id="plunger_gate", dc_voltage=0.43, opx_output=("con1", 1)) ``` -Notice that the keyword argument `opx_output` now also needs to be passed. This is because it's a required argument for [quam.components.channels.SingleChannel][]. +Notice that the keyword argument `opx_output` now also needs to be passed. This is because it's a required argument for [SingleChannel][quam.components.channels.SingleChannel]. diff --git a/docs/components/index.md b/docs/components/index.md new file mode 100644 index 00000000..9f5c7bdf --- /dev/null +++ b/docs/components/index.md @@ -0,0 +1,25 @@ +# QuAM Components + +The components section of the Quantum Abstract Machine (QuAM) documentation outlines the modular parts of the QuAM framework, each designed to enable flexible and efficient quantum programming. Below, you'll find an overview of the main components that you can utilize and extend in your quantum projects. + +## Channels +Channels are fundamental building blocks in QuAM that facilitate the routing of quantum signals to various hardware components. They serve as the conduits for pulses and other quantum operations, translating abstract quantum actions into physical outcomes on a quantum processor. + +- **[Channels Documentation](channels.md)**: Explore the detailed documentation on different types of channels including IQ Channels, Single Analog Output Channels, and more. + +## Pulses +Pulses in QuAM are used to manipulate qubit states through precise control over their quantum properties. These are defined with specific parameters like amplitude, duration, and waveform, allowing detailed control over quantum operations. + +- **[Pulses Documentation](pulses.md)**: Learn how to define and use different types of pulses such as Gaussian, Square, and DRAG pulses in your quantum circuits. + +## Octave +The Octave component in QuAM handles the upconversion and downconversion of frequencies, enabling high-fidelity signal processing for quantum experiments. This is particularly important for setups requiring complex signal manipulations across multiple frequency bands. + +- **[Octave Documentation](octave.md)**: Discover how to integrate and configure Octave components to work seamlessly within your QuAM environment. + +## Custom QuAM Components +For users looking to expand beyond the standard QuAM toolkit, custom components provide a way to introduce novel functionalities tailored to specific quantum computing needs or experimental setups. + +- **[Custom Components Documentation](custom-components.md)**: Get guidance on how to develop and integrate your own custom components into the QuAM framework. + +Each component is designed with modularity and integration in mind, ensuring that users can build and customize their quantum computing environments effectively. For more detailed instructions and examples, visit the individual documentation pages linked above. diff --git a/docs/features/index.md b/docs/features/index.md new file mode 100644 index 00000000..d7dc3013 --- /dev/null +++ b/docs/features/index.md @@ -0,0 +1,10 @@ +# QuAM Features + +The features section of the Quantum Abstract Machine (QuAM) documentation highlights the unique capabilities and functionalities that enhance the usability and performance of the QuAM framework. Here, you will find detailed explanations and examples of how to leverage these features in your quantum projects. + +## QuAM Referencing +QuAM referencing is a sophisticated feature designed to streamline the management and modification of quantum configurations. It allows users to define relationships and dependencies between various components within a QuAM setup, facilitating easier updates and scalability. + +- **[QuAM Referencing Documentation](features/quam-references.md)**: Learn about the syntax and usage of QuAM’s powerful referencing system. This feature simplifies the process of modifying and scaling quantum experiments by allowing users to reference previously defined elements, parameters, and configurations, thus avoiding redundancy and reducing the potential for errors. + +This section of the documentation provides insights into the foundational features that make QuAM a robust and adaptable framework for quantum computing. Explore the detailed documentation to fully utilize these features in your work. diff --git a/docs/quam-references.md b/docs/features/quam-references.md similarity index 100% rename from docs/quam-references.md rename to docs/features/quam-references.md diff --git a/docs/index.md b/docs/index.md index f90d448b..e3202175 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,13 +1,29 @@ # Welcome to QuAM -Welcome to the documentation for QuAM (Quantum Abstraction Machine). -QuAM is a software framework that provides an abstraction layer for the [QUA programming language](https://docs.quantum-machines.co/). -Whereas QUA, and especially the QUA configuration, approaches quantum control from a generic hardware perspective, QuAM allows the user to interact with the Quantum Orchestration Platform from the physicist's perspective. -It does so by providing a framework that allows the creation of abstraction layers, such that instead of channels and waveforms, users can interact with qubits and qubit operations. - -## Key Features -- Standard set of QuAM components (e.g. Mixer, IQChannel) that allow you to digitally represent your quantum setup. -- Automated generation of the QUA configuration from QuAM components -- Framework for easily extending QuAM with custom classes. - This allows you to build abstraction layers to manage even the most complex quantum setups. -- Saving / loading your QuAM state. \ No newline at end of file +**Empowering Quantum Innovation with Enhanced Abstraction** + +Welcome to the official documentation for the Quantum Abstract Machine (QuAM), a software framework designed to enhance the user experience of quantum computing by providing an abstraction layer over the [QUA programming language](https://docs.quantum-machines.co/). QuAM allows users, particularly physicists, to interact with the Quantum Orchestration Platform more intuitively, shifting from a hardware-centric to a physicist-friendly approach. + +## What is QuAM? +QuAM stands out by transforming the way quantum control is perceived and implemented. While QUA and its configurations tackle quantum control from a generic hardware perspective, QuAM introduces a higher level of abstraction. It allows you to think in terms of qubits and quantum operations rather than just channels and waveforms, aligning more closely with the thought processes of physicists. + +## Why Choose QuAM? +QuAM is not just a tool but a gateway to streamlined and efficient quantum computing: + +- **Component-Based Setup:** Utilize a standard set of QuAM components like Mixers and IQChannels to digitally represent and manipulate your quantum environment. +- **Automated Configuration:** Automatically generate the necessary QUA configuration from your QuAM setup, simplifying the transition from design to deployment. +- **Extensibility:** Easily extend QuAM with custom classes to accommodate complex quantum setups, providing flexibility and power in your quantum computing applications. +- **State Management:** Effortlessly save and load your QuAM state, enabling consistent results and reproducibility in experiments. + +## Getting Started + +- **[QuAM Installation](installation.md):** Set up QuAM on your system and get ready to explore its capabilities. +- **[QuAM Components](components/index.md):** Explore the core components that form the building blocks of the QuAM architecture. +- **[QuAM Features](features/index.md):** Discover the unique features and capabilities that QuAM offers for your quantum projects. +- **[QuAM Demonstration](demonstration.md):** Witness QuAM in action with practical examples and hands-on tutorials. +- **[QuAM Migration](migrating-to-quam.md)**: Already using QUA? Our detailed guide on [migrating-to-quam] and tools are designed for a smooth transition to QuAM, letting you migrate your existing projects without hassle. + +## Explore More +Delve into our detailed reference materials and API documentation to fully leverage QuAM’s capabilities and optimize your quantum applications. + +We are thrilled to support your journey into the quantum future with QuAM. Together, let's push the boundaries of what's possible in quantum computing! diff --git a/docs/getting-started.md b/docs/installation.md similarity index 99% rename from docs/getting-started.md rename to docs/installation.md index 465db99c..855b1a0c 100644 --- a/docs/getting-started.md +++ b/docs/installation.md @@ -1,4 +1,4 @@ -# Getting Started +# QuAM Installation ## :one: Pre-requisites diff --git a/mkdocs.yml b/mkdocs.yml index 77e9c28c..3def384b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,15 +43,17 @@ extra_css: nav: - index.md - - getting-started.md + - installation.md - demonstration.md - "QuAM Components": + - "components/index.md" - "components/channels.md" - "components/pulses.md" - "components/octave.md" - - custom-components.md + - "components/custom-components.md" - "QuAM Features": - - quam-references.md + - "features/index.md" + - "features/quam-references.md" - migrating-to-quam.md plugins: From 9c01d997d096550936aa453e54882923f8e029d0 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 30 Apr 2024 14:21:29 +0200 Subject: [PATCH 19/27] Update readme --- README.md | 80 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 337eb880..b3cc0b91 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,65 @@ -# QuAM (Quantum Abstract Machine) - -Welcome to QuAM! -The documentation is currently being added to the QM documentation. In the mean time, -you can view the documentation files in `docs`. -In particular, this includes installation instructions at `docs/getting-started.md`. - -You can also run the documentation website locally as follows: -1. Open terminal / Powershell and navigate to the root QuAM folder -2. Ensure you are in a virtual environment. - See installation instructions in `docs/getting-started.md` for details -2. Run the following commands: -``` -pip install ".[docs]" -mkdocs serve +Here's a README template for the QuAM GitHub repository front page. This README provides a concise overview of QuAM, useful links, installation instructions, and a placeholder for code examples: + +--- + +# QuAM: Quantum Abstract Machine + +## Overview +QuAM (Quantum Abstract Machine) is an innovative software framework designed to provide an abstraction layer over the QUA programming language, facilitating a more intuitive interaction with quantum computing platforms. Aimed primarily at physicists and researchers, QuAM allows users to think and operate in terms of qubits and quantum operations rather than the underlying hardware specifics. + +Explore detailed documentation and get started with QuAM here: [QuAM Documentation](ENTER_URL_HERE). + +## Key Features +- **Abstraction Layer**: Simplifies quantum programming by providing higher-level abstractions for qubit operations. +- **Component-Based Structure**: Utilize modular components like Mixers and IQChannels for flexible quantum circuit design. +- **Automated Configuration**: Generate QUA configurations from QuAM setups seamlessly. +- **Extensibility**: Extend QuAM with custom classes to handle complex quantum computing scenarios. +- **State Management**: Features robust tools for saving and loading your quantum states, promoting reproducibility and consistency. + +## Installation +To install QuAM, follow these simple steps: + +1. Ensure you have Python 3.x installed on your system. +2. Clone the repository: + ```bash + git clone https://github.com/qua-platform/quam.git + ``` +3. Navigate to the cloned directory and install the required dependencies: + ```bash + cd quam + pip install . + ``` + +## Quick Start +Here’s a basic example to get you started with QuAM: + +```python +from quam.components import BasicQuAM, SingleChannel, pulses + +# Create a root-level QuAM instance +machine = BasicQuAM() + +# Add an OPX output channel +channel = SingleChannel(opx_output=("con1", 1)) +machine.channels["output"] = channel + +# Add a Gaussian pulse to the channel +channel.operations["gaussian"] = pulses.Gaussian( + length=100, # Pulse length in ns + amplitude=0.5, # Peak amplitude of Gaussian pulse + sigma=20, # Standard deviation of Guassian pulse +) + +# Play the Gaussian pulse on the channel within a QUA program +with program() as prog: + channel.play("gaussian") + +# Generate the QUA configuration from QuAM +qua_configuration = machine.generate_config() ``` -3. Navigate to `127.0.0.1:8000` \ No newline at end of file + +Replace `ENTER_CODE_HERE` with an actual QuAM code snippet that demonstrates a simple operation or setup. + + +## License +QuAM is released under the BSD-3 License. See the LICENSE file for more details. From b6aac597cced268c83197be467aafddce84b8e96 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Tue, 30 Apr 2024 15:03:04 +0200 Subject: [PATCH 20/27] docs: Add readme and code example --- README.md | 5 ++--- docs/index.md | 31 ++++++++++++++++++++++++++++++- mkdocs.yml | 1 + 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b3cc0b91..e8d068f3 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Here's a README template for the QuAM GitHub repository front page. This README QuAM (Quantum Abstract Machine) is an innovative software framework designed to provide an abstraction layer over the QUA programming language, facilitating a more intuitive interaction with quantum computing platforms. Aimed primarily at physicists and researchers, QuAM allows users to think and operate in terms of qubits and quantum operations rather than the underlying hardware specifics. Explore detailed documentation and get started with QuAM here: [QuAM Documentation](ENTER_URL_HERE). + ## Key Features - **Abstraction Layer**: Simplifies quantum programming by providing higher-level abstractions for qubit operations. @@ -19,7 +20,7 @@ Explore detailed documentation and get started with QuAM here: [QuAM Documentati ## Installation To install QuAM, follow these simple steps: -1. Ensure you have Python 3.x installed on your system. +1. Ensure you have Python ≥ 3.8 installed on your system. 2. Clone the repository: ```bash git clone https://github.com/qua-platform/quam.git @@ -58,8 +59,6 @@ with program() as prog: qua_configuration = machine.generate_config() ``` -Replace `ENTER_CODE_HERE` with an actual QuAM code snippet that demonstrates a simple operation or setup. - ## License QuAM is released under the BSD-3 License. See the LICENSE file for more details. diff --git a/docs/index.md b/docs/index.md index e3202175..0b4621b7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,13 +8,42 @@ Welcome to the official documentation for the Quantum Abstract Machine (QuAM), a QuAM stands out by transforming the way quantum control is perceived and implemented. While QUA and its configurations tackle quantum control from a generic hardware perspective, QuAM introduces a higher level of abstraction. It allows you to think in terms of qubits and quantum operations rather than just channels and waveforms, aligning more closely with the thought processes of physicists. ## Why Choose QuAM? -QuAM is not just a tool but a gateway to streamlined and efficient quantum computing: + +QuAM is not just a tool but a gateway to streamlined and efficient quantum computing: + - **Component-Based Setup:** Utilize a standard set of QuAM components like Mixers and IQChannels to digitally represent and manipulate your quantum environment. - **Automated Configuration:** Automatically generate the necessary QUA configuration from your QuAM setup, simplifying the transition from design to deployment. - **Extensibility:** Easily extend QuAM with custom classes to accommodate complex quantum setups, providing flexibility and power in your quantum computing applications. - **State Management:** Effortlessly save and load your QuAM state, enabling consistent results and reproducibility in experiments. +```python +from quam.components import BasicQuAM, SingleChannel, pulses + +# Create a root-level QuAM instance +machine = BasicQuAM() + +# Add an OPX output channel +channel = SingleChannel(opx_output=("con1", 1)) +machine.channels["output"] = channel + +# Add a Gaussian pulse to the channel +channel.operations["gaussian"] = pulses.Gaussian( + length=100, # Pulse length in ns + amplitude=0.5, # Peak amplitude of Gaussian pulse + sigma=20, # Standard deviation of Guassian pulse +) + +# Play the Gaussian pulse on the channel within a QUA program +with program() as prog: + channel.play("gaussian") + +# Generate the QUA configuration from QuAM +qua_configuration = machine.generate_config() +``` + + + ## Getting Started - **[QuAM Installation](installation.md):** Set up QuAM on your system and get ready to explore its capabilities. diff --git a/mkdocs.yml b/mkdocs.yml index 3def384b..b3614ecd 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -72,6 +72,7 @@ plugins: paths: [quam] markdown_extensions: + - md_in_html - pymdownx.blocks.tab: # Add tabs to markdown using: === "title" alternate_style: true # Somehow this is required for tabs to work - pymdownx.blocks.details # Enable collapsible elements, e.g.: ??? tip "title" From 9400469feb05d3af1051f9abfae95f8409a51698 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Wed, 1 May 2024 11:17:16 +0200 Subject: [PATCH 21/27] docs: allow html in div --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index b3614ecd..cc490509 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -72,7 +72,7 @@ plugins: paths: [quam] markdown_extensions: - - md_in_html + - md_in_html # Add markdown within html
tags - pymdownx.blocks.tab: # Add tabs to markdown using: === "title" alternate_style: true # Somehow this is required for tabs to work - pymdownx.blocks.details # Enable collapsible elements, e.g.: ??? tip "title" From dc2433c6aa86a588eb1a89103552ecc0bc58353b Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Thu, 2 May 2024 20:25:09 +0200 Subject: [PATCH 22/27] reference fixes --- .../API_references/components/channels_API.md | 3 +++ .../API_references/components/hardware_API.md | 3 +++ docs/API_references/components/octave_API.md | 11 ++++++++++ docs/API_references/components/pulses_API.md | 9 ++++++++ docs/API_references/core/quam_classes_API.md | 11 ++++++++++ .../API_references/core/quam_instantiation.md | 0 docs/API_references/index.md | 21 +++++++++++++++++++ docs/components/index.md | 2 +- docs/components/pulses.md | 4 ++-- docs/features/index.md | 2 +- docs/gen_ref_pages.py | 2 +- docs/index.md | 17 ++++++++------- docs/installation.md | 2 +- docs/migrating-to-quam.md | 2 +- mkdocs.yml | 8 +++++++ quam/components/channels.py | 3 +-- 16 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 docs/API_references/components/channels_API.md create mode 100644 docs/API_references/components/hardware_API.md create mode 100644 docs/API_references/components/octave_API.md create mode 100644 docs/API_references/components/pulses_API.md create mode 100644 docs/API_references/core/quam_classes_API.md create mode 100644 docs/API_references/core/quam_instantiation.md create mode 100644 docs/API_references/index.md diff --git a/docs/API_references/components/channels_API.md b/docs/API_references/components/channels_API.md new file mode 100644 index 00000000..cacb6991 --- /dev/null +++ b/docs/API_references/components/channels_API.md @@ -0,0 +1,3 @@ +# QuAM Channels API + +::: quam.components.channels \ No newline at end of file diff --git a/docs/API_references/components/hardware_API.md b/docs/API_references/components/hardware_API.md new file mode 100644 index 00000000..2fa536ef --- /dev/null +++ b/docs/API_references/components/hardware_API.md @@ -0,0 +1,3 @@ +# QuAM Hardware API + +::: quam.components.hardware \ No newline at end of file diff --git a/docs/API_references/components/octave_API.md b/docs/API_references/components/octave_API.md new file mode 100644 index 00000000..14b3f80e --- /dev/null +++ b/docs/API_references/components/octave_API.md @@ -0,0 +1,11 @@ +# Welcome to the QuAM Octave API Documentation + +The Octave component in the Quantum Abstract Machine (QuAM) manages signal upconversion and downconversion through its frequency converters. This section provides an API guide for setting up and customizing the Octave, detailing its integration with quantum processors for efficient signal processing. Explore the capabilities, configuration options, and practical examples to enhance your quantum operations with Octave's advanced functionalities. + +::: quam.components.octave + options: + members: + - Octave + - OctaveFrequencyConverter + - OctaveUpConverter + - OctaveDownConverter diff --git a/docs/API_references/components/pulses_API.md b/docs/API_references/components/pulses_API.md new file mode 100644 index 00000000..12df6b95 --- /dev/null +++ b/docs/API_references/components/pulses_API.md @@ -0,0 +1,9 @@ +# QuAM Pulses API + +Welcome to the QuAM Pulses API Documentation. +The QuAM Pulses module offers a versatile framework for creating and controlling pulse schemes essential for quantum operations. +Information can be found in [QuAM Pulses Documentation](components/pulses) in the User Guide. + +This section provides detailed API references for various pulse types—ranging from simple waveforms to complex modulated pulses—tailored for precise quantum state manipulation and measurement. Explore the properties, methods, and examples to effectively integrate these pulse components into your quantum experiments. + +::: quam.components.pulses \ No newline at end of file diff --git a/docs/API_references/core/quam_classes_API.md b/docs/API_references/core/quam_classes_API.md new file mode 100644 index 00000000..2fda0cc7 --- /dev/null +++ b/docs/API_references/core/quam_classes_API.md @@ -0,0 +1,11 @@ +# QuAM Classes API + +::: quam.core.quam_classes + handler: python + options: + members: + - QuamBase + - QuamRoot + - QuamComponent + - QuamDict + - QuamList \ No newline at end of file diff --git a/docs/API_references/core/quam_instantiation.md b/docs/API_references/core/quam_instantiation.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/API_references/index.md b/docs/API_references/index.md new file mode 100644 index 00000000..4d78b16a --- /dev/null +++ b/docs/API_references/index.md @@ -0,0 +1,21 @@ +# QuAM API Reference + +Welcome to the API Reference section of the Quantum Abstract Machine (QuAM) documentation. Here, you'll find comprehensive details on all components, classes, and methods that make up the QuAM framework. This documentation is designed to help developers understand and effectively utilize the powerful capabilities of QuAM for quantum computing applications. + +## Quick Links + +- [**Core Components**](/API_references/core/quam_classes_API.md) + Details on fundamental building blocks like [QuamBase][quam.core.quam_classes.QuamBase], [QuamComponent][quam.core.quam_classes.QuamComponent] and [QuamRoot][quam.core.quam_classes.QuamRoot]. + [QuamBase][quam.core.quam_classes.QuamBase] + +- [**Channel Components**](/API_references/components/channels_API.md) + Learn about channel configurations and their operations within the QuAM framework. + +- [**Pulse Components**](/API_references/components/pulses_API.md) + A detailed look at various pulse types and their properties used in quantum operations. + +- [**Hardware Components**](/API_references/components/hardware_API.md) + Explore the hardware-related classes such as [Mixer][quam.components.hardware.Mixer], [LocalOscillator][quam.components.hardware.LocalOscillator], and [FrequencyConverter][quam.components.hardware.FrequencyConverter]. + +- [**Octave Components**](/API_references/components/octave_API.md) + Documentation on the `Octave` component and its associated up and down converters. diff --git a/docs/components/index.md b/docs/components/index.md index 9f5c7bdf..7ba55665 100644 --- a/docs/components/index.md +++ b/docs/components/index.md @@ -20,6 +20,6 @@ The Octave component in QuAM handles the upconversion and downconversion of freq ## Custom QuAM Components For users looking to expand beyond the standard QuAM toolkit, custom components provide a way to introduce novel functionalities tailored to specific quantum computing needs or experimental setups. -- **[Custom Components Documentation](custom-components.md)**: Get guidance on how to develop and integrate your own custom components into the QuAM framework. +- **[Custom QuAM Components](/components/custom-components)**: Get guidance on how to develop and integrate your own custom components into the QuAM framework. Each component is designed with modularity and integration in mind, ensuring that users can build and customize their quantum computing environments effectively. For more detailed instructions and examples, visit the individual documentation pages linked above. diff --git a/docs/components/pulses.md b/docs/components/pulses.md index be90d6b0..89f01f94 100644 --- a/docs/components/pulses.md +++ b/docs/components/pulses.md @@ -16,7 +16,7 @@ Users can also define custom pulses by subclassing the `Pulse` class. This flexi All pulses in QuAM are instances of the [Pulse][quam.components.pulses.Pulse] class. The QuAM library contains a set of common pulse types in the [pulses][quam.components.pulses] module. Typical examples are [SquarePulse][quam.components.pulses.SquarePulse], [GaussianPulse][quam.components.pulses.GaussianPulse], and [DragPulse][quam.components.pulses.DragPulse]. -Users can supplement these common pulses with their own custom pulses by subclassing the [Pulse][quam.components.pulses.Pulse] class (see [Custom QuAM components][custom-components] for details). +Users can supplement these common pulses with their own custom pulses by subclassing the [Pulse][quam.components.pulses.Pulse] class (see [Custom QuAM Components](/components/custom-components) for details). ## Usage @@ -86,7 +86,7 @@ class TriangularPulse(pulses.Pulse): # This function generates a linearly spaced array to form a triangular waveform return np.linspace(self.amplitude_start, self.amplitude_stop, self.length) ``` -Ensure this code is saved in a properly structured Python module within your project so that it can be imported as needed. For details on organizing custom components, refer to the [Custom Components][custom-components] section of the QuAM documentation +Ensure this code is saved in a properly structured Python module within your project so that it can be imported as needed. For details on organizing custom components, refer to the [Custom QuAM Components](/components/custom-components) section of the QuAM documentation ### Extending to Readout Pulses To create a readout pulse derived from a control pulse, subclass both the specific control pulse and the [ReadoutPulse][quam.components.pulses.ReadoutPulse] class. Below is an example of how to adapt the Triangular Pulse into a readout pulse. diff --git a/docs/features/index.md b/docs/features/index.md index d7dc3013..1d2977d9 100644 --- a/docs/features/index.md +++ b/docs/features/index.md @@ -5,6 +5,6 @@ The features section of the Quantum Abstract Machine (QuAM) documentation highli ## QuAM Referencing QuAM referencing is a sophisticated feature designed to streamline the management and modification of quantum configurations. It allows users to define relationships and dependencies between various components within a QuAM setup, facilitating easier updates and scalability. -- **[QuAM Referencing Documentation](features/quam-references.md)**: Learn about the syntax and usage of QuAM’s powerful referencing system. This feature simplifies the process of modifying and scaling quantum experiments by allowing users to reference previously defined elements, parameters, and configurations, thus avoiding redundancy and reducing the potential for errors. +- **[QuAM Referencing Documentation](quam-references.md)**: Learn about the syntax and usage of QuAM’s powerful referencing system. This feature simplifies the process of modifying and scaling quantum experiments by allowing users to reference previously defined elements, parameters, and configurations, thus avoiding redundancy and reducing the potential for errors. This section of the documentation provides insights into the foundational features that make QuAM a robust and adaptable framework for quantum computing. Explore the detailed documentation to fully utilize these features in your work. diff --git a/docs/gen_ref_pages.py b/docs/gen_ref_pages.py index e29bde0a..932de154 100644 --- a/docs/gen_ref_pages.py +++ b/docs/gen_ref_pages.py @@ -7,7 +7,7 @@ for path in sorted(Path("quam").rglob("*.py")): # module_path = path.relative_to("quam").with_suffix("") # doc_path = path.relative_to("quam").with_suffix(".md") # - full_doc_path = Path("reference", doc_path) # + full_doc_path = Path("API_references", doc_path) # parts = list(module_path.parts) parts = ["quam"] + parts diff --git a/docs/index.md b/docs/index.md index 0b4621b7..ee179e38 100644 --- a/docs/index.md +++ b/docs/index.md @@ -10,7 +10,7 @@ QuAM stands out by transforming the way quantum control is perceived and impleme ## Why Choose QuAM? QuAM is not just a tool but a gateway to streamlined and efficient quantum computing: - +
- **Component-Based Setup:** Utilize a standard set of QuAM components like Mixers and IQChannels to digitally represent and manipulate your quantum environment. - **Automated Configuration:** Automatically generate the necessary QUA configuration from your QuAM setup, simplifying the transition from design to deployment. @@ -18,7 +18,7 @@ QuAM is not just a tool but a gateway to streamlined and efficient quantum compu - **State Management:** Effortlessly save and load your QuAM state, enabling consistent results and reproducibility in experiments. ```python -from quam.components import BasicQuAM, SingleChannel, pulses +from quam.components import * # Create a root-level QuAM instance machine = BasicQuAM() @@ -29,19 +29,20 @@ machine.channels["output"] = channel # Add a Gaussian pulse to the channel channel.operations["gaussian"] = pulses.Gaussian( - length=100, # Pulse length in ns - amplitude=0.5, # Peak amplitude of Gaussian pulse - sigma=20, # Standard deviation of Guassian pulse + length=100, amplitude=0.5, sigma=20 ) -# Play the Gaussian pulse on the channel within a QUA program +# Play the Gaussian pulse within a QUA program with program() as prog: channel.play("gaussian") # Generate the QUA configuration from QuAM qua_configuration = machine.generate_config() + +# Save QuAM to a JSON file +machine.save("state.json") ``` - +
## Getting Started @@ -53,6 +54,6 @@ qua_configuration = machine.generate_config() - **[QuAM Migration](migrating-to-quam.md)**: Already using QUA? Our detailed guide on [migrating-to-quam] and tools are designed for a smooth transition to QuAM, letting you migrate your existing projects without hassle. ## Explore More -Delve into our detailed reference materials and API documentation to fully leverage QuAM’s capabilities and optimize your quantum applications. +Delve into our [API documentation](API_references/index.md) to fully leverage QuAM’s capabilities and optimize your quantum applications. We are thrilled to support your journey into the quantum future with QuAM. Together, let's push the boundaries of what's possible in quantum computing! diff --git a/docs/installation.md b/docs/installation.md index 855b1a0c..ce0e4e02 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -85,7 +85,7 @@ If this raises a similar error, it likely means that Python cannot be found. Ple QuAM comes with a range of standard QuAM components that can kick-start experimental setups. An example of these components are used can be found at the [QuAM demonstration](demonstration.md). -Beyond the standard components, QuAM provides a framework to create custom components that are tailored to a specific quantum setup. This allows you to create their own abstraction layers, enabling you to digitally represent and interact with your quantum setup. See [Creating custom QuAM components](custom-components.md) for details +Beyond the standard components, QuAM provides a framework to create custom components that are tailored to a specific quantum setup. This allows you to create their own abstraction layers, enabling you to digitally represent and interact with your quantum setup. See [Creating custom QuAM components](/components/custom-components) for details + +```title="output" +QuAM: + channels: QuamDict Empty + octaves: QuamDict Empty +``` Next we populate the root-level `machine` object with QuAM components diff --git a/mkdocs.yml b/mkdocs.yml index abe215dd..55578565 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -46,7 +46,6 @@ nav: - index.md - installation.md - demonstration.md - - demonstration-original.md - "QuAM Components": - "components/index.md" - "components/quam-root.md" @@ -66,6 +65,7 @@ nav: - "QuAM Pulses API": "API_references/components/pulses_API.md" - "QuAM Hardware API": "API_references/components/hardware_API.md" - "QuAM Octave API": "API_references/components/octave_API.md" + - "BasicQuAM API": "API_references/components/basic_quam_API.md" - "QuAM Core Classes API": "API_references/core/quam_classes_API.md" plugins: # - mkdocs-jupyter: diff --git a/quam/components/basic_quam.py b/quam/components/basic_quam.py index d7cd5ee6..1209bcfa 100644 --- a/quam/components/basic_quam.py +++ b/quam/components/basic_quam.py @@ -13,5 +13,14 @@ @quam_dataclass class BasicQuAM(QuamRoot): + """Basic top-level QuAM root component. + + If custom QuAM components are used, a custom QuAM root component should be created. + + Args: + channels (Dict[str, Channel], optional): A dictionary of channels. + octaves (Dict[str, Octave], optional): A dictionary of octaves. + """ + channels: Dict[str, Channel] = field(default_factory=dict) octaves: Dict[str, Octave] = field(default_factory=dict) From 23be0f085543c8fa9ff5e8fb42ea694230caeb37 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Mon, 6 May 2024 15:54:43 +0200 Subject: [PATCH 27/27] docs: add FrequencyConverter --- docs/components/quam-root.md | 2 +- quam/components/hardware.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/components/quam-root.md b/docs/components/quam-root.md index a47ff205..e986b7c7 100644 --- a/docs/components/quam-root.md +++ b/docs/components/quam-root.md @@ -4,7 +4,7 @@ The Quantum Abstract Machine (QuAM) utilizes a hierarchical data structure in wh ## Overview -The root QuAM object is structured as a subclass of [QuamRoot](quam.core.quam_classes.QuamRoot) module. For straightforward implementations, such as those described in the [Migrating to QuAM](migrating-to-quam) section, the [BasicQuAM][quam.components.basic_quam.BasicQuAM] class typically suffices: +The root QuAM object is structured as a subclass of [QuamRoot][quam.core.quam_classes.QuamRoot] module. For straightforward implementations, such as those described in the [Migrating to QuAM](/migrating-to-quam) section, the [BasicQuAM][quam.components.basic_quam.BasicQuAM] class typically suffices: ```python from quam.components import BasicQuAM diff --git a/quam/components/hardware.py b/quam/components/hardware.py index cc989c07..ff09c814 100644 --- a/quam/components/hardware.py +++ b/quam/components/hardware.py @@ -116,6 +116,22 @@ class BaseFrequencyConverter(QuamComponent): @quam_dataclass class FrequencyConverter(BaseFrequencyConverter): + """Frequency up/down converter component. + + This component encapsulates the local oscillator and mixer used to upconvert or + downconvert an RF signal. + + The FrequencyConverter component is attached to IQ channels through + + - `IQChannel.frequency_converter_up` + - `InOutIQChannel.frequency_converter_down` + + Args: + local_oscillator (LocalOscillator): The local oscillator for the frequency converter. + mixer (Mixer): The mixer for the frequency converter. + gain (float): The gain of the frequency converter. + """ + local_oscillator: LocalOscillator = None mixer: Mixer = None gain: float = None