diff --git a/docs/API_references/components/basic_quam_API.md b/docs/API_references/components/basic_quam_API.md new file mode 100644 index 00000000..4139905d --- /dev/null +++ b/docs/API_references/components/basic_quam_API.md @@ -0,0 +1,3 @@ +# BasicQuAM API + +::: quam.components.basic_quam \ No newline at end of file diff --git a/docs/API_references/components/pulses_API.md b/docs/API_references/components/pulses_API.md index 12df6b95..fb80d8cb 100644 --- a/docs/API_references/components/pulses_API.md +++ b/docs/API_references/components/pulses_API.md @@ -2,7 +2,7 @@ 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. +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. diff --git a/docs/API_references/index.md b/docs/API_references/index.md index 4d78b16a..90a973fe 100644 --- a/docs/API_references/index.md +++ b/docs/API_references/index.md @@ -4,18 +4,21 @@ Welcome to the API Reference section of the Quantum Abstract Machine (QuAM) docu ## Quick Links -- [**Core Components**](/API_references/core/quam_classes_API.md) +- [**Core Components**](/API_references/core/quam_classes_API) 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) +- [**Channel Components**](/API_references/components/channels_API) Learn about channel configurations and their operations within the QuAM framework. -- [**Pulse Components**](/API_references/components/pulses_API.md) +- [**Pulse Components**](/API_references/components/pulses_API) A detailed look at various pulse types and their properties used in quantum operations. -- [**Hardware Components**](/API_references/components/hardware_API.md) +- [**Hardware Components**](/API_references/components/hardware_API) 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) +- [**Octave Components**](/API_references/components/octave_API) Documentation on the `Octave` component and its associated up and down converters. + +- [**BasicQuAM Class**](/API_references/components/basic_quam_API) + Details on the `BasicQuAM` class, the root-level QuAM instance that serves as the entry point for QuAM configurations. \ No newline at end of file diff --git a/docs/components/channels.md b/docs/components/channels.md index d13a376c..26e2aae8 100644 --- a/docs/components/channels.md +++ b/docs/components/channels.md @@ -49,7 +49,7 @@ IQ_channel = IQChannel( ### 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`. +This can be set through `SingleChannel.opx_output_offset` for the [SingleChannel][quam.components.channels.SingleChannel], and through `IQChannel.opx_output_offset_I` and `IQChannel.opx_output_offset_Q` for the [IQChannel][quam.components.channels.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. @@ -86,7 +86,7 @@ IQ_channel = IQChannel( 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. +See the [QuAM Octave Documentation][octave] documentation for details. ### Analog Pulses @@ -110,7 +110,7 @@ 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][]. +Details on pulses in QuAM can be found at the [Pulses Documentation][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. diff --git a/docs/components/index.md b/docs/components/index.md index 7ba55665..ee56fd1d 100644 --- a/docs/components/index.md +++ b/docs/components/index.md @@ -21,5 +21,3 @@ The Octave component in QuAM handles the upconversion and downconversion of freq 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 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 89f01f94..41d0a03f 100644 --- a/docs/components/pulses.md +++ b/docs/components/pulses.md @@ -20,7 +20,7 @@ Users can supplement these common pulses with their own custom pulses by subclas ## 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": +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 @@ -29,10 +29,10 @@ from quam.components import pulses, SingleChannel 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)``` +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: +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 @@ -68,8 +68,8 @@ with program() as prog: ## 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. +### Example: Creating a Ramp Pulse +To illustrate, let's create a pulse that ramps in amplitude. This involves subclassing the Pulse class from the QuAM library and defining specific parameters and the waveform function. ```python import numpy as np @@ -77,25 +77,25 @@ 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 +class RampPulse(pulses.Pulse): + # Define the starting and stopping amplitudes for the ramp 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 + # This function generates a linearly spaced array to form a ramp 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 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. +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 RampPulse 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 +class RampReadoutPulse(pulses.ReadoutPulse, RampPulse): + """Extend RampPulse to include readout-specific functionality.""" + # No additional fields needed; inherits all from RampPulse and ReadoutPulse pass ``` Readout pulses utilize additional parameters for integration weights which are crucial for signal processing: @@ -105,7 +105,7 @@ Readout pulses utilize additional parameters for integration weights which are c 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. +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][quam.components.pulses.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. @@ -127,7 +127,7 @@ In the QUA configuration, pulses are decomposed into multiple components, such a 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. +- **Waveform Generation**: These parameters are used to generate the waveform dynamically using the method `waveform_function()`. This approach integrates waveform generation within the pulse definition, streamlining the configuration process. - **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 diff --git a/docs/components/quam-root.md b/docs/components/quam-root.md index e8895470..a47ff205 100644 --- a/docs/components/quam-root.md +++ b/docs/components/quam-root.md @@ -20,13 +20,14 @@ For more complex setups requiring custom components, you can extend the QuAM roo ### Example of a Custom QuAM Class ```python title="custom_components/quam.py" +from typing import Dict from quam.core import QuamRoot, quam_dataclass from quam.components import Octave from custom_components.qubit import Qubit @quam_dataclass class QuAM(QuamRoot): - qubit: Dict[str, Qubit] + qubits: Dict[str, Qubit] octaves: Dict[str, Octave] ``` diff --git a/docs/demonstration-original.md b/docs/demonstration-original.md deleted file mode 100644 index 9e42bccb..00000000 --- a/docs/demonstration-original.md +++ /dev/null @@ -1,576 +0,0 @@ -# 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. - -The standard QuAM components can be imported using - -```python -from quam.components import * -from quam.examples.superconducting_qubits import Transmon, QuAM -``` - -Since we're starting from scratch, we will have to instantiate all QuAM components. This has to be done once, after which we will generally save and load QuAM from a file. -To begin, we create the top-level QuAM object, which inherits from [quam.core.quam_classes.QuamRoot][]. Generally the user is encouraged to create a custom component for this. - -We will call our top-level object `machine`: -```python -machine = QuAM() -``` - -So far, this object `machine` is empty, so we'll populate it with objects. -In this case, we will create two Transmon objects and fill them with contents. - - -/// details | Autocomplete with IDEs - type: tip -Code editors with Python language support (e.g., VS Code, PyCharm) are very useful here because they explain what attributes each class has, what the type should be, and docstrings. This makes it a breeze to create a QuAM from scratch. -/// - - -```python -num_qubits = 2 -for idx in range(num_qubits): - # Create qubit components - transmon = Transmon( - id=idx, - xy=IQChannel( - frequency_converter_up=FrequencyConverter( - local_oscillator=LocalOscillator(power=10, frequency=6e9), - mixer=Mixer(), - ), - opx_output_I=("con1", 3 * idx + 3), - opx_output_Q=("con1", 3 * idx + 4), - ), - z=SingleChannel(opx_output=("con1", 3 * idx + 5)), - ) - machine.qubits.append(transmon) - - # Create resonator components - resonator = InOutIQChannel( - opx_input_I=("con1", 1), - opx_input_Q=("con1", 2), - opx_output_I=("con1", 1), - opx_output_Q=("con1", 2), - id=idx, - frequency_converter_up=FrequencyConverter( - local_oscillator=LocalOscillator(power=10, frequency=6e9), - mixer=Mixer() - ) - ) - machine.resonators.append(resonator) -``` -This example demonstrates that QuAM follows a tree structure: each component can have a parent and it can have children as attributes. - -We can print a summary of QuAM using -```python -machine.print_summary() -``` - -/// details | `machine.print_summary()` output -```json -QuAM: - mixers: QuamList = [] - qubits: QuamList: - 0: Transmon - id: 0 - xy: IQChannel - operations: QuamDict Empty - id: None - digital_outputs: QuamDict Empty - opx_output_I: ('con1', 3) - opx_output_Q: ('con1', 4) - opx_output_offset_I: None - opx_output_offset_Q: None - frequency_converter_up: FrequencyConverter - local_oscillator: LocalOscillator - frequency: 6000000000.0 - power: 10 - mixer: Mixer - local_oscillator_frequency: "#../local_oscillator/frequency" - intermediate_frequency: "#../../intermediate_frequency" - correction_gain: 0 - correction_phase: 0 - gain: None - intermediate_frequency: 0.0 - z: SingleChannel - operations: QuamDict Empty - id: None - digital_outputs: QuamDict Empty - opx_output: ('con1', 5) - filter_fir_taps: None - filter_iir_taps: None - opx_output_offset: None - intermediate_frequency: None - resonator: None - 1: Transmon - id: 1 - xy: IQChannel - operations: QuamDict Empty - id: None - digital_outputs: QuamDict Empty - opx_output_I: ('con1', 6) - opx_output_Q: ('con1', 7) - opx_output_offset_I: None - opx_output_offset_Q: None - frequency_converter_up: FrequencyConverter - local_oscillator: LocalOscillator - frequency: 6000000000.0 - power: 10 - mixer: Mixer - local_oscillator_frequency: "#../local_oscillator/frequency" - intermediate_frequency: "#../../intermediate_frequency" - correction_gain: 0 - correction_phase: 0 - gain: None - intermediate_frequency: 0.0 - z: SingleChannel - operations: QuamDict Empty - id: None - digital_outputs: QuamDict Empty - opx_output: ('con1', 8) - filter_fir_taps: None - filter_iir_taps: None - opx_output_offset: None - intermediate_frequency: None - resonator: None - resonators: QuamList: - 0: InOutIQChannel - operations: QuamDict Empty - id: 0 - digital_outputs: QuamDict Empty - opx_output_I: ('con1', 1) - opx_output_Q: ('con1', 2) - opx_output_offset_I: None - opx_output_offset_Q: None - frequency_converter_up: FrequencyConverter - local_oscillator: LocalOscillator - frequency: 6000000000.0 - power: 10 - mixer: Mixer - local_oscillator_frequency: "#../local_oscillator/frequency" - intermediate_frequency: "#../../intermediate_frequency" - correction_gain: 0 - correction_phase: 0 - gain: None - intermediate_frequency: 0.0 - opx_input_I: ('con1', 1) - opx_input_Q: ('con1', 2) - time_of_flight: 24 - smearing: 0 - opx_input_offset_I: None - opx_input_offset_Q: None - input_gain: None - frequency_converter_down: None - 1: InOutIQChannel - operations: QuamDict Empty - id: 1 - digital_outputs: QuamDict Empty - opx_output_I: ('con1', 1) - opx_output_Q: ('con1', 2) - opx_output_offset_I: None - opx_output_offset_Q: None - frequency_converter_up: FrequencyConverter - local_oscillator: LocalOscillator - frequency: 6000000000.0 - power: 10 - mixer: Mixer - local_oscillator_frequency: "#../local_oscillator/frequency" - intermediate_frequency: "#../../intermediate_frequency" - correction_gain: 0 - correction_phase: 0 - gain: None - intermediate_frequency: 0.0 - opx_input_I: ('con1', 1) - opx_input_Q: ('con1', 2) - time_of_flight: 24 - smearing: 0 - opx_input_offset_I: None - opx_input_offset_Q: None - input_gain: None - frequency_converter_down: None - local_oscillators: QuamList = [] - wiring: QuamDict Empty -``` -/// - - -## Saving and Loading QuAM - -Now that we have defined our QuAM structure, we can save its contents to a JSON file: - -```python -machine.save("state.json") -``` - -/// details | state.json -```json -{ - "qubits": [ - { - "id": 0, - "xy": { - "opx_output_I": [ - "con1", - 3 - ], - "opx_output_Q": [ - "con1", - 4 - ], - "frequency_converter_up": { - "local_oscillator": { - "frequency": 6000000000.0, - "power": 10 - }, - "mixer": {} - } - }, - "z": { - "opx_output": [ - "con1", - 5 - ] - } - }, - { - "id": 1, - "xy": { - "opx_output_I": [ - "con1", - 6 - ], - "opx_output_Q": [ - "con1", - 7 - ], - "frequency_converter_up": { - "local_oscillator": { - "frequency": 6000000000.0, - "power": 10 - }, - "mixer": {} - } - }, - "z": { - "opx_output": [ - "con1", - 8 - ] - } - } - ], - "resonators": [ - { - "id": 0, - "opx_output_I": [ - "con1", - 1 - ], - "opx_output_Q": [ - "con1", - 2 - ], - "frequency_converter_up": { - "local_oscillator": { - "frequency": 6000000000.0, - "power": 10 - }, - "mixer": {} - }, - "opx_input_I": [ - "con1", - 1 - ], - "opx_input_Q": [ - "con1", - 2 - ] - }, - { - "id": 1, - "opx_output_I": [ - "con1", - 1 - ], - "opx_output_Q": [ - "con1", - 2 - ], - "frequency_converter_up": { - "local_oscillator": { - "frequency": 6000000000.0, - "power": 10 - }, - "mixer": {} - }, - "opx_input_I": [ - "con1", - 1 - ], - "opx_input_Q": [ - "con1", - 2 - ] - } - ], - "__class__": "quam.components.superconducting_qubits.QuAM" -} -``` -/// - -This JSON file is a serialised representation of QuAM. As a result, QuAM can also be loaded from this JSON file: - -```python -loaded_machine = QuAM.load("state.json") -``` - -## Generating the QUA Configuration - -We can also generate the QUA config from QuAM. This recursively calls `QuamComponent.apply_to_config()` on all QuAM components. - -```python -qua_config = machine.generate_config() -``` - -/// details | qua_config -```json -{ - "version": 1, - "controllers": { - "con1": { - "analog_outputs": { - "3": { - "offset": 0 - }, - "4": { - "offset": 0 - }, - "5": { - "offset": 0 - }, - "6": { - "offset": 0 - }, - "7": { - "offset": 0 - }, - "8": { - "offset": 0 - }, - "1": { - "offset": 0 - }, - "2": { - "offset": 0 - } - }, - "digital_outputs": {}, - "analog_inputs": { - "1": { - "offset": 0 - }, - "2": { - "offset": 0 - } - } - } - }, - "elements": { - "q0.xy": { - "mixInputs": { - "I": [ - "con1", - 3 - ], - "Q": [ - "con1", - 4 - ], - "lo_frequency": 6000000000.0, - "mixer": "q0.xy.mixer" - }, - "intermediate_frequency": 0.0, - "operations": {} - }, - "q0.z": { - "singleInput": { - "port": [ - "con1", - 5 - ] - }, - "operations": {} - }, - "q1.xy": { - "mixInputs": { - "I": [ - "con1", - 6 - ], - "Q": [ - "con1", - 7 - ], - "lo_frequency": 6000000000.0, - "mixer": "q1.xy.mixer" - }, - "intermediate_frequency": 0.0, - "operations": {} - }, - "q1.z": { - "singleInput": { - "port": [ - "con1", - 8 - ] - }, - "operations": {} - }, - "IQ0": { - "mixInputs": { - "I": [ - "con1", - 1 - ], - "Q": [ - "con1", - 2 - ], - "lo_frequency": 6000000000.0, - "mixer": "IQ0.mixer" - }, - "intermediate_frequency": 0.0, - "operations": {}, - "outputs": { - "out1": [ - "con1", - 1 - ], - "out2": [ - "con1", - 2 - ] - }, - "smearing": 0, - "time_of_flight": 24 - }, - "IQ1": { - "mixInputs": { - "I": [ - "con1", - 1 - ], - "Q": [ - "con1", - 2 - ], - "lo_frequency": 6000000000.0, - "mixer": "IQ1.mixer" - }, - "intermediate_frequency": 0.0, - "operations": {}, - "outputs": { - "out1": [ - "con1", - 1 - ], - "out2": [ - "con1", - 2 - ] - }, - "smearing": 0, - "time_of_flight": 24 - } - }, - "pulses": { - "const_pulse": { - "operation": "control", - "length": 1000, - "waveforms": { - "I": "const_wf", - "Q": "zero_wf" - } - } - }, - "waveforms": { - "zero_wf": { - "type": "constant", - "sample": 0.0 - }, - "const_wf": { - "type": "constant", - "sample": 0.1 - } - }, - "digital_waveforms": { - "ON": { - "samples": [ - [ - 1, - 0 - ] - ] - } - }, - "integration_weights": {}, - "mixers": { - "q0.xy.mixer": [ - { - "intermediate_frequency": 0.0, - "lo_frequency": 6000000000.0, - "correction": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ], - "q1.xy.mixer": [ - { - "intermediate_frequency": 0.0, - "lo_frequency": 6000000000.0, - "correction": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ], - "IQ0.mixer": [ - { - "intermediate_frequency": 0.0, - "lo_frequency": 6000000000.0, - "correction": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ], - "IQ1.mixer": [ - { - "intermediate_frequency": 0.0, - "lo_frequency": 6000000000.0, - "correction": [ - 1.0, - 0.0, - 0.0, - 1.0 - ] - } - ] - }, - "oscillators": {} -} -``` -/// - -This QUA config can then be used in QUA to open a Quantum Machine: -```python -qm = qmm.open_qm(qua_config) # opens a quantum machine with configuration -``` \ No newline at end of file diff --git a/docs/demonstration.md b/docs/demonstration.md index bfcca112..f2b5a1ef 100644 --- a/docs/demonstration.md +++ b/docs/demonstration.md @@ -2,7 +2,7 @@ ## Introduction -Welcome to our QuAM tutorial! This guide will demonstrate setting up a basic superconducting quantum circuit with two Transmon qubits and their resonators. We'll equip these qubits with control and readout pulses and generate a QUA configuration for interacting with quantum hardware. +Welcome to our QuAM tutorial! This guide will demonstrate setting up a basic superconducting quantum circuit with two transmon qubits and their resonators. We'll equip these qubits with control and readout pulses and generate a QUA configuration for interacting with quantum hardware. QuAM is not limited to any specific quantum hardware platform. It is designed to be adaptable and extensible for various quantum systems. You can customize components or expand the framework to add new functionalities as needed. For details on customization, visit [Custom QuAM Components](/components/custom-components). @@ -279,7 +279,7 @@ QuAM: The output provides a detailed hierarchical view of the machine's configuration, illustrating the connectivity and settings of each component. -## Persisting the Setup +## Saving the QuAM Setup Save the current state of your QuAM setup to a file for later use or inspection: @@ -374,10 +374,6 @@ To resume work with a previously configured setup: loaded_machine = QuAM.load("state.json") ``` -## Workflow -Certainly! Here's an improved version of the "Workflow" section with a clearer structure and concise language: - ---- ## Workflow diff --git a/docs/features/quam-references.md b/docs/features/quam-references.md index 115a8d63..c28c7f9e 100644 --- a/docs/features/quam-references.md +++ b/docs/features/quam-references.md @@ -18,7 +18,7 @@ machine = QuAM() Next, we can add a qubit as a component: ```python -qubit = superconducting_qubits.Transmon(xy=IQChannel(opx_output_I=("con1", 1"), opx_output_Q=("con1", 2")) +qubit = superconducting_qubits.Transmon(xy=IQChannel(opx_output_I=("con1", 1), opx_output_Q=("con1", 2")) machine.qubit = qubit assert qubit.parent == machine ``` @@ -27,7 +27,7 @@ One of the rules in QuAM is that a component can only have one parent. This is e As a result, the following raises an error: ```python -channel = IQChannel(opx_output_I=("con1", 1"), opx_output_Q=("con1", 2") +channel = IQChannel(opx_output_I=("con1", 1), opx_output_Q=("con1", 2") qubit1 = superconducting_qubits.Transmon(xy=channel) qubit2 = superconducting_qubits.Transmon(xy=channel) # Raises ValueError ``` @@ -40,16 +40,15 @@ A reference in QuAM is a way for a component's attribute to be a reference to an ```python @quam_dataclass class Component(QuamComponent): + a: int + b: int - -component = Component() -component.a = 42 -component.b = "#./a" +component = Component(a=42, b="#./a") print(component.b) # Prints 42 ``` -As can be seen, the Quam component attribute `component.b` was set to a reference, i.e. a string starting with `"#"`. This reference indicates that when the component is retrieved, e.g. through the `print()` statement, it should instead return the value of its reference. +As can be seen, the QuAM component attribute `component.b` was set to a reference, i.e. a string starting with `"#"`. This reference indicates that when the component is retrieved, e.g. through the `print()` statement, it should instead return the value of its reference. -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. +QuAM references follow the JSON reference syntax (For a description see [https://json-spec.readthedocs.io/reference.html](https://json-spec.readthedocs.io/reference.html)), 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 always start with `"#/"`, e.g. `"#/absolute/path/to/value`. @@ -70,35 +69,40 @@ An example was given above, and is reiterated here: ```python @quam_dataclass class Component(QuamComponent): + a: int + b: int - -component = Component() -component.a = 42 -component.b = "#./a" +component = Component(a=42, b="#./a") print(component.b) # Prints 42 ``` ### 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 -An example was given above, and is reiterated here: + +To illustrate relative parent references, we modify `Component` to allow for a subcomponent: ```python @quam_dataclass class Component(QuamComponent): - + sub_component: "Component" = None + a: int = None + b: int = None -component = Component() -component.a = 42 -component.b = "#./a" -print(component.b) # Prints 42 +component = Component(a=42) +component.subcomponent = Component(a="#../a") +print(component.subcomponent.a) # Prints 42 ``` +As can be seen in this example, `component.subcomponent.a = "#../a"` is a relative parent reference, which means that `component.subcomponent.a` should be the same as `component.a`. + +Parent references can also be stacked, e.g. `"#../../a"` would be a reference to the grandparent of the current component. + + ## Additional Notes on References ### 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: +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 component = Component() diff --git a/docs/index.md b/docs/index.md index ee179e38..3c7029ef 100644 --- a/docs/index.md +++ b/docs/index.md @@ -12,9 +12,9 @@ QuAM stands out by transforming the way quantum control is perceived and impleme 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. +- **Component-Based Setup:** Utilize a standard set of QuAM components like [Mixers][quam.components.hardware.Mixer] and [IQChannels][quam.components.channels.IQChannel] 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. +- **Extensibility:** Easily extend QuAM with [custom classes](components/custom-components.md) 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 @@ -48,12 +48,10 @@ machine.save("state.json") ## Getting Started - **[QuAM Installation](installation.md):** Set up QuAM on your system and get ready to explore its capabilities. +- **[QuAM Demonstration](demonstration.md):** Witness QuAM in action with practical examples and hands-on tutorials. - **[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 [API documentation](API_references/index.md) to fully leverage QuAM’s capabilities and optimize your quantum applications. +- **[QuAM Migration](migrating-to-quam.md)**: Already using QUA? Our detailed guide on migrating to QuAM are designed for a smooth transition to QuAM, letting you migrate your existing QUA projects without hassle. +- **[API References](API_references/index.md)**: Dive into the detailed API documentation to explore the classes, methods, and attributes available in QuAM. 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/migrating-to-quam.md b/docs/migrating-to-quam.md index 1e4d0558..b229a984 100644 --- a/docs/migrating-to-quam.md +++ b/docs/migrating-to-quam.md @@ -6,7 +6,7 @@ QuAM, the Quantum Abstract Machine, serves as a powerful abstraction framework b 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. **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. +1. **Create a Root QuAM Object:** Start by establishing a foundational [QuamRoot][quam.core.quam_classes.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. **Add Octaves:** If your original QUA setup includes Octave components, this step involves integrating these components into the QuAM configuration, utilizing existing connectivity settings. @@ -22,7 +22,7 @@ Each of these steps is designed to ensure a seamless transition to QuAM, leverag ## 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: +Begin by establishing a [QuamRoot][quam.core.quam_classes.QuamRoot] object, which serves as the top-level container for all other QuAM components. For simplicity, you can use the pre-defined [BasicQuAM][quam.components.basic_quam.BasicQuAM] class: ```python from quam.components import BasicQuAM @@ -30,7 +30,12 @@ from quam.components import BasicQuAM machine = BasicQuAM() machine.print_summary() # outputs the current QuAM state ``` - + +```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)