Principles of Quantum Computing

Teaching experiments on quantum computing process

NMR Phenomena and Signals

The most basic NMR experiment is used to observe nuclear magnetic resonance phenomena:

from spinqlablink import SpinQLabLink, ExperimentType, Pulse
from spinqlablink import print_graph

def nmr_signal_experiment():
    """NMR Phenomenon and Signal Experiment"""
    # Connect to device
    spinqlablink = SpinQLabLink("192.168.9.121", 8181, "username", "password")
    spinqlablink.connect()
    spinqlablink.wait_for_login()

    try:
        # Register experiment
        _, exp_para = spinqlablink.register_experiment(ExperimentType.NMR_PHENOMENON_AND_SIGNAL)

        # Set pulse sequence
        exp_para.pulses = [Pulse(path=0, width=40, amplitude=100, phase=90, detuning=0)]

        # Set frequency parameters
        exp_para.freq_h = 37.852105  # Hydrogen resonance frequency
        exp_para.freq_p = 15.322872  # Phosphorus resonance frequency
        exp_para.makePps = True
        exp_para.samplePath = 0
        exp_para.custom_freq = False

        # Run experiment
        spinqlablink.run_experiment()
        spinqlablink.wait_for_experiment_completion()

        # Get and display results
        result = spinqlablink.get_experiment_result()
        print_graph(result["result"])

    finally:
        spinqlablink.deregister_experiment()
        spinqlablink.disconnect()

if __name__ == "__main__":
    nmr_signal_experiment()

Experimental Parameters Analysis

  • ExperimentType: Select NMR_PHENOMENON_AND_SIGNAL(for details, see:class:spinqlablink.ExperimentType class)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • freq_h: Hydrogen resonance frequency (hz) [0- 100M]

  • freq_p: Phosphorus resonance frequency (hz) [0- 100M]

  • makePps: Whether to use PPS pulse sequences

  • samplePath: Sampling path, 0= hydrogen channel, 1= phosphorus channel [0-1]

  • custom_freq: Whether to use custom frequency [True,False]

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "fftMod":[[x,y],...],
                "fidMod":[[x,y],...],
                "fftFit":[[x,y],...]
            },
            { # step 1},
            ...
            ]
        }
    }
}
  • graph: Chart data, including real and imaginary parts. The graph contains 1 step, and each step may contain the following data:
    • fidRe: FID Real Component

    • fidIm: FID Imaginary Component

    • fidMod: FID Modulus

    • lorenz: Lorenz fitted curve

    • fftRe: FFT Real Component

    • fftIm: FFT Imaginary Component

    • fftMod: FFT Modulus

    • fftFit: FFT Fit Curve

Rabi oscillation experiment

Measure Rabi oscillations at different pulse widths to determine π/2 and π pulse widths:

import time
import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
from spinqlablink import SpinQLabLink, ExperimentType, Pulse

def rabi_oscillation_experiment():
    """Rabi Oscillation Experiment - Pulse Width Scanning"""
    spinqlablink = SpinQLabLink("192.168.9.121", 8181, "username", "password")
    spinqlablink.connect()
    spinqlablink.wait_for_login()

    # Pulse width range
    width_list = [i * 40 for i in range(10)]  # 0, 40, 80, ..., 360 μs
    intensities = []

    try:
        for width in width_list:
            print(f"Testing pulse width: {width} μs")

            # Register experiment
            _, exp_para = spinqlablink.register_experiment(ExperimentType.RABI_OSCILLATIONS)

            # Set parameters
            exp_para.freq_h = 37.852105
            exp_para.freq_p = 15.322872
            exp_para.makePps = True
            exp_para.samplePath = 0
            exp_para.custom_freq = False
            exp_para.pulses = [Pulse(path=0, width=width, amplitude=100, phase=90, detuning=0)]

            # Run experiment
            spinqlablink.run_experiment()
            spinqlablink.wait_for_experiment_completion()

            # Get results
            result = spinqlablink.get_experiment_result()
            signal_data = result["result"]["real"]

            # Calculate signal intensity (FFT peak)
            if signal_data is not None:
                if isinstance(signal_data, (int, float)):
                    signal_array = np.array([signal_data])
                elif isinstance(signal_data, (list, tuple, np.ndarray)):
                    signal_array = np.array([point[1] for point in signal_data if isinstance(point, (list, tuple, np.ndarray))])
                else:
                    signal_array = np.array([])
                if len(signal_array) > 0:
                    intensity = np.max(np.abs(np.fft.fft(signal_array)))
                else:
                    intensity = 0
                intensities.append(intensity)
            else:
                intensities.append(0)

            spinqlablink.deregister_experiment()
            time.sleep(2)  # Wait for system stabilization

        # Fit Rabi oscillation curve
        def rabi_function(x, A, B, freq, phase):
            return A * np.cos(2 * np.pi * freq * x + phase) + B

        try:
            popt, _ = curve_fit(rabi_function, width_list, intensities)
            pi_pulse_width = np.pi / (2 * np.pi * popt[2])
            print(f"Estimated π pulse width: {pi_pulse_width:.1f} μs")

            # Plot results
            plt.figure(figsize=(10, 6))
            plt.plot(width_list, intensities, 'bo-', label='Experimental data')
            x_fit = np.linspace(min(width_list), max(width_list), 100)
            y_fit = rabi_function(x_fit, *popt)
            plt.plot(x_fit, y_fit, 'r-', label='Fitted curve')
            plt.xlabel('Pulse width (μs)')
            plt.ylabel('Signal intensity')
            plt.title('Rabi Oscillation')
            plt.legend()
            plt.grid(True)
            plt.show()

        except Exception as e:
            print(f"Fitting failed: {e}")

    finally:
        spinqlablink.disconnect()

if __name__ == "__main__":
    rabi_oscillation_experiment()

Experimental Parameters Analysis

  • ExperimentType: Select RABI_OSCILLATIONS for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • freq_h: Hydrogen resonance frequency (hz) [0- 100M]

  • freq_p: Phosphorus resonance frequency (hz) [0- 100M]

  • makePps: Whether to use PPS pulse sequences

  • samplePath: Sampling path, 0= hydrogen channel, 1= phosphorus channel [0-1]

  • custom_freq: Whether to use custom frequency [True,False]

Code flow analysis

