### Install QUAM via pip (Recommended) Source: https://github.com/qua-platform/quam/blob/main/docs/installation.md The easiest and recommended way to install the QUAM framework directly using pip, Python's package installer. ```bash pip install quam ``` -------------------------------- ### Developer Installation: Clone and Install QUAM from Git Source: https://github.com/qua-platform/quam/blob/main/docs/installation.md Instructions for installing QUAM in developer mode by first cloning the repository from GitHub and then installing it using pip3. This method is suitable for contributing to the project or making local modifications. ```bash git clone https://github.com/qua-platform/quam.git pip3 install ./quam ``` -------------------------------- ### Configure Quam Machine with Octave and IQ Channels in Python Source: https://github.com/qua-platform/quam/blob/main/docs/components/octave.md This comprehensive Python example demonstrates the setup of a `Quam` machine. It defines the `Quam` root, initializes an `Octave` component with IP and port, and configures its frequency converters. Subsequently, it adds `IQChannel` and `InOutIQChannel` instances, linking them to the Octave's RF outputs and inputs, and setting LO frequencies. Finally, it generates the QUA configuration from the assembled machine object. ```python from typing import Dict from dataclasses import field from quam.core import QuamRoot, quam_dataclass from quam.components import Octave, OctaveUpConverter, OctaveDownConverter, Channel @quam_dataclass class Quam(QuamRoot): octave: Octave = None channels: Dict[str, Channel] = field(default_factory=dict) machine = Quam() octave = Octave( name="octave1", ip="127.0.0.1", port=80, ) machine.octave = octave octave.initialize_frequency_converters() octave.print_summary() from quam.components import IQChannel, InOutIQChannel machine.channels["IQ1"] = IQChannel( opx_output_I=("con1", 1), opx_output_Q=("con1", 2), frequency_converter_up=octave.RF_outputs[1].get_reference() ) octave.RF_outputs[1].channel = machine.channels["IQ1"].get_reference() octave.RF_outputs[1].LO_frequency = 2e9 machine.channels["IQ2"] = InOutIQChannel( opx_output_I=("con1", 3), opx_output_Q=("con1", 4), opx_input_I=("con1", 1), opx_input_Q=("con1", 2), frequency_converter_up=octave.RF_outputs[2].get_reference(), frequency_converter_down=octave.RF_inputs[1].get_reference() ) 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[1].LO_frequency = 2e9 qua_config = machine.generate_config() ``` -------------------------------- ### Developer Installation: Install QUAM from Cloned Repository Source: https://github.com/qua-platform/quam/blob/main/docs/installation.md Instructions for installing QUAM in developer mode after the repository has already been cloned, typically when using a Git GUI. This command installs the local repository as an editable package. ```bash pip3 install . ``` -------------------------------- ### Initialize QUAM Root Object Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This code instantiates the root `Quam` object, named `machine`, which serves as the top-level container for the entire quantum setup. Initially, it's an empty container to be populated with quantum circuit components. ```python machine = Quam() # (1) ``` -------------------------------- ### Load QUAM Machine Configuration Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This snippet shows how to load a previously saved QUAM machine configuration from a specified JSON file using Python, allowing users to resume work with an existing setup. ```python loaded_machine = Quam.load("state.json") ``` -------------------------------- ### Import QUAM Components for Superconducting Qubits Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This snippet imports necessary classes from the QUAM library, including general components and specific Transmon and Quam classes from the superconducting qubits example module. These imports are the first step in setting up a quantum circuit. ```python from quam.components import * from quam.examples.superconducting_qubits import Transmon, Quam ``` -------------------------------- ### Reiterate Relative QUAM Reference Example Source: https://github.com/qua-platform/quam/blob/main/docs/features/quam-references.md This snippet re-emphasizes the concept of relative references, which start with `#./` and are relative to the current component. It demonstrates how `component.b` can reference `component.a` within the same component, providing a clear example of intra-component referencing. ```python @quam_dataclass class Component(QuamComponent): a: int b: int component = Component(a=42, b="#./a") print(component.b) # Prints 42 ``` -------------------------------- ### Workflow for Updating and Saving QUAM Configuration Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This example illustrates a typical workflow for iteratively updating a QUAM machine's configuration based on experimental results. It covers loading a configuration, running a QUA program, analyzing results to extract optimal parameters (e.g., pulse amplitude), updating the machine object, and then saving the modified configuration back to the file. ```python # Load QUAM machine = Quam.load("state.json") # Run QUA program and analyse results to extract the optimal pulse amplitude results = some_qua_program() pulse_amplitude = amplitude_analysis_function(results) # Update the pulse amplitude for the relevant qubit machine.qubits["q0"].xy.operations["X90"].amplitude = pulse_amplitude # Save the updated QUAM configuration machine.save("state.json") ``` -------------------------------- ### Create and Activate Python Virtual Environment (Anaconda) Source: https://github.com/qua-platform/quam/blob/main/docs/installation.md Instructions for creating and activating a Python virtual environment using Anaconda. This helps isolate project dependencies and manage different Python environments. ```bash conda create -n {environment_name} conda activate {environment_name} ``` -------------------------------- ### Configure Time Tagging for InSingleChannel Source: https://github.com/qua-platform/quam/blob/main/docs/components/channels.md Illustrates how to initialize an `InSingleChannel` with a `TimeTaggingAddon` to enable time-of-arrival measurements. This example sets optional parameters like signal and derivative thresholds and polarities for precise signal detection. ```Python from quam.components.channels import InSingleChannel, TimeTaggingAddon channel = InSingleChannel( id="channel", opx_input=("con1", 1), time_tagging=TimeTaggingAddon( signal_threshold=0.195, # in units of V signal_polarity="below", derivative_threshold=0.073, # in units of V/ns derivative_polarity="below", ) ) ``` -------------------------------- ### Example QUA Configuration JSON Structure Source: https://github.com/qua-platform/quam/blob/main/docs/components/octave.md This JSON snippet provides an example of the structured configuration generated by the 'machine.generate_config()' method in QUAM. It details the controllers, elements, pulses, waveforms, and octave settings, which define the hardware and experimental parameters for QUA programs. ```json { "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 } } } }, "elements": { "IQ1": { "operations": {}, "intermediate_frequency": 0.0, "RF_inputs": { "port": ["octave1", 1] } }, "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" } } }, "waveforms": { "zero_wf": { "type": "constant", "sample": 0.0 }, "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] } }, "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": [] } } } ``` -------------------------------- ### Developer Installation: Alternative Pip Install Command Source: https://github.com/qua-platform/quam/blob/main/docs/installation.md An alternative command for installing QUAM in developer mode, to be used if the 'pip3' command is not found. This suggests using 'pip' instead, which might be the default Python package installer on some systems. ```bash pip install ./quam ``` -------------------------------- ### Initialize Basic QUAM Machine in Python Source: https://github.com/qua-platform/quam/blob/main/docs/migrating-to-quam.md Demonstrates how to create a foundational BasicQuam object, which serves as the top-level container for all other QUAM components. This object is the starting point for building a new QUAM configuration. The snippet also shows how to print a summary of the current, empty QUAM state. ```Python from quam.components import BasicQuam machine = BasicQuam() machine.print_summary() ``` ```text QUAM: channels: QuamDict Empty octaves: QuamDict Empty ``` -------------------------------- ### Basic QUAM Program to Play a Gaussian Pulse Source: https://github.com/qua-platform/quam/blob/main/README.md This example demonstrates the fundamental steps to use QUAM: initializing a QUAM instance, defining a qubit connected to an OPX output channel, adding a Gaussian pulse operation, and generating the QUA configuration. It showcases how QUAM abstracts hardware specifics, allowing users to define quantum operations at a higher level. ```python from quam.components import BasicQuam, SingleChannel, pulses from qm import qua # Create a root-level QUAM instance machine = BasicQuam() # Add a qubit connected to an OPX output channel qubit = SingleChannel(opx_output=("con1", 1)) machine.channels["qubit"] = qubit # Add a Gaussian pulse to the channel qubit.operations["gaussian"] = pulses.GaussianPulse( 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 qua.program() as prog: qubit.play("gaussian") # Generate the QUA configuration from QUAM qua_configuration = machine.generate_config() ``` -------------------------------- ### Define and Use Basic Relative QUAM Reference Source: https://github.com/qua-platform/quam/blob/main/docs/features/quam-references.md This code introduces the concept of QUAM references, showing how an attribute can be set as a string starting with "#". This example demonstrates a relative reference (`#./a`) where `component.b` dynamically retrieves the value of `component.a` from within the same component. ```python @quam_dataclass class Component(QuamComponent): a: int b: int component = Component(a=42, b="#./a") print(component.b) # Prints 42 ``` -------------------------------- ### Generate QUA Configuration using Python Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This Python snippet demonstrates how to generate a QUA configuration object from the current QUAM machine setup. The generate_config() method is called on the machine object, producing a dictionary that defines the quantum hardware configuration. ```python qua_config = machine.generate_config() ``` -------------------------------- ### Install QUAM Python Package Source: https://github.com/qua-platform/quam/blob/main/README.md Installs the QUAM library using pip, the Python package installer. This command is executed in the terminal and requires Python version 3.9 to 3.12 to be installed on the system. ```bash pip install quam ``` -------------------------------- ### Add Octave Component to QUAM Configuration in Python Source: https://github.com/qua-platform/quam/blob/main/docs/migrating-to-quam.md Illustrates how to integrate an Octave component into the QUAM configuration, specifying its name, IP address, and port. This step is crucial for setups that include Octave hardware. The example also demonstrates initializing the Octave's frequency converters using default connectivity. ```Python from quam.components import Octave machine.octaves["octave1"] = Octave(name="octave1", ip="127.0.0.1", port=80) # Initialize all frequency converters using the default connectivity to the OPX machine.octave.initialize_frequency_converters() ``` -------------------------------- ### Configure Single Analog Input/Output Channel Source: https://github.com/qua-platform/quam/blob/main/docs/migrating-to-quam.md Illustrates the setup for a single analog channel that functions as both input and output. It provides the QUA configuration for `singleInput` and `outputs` and the QUAM instantiation using `InOutSingleChannel` for efficient bidirectional communication. ```json "qubit_readout": { "singleInput": { "port": ("con1", 1), }, "outputs": {"out1": ("con1", 2)}, "operations": {...} } ``` ```python from quam.components import InOutSingleChannel machine.channels["qubit_readout"] = InOutSingleChannel( opx_output=("con1", 1), opx_input=("con1", 2), ) ``` -------------------------------- ### Use Relative Parent QUAM Reference Source: https://github.com/qua-platform/quam/blob/main/docs/features/quam-references.md This example explains relative parent references, which start with `#../` and refer to paths relative to the parent of the current QUAM component. It shows how a subcomponent can reference an attribute of its direct parent, demonstrating hierarchical data access. ```python @quam_dataclass class Component(QuamComponent): sub_component: "Component" = None a: int = None b: int = None component = Component(a=42) component.subcomponent = Component(a="#../a") print(component.subcomponent.a) # Prints 42 ``` -------------------------------- ### Configure QUAM for Qubit Control and QUA Program Generation Source: https://github.com/qua-platform/quam/blob/main/docs/index.md This Python snippet illustrates how to initialize a QUAM instance, define a qubit connected to an OPX output channel, and associate a Gaussian pulse with it. It then demonstrates integrating this setup into a QUA program to play the pulse and automatically generating the full QUA configuration from the QUAM machine, showcasing QUAM's abstraction capabilities for quantum control. ```Python from quam.components import BasicQUAM, SingleChannel, pulses from qm import qua # Create a root-level QUAM instance machine = BasicQuam() # Add a qubit connected to an OPX output channel qubit = SingleChannel(opx_output=("con1", 1)) machine.channels["qubit"] = qubit # Add a Gaussian pulse to the channel qubit.operations["gaussian"] = pulses.GaussianPulse( 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 qua.program() as prog: qubit.play("gaussian") # Generate the QUA configuration from QUAM qua_configuration = machine.generate_config() ``` -------------------------------- ### Use Absolute QUAM Reference from Root Source: https://github.com/qua-platform/quam/blob/main/docs/features/quam-references.md This snippet illustrates the use of absolute references in QUAM, which start with `#/` and refer to paths from the top-level `QuamRoot` object. This example shows how a qubit's frequency can reference a global frequency defined at the machine level. ```python machine = Quam() machine.frequency = 6e9 machine.qubit = Transmon(frequency="#/frequency") print(machine.qubit.frequency) # Prints 6e9 ``` -------------------------------- ### Save QUAM Machine Configuration Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This snippet demonstrates how to save the current state of a QUAM machine object to a specified JSON file using Python, and provides an example of the resulting JSON file structure. ```python machine.save("state.json") ``` ```json { "__class__": "quam.examples.superconducting_qubits.components.Quam", "qubits": { "q0": { "id": 0, "resonator": { "frequency_converter_up": { "__class__": "quam.components.hardware.FrequencyConverter", "local_oscillator": { "frequency": 6000000000.0, "power": 10 }, "mixer": {} }, "id": 0, "operations": { "readout": { "__class__": "quam.components.pulses.SquareReadoutPulse", "amplitude": 0.1, "length": 1000 } }, "opx_input_I": ["con1", 1], "opx_input_Q": ["con1", 2], "opx_output_I": ["con1", 1], "opx_output_Q": ["con1", 2] }, "xy": { "frequency_converter_up": { "__class__": "quam.components.hardware.FrequencyConverter", "local_oscillator": { "frequency": 6000000000.0, "power": 10 }, "mixer": {} }, "intermediate_frequency": 100000000.0, "operations": { "X90": { "__class__": "quam.components.pulses.GaussianPulse", "amplitude": 0.2, "length": 20, "sigma": 3 } }, "opx_output_I": ["con1", 3], "opx_output_Q": ["con1", 4] }, "z": { "opx_output": ["con1", 5] } }, "q1": { "id": 1, "resonator": { "frequency_converter_up": { "__class__": "quam.components.hardware.FrequencyConverter", "local_oscillator": { "frequency": 6000000000.0, "power": 10 }, "mixer": {} }, "id": 1, "opx_input_I": ["con1", 1], "opx_input_Q": ["con1", 2], "opx_output_I": ["con1", 4], "opx_output_Q": ["con1", 5] }, "xy": { "frequency_converter_up": { "__class__": "quam.components.hardware.FrequencyConverter", "local_oscillator": { "frequency": 6000000000.0, "power": 10 }, "mixer": {} }, "intermediate_frequency": 100000000.0, "opx_output_I": ["con1", 6], "opx_output_Q": ["con1", 7] }, "z": { "opx_output": ["con1", 8] } } } } ``` -------------------------------- ### Create and Activate Python Virtual Environment (venv) Source: https://github.com/qua-platform/quam/blob/main/docs/installation.md Instructions for creating and activating a Python virtual environment using the built-in `venv` module. This is recommended for isolating project dependencies. Commands vary slightly between Windows PowerShell and MacOS/Linux terminals. ```bash python -m venv {environment_name} source {environment_name}\Scripts\Activate.ps1 ``` ```bash python -m venv {environment_name} source {environment_name}/bin/activate ``` -------------------------------- ### Example Octave Configuration Summary Output Source: https://github.com/qua-platform/quam/blob/main/docs/components/octave.md This JSON output represents the detailed configuration summary of an `Octave` instance after its frequency converters have been initialized. It shows the `RF_outputs` (OctaveUpConverter) and `RF_inputs` (OctaveDownConverter) with their default properties, demonstrating the structure of the Octave's internal state. ```json Octave (parent unknown): name: "octave1" ip: "127.0.0.1" port: 80 calibration_db_path: None RF_outputs: QuamDict 1: OctaveUpConverter id: 1 channel: None LO_frequency: None LO_source: "internal" gain: 0 output_mode: "always_off" input_attenuators: "off" 2: OctaveUpConverter id: 2 channel: None LO_frequency: None LO_source: "internal" gain: 0 output_mode: "always_off" input_attenuators: "off" 3: OctaveUpConverter id: 3 channel: None LO_frequency: None LO_source: "internal" gain: 0 output_mode: "always_off" input_attenuators: "off" 4: OctaveUpConverter id: 4 channel: None LO_frequency: None LO_source: "internal" gain: 0 output_mode: "always_off" input_attenuators: "off" 5: OctaveUpConverter id: 5 channel: None LO_frequency: None LO_source: "internal" gain: 0 output_mode: "always_off" input_attenuators: "off" RF_inputs: QuamDict 1: OctaveDownConverter id: 1 channel: None LO_frequency: None LO_source: "internal" IF_mode_I: "direct" IF_mode_Q: "direct" IF_output_I: 1 IF_output_Q: 2 2: OctaveDownConverter id: 2 channel: None LO_frequency: None LO_source: "internal" IF_mode_I: "direct" IF_mode_Q: "direct" IF_output_I: 1 IF_output_Q: 2 loopbacks: QuamList = [] ``` -------------------------------- ### QUA Hardware Configuration JSON Schema Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This JSON structure represents a generated QUA configuration, detailing controllers, elements, mixers, pulses, and waveforms. It defines the setup for quantum hardware, including analog/digital I/O, qubit definitions, and pulse parameters. This configuration is crucial for programming quantum experiments. ```json { "controllers": { "con1": { "analog_inputs": {"1": {"offset": 0.0}, "2": {"offset": 0.0}}, "analog_outputs": { "1": {"offset": 0.0}, "2": {"offset": 0.0}, "3": {"offset": 0.0}, "4": {"offset": 0.0}, "5": {"offset": 0.0}, "6": {"offset": 0.0}, "7": {"offset": 0.0}, "8": {"offset": 0.0} }, "digital_outputs": {} } }, "digital_waveforms": {"ON": {"samples": [[1, 0]]}}, "elements": { "IQ0": { "intermediate_frequency": 0.0, "mixInputs": { "I": ["con1", 1], "Q": ["con1", 2], "lo_frequency": 6000000000.0, "mixer": "IQ0.mixer" }, "operations": {"readout": "IQ0.readout.pulse"}, "outputs": {"out1": ["con1", 1], "out2": ["con1", 2]}, "smearing": 0, "time_of_flight": 24 }, "IQ1": { "intermediate_frequency": 0.0, "mixInputs": { "I": ["con1", 4], "Q": ["con1", 5], "lo_frequency": 6000000000.0, "mixer": "IQ1.mixer" }, "operations": {}, "outputs": {"out1": ["con1", 1], "out2": ["con1", 2]}, "smearing": 0, "time_of_flight": 24 }, "q0.xy": { "intermediate_frequency": 100000000.0, "mixInputs": { "I": ["con1", 3], "Q": ["con1", 4], "lo_frequency": 6000000000.0, "mixer": "q0.xy.mixer" }, "operations": {"X90": "q0.xy.X90.pulse"} }, "q0.z": {"operations": {}, "singleInput": {"port": ["con1", 5]}}, "q1.xy": { "intermediate_frequency": 100000000.0, "mixInputs": { "I": ["con1", 6], "Q": ["con1", 7], "lo_frequency": 6000000000.0, "mixer": "q1.xy.mixer" }, "operations": {} }, "q1.z": {"operations": {}, "singleInput": {"port": ["con1", 8]}} }, "integration_weights": { "IQ0.readout.iw1": {"cosine": [[1.0, 1000]], "sine": [[-0.0, 1000]]}, "IQ0.readout.iw2": {"cosine": [[0.0, 1000]], "sine": [[1.0, 1000]]}, "IQ0.readout.iw3": {"cosine": [[-0.0, 1000]], "sine": [[-1.0, 1000]]} }, "mixers": { "IQ0.mixer": [ { "correction": [1.0, 0.0, 0.0, 1.0], "intermediate_frequency": 0.0, "lo_frequency": 6000000000.0 } ], "IQ1.mixer": [ { "correction": [1.0, 0.0, 0.0, 1.0], "intermediate_frequency": 0.0, "lo_frequency": 6000000000.0 } ], "q0.xy.mixer": [ { "correction": [1.0, 0.0, 0.0, 1.0], "intermediate_frequency": 100000000.0, "lo_frequency": 6000000000.0 } ], "q1.xy.mixer": [ { "correction": [1.0, 0.0, 0.0, 1.0], "intermediate_frequency": 100000000.0, "lo_frequency": 6000000000.0 } ] }, "oscillators": {}, "pulses": { "IQ0.readout.pulse": { "digital_marker": "ON", "integration_weights": { "iw1": "IQ0.readout.iw1", "iw2": "IQ0.readout.iw2", "iw3": "IQ0.readout.iw3" }, "length": 1000, "operation": "measurement", "waveforms": {"I": "IQ0.readout.wf.I", "Q": "IQ0.readout.wf.Q"} }, "const_pulse": { "length": 1000, "operation": "control", "waveforms": {"I": "const_wf", "Q": "zero_wf"} }, "q0.xy.X90.pulse": { "length": 20, ``` -------------------------------- ### Example QUA Program with Gate Operations Source: https://github.com/qua-platform/quam/blob/main/docs/examples/Gate-Level Operations.ipynb This snippet demonstrates a simple QUA program applying single-qubit and Clifford gates, followed by a measurement operation on qubit 'q1'. It illustrates how high-level gate instructions are used within the QUA framework. ```python with program() as prog: X(q1) # Single-qubit gate clifford(q1, 4) # Clifford gate from a predefined set qubit_state = measure(q1) ``` -------------------------------- ### Install Custom QUAM Components Python Package Source: https://github.com/qua-platform/quam/blob/main/docs/components/custom-components.md Command to install the newly created Python package containing custom QUAM components in editable mode. This makes the components available for import in Python environments. ```bash pip install . ``` -------------------------------- ### Add Component to QUAM Tree and Verify Parent Source: https://github.com/qua-platform/quam/blob/main/docs/features/quam-references.md This example illustrates how to add a new component, specifically a `Transmon` qubit, to an existing `QuamRoot` instance. It highlights QUAM's single-parent rule by showing how the `parent` attribute is automatically set and can be asserted. ```python qubit = superconducting_qubits.Transmon(xy=IQChannel(opx_output_I=("con1", 1), opx_output_Q=("con1", 2")) machine.qubit = qubit assert qubit.parent == machine ``` -------------------------------- ### QUAM Quantum Component API Reference Source: https://github.com/qua-platform/quam/blob/main/docs/components/qubits-and-qubit-pairs.md This section provides an overview of core classes in the QUAM framework for defining quantum components, including their properties, methods, and relationships. It details the base `QuantumComponent`, specific `Qubit` and `QubitPair` classes, and an example `Transmon` subclass. ```APIDOC QuantumComponent: Base class for qubits and qubit pairs. Properties: id: Unique identifier. macros: Collection of QuamMacro instances. name: Abstract property, must be implemented by subclasses. Methods: apply(operation_name: str, *args, **kwargs): Applies a defined operation/macro. @register_macro: Decorator to register class methods as macros. Qubit(QuantumComponent): Models a physical qubit on the QPU. Properties: channels: Dictionary of all associated channels. Methods: get_pulse(name: str): Retrieves a pulse by name from any channel. align(*other_qubits): Synchronizes all channels of the qubit(s). get_reference(): Returns a string reference to the qubit (e.g., "#/qubits/q1"). Transmon(Qubit): Example subclass of Qubit for a Transmon qubit. Properties: drive: IQChannel flux: SingleChannel QubitPair: Models the interaction between two qubits. Properties: qubit_control: Reference to the control qubit. qubit_target: Reference to the target qubit. name: Automatically generated name (e.g., "q1@q2"). Methods: apply(macro_name: str): Applies a two-qubit gate macro. ``` -------------------------------- ### Demonstrate Single-Parent Rule Enforcement Error Source: https://github.com/qua-platform/quam/blob/main/docs/features/quam-references.md This snippet provides an example of how QUAM enforces the single-parent rule for components. It shows that attempting to assign the same `IQChannel` instance as a child to multiple parent components will result in a `ValueError`, preventing invalid tree structures. ```python 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 ``` -------------------------------- ### Playing a Registered Analog Pulse in QUA Program Source: https://github.com/qua-platform/quam/blob/main/docs/components/channels.md This example shows how to play a previously registered analog pulse within a QUA program. The `channel.play()` method is used to trigger the 'X180' pulse, which is a light wrapper around the QUA SDK's `qm.qua.play()` statement. ```python with program() as prog: channel.play("X180") ``` -------------------------------- ### Registering a Readout Pulse for Input/Output Channels Source: https://github.com/qua-platform/quam/blob/main/docs/components/channels.md This example demonstrates how to register a specialized readout pulse, `SquareReadoutPulse`, with an input/output channel's operations. Readout pulses are similar to standard pulses but include additional parameters like `integration_weights_angle` to specify how the received signal should be integrated for measurement. ```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 ) ``` -------------------------------- ### Configure IQ Analog Output Channel with Frequency Upconverter Source: https://github.com/qua-platform/quam/blob/main/docs/migrating-to-quam.md Demonstrates how to configure an IQ analog output channel in QUA (JSON) and instantiate it in QUAM (Python), including a frequency upconverter with a local oscillator and mixer. This setup is used for IQ modulation and upconversion. ```json "qubit_xy": { "intermediate_frequency": 100e6, "mixInputs": { "I": ("con1", 1), "Q": ("con1", 2), "lo_frequency": 5e9, "mixer": "mixer_qubit", }, "operations": {...} }, ``` ```python from quam.components import IQChannel, FrequencyConverter, LocalOscillator, Mixer 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() ) ) ``` -------------------------------- ### Define OPX+ Analog Output Port and Single Channel in QUAM Source: https://github.com/qua-platform/quam/blob/main/docs/components/channel-ports.md This Python example demonstrates how to define an "OPXPlusAnalogOutputPort" for an OPX+ analog output, specifying its offset and delay. It then shows how to associate this defined port with a "SingleChannel" component, illustrating the method for managing port-specific properties directly through the port object rather than the channel's default output settings. ```python from quam.components.ports import OPXPlusAnalogOutputPort from quam.components import SingleChannel port = OPXPlusAnalogOutputPort(port=("con1", 3), offset=0.2, delay=12) channel = SingleChannel(opx_output=port) ``` -------------------------------- ### Customize Root QUAM Object with Qubit Dictionary Source: https://github.com/qua-platform/quam/blob/main/docs/migrating-to-quam.md This Python snippet demonstrates how to customize the root-level QUAM object to include a dictionary of custom `Qubit` components. By extending `QuamRoot` and defining a `qubits` dictionary, it allows for structured management of multiple qubits within the overall machine configuration. This is essential for scaling and organizing complex quantum setups. ```python from typing import Dict from quam.core import QuamRoot @quam_dataclass class Quam(QuamRoot): qubits: Dict[str, Qubit] machine = Quam(qubits={"qubit1": qubit}) ``` -------------------------------- ### Attaching Multiple Digital Output Channels to an Analog Channel Source: https://github.com/qua-platform/quam/blob/main/docs/components/channels.md This example illustrates how to attach multiple `DigitalOutputChannel` instances to a single analog channel's `digital_outputs` attribute. This configuration enables playing digital pulses simultaneously across several digital channels associated with the same analog channel. ```python analog_channel.digital_outputs = { "dig_out1": DigitalOutputChannel(opx_output=("con1", 1)), "dig_out2": DigitalOutputChannel(opx_output=("con1", 2)) } ``` -------------------------------- ### Initialize QUAM Environment and Create Output Directories Source: https://github.com/qua-platform/quam/blob/main/docs/examples/QuAM features.ipynb This snippet imports necessary QUAM components and sets up the output directory structure for saving QUAM states and QUA configurations. It ensures that required folders exist for different demonstration scenarios, preparing the environment for QUAM operations. ```python import json from quam.components import * from quam.examples.superconducting_qubits import * from pathlib import Path root_folder = Path("./output") root_folder.mkdir(exist_ok=True) for key in ["basic", "referenced", "referenced_multifile"]: (root_folder / key).mkdir(exist_ok=True) ``` -------------------------------- ### Open Quantum Machine with QUA Configuration Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This Python snippet demonstrates how to open a quantum machine (QM) using a previously defined QUA configuration. The `open_qm` method from `qmm` (Quantum Machine Manager) initializes the hardware connection, making it ready for executing quantum experiments. ```python qm = qmm.open_qm(qua_config) # Open a quantum machine with the configuration ``` -------------------------------- ### Display QUAM Machine Configuration and Output Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This snippet demonstrates how to retrieve and view the current hardware configuration of a QUAM machine. It shows the Python command used to initiate the display and the resulting detailed JSON output, which outlines the structure of qubits, channels, and their properties such as operations, frequencies, and connectivity. ```python machine.print_summary() ``` ```json QUAM: qubits: QuamDict q0: Transmon id: 0 xy: IQChannel operations: QuamDict X90: GaussianPulse length: 20 id: None digital_marker: None amplitude: 0.2 sigma: 3 axis_angle: None subtracted: True 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: 100000000.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: InOutIQChannel operations: QuamDict readout: SquareReadoutPulse length: 1000 id: None digital_marker: "ON" amplitude: 0.1 axis_angle: None threshold: None rus_exit_threshold: None integration_weights: None integration_weights_angle: 0 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 q1: 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: 100000000.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: InOutIQChannel operations: QuamDict Empty id: 1 digital_outputs: QuamDict Empty opx_output_I: ('con1', 4) opx_output_Q: ('con1', 5) 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 wiring: QuamDict Empty ``` -------------------------------- ### Instantiate a New Empty QUAM Machine Object Source: https://github.com/qua-platform/quam/blob/main/docs/examples/QuAM features.ipynb This code initializes an empty `Quam` object, which serves as the root container for defining the quantum machine's configuration. It's the foundational step before populating the machine with various components. ```python machine = Quam() machine ``` -------------------------------- ### Populate QUAM Machine with Transmon Qubits and Channels Source: https://github.com/qua-platform/quam/blob/main/docs/demonstration.md This snippet iterates to create and configure two Transmon qubits. For each qubit, it instantiates a `Transmon` object, adds it to the `machine.qubits` dictionary, and defines its `xy` (drive), `z` (flux), and `resonator` channels with their respective OPX outputs, frequency converters, and local oscillators. ```python num_qubits = 2 for idx in range(num_qubits): # Create transmon qubit component transmon = Transmon(id=idx) machine.qubits[transmon.name] = transmon # Add xy drive line channel transmon.xy = IQChannel( opx_output_I=("con1", 3 * idx + 3), opx_output_Q=("con1", 3 * idx + 4), frequency_converter_up=FrequencyConverter( mixer=Mixer(), local_oscillator=LocalOscillator(power=10, frequency=6e9), ), intermediate_frequency=100e6, ) # Add transmon flux line channel transmon.z = SingleChannel(opx_output=("con1", 3 * idx + 5)) # Add resonator channel transmon.resonator = InOutIQChannel( id=idx, opx_output_I=("con1", 1), opx_output_Q=("con1", 2), opx_input_I=("con1", 1), opx_input_Q=("con1", 2,), frequency_converter_up=FrequencyConverter( mixer=Mixer(), local_oscillator=LocalOscillator(power=10, frequency=6e9) ), ) ``` -------------------------------- ### Instantiate Basic QUAM Root Object in Python Source: https://github.com/qua-platform/quam/blob/main/docs/components/quam-root.md Demonstrates how to create a basic QUAM root object using `BasicQuam` from `quam.components`. This snippet also shows how to add a channel to the machine, suitable for straightforward QUAM implementations. ```python from quam.components import BasicQuam machine = BasicQuam() machine.channels["qubit_xy"] = IQChannel(opx_output_I=("con1", 1), opx_output_Q=("con1", 2), ...) ``` -------------------------------- ### Populate QUAM with Components Using Internal References for Wiring Source: https://github.com/qua-platform/quam/blob/main/docs/examples/QuAM features.ipynb This advanced snippet demonstrates how to use internal references within QUAM to define component properties, such as `opx_output_I`, by pointing to other parts of the QUAM structure. This promotes reusability and better organization of complex configurations, especially for centralized wiring definitions. ```python num_qubits = 2 machine = Quam() machine.wiring = { "qubits": { f"q{idx}": { "port_I": ("con1", 3 * idx + 3), "port_Q": ("con1", 3 * idx + 4), "port_Z": ("con1", 3 * idx + 5), } for idx in range(num_qubits) }, "feedline": { "opx_output_I": ("con1", 1), "opx_output_Q": ("con1", 2), "opx_input_I": ("con1", 1), "opx_input_Q": ("con1", 2), }, } for idx in range(num_qubits): # Create qubit components transmon = Transmon( id=idx, xy=IQChannel( opx_output_I=f"#/wiring/qubits/q{idx}/port_I", opx_output_Q=f"#/wiring/qubits/q{idx}/port_Q", frequency_converter_up=FrequencyConverter( mixer=Mixer(), local_oscillator=LocalOscillator(power=10, frequency=6e9), ), intermediate_frequency=100e6, ), z=SingleChannel(opx_output=f"#/wiring/qubits/q{idx}/port_Z"), ) machine.qubits[transmon.name] = transmon readout_resonator = InOutIQChannel( id=idx, opx_output_I="#/wiring/feedline/opx_output_I", opx_output_Q="#/wiring/feedline/opx_output_Q", opx_input_I="#/wiring/feedline/opx_input_I", opx_input_Q="#/wiring/feedline/opx_input_Q", frequency_converter_up=FrequencyConverter( mixer=Mixer(), local_oscillator=LocalOscillator(power=10, frequency=6e9) ), ) transmon.resonator = readout_resonator machine.print_summary() ``` -------------------------------- ### Playing a Registered Pulse in a QUAM Program Source: https://github.com/qua-platform/quam/blob/main/docs/components/pulses.md After a pulse is registered to a channel, this example shows how to use the 'program' context manager from 'qm.qua' to play the 'X180' pulse on the previously defined channel, executing the quantum operation. ```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") ``` -------------------------------- ### Populate QUAM with Superconducting Qubit and Resonator Components Source: https://github.com/qua-platform/quam/blob/main/docs/examples/QuAM features.ipynb This snippet demonstrates how to programmatically add `Transmon` qubits and their associated `InOutIQChannel` readout resonators to the `Quam` machine. It configures their physical connections and frequency converters, building a basic quantum system definition within QUAM. ```python num_qubits = 2 for idx in range(num_qubits): # Create qubit components transmon = Transmon( id=idx, xy=IQChannel( opx_output_I=("con1", 3 * idx + 3), opx_output_Q=("con1", 3 * idx + 4), frequency_converter_up=FrequencyConverter( mixer=Mixer(), local_oscillator=LocalOscillator(power=10, frequency=6e9), ), intermediate_frequency=100e6, ), z=SingleChannel(opx_output=("con1", 3 * idx + 5)), ) machine.qubits[transmon.name] = transmon readout_resonator = InOutIQChannel( id=idx, opx_output_I=("con1", 3 * idx + 1), opx_output_Q=("con1", 3 * idx + 2), opx_input_I=("con1", 1), opx_input_Q=("con1", 2,), frequency_converter_up=FrequencyConverter( mixer=Mixer(), local_oscillator=LocalOscillator(power=10, frequency=6e9) ), ) transmon.resonator = readout_resonator machine.print_summary() ``` -------------------------------- ### Creating a Custom Ramp Pulse in QUAM Source: https://github.com/qua-platform/quam/blob/main/docs/components/pulses.md This example shows how to define a custom RampPulse by subclassing 'pulses.Pulse'. It uses 'quam_dataclass' to define 'amplitude_start' and 'amplitude_stop' parameters and implements a 'waveform_function' using NumPy to generate a linear ramp. ```python import numpy as np from quam.core import quam_dataclass from quam.components import pulses @quam_dataclass 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 ramp waveform return np.linspace(self.amplitude_start, self.amplitude_stop, self.length) ``` -------------------------------- ### Instantiate Octave Component Source: https://github.com/qua-platform/quam/blob/main/docs/components/octave.md This code demonstrates how to create an `Octave` instance with a name, IP address, and port, and then assign it to the `octave` attribute of the root `Quam` machine. This is the first step in configuring an Octave device. ```python octave = Octave(name="octave1", ip="127.0.0.1", port=80) machine.octave = octave ``` -------------------------------- ### Measuring Quantum State with a Readout Pulse in QUAM Source: https://github.com/qua-platform/quam/blob/main/docs/components/pulses.md Once a readout pulse is defined, this example demonstrates how to use it within a QUAM program to measure the state of a quantum system. The 'measure' method on the 'readout_channel' executes the defined 'readout' pulse. ```python with program() as prog: # Measure the state of the quantum system using the "readout" pulse qua_result = readout_channel.measure("readout") ``` -------------------------------- ### Load QuAM Configuration from a Folder (Python) Source: https://github.com/qua-platform/quam/blob/main/docs/examples/QuAM features.ipynb This snippet shows how to load a QuAM machine configuration from a specified root folder. It assumes the configuration might be spread across multiple files within that folder, as set up by the saving process. ```python machine = Quam.load(root_folder / "referenced_multifile" / "quam") ``` -------------------------------- ### Instantiate a QubitPair Source: https://github.com/qua-platform/quam/blob/main/docs/components/qubits-and-qubit-pairs.md This snippet shows how to create a `QubitPair` instance, linking two existing `Qubit` objects using their references. It highlights the use of `get_reference()` to ensure proper hierarchical linking within the QUAM structure, which is crucial for managing component relationships. ```python machine.qubit_pairs["q1@q2"] = QubitPair( qubit_control=q1.get_reference(), # = "#/qubits/q1" qubit_target=q2.get_reference() # = "#/qubits/q2" ) ```