Skip to content

qubosolver.drive_shaping

qubosolver.drive_shaping

Drive shaping algorithms for generating quantum drive schedules.

Provides several algorithms for constructing amplitude and detuning waveforms used to solve QUBO problems on neutral-atom hardware.

Modules:

  • local_energy_scale –

    Local-energy-scale heuristic drive schedule generation for QUBO solving.

  • proportional_diagonal –

    Proportional-diagonal drive schedule generation for QUBO solving.

qubosolver.drive_shaping.local_energy_scale

Local-energy-scale heuristic drive schedule generation for QUBO solving.

Functions:

  • build_drive –

    Generate a local-energy-scale heuristic drive for QUBO solving.

build_drive

build_drive(instance: Instance, register: qoolqit.Register, *, device: qoolqit.Device, dmm: bool = True, kappa: float = 0.1) -> qoolqit.Drive

Generate a local-energy-scale heuristic drive for QUBO solving.

For each qubit, the local physical energy scale is

\[E_i = |\delta_i(T)| + \sum_{j \neq i} |V_{ij}|,\]

where \(\delta_i(T)\) is the final detuning effectively applied to qubit \(i\) and \(V_{ij}\) is the physical interaction generated by the embedded register.

The peak Rabi frequency is defined as

\[\omega_{\max} = \kappa \cdot \text{mean}_i(E_i).\]

When DMM is available, the final local detunings are encoded as

\[\delta_i(T) = \delta_g(T) + \delta_{\text{dmm}}(T) \cdot w_i,\]

with

\[\delta_g(T) = d_{\max}, \quad \delta_{\text{dmm}}(T) = -(d_{\max} - d_{\min}), \quad w_i = \frac{d_{\max} - d_i}{d_{\max} - d_{\min}}.\]

Without DMM, all atoms receive the same final global detuning

\[\delta_i(T) = \delta_g(T) = \text{mean}_i(d_i).\]

The resulting amplitude and detuning waveforms are clamped or rescaled when necessary so they remain compilable on the target device.

Parameters:

  • instance (Instance) –

    The QUBO instance whose diagonal encodes target detunings.

  • register (qoolqit.Register) –

    The physical register the drive will run on.

  • device (qoolqit.Device) –

    Target quantum device providing the hardware limits.

  • dmm (bool, default: True ) –

    Whether to use the Detuning Map Modulator for local control.

  • kappa (float, default: 0.1 ) –

    Ratio between the peak Rabi frequency and the average local physical energy scale.

Returns:

  • qoolqit.Drive –

    A drive ready for compilation and execution.