The code flow of the Rabi Oscillation experiment can be divided into the following key steps:

  1. ** Initialize connection **:

    • Create a SpinQLabLink object and connect it to a quantum computing device

    • Verify login status and ensure successful connection

  2. ** Experimental parameter settings **:

    • Register Rabbi Oscillation Experiments (RABI_OSCILLATIONS)

    • Set experimental parameters, including resonance frequency, sampling path, etc.

    • Define a list of pulse widths for observing oscillation effects at different widths

  3. ** Experimental execution cycle **:

    • Iterates for each pulse width

    • Set the corresponding pulse parameters for each iteration

    • Run the experiment and wait for completion

    • Collect experimental results and extract signal strength data

    • Log out experiments between iterations and wait for the system to stabilize

  4. ** Data analysis and visualization **:

    • Fitting Rabi oscillation curve using nonlinear least squares method

    • Calculate π pulse width from fitting parameters

    • Plot experimental data points and fitted curves

    • Display results chart

  5. ** Resource release **:

    • Disconnect the connection from the device after the experiment is completed

This experiment demonstrates the Rabi oscillation phenomenon of qubits under the action of radio frequency pulses by observing the changes in signal strength under different pulse widths. This is the basis of quantum control and an important method for determining the π pulse width (used for qubit flipping).

Analysis of experimental results

Results of Rabi's oscillation experiment
{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "width": 80.0, # Pulse Width
        "real": 0.85 # Real part of signal strength
    }
}
  • graph: Chart data, including real and imaginary parts, the graph contains 1 step

  • width: Pulse width

  • real: real part of signal strength

qubit experiment

Observe the physical properties of qubits

from spinqlablink import SpinQLabLink, ExperimentType, Pulse
from spinqlablink import print_graph

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    # Register Quantum Bit experiment
    # This experiment demonstrates the basic operations and measurements of a single qubit
    # In NMR systems, nuclear spins serve as qubits with two energy states (|0⟩ and |1⟩)
    _, exp_qubit_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_BIT)

    # Set experiment parameters
    # Channel selection
    exp_qubit_para.samplePath = 0  # Sampling path: 0=Hydrogen channel, 1=Phosphorus channel
                                # Hydrogen nuclei are commonly used as qubits in NMR quantum computing

    # Define the pulse sequence for qubit manipulation
    # This example uses a π/2 pulse (90° rotation) which creates a superposition state
    # Parameters:
    # - path: 0 for hydrogen channel
    # - width: 40 microseconds pulse duration
    # - amplitude: 100% of maximum amplitude
    # - phase: 90 degrees phase angle (creates rotation around Y-axis)
    # - detuning: 0 Hz frequency offset from resonance
    exp_qubit_para.pulses = [Pulse(path=0,width=40, amplitude=100, phase=90, detuning=0)]

    # Run the experiment
    spinqlablink.run_experiment()
    print("Waiting for experiment completion")
    spinqlablink.wait_for_experiment_completion()

    # Get the results
    exp_info = spinqlablink.get_experiment_result()

    # Clean up and disconnect
    spinqlablink.deregister_experiment()
    spinqlablink.disconnect()

    # Display the results
    # The results should show the quantum state of the qubit after manipulation
    if "result" in exp_info:
        exp_result = exp_info["result"]
        for key, value in exp_result.items():
            if key != "graph":
                print(f"{key}: {value}")

        print_graph(exp_info["result"])
    else:
        print("Experiment failed")

if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_BIT for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • samplePath: Sampling path, 0= hydrogen channel, 1= phosphorus channel [0-1]

  • pulses: List of pulse sequences, containing a series of Pulse objects

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "coordinate": {  # The coordinates of a qubit on the Bloch sphere
            "x": [0, 1],
            "y": [0, 1],
            "z": [0, 1]
        },
        "matrix": {  # The density matrix of a quantum state, including its real and imaginary parts
            "real": [[1, 0], [0, 1]],
            "imag": [[0, 0], [0, 0]]
        },
        "probability": [0.5, 0.5]  # Probability distribution of measurement results
    }
}
  • graph: Chart data, including real and imaginary parts, the graph contains 2 steps

  • coordinate: The coordinates of the qubit on the Bloch sphere

  • matrix: The density matrix of the quantum state, including the real and imaginary parts

  • probability: probability distribution of measurement results

Quantum decoherence T1 experiment

Observation of quantum decoherence phenomenon T1

from spinqlablink import SpinQLabLink, ExperimentType, Pulse

# Drawing charts
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
import numpy as np
from scipy.optimize import curve_fit

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    width_real_map = {}
    width_list = []

    for i in range(5):
        width_list.append(i * 100000)

    for width in width_list:
        _, exp_decot1_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_DECOHERENCE_T1)

        # Set other parameters
        exp_decot1_para.samplePath = 0  # Sampling path: 0=Hydrogen channel, 1=Phosphorus channel

        exp_decot1_para.pulses = [Pulse(path=0,width=80, amplitude=100, phase=90, detuning=0)
                                ,Pulse(path=0,width=width, amplitude=0, phase=0, detuning=0)]

        spinqlablink.run_experiment()
        print("Waiting for experiment completion")
        spinqlablink.wait_for_experiment_completion()

        exp_info = spinqlablink.get_experiment_result()

        width_real_map[width] = exp_info["result"]["real"]

        spinqlablink.deregister_experiment()

    spinqlablink.disconnect()

    print("width_real_map: ", width_real_map)
    # Convert data to format suitable for fitting
    x_data = list(width_real_map.keys())
    y_data = list(width_real_map.values())

    # Plot experiment results and fitting curve
    app = QtWidgets.QApplication([])
    win = pg.GraphicsLayoutWidget(show=True, title="Rabi Oscillation Experiment Results")
    win.resize(800, 600)

    # Set background to white
    win.setBackground('w')

    # Add plot area
    plot = win.addPlot(title="Decoherence T1")
    plot.setLabel('left', 'Amplitude')
    plot.setLabel('bottom', 'Pulse Width (us)')

    # Execute fitting and display results
    fit_results = fit_decot1_oscillations(x_data, y_data, plot)

    # Start Qt event loop
    app.exec_()

def fit_decot1_oscillations(x_data, y_data, plot):
    """
    Fit T1 relaxation data with an exponential decay model and display the results.

    T1 relaxation (longitudinal/amplitude relaxation) follows the model:
    A + (|A| - A) * (1 - exp(-t/T1))

    where:
    - A is the equilibrium amplitude
    - T1 is the relaxation time constant
    - t is the delay time

    Parameters:
        x_data: List of delay times (in microseconds)
        y_data: Corresponding experimental signal amplitudes
        plot: pyqtgraph Plot object to display the results

    Returns:
        Dictionary containing fitting parameters: A (equilibrium amplitude),
        T1 (relaxation time), and R (correlation coefficient)
    """
    # Draw experimental data points
    scatter = pg.ScatterPlotItem(x=x_data, y=y_data, pen=None, brush=pg.mkBrush(0, 0, 255, 200), size=10)
    plot.addItem(scatter)

    # Prepare fitting parameters
    min_sig = min(y_data)

    # T1 relaxation model: equilibrium + (max_change) * (1 - exp(-t/T1))
    # This models how the system returns to equilibrium after excitation
    def t1_model(x, A, t1):
        return A + (np.abs(A) - A) * (1 - np.exp(-x / t1));

    # Initial parameter guesses: equilibrium amplitude and approximate T1 time
    p0 = [min_sig, 5000000]

    # Execute fitting
    try:
        popt, pcov = curve_fit(t1_model, x_data, y_data, p0=p0)

        # Get fitting parameters
        A_fit, t1_fit = popt

        # Calculate fitting quality R² (coefficient of determination)
        # R² = 1 - (residual sum of squares / total sum of squares)
        residuals = y_data - t1_model(np.array(x_data), *popt)
        ss_res = np.sum(residuals**2)
        ss_tot = np.sum((y_data - np.mean(y_data))**2)
        r = np.sqrt(1 - (ss_res / ss_tot))

        # Generate fitting curve with higher resolution for smooth display
        x_fit = np.linspace(0, 20000000, 5000)
        y_fit = t1_model(x_fit, *popt)

        # Draw fitting curve
        fit_curve = pg.PlotCurveItem(x=x_fit, y=y_fit, pen=pg.mkPen('r', width=2))
        plot.addItem(fit_curve)

        # Add legend
        legend = plot.addLegend()
        legend.addItem(scatter, 'experimental data')
        legend.addItem(fit_curve, 'fitting curve')

        # Display fitting parameters
        text = pg.TextItem(text=f"A = {A_fit:.4f}\nt1 = {t1_fit:.4f}\nR = {r:.4f}",
                        color=(0, 0, 0), anchor=(0, 0))
        text.setPos(min(x_data), max(y_data) * 0.5)
        plot.addItem(text)

        print("fitting parameters:")
        print(f"A = {A_fit:.4f}")
        print(f"t1 = {t1_fit:.4f}")
        print(f"fitting quality R = {r:.4f}")

        return {
            "A": A_fit,
            "t1": t1_fit,
            "r": r
        }

    except Exception as e:
        print(f"fitting error: {e}")
        return None


if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_DECOHERENCE_T1 for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • samplePath: Sampling path, 0= hydrogen channel, 1= phosphorus channel [0-1]

  • pulses: List of pulse sequences, containing a series of Pulse objects, usually containing two pulses: -First pulse: π/2 pulse, used to excite the qubit-Second pulse: delayed pulse, width change used to measure T1 relaxation time

Code flow analysis

The code flow of the quantum decoherence T1 experiment can be divided into the following key steps:

  1. ** Initialize connection **:

    • Create a SpinQLabLink object and connect it to a quantum computing device

    • Verify login status and ensure successful connection

  2. ** Preparation of experimental parameters **:

    • Create a data structure to store measurement results with different latency times

    • Define a list of delay times for observing the relaxation process of qubits

  3. ** Experimental execution cycle **:

    • Iterates for each delay time

    • Register the Quantum Decoherence T1 Experiment (QUANTUM_DECOHERENCE_T1)

    • Set experimental parameters, including sampling path and pulse sequence

    • A pulse sequence usually consists of two pulses:

      • The first pulse: π/2 pulse (90°), which transfers the qubit from| Excitation of 0 state to superposition state

      • Second pulse: delayed pulse, with varying width used to measure quantum states after different waiting times

    • Run the experiment and wait for completion

    • Collect experimental results and extract signal strength data

    • Cancel experiments between iterations

  4. ** Data analysis and fitting **:

    • Fit the T1 relaxation curve using an exponential decay model: f(t) = A * exp(-t/T1) + C

    • Extraction of T1 time constant from fitting parameters

    • Calculate the fitting quality (R value) to evaluate the fitting accuracy

  5. ** Results visualization **:

    • Plot experimental data points and fitted curves

    • Display fitting parameters, including amplitude A, T1 time, and fit quality R

    • Add legend and parameter text to the chart

  6. ** Resource release **:

    • Disconnect the connection from the device after the experiment is completed

This experiment measured the longitudinal relaxation time (T1) of the qubit by observing the process of returning the qubit from the excited state to the ground state. This is an important parameter for evaluating the quality of the qubit and represents the time scale on which the qubit can retain energy.

Analysis of experimental results

T1 experimental results
{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "width": 100000,  # Delay pulse width
        "real": 0.75,  # Real part of signal strength
        "coordinate": {  # The coordinates of a qubit on the Bloch sphere
            "x": [0, 1],
            "y": [0, 1],
            "z": [0, 1]
        },
        "matrix": {  # The density matrix of a quantum state, including its real and imaginary parts
            "real": [[1, 0], [0, 1]],
            "imag": [[0, 0], [0, 0]]
        },
        "probability": [0.5, 0.5]  # Probability distribution of measurement results
    }
}
  • graph: Chart data, including real and imaginary parts, the graph contains 2 steps

  • width: Delay pulse width

  • real: real part of signal strength

  • coordinate: The coordinates of the qubit on the Bloch sphere

  • matrix: The density matrix of the quantum state, including the real and imaginary parts

  • probability: probability distribution of measurement results

Quantum decoherence T2 experiment

Observation of quantum decoherence phenomenon T2

from spinqlablink import SpinQLabLink, ExperimentType, Pulse