Source code in qubosolver/drive_shaping/local_energy_scale.py
def build_drive(
    instance: Instance,
    register: qoolqit.Register,
    *,
    device: qoolqit.Device,
    dmm: bool = True,
    kappa: float = 0.1,
) -> qoolqit.Drive:
    r"""Generate a local-energy-scale heuristic drive for QUBO solving.

    For each qubit, the local physical energy scale is

    $$E_i = |\delta_i(T)| + \sum_{j \neq i} |V_{ij}|,$$

    where $\delta_i(T)$ is the final detuning effectively applied to qubit
    $i$ and $V_{ij}$ is the physical interaction generated by the embedded
    register.

    The peak Rabi frequency is defined as

    $$\omega_{\max} = \kappa \cdot \text{mean}_i(E_i).$$

    When DMM is available, the final local detunings are encoded as

    $$\delta_i(T) = \delta_g(T) + \delta_{\text{dmm}}(T) \cdot w_i,$$

    with

    $$\delta_g(T) = d_{\max}, \quad
    \delta_{\text{dmm}}(T) = -(d_{\max} - d_{\min}), \quad
    w_i = \frac{d_{\max} - d_i}{d_{\max} - d_{\min}}.$$

    Without DMM, all atoms receive the same final global detuning

    $$\delta_i(T) = \delta_g(T) = \text{mean}_i(d_i).$$

    The resulting amplitude and detuning waveforms are clamped or rescaled
    when necessary so they remain compilable on the target device.

    Args:
        instance: The QUBO instance whose diagonal encodes target detunings.
        register: The physical register the drive will run on.
        device: Target quantum device providing the hardware limits.
        dmm: Whether to use the Detuning Map Modulator for local control.
        kappa: Ratio between the peak Rabi frequency and the average local
            physical energy scale.

    Returns:
        A drive ready for compilation and execution.
    """
    # Hardware bounds
    specs = device.specs
    max_seq_duration: float = specs["max_duration"] or 1000.0
    use_dmm = dmm
    if use_dmm and not support_dmm(device):
        logging.warning(
            "dmm=True was requested but device %r does not support a DMM channel; "
            "falling back to a global detuning drive.",
            device,
        )
        use_dmm = False

    if specs.get("max_amplitude") is not None and specs.get("max_abs_detuning") is not None:
        device_max_amplitude = specs["max_amplitude"]
        device_max_abs_detuning = specs["max_abs_detuning"]
        assert device_max_amplitude is not None  # nosec B101
        assert device_max_abs_detuning is not None  # nosec B101

        det_amp_ratio = device_max_amplitude / device_max_abs_detuning

        if kappa < det_amp_ratio:
            logger.warning(
                f"local_energy_scale_kappa is too small ({kappa}), you're likely to get a "
                f"qoolqit CompilationError. Set it above {det_amp_ratio}."
            )

    # Target local final detunings.
    d = (-0.5 * torch.diag(instance.matrix)).detach().cpu()
    delta_g_T, delta_dmm_T, weights, use_dmm = _detunings(d, use_dmm)

    # Final detuning effectively applied to each qubit:
    #
    # delta_i(T) = delta_g(T) + delta_dmm(T) * w_i.
    #
    # with delta_dmm(T) = 0 when dmm is disabled
    final_local_detunings = delta_g_T + delta_dmm_T * weights

    # Physical interactions generated by the embedded register:
    #
    # V_ij = 1 / r_ij**6.
    #
    # For each qubit i, compute:
    #
    # sum_{j != i} |V_ij|.
    interaction_scale = matrix.as_tensor(register.interaction_matrix()).abs().sum(dim=0)

    # Local physical energy scale:
    #
    # E_i = |delta_i(T)| + sum_{j != i} |V_ij|.
    local_energy_scale = final_local_detunings.abs() + interaction_scale

    # Average local physical energy scale:
    #
    # E_mean = (1 / n) * sum_i E_i.
    mean_local_energy_scale = local_energy_scale.mean().item()

    # Local-energy-scale mixing rule:
    #
    # omega_max = kappa * E_mean.
    omega_max = kappa * mean_local_energy_scale

    # Clamp the amplitude to what can be compiled for this device and register.
    max_amplitude = max_virtual_amplitude(device, register)

    if omega_max > max_amplitude:
        logger.info(
            f"The local-energy-scale drive amplitude ({omega_max}) exceeds the maximum "
            f"amplitude compilable on the device for this register "
            f"({max_amplitude}); clamping to it."
        )
        omega_max = max_amplitude

    # Ensure that the target detunings remain compilable for the selected amplitude.
    max_detuning = detuning_amplitude_ratio(device) * omega_max * (1.0 - 1e-3)
    max_abs_d = d.abs().max().item()

    if max_abs_d > max_detuning:
        logger.info(
            f"The local-energy-scale detuning ({max_abs_d}) exceeds the maximum detuning "
            f"compilable on the device for this amplitude ({max_detuning}); "
            f"scaling the detuning down."
        )
        d = d * (max_detuning / max_abs_d)
        # Recompute the DMM encoding after rescaling the target local detunings.
        delta_g_T, delta_dmm_T, weights, use_dmm = _detunings(d, use_dmm)

    # Keep the initial detuning rule identical to the standard heuristic drive.
    delta_0 = -d.abs().max().item()

    # Amplitude waveform: 0 -> omega_max -> omega_max -> 0.
    eps = 1e-9
    amp_wave = qoolqit.InterpolatedWaveform(
        max_seq_duration,
        [eps, omega_max, omega_max, eps],
    )

    # Global detuning waveform: initial negative value -> final target.
    det_wave = qoolqit.InterpolatedWaveform(
        max_seq_duration,
        [delta_0, delta_0, delta_g_T, delta_g_T],
    )

    # Optional DMM weighted detunings.
    wdetunings = None

    if use_dmm:
        energy_scale = device._target_amp / omega_max
        wdetunings = constant_weighted_dmm(
            weights.tolist(),
            max_seq_duration,
            final_detuning=delta_dmm_T,
            device=device,
            energy_scale=energy_scale,
        )

    return qoolqit.Drive(
        amplitude=amp_wave,
        detuning=det_wave,
        dmm=wdetunings,
    )

qubosolver.drive_shaping.proportional_diagonal

Proportional-diagonal drive schedule generation for QUBO solving.

Functions:

  • build_drive –

    Generate a proportional-diagonal drive schedule for QUBO solving.

build_drive

build_drive(instance: Instance, register: qoolqit.Register, *, device: qoolqit.Device, dmm: bool = True, kappa: float = 1.0) -> qoolqit.Drive

Generate a proportional-diagonal drive schedule for QUBO solving.

Constructs amplitude and detuning waveforms from the QUBO diagonal coefficients, clamped so they stay within what the compiler can realize on device for register. When DMM is available, per-atom detuning weights are computed so that the final local detuning encodes the QUBO diagonal.

Parameters:

  • instance (Instance) –

    The QUBO instance whose diagonal encodes target detunings.

  • register (qoolqit.Register) –

    The physical register the drive will run on.

  • device (qoolqit.Device) –

    Target quantum device (provides hardware limits).

  • dmm (bool, default: True ) –

    Whether to use the Detuning Map Modulator for local control.

  • kappa (float, default: 1.0 ) –

    Ratio between peak Rabi frequency and peak detuning.