# Drawing charts
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets
import numpy as np
from scipy.optimize import curve_fit

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    width_mod_map = {}
    width_list = []

    for i in range(10):
        width_list.append(i * 500000)

    for width in width_list:
        _, exp_decot2_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_DECOHERENCE_T2)

        # Set other parameters
        exp_decot2_para.samplePath = 0  # Sampling path: 0=Hydrogen channel, 1=Phosphorus channel

        exp_decot2_para.pulses = [Pulse(path=0,width=40, amplitude=100, phase=90, detuning=0)
                                ,Pulse(path=0,width=width/2, amplitude=0, phase=0, detuning=0)
                                ,Pulse(path=0,width=80, amplitude=100, phase=90, detuning=0)
                                ,Pulse(path=0,width=width/2, amplitude=0, phase=0, detuning=0)]

        spinqlablink.run_experiment()
        print("Waiting for experiment completion")
        spinqlablink.wait_for_experiment_completion()

        exp_info = spinqlablink.get_experiment_result()

        width_mod_map[width] = exp_info["result"]["mod"]

        spinqlablink.deregister_experiment()

    spinqlablink.disconnect()

    print("width_mod_map: ", width_mod_map)
    # Convert data to format suitable for fitting
    x_data = list(width_mod_map.keys())
    y_data = list(width_mod_map.values())

    # Plot experiment results and fitting curve
    app = QtWidgets.QApplication([])
    win = pg.GraphicsLayoutWidget(show=True, title="Decoherence T2 Experiment Results")
    win.resize(800, 600)

    # Set background to white
    win.setBackground('w')

    # Add plot area
    plot = win.addPlot(title="Decoherence T2")
    plot.setLabel('left', 'Amplitude')
    plot.setLabel('bottom', 'Pulse Width (us)')

    # Execute fitting and display results
    fit_results = fit_decot2_oscillations(x_data, y_data, plot)

    # Start Qt event loop
    app.exec_()

def fit_decot2_oscillations(x_data, y_data, plot):
    """
    Fit Decoherence t2 oscillation data with a sine function and display the results on the specified plot

    Parameters:
        x_data: List of pulse widths
        y_data: Corresponding experimental data
        plot: pyqtgraph Plot object to display the results

    Returns:
        Fitting parameters and results
    """
    # Draw experimental data points
    scatter = pg.ScatterPlotItem(x=x_data, y=y_data, pen=None, brush=pg.mkBrush(0, 0, 255, 200), size=10)
    plot.addItem(scatter)

    # Prepare fitting parameters
    max_sig = max(y_data)

    # Decoherence T2 fitting function A * exp(- x / B)
    def t2_model(x, A, t2):
        return abs(A) * np.exp(- x / t2);

    p0 = [max_sig, 500000]

    # Execute fitting
    try:
        popt, pcov = curve_fit(t2_model, x_data, y_data, p0=p0)

        # Get fitting parameters
        A_fit, t2_fit = popt

        # Calculate fitting quality R²
        residuals = y_data - t2_model(np.array(x_data), *popt)
        ss_res = np.sum(residuals**2)
        ss_tot = np.sum((y_data - np.mean(y_data))**2)
        r = np.sqrt(1 - (ss_res / ss_tot))

        # Generate fitting curve
        x_fit = np.linspace(0, 5000000, 1000)
        y_fit = t2_model(x_fit, *popt)

        # Draw fitting curve
        fit_curve = pg.PlotCurveItem(x=x_fit, y=y_fit, pen=pg.mkPen('r', width=2))
        plot.addItem(fit_curve)

        # Add legend
        legend = plot.addLegend()
        legend.addItem(scatter, 'experimental data')
        legend.addItem(fit_curve, 'fitting curve')

        # Display fitting parameters
        text = pg.TextItem(text=f"A = {A_fit:.4f}\nt2 = {t2_fit:.4f}\nR = {r:.4f}",
                        color=(0, 0, 0), anchor=(0, 0))
        text.setPos(min(x_data), max(y_data) * 0.5)
        plot.addItem(text)

        print("fitting parameters:")
        print(f"A = {A_fit:.4f}")
        print(f"t2 = {t2_fit:.4f}")
        print(f"fitting quality R = {r:.4f}")

        return {
            "A": A_fit,
            "t2": t2_fit,
            "r": r
        }

    except Exception as e:
        print(f"fitting error: {e}")
        return None


if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_DECOHERENCE_T2 for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • samplePath: Sampling path, 0= hydrogen channel, 1= phosphorus channel [0-1]

  • pulses: List of pulse sequences, containing a series of Pulse objects, usually containing four pulses: -First pulse: π/2 pulse, used to excite the qubit-Second pulse: delayed pulse, width change used to measure T2 relaxation time-Third pulse: π pulse, used to echo-Fourth pulse: delayed pulse, width change used to measure T2 relaxation time

Code flow analysis

The code flow of the quantum decoherence T2 experiment can be divided into the following key steps:

  1. ** Initialize connection **:

    • Create a SpinQLabLink object and connect it to a quantum computing device

    • Verify login status and ensure successful connection

  2. ** Preparation of experimental parameters **:

    • Create a data structure to store measurement results with different latency times

    • Define a list of delay times for observing the decay of coherence of qubits over time

  3. ** Experimental execution cycle **:

    • Iterates for each delay time

    • Register the Quantum Decoherence T2 Experiment (QUANTUM_DECOHERENCE_T2)

    • Set experimental parameters, including sampling path and pulse sequence

    • The pulse sequence usually contains four pulses:

      • The first pulse: π/2 pulse (90°), which transfers the qubit from| The 0 state is excited to the equatorial plane

      • Second pulse: delayed pulse, width variation used to measure free evolution time

      • The third pulse: π pulse (180°), used for echo formation, canceling static field inhomogeneities

      • Fourth pulse: Delayed pulse, same width as the second pulse, used for echo formation

    • Run the experiment and wait for completion

    • Collect experimental results and extract signal strength data

    • Cancel experiments between iterations

  4. ** Data analysis and fitting **:

    • Fit T2 relaxation curve using exponential decay model: f(t) = A * exp(-t/T2)

    • Extraction of T2 time constant from fitting parameters

    • Calculate the fitting quality (R value) to evaluate the fitting accuracy

  5. ** Results visualization **:

    • Plot experimental data points and fitted curves

    • Displays fit parameters, including amplitude A, T2 time, and fit quality R

    • Add legend and parameter text to the chart

  6. ** Resource release **:

    • Disconnect the connection from the device after the experiment is completed

This experiment measures the lateral relaxation time (T2) of the qubit by observing the decay of the coherence of the qubit over time. This is another important parameter for evaluating the quality of the qubit and represents the time scale at which the qubit can maintain a coherent superposition state. T2 time is usually shorter than T1 time because coherence is more sensitive to environmental noise.

Analysis of experimental results

T2 experimental results
{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "width": 500000,  # Delay pulse width
        "mod": 0.65,  # Signal Strength Magnitude
        "coordinate": {  # The coordinates of a qubit on the Bloch sphere
            "x": [0, 1],
            "y": [0, 1],
            "z": [0, 1]
        },
        "matrix": {  # The density matrix of a quantum state, including its real and imaginary parts
            "real": [[1, 0], [0, 1]],
            "imag": [[0, 0], [0, 0]]
        },
        "probability": [0.5, 0.5]  # Probability distribution of measurement results
    }
}
  • graph: Chart data, including real and imaginary parts, the graph contains 2 steps

  • width: Delay pulse width

  • mod: Signal strength modulus

  • coordinate: The coordinates of the qubit on the Bloch sphere

  • matrix: The density matrix of the quantum state, including the real and imaginary parts

  • probability: probability distribution of measurement results

quantum control experiment

Using radio frequency fields to regulate the state of qubits

from spinqlablink import SpinQLabLink, ExperimentType, Pulse
from spinqlablink import print_graph

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    _, exp_qcontrol_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_CONTROL)

    # Set other parameters
    exp_qcontrol_para.samplePath = -1  # Sampling path: 0=Hydrogen channel, 1=Phosphorus channel

    exp_qcontrol_para.pulses = [Pulse(path=0,width=40, amplitude=100, phase=90, detuning=0),
                                Pulse(path=1,width=40, amplitude=100, phase=90, detuning=0)]

    spinqlablink.run_experiment()
    print("Waiting for experiment completion")
    spinqlablink.wait_for_experiment_completion()

    exp_info = spinqlablink.get_experiment_result()

    spinqlablink.deregister_experiment()

    spinqlablink.disconnect()

    if "result" in exp_info:
        exp_result = exp_info["result"]
        for key, value in exp_result.items():
            if key != "graph":
                print(f"{key}: {value}")

        print_graph(exp_info["result"])
    else:
        print("Experiment failed")

if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_CONTROL for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • samplePath: Sampling path,-1= all channels, 0= hydrogen channel, 1= phosphorus channel [-1,0,1]

  • pulses: List of pulse sequences, containing a series of Pulse objects, which contain two pulses: -First pulse: π/2 pulse acting on the hydrogen channel (path=0)-Second pulse: π/2 pulse acting on the phosphorus channel (path=1)

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            },
            { # step 1
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "coordinate": {  # The coordinates of a qubit on the Bloch sphere
            "x": [0, 1],
            "y": [0, 1],
            "z": [0, 1]
        },
        "matrix": {  # The density matrix of a two-qubit system, including the real and imaginary parts
            "real": [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
            "imag": [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        },
        "probability": [0.25, 0.25, 0.25, 0.25]  # Probability distribution of measurement results
    }
}
  • graph: Chart data, the graph contains 2/6 steps

  • coordinate: The coordinates of the qubit on the Bloch sphere

  • matrix: The density matrix of two qubit systems, including real and imaginary parts

  • probability: probability distribution of measurement results

Quantum system initialization experiment

Implement the initialization process of quantum systems

from spinqlablink import SpinQLabLink, ExperimentType, Pulse
from spinqlablink import print_graph

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    _, exp_sysinit_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_SYSTEM_INITIALIZATION)

    # Set other parameters
    exp_sysinit_para.repeat = 9

    exp_sysinit_para.pulses = [Pulse(path=0,phase=90,amplitude=100,width=40),
                                Pulse(path=0,phase=0,amplitude=0,width=718),
                                Pulse(path=0,phase=0,amplitude=100,width=40),
                                Pulse(path=0,phase=0,amplitude=0,width=718),
                                Pulse(path=0,phase=0,amplitude=0,width=40),
                                Pulse(path=0,phase=0,amplitude=0,width=500000),
                                Pulse(path=1,phase=0,amplitude=0,width=40),
                                Pulse(path=1,phase=0,amplitude=0,width=718),
                                Pulse(path=1,phase=90,amplitude=100,width=40),
                                Pulse(path=1,phase=0,amplitude=0,width=718),
                                Pulse(path=1,phase=0,amplitude=100,width=40),
                                Pulse(path=1,phase=0,amplitude=0,width=500000)]

    spinqlablink.run_experiment()
    print("Waiting for experiment completion")
    spinqlablink.wait_for_experiment_completion()

    exp_info = spinqlablink.get_experiment_result()

    spinqlablink.deregister_experiment()

    spinqlablink.disconnect()

    if "result" in exp_info:
        exp_result = exp_info["result"]
        for key, value in exp_result.items():
            if key != "graph":
                print(f"{key}: {value}")

        print_graph(exp_info["result"])
    else:
        print("Experiment failed")