Returns:

  • qoolqit.Drive –

    A drive ready for compilation and execution.

Source code in qubosolver/drive_shaping/proportional_diagonal.py
def build_drive(
    instance: Instance,
    register: qoolqit.Register,
    *,
    device: qoolqit.Device,
    dmm: bool = True,
    kappa: float = 1.0,
) -> qoolqit.Drive:
    """Generate a proportional-diagonal drive schedule for QUBO solving.

    Constructs amplitude and detuning waveforms from the QUBO diagonal
    coefficients, clamped so they stay within what the compiler can realize
    on `device` for `register`.  When DMM is available, per-atom detuning
    weights are computed so that the final local detuning encodes the QUBO
    diagonal.

    Args:
        instance: The QUBO instance whose diagonal encodes target detunings.
        register: The physical register the drive will run on.
        device: Target quantum device (provides hardware limits).
        dmm: Whether to use the Detuning Map Modulator for local control.
        kappa: Ratio between peak Rabi frequency and peak detuning.

    Returns:
        A drive ready for compilation and execution.
    """
    # Hardware bounds
    specs = device.specs
    max_seq_duration: float = specs["max_duration"] or 1000.0
    use_dmm = dmm
    if use_dmm and not support_dmm(device):
        logging.warning(
            "dmm=True was requested but device %r does not support a DMM channel; "
            "falling back to a global detuning drive.",
            device,
        )
        use_dmm = False

    if specs.get("max_amplitude") is not None and specs.get("max_abs_detuning") is not None:
        max_amplitude = specs["max_amplitude"]
        max_abs_detuning = specs["max_abs_detuning"]
        assert max_amplitude is not None and max_abs_detuning is not None  # nosec B101
        det_amp_ratio = max_amplitude / max_abs_detuning
        if kappa < det_amp_ratio:
            logger.warning(
                f"proportional_diagonal_kappa is too small ({kappa}), you're likely to get a "
                f"qoolqit CompilationError. Set it above {det_amp_ratio}."
            )

    n = instance.size

    # Target local final detunings
    d = (-0.5 * torch.diag(instance.matrix)).cpu().numpy()
    d_min = float(np.min(d))
    d_max = float(np.max(d))

    omega_max = kappa * float(np.max(np.abs(d)))

    max_amplitude = max_virtual_amplitude(device, register)
    if omega_max > max_amplitude:
        logger.info(
            f"The proportional-diagonal drive amplitude ({omega_max}) exceeds the maximum "
            f"amplitude compilable on the device for this register "
            f"({max_amplitude}); clamping to it."
        )
        omega_max = max_amplitude

    max_detuning = detuning_amplitude_ratio(device) * omega_max * (1.0 - 1e-3)
    max_abs_d = float(np.max(np.abs(d)))
    if max_abs_d > max_detuning:
        logger.info(
            f"The proportional-diagonal detuning ({max_abs_d}) exceeds the maximum detuning "
            f"compilable on the device for this amplitude ({max_detuning}); "
            f"scaling the detuning down."
        )
        d = d * (max_detuning / max_abs_d)
        d_min = float(np.min(d))
        d_max = float(np.max(d))

    if use_dmm:
        # Final global detuning is the top value, DMM pulls down locally
        delta_g_T = d_max

        # DMM convention required by WeightedDetuning:
        # waveform must be <= 0
        spread = max(0.0, d_max - d_min)
        # if spread > 1e-15 and delta_dmm_max > 0.0:
        if spread > 1e-15:
            delta_dmm_T = -spread  # must be <= 0
            denom = d_max - d_min
            weights = ((d_max - d) / denom).clip(0.0, 1.0).tolist()
        else:
            use_dmm = False
            delta_dmm_T = 0.0
            weights = [0.0] * n
    else:
        # No DMM: use a single global final detuning
        delta_g_T = np.mean(d)
        delta_dmm_T = 0.0
        weights = [0.0] * n

    # How to get max detuning ?
    delta_0 = -np.max(np.abs(d))

    # Amplitude waveform: 0 -> plateau -> 0
    eps = 1e-9
    amp_wave = qoolqit.InterpolatedWaveform(
        max_seq_duration,
        [eps, omega_max, omega_max, eps],
    )

    # Global detuning waveform: initial negative -> final target
    det_wave = qoolqit.InterpolatedWaveform(
        max_seq_duration,
        [delta_0, delta_0, delta_g_T, delta_g_T],
    )

    # DMM weighted detunings
    wdetunings = None
    if use_dmm:
        energy_scale = device._target_amp / omega_max
        wdetunings = constant_weighted_dmm(
            weights,
            max_seq_duration,
            final_detuning=delta_dmm_T,
            device=device,
            energy_scale=energy_scale,
        )

    return qoolqit.Drive(
        amplitude=amp_wave,
        detuning=det_wave,
        dmm=wdetunings,
    )