if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_SYSTEM_INITIALIZATION for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • Repeat: The number of repeats is used to enhance signal strength, usually set to 9 times

  • pulses: Pulse sequence list, containing a series of Pulse objects, which contains 12 pulses: -First 6 pulses: Pulse sequence acting on the hydrogen channel (path=0), used to initialize hydrogen nuclear spin-Last 6 pulses: Pulse sequence acting on the phosphorus channel (path=1), used to initialize phosphorus nuclear spin

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            },
            { # step 1
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "Hlamda": 8349439,  # Lambda parameter of the hydrogen nucleus
        "Plamda": 2714902,  # Lambda parameter of the hydrogen nucleus
        "coordinate": {  # The coordinates of the qubit on the Bloch sphere, initialized to the |00⟩ state
            "x": [0, 0],
            "y": [0, 0],
            "z": [1, 1]
        },
        "matrix": {  # The density matrix of a two-qubit system, initialized in the |00⟩ state
            "real": [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
            "imag": [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        },
        "probability": [1, 0, 0, 0]  # The probability distribution of measurement results, initialized with the probability of the |00⟩ state being 1
    }
}
  • graph: Chart data, the graph contains 6 steps

  • Hlamda: Lambda parameter of the hydrogen core, used for custom PPS settings in subsequent experiments

  • Plamda: Lambda parameter of the phosphorus core, used for custom PPS settings in subsequent experiments

  • coordinate: The coordinates of the qubit on the Bloch sphere, initialized to| 00 丨 state

  • matrix: density matrix of a two-qubit system, initialized to| 00 丨 state

  • probability: The probability distribution of the measurement result, initialized to| The probability of the 00 state is 1

Quantum logic gates and quantum circuits

Build quantum gates and quantum circuits based on control operations

from spinqlablink import SpinQLabLink, ExperimentType, Pulse, Gate, CustomGate, Circuit
from spinqlablink import print_graph

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    _, exp_gates_and_circuit_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_GATES_AND_CIRCUIT)

    # Configuration flags
    using_pulse = False      # True: use direct pulse sequence, False: use quantum gates
    using_custom_gate = False  # True: use custom-defined gates, False: use built-in gates
    using_custom_pps = False   # True: use custom Pseudo-Pure State initialization, False: use default PPS

    # Custom PPS (Pseudo-Pure State) initialization sequence
    # This JSON defines pulse sequences for both channels (hydrogen and phosphorus)
    pps_json = '{"pulse":{"channel1_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":500000.0}],"channel2_pulse":[{"amplitude":0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100.0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":500000.0}]}}'

    # System parameters from system initialization experiment
    Hlamda = 8349439  # Hydrogen lambda parameter (obtained from system initialization)
    Plamda = 2714902  # Phosphorus lambda parameter (obtained from system initialization)

    # Set experiment parameters
    exp_gates_and_circuit_para.samplePath = -1 # -1 for all channels, 0 for hydrogen channel, 1 for phosphorus channel
    exp_gates_and_circuit_para.using_pulse = using_pulse # True for using pulse, False for using gate

    if not using_pulse:
        exp_gates_and_circuit_para.using_custom_gate = using_custom_gate # True for using custom gate, False for using default gate
        exp_gates_and_circuit_para.using_custom_pps = using_custom_pps # True for using custom pps, False for using default pps

        # Configure custom PPS parameters if enabled
        if using_custom_pps:
            exp_gates_and_circuit_para.pps_repeat = 9  # Number of times to repeat the PPS sequence
            exp_gates_and_circuit_para.pps_json = pps_json  # Custom PPS pulse sequence
            exp_gates_and_circuit_para.Hlamda = Hlamda  # Hydrogen lambda parameter for PPS
            exp_gates_and_circuit_para.Plamda = Plamda  # Phosphorus lambda parameter for PPS

        # Create a 2-qubit quantum circuit
        circuit = Circuit(2)

        if using_custom_gate: # using custom gate
            # Example of custom gate definition using JSON (commented out)
            # H0_file_json = '{"pulse":{"channel1_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0}],"channel2_pulse":[{"amplitude":0.0,"detuning":0.0,"phase":0.0,"width":40.0}]}}'
            # H1_file_json = '{"pulse":{"channel1_pulse":[{"amplitude":0.0,"detuning":0.0,"phase":0.0,"width":40.0}],"channel2_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0}]}}'
            # circuit << CustomGate(type='H',customType='H_custom_gate',qubitIndex=0,gateJson=H0_file_json)
            # circuit << CustomGate(type='H',customType='H_custom_gate',qubitIndex=1,gateJson=H1_file_json)

            # Define custom Hadamard gates for each qubit using direct pulse definitions
            # H0_custom_gate: Custom Hadamard gate for qubit 0 (hydrogen channel)
            circuit << CustomGate(type='H',customType='H0_custom_gate',qubitIndex=0,pulses=[Pulse(path=0,phase=90,amplitude=100,width=40)])
            # H1_custom_gate: Custom Hadamard gate for qubit 1 (phosphorus channel)
            circuit << CustomGate(type='H',customType='H1_custom_gate',qubitIndex=1,pulses=[Pulse(path=1,phase=90,amplitude=100,width=40)])
            circuit.print_circuit()
        else: # using built-in gate
            # Add standard Hadamard gates to both qubits
            circuit << Gate(type='H', qubitIndex=0)  # Hadamard gate on qubit 0
            circuit << Gate(type='H', qubitIndex=1)  # Hadamard gate on qubit 1
            circuit.print_circuit()

        # Set the circuit to the experiment
        exp_gates_and_circuit_para.set_circuit(circuit)
    else: # using pulse
        # Define a direct pulse sequence instead of quantum gates
        exp_gates_and_circuit_para.pulses = [Pulse(path=0,phase=90,amplitude=100,width=40)]

    # Run the experiment
    spinqlablink.run_experiment()
    print("Waiting for experiment completion")
    spinqlablink.wait_for_experiment_completion()

    # Get experiment results
    exp_info = spinqlablink.get_experiment_result()

    spinqlablink.deregister_experiment()

    spinqlablink.disconnect()

    # Process and display results
    if "result" in exp_info:
        exp_result = exp_info["result"]
        for key, value in exp_result.items():
            if key != "graph":
                print(f"{key}: {value}")

        print_graph(exp_info["result"])
    else:
        print("Experiment failed")

if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_GATES_AND_CIRCUIT(for details, see:class:spinqlablink.ExperimentType class)

  • Pulse: Define the pulse sequence and set the path, width, amplitude, phase and frequency offset of the pulse (see:class:spinqlablink.Pulse class for details)

  • Gate: Defines the quantum gate operation, specifies the gate type and the qubit used (see:class:spinqlablink.Gate class for details)

  • CustomGate: Define a custom quantum gate, and the gate operation can be defined through pulse sequences or JSON (for details, see:class:spinqlablink.CustomGate class)

  • Circuit: Build a quantum circuit and add quantum gate operations (see:class:spinqlablink.Circuit class for details)

  • samplePath: Sampling path,-1= all channels, 0= hydrogen channel, 1= phosphorus channel [-1,0,1]

  • using_pulse: Whether to directly use pulse sequences instead of quantum gates [True,False]

  • using_custom_gate: Whether to use a custom quantum gate [True,False]

  • using_custom_pps: Whether to use custom PPS to initialize [True,False]

  • pps_json: Customizes the JSON configuration for PPS initialization (see class:spinqlablink.CustomGate class for details on string format)

  • pps_repeat: Customize the number of iterations for PPS initialization

  • Hlamda: Lambda parameter of the hydrogen core, used to customize PPS settings (parameter source: quantum system initialization experiment)

  • Plamda: Lambda parameter of the phosphorus core, used to customize PPS settings (parameter source: quantum system initialization experiment)

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            },
            { # step 1
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "matrix": {  # The density matrix of a quantum state, including its real and imaginary parts
            "real": [[0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]],
            "imag": [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        },
        "probability": [0.25, 0.25, 0.25, 0.25]  # Probability distribution of measurement results
    }
}
  • graph: Chart data, the graph contains 2/6 steps

  • matrix: The density matrix of the quantum state, including the real and imaginary parts

  • probability: The probability distribution of the measurement result. For the result after Hadamard gate operation of two qubits, the probability of each ground state is equal

Quantum state reconstruction

Observation and reconstruction of quantum states

from spinqlablink import SpinQLabLink, ExperimentType, Pulse, Gate, CustomGate, Circuit
from spinqlablink import print_graph

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    # Register Quantum State Tomography experiment
    # Quantum State Tomography is a technique to fully reconstruct the quantum state
    # by performing multiple measurements in different bases
    _, exp_state_tomography_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_STATE_TOMOGRAPHY)

    # Configuration flags
    using_custom_gate = False  # True: use custom-defined gates, False: use built-in gates
    using_custom_pps = False   # True: use custom Pseudo-Pure State initialization, False: use default PPS

    # Custom Pseudo-Pure State (PPS) initialization sequence
    # This JSON defines pulse sequences for both hydrogen (channel1) and phosphorus (channel2)
    # Each entry in the array represents a pulse with parameters: amplitude, detuning, phase, and width
    pps_json = '{"pulse":{"channel1_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":500000.0}],"channel2_pulse":[{"amplitude":0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100.0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":500000.0}]}}'

    # System parameters from system initialization experiment
    # These values represent the J-coupling constants between nuclei in Hz
    Hlamda = 8349439  # Hydrogen lambda coupling constant
    Plamda = 2714902  # Phosphorus lambda coupling constant

    # Set experiment parameters
    # Channel selection for measurement
    exp_state_tomography_para.samplePath = -1  # -1 for all channels, 0 for hydrogen channel, 1 for phosphorus channel
                                            # Using all channels is necessary for full state tomography

    # Configure custom Pseudo-Pure State if enabled
    if using_custom_pps:
        exp_state_tomography_para.pps_repeat = 9  # Number of times to repeat the PPS preparation sequence
        exp_state_tomography_para.pps_json = pps_json  # Custom PPS pulse sequence
        exp_state_tomography_para.Hlamda = Hlamda  # Hydrogen coupling constant from system initialization
        exp_state_tomography_para.Plamda = Plamda  # Phosphorus coupling constant from system initialization

    # Create a quantum circuit for state preparation
    # This circuit will prepare the state that we want to characterize with tomography
    circuit = Circuit(2)  # Create a 2-qubit circuit

    if using_custom_gate:  # Using custom-defined gates
        # Commented code shows alternative way to define custom gates using JSON
        # H0_file_json = '{"pulse":{"channel1_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0}],"channel2_pulse":[{"amplitude":0.0,"detuning":0.0,"phase":0.0,"width":40.0}]}}'
        # H1_file_json = '{"pulse":{"channel1_pulse":[{"amplitude":0.0,"detuning":0.0,"phase":0.0,"width":40.0}],"channel2_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0}]}}'
        # circuit << CustomGate(type='H',customType='H_custom_gate',qubitIndex=0,gateJson=H0_file_json)
        # circuit << CustomGate(type='H',customType='H_custom_gate',qubitIndex=1,gateJson=H1_file_json)

        # Define custom Hadamard gates for each qubit using direct pulse definitions
        # H gate on qubit 0 (hydrogen nucleus)
        circuit << CustomGate(type='H',customType='H0_custom_gate',qubitIndex=0,
                            pulses=[Pulse(path=0,phase=90,amplitude=100,width=40)])
        # H gate on qubit 1 (phosphorus nucleus)
        circuit << CustomGate(type='H',customType='H1_custom_gate',qubitIndex=1,
                            pulses=[Pulse(path=1,phase=90,amplitude=100,width=40)])
        circuit.print_circuit()
    else:  # Using built-in gates
        # Apply Hadamard gates to create a superposition state on both qubits
        # This creates the state |++⟩ = (|00⟩ + |01⟩ + |10⟩ + |11⟩)/2
        circuit << Gate(type='H', qubitIndex=0)  # Hadamard on qubit 0
        circuit << Gate(type='H', qubitIndex=1)  # Hadamard on qubit 1
        circuit.print_circuit()

    # Set the circuit for the experiment
    exp_state_tomography_para.set_circuit(circuit)

    # Run the experiment
    spinqlablink.run_experiment()
    print("Waiting for experiment completion")
    spinqlablink.wait_for_experiment_completion()

    # Get the results
    exp_info = spinqlablink.get_experiment_result()

    # Clean up and disconnect
    spinqlablink.deregister_experiment()
    spinqlablink.disconnect()

    # Display the results
    # The results will include the reconstructed density matrix of the quantum state
    if "result" in exp_info:
        exp_result = exp_info["result"]
        for key, value in exp_result.items():
            if key != "graph":
                print(f"{key}: {value}")

        print_graph(exp_info["result"])
    else:
        print("Experiment failed")

if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_STATE_TOMOGRAPHY for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Gate: Defines the quantum gate operation, specifies the gate type and the qubit used (see:class:spinqlablink.Gate class for details)

  • CustomGate: Define a custom quantum gate, and the gate operation can be defined through pulse sequences or JSON (for details, see:class:spinqlablink.CustomGate class)

  • Circuit: Build a quantum circuit and add quantum gate operations (see:class:spinqlablink.Circuit class for details)

  • samplePath: Sampling path,-1= all channels, 0= hydrogen channel, 1= phosphorus channel [-1,0,1]

  • using_custom_gate: Whether to use a custom quantum gate [True,False]

  • using_custom_pps: Whether to use custom PPS to initialize [True,False]

  • pps_json: Customize JSON configuration for PPS initialization

  • pps_repeat: Customize the number of iterations for PPS initialization

  • Hlamda: Lambda parameter of hydrogen core, used to customize PPS settings

  • Plamda: Lambda parameter of the phosphorus core, used to customize PPS settings

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            },
            { # step 1
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "matrix": {  # Reconstructed quantum state density matrix, including real and imaginary parts
            "real": [[0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]],
            "imag": [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        },
        "probability": [0.25, 0.25, 0.25, 0.25],  # Probability distribution of measurement results
        "fidelity": 0.95,  # Fidelity between quantum state and ideal state
        "purity": 0.98,  # The purity of a quantum state indicates the degree of mixing of the quantum state.
        "entropy": 0.05  # The entropy of a quantum state represents the degree of disorder of the quantum state.
    }
}
  • graph: Chart data, the graph contains 2/6 steps

  • matrix: Reconstructed quantum state density matrix, including real and imaginary parts

  • probability: probability distribution of measurement results

  • Fidelity: Fidelity between quantum and ideal states

  • purity: Purity of the quantum state, indicating the degree of mixing of the quantum state

  • entropy: Entropy of the quantum state, indicating the degree of chaos of the quantum state

quantum computational tasks

Carry out real quantum computing tasks

from spinqlablink import SpinQLabLink, ExperimentType, Pulse, Gate, CustomGate, Circuit
from spinqlablink import print_graph

def main():
    # Create connection
    spinqlablink = SpinQLabLink("192.168.15.4", 8181, "anyword", "anyword")
    spinqlablink.connect()

    if not spinqlablink.wait_for_login():
        print("Login failed")
        return

    _, exp_computing_task_para = spinqlablink.register_experiment(ExperimentType.QUANTUM_COMPUTING_TASK)

    using_custom_gate = False
    using_custom_pps = False
    pps_json = '{"pulse":{"channel1_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":500000.0}],"channel2_pulse":[{"amplitude":0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":718.0},{"amplitude":100.0,"detuning":0.0,"phase":0.0,"width":40.0},{"amplitude":0,"detuning":0.0,"phase":0.0,"width":500000.0}]}}'
    Hlamda = 8349439
    Plamda = 2714902

    # Set other parameters
    exp_computing_task_para.samplePath = 0 # -1 for all channels, 0 for hydrogen channel, 1 for phosphorus channel

    exp_computing_task_para.using_custom_gate = using_custom_gate # True for using custom gate, False for using default gate
    exp_computing_task_para.using_custom_pps = using_custom_pps # True for using custom pps, False for using default pps
    if using_custom_pps:
        exp_computing_task_para.pps_repeat = 9
        exp_computing_task_para.pps_json = pps_json # Custom pps json
        exp_computing_task_para.Hlamda = Hlamda # Hlamda,which is from exp_system_initialization
        exp_computing_task_para.Plamda = Plamda # Plamda,which is from exp_system_initialization

    circuit = Circuit(2)
    if using_custom_gate: # using custom gate
        # H0_file_json = '{"pulse":{"channel1_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0}],"channel2_pulse":[{"amplitude":0.0,"detuning":0.0,"phase":0.0,"width":40.0}]}}'
        # H1_file_json = '{"pulse":{"channel1_pulse":[{"amplitude":0.0,"detuning":0.0,"phase":0.0,"width":40.0}],"channel2_pulse":[{"amplitude":100.0,"detuning":0.0,"phase":90.0,"width":40.0}]}}'
        # circuit << CustomGate(type='H',customType='H_custom_gate',qubitIndex=0,gateJson=H0_file_json)
        # circuit << CustomGate(type='H',customType='H_custom_gate',qubitIndex=1,gateJson=H1_file_json)
        circuit << CustomGate(type='X',customType='X0_custom_gate',qubitIndex=0,pulses=[Pulse(path=0,phase=90,amplitude=100,width=80)])
        circuit << CustomGate(type='X',customType='X1_custom_gate',qubitIndex=1,pulses=[Pulse(path=1,phase=90,amplitude=100,width=80)])
        circuit.print_circuit()
    else: # using built-in gate
        circuit << Gate(type='H', qubitIndex=0)
        circuit << Gate(type='H', qubitIndex=1)
        circuit.print_circuit()
    exp_computing_task_para.set_circuit(circuit)

    spinqlablink.run_experiment()
    print("Waiting for experiment completion")
    spinqlablink.wait_for_experiment_completion()

    exp_info = spinqlablink.get_experiment_result()

    spinqlablink.deregister_experiment()

    spinqlablink.disconnect()

    if "result" in exp_info:
        exp_result = exp_info["result"]
        for key, value in exp_result.items():
            if key != "graph":
                print(f"{key}: {value}")

        print_graph(exp_info["result"])
    else:
        print("Experiment failed")

if __name__ == "__main__":
    main()

Experimental Parameters Analysis

  • ExperimentType: Select QUANTUM_COMPUTING_TASK for experimental type (see:class:spinqlablink.ExperimentType class for details)

  • Gate: Defines the quantum gate operation, specifies the gate type and the qubit used (see:class:spinqlablink.Gate class for details)

  • CustomGate: Define a custom quantum gate, and the gate operation can be defined through pulse sequences or JSON (for details, see:class:spinqlablink.CustomGate class)

  • Circuit: Build a quantum circuit and add quantum gate operations (see:class:spinqlablink.Circuit class for details)

  • samplePath: Sampling path,-1= all channels, 0= hydrogen channel, 1= phosphorus channel [-1,0,1]

  • using_custom_gate: Whether to use a custom quantum gate [True,False]

  • using_custom_pps: Whether to use custom PPS to initialize [True,False]

  • pps_json: Customize JSON configuration for PPS initialization

  • pps_repeat: Customize the number of iterations for PPS initialization

  • Hlamda: Lambda parameter of hydrogen core, used to customize PPS settings

  • Plamda: Lambda parameter of the phosphorus core, used to customize PPS settings

Analysis of experimental results

{
    "result":{
        "graph":[
            { # step 0
                "fidRe": [[x,y],...],
                "fidIm":[[x,y],...],
                "fftRe":[[x,y],...],
                "fftIm":[[x,y],...],
                "lorenz":[[x,y],...],
                "fftMod":[[x,y],...]
            }
        ],
        "matrix": {  # The density matrix of a quantum state, including its real and imaginary parts
            "real": [[0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25], [0.25, 0.25, 0.25, 0.25]],
            "imag": [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        },
        "probability": [0.25, 0.25, 0.25, 0.25],  # Probability distribution of measurement results
        "execution_time": 2500,  # Circuit Execution Time (Microseconds)
        "circuit_depth": 2,  # Circuit depth
        "gate_count": 2  # Number of gates in the circuit
    }
}
  • graph: Chart data, the graph contains 2/6 steps

  • matrix: The density matrix of the quantum state, including the real and imaginary parts

  • probability: probability distribution of measurement results

  • execution_time: Circuit execution time (microseconds)

  • circuit_depth: Circuit depth

  • gate_count: Number of gates in the circuit