Skip to content
Pasqal Documentation

Adiabatic Pulse

AdiabaticPulseShaper is a class for implementing a standard adiabatic pulse shaping method. It creates an InterpolatedWaveform pulse for solving a QUBOInstance using adiabatic quantum evolution, There are no parameters to be customized.

  • Creates a normalized weights list for the later application of DMM.
  • Computes the maximum amplitude value.
  • Computes the global detuning values (initial and final).
  • Creates a pulse with the values of amplitude, detuning and duration (4000 ns).
Field Type Description
pulse Pulse A Pulser-compatible pulse object generated by generate().

generate(register: Register, instance: QUBOInstance) -> tuple[Pulse, QUBOSolution] Generates a shaped adiabatic pulse for the given QUBO problem and register layout.

Argument Type Description
register Register The spatial layout of qubits/atoms in the physical system.
instance QUBOInstance The QUBO matrix of the problem.
Type Description
tuple[Pulse, QUBOSolution] Returns the generated Pulse object and a placeholder QUBOSolution (with all fields set to None)

The method sets:

  • pulse.norm_weights: A normalized weight per node, used for DMM.

  • pulse.duration: Total evolution time (fixed at T = 4000 ns by default).

For the Adiabatic Pulse, the values of the amplitude Ω\Omega (Rabi frequency) and global detuning δ\delta are defined in terms of the QUBOInstance, as follows:

  • Amplitude: has a sine-like shape, starting from 00 and ending in 00, with a maximum value being the maximum value among the off-diagonal terms of the QUBO matrix:
Ωmax=max(Qoff)\Omega_{max} = max(Q_{off})

If Ωmax\Omega_{max} reaches a value above the maximum amplitude allowed by the device, it uses this max_amp as Ωmax\Omega_{max}.

  • Detuning: starts from a negative value δ0\delta_0 that is the minimum value among the diagonal terms of the QUBO matrix (since diagonal terms are either negative or 00), reaches 00 and ends in a positive final value δf\delta_f, following a linear behavior:
δ0=min(Qdiag)\delta_0 = min(Q_{diag})δf=δ0\delta_f = -\delta_0

Along with the pulse created with the amplitude and detuning values, the detuning of individual qubits (defined as list of values between 0 and 1) is applied using a channel called Detuning Map Modulator or DMM. Proportionally to the weights of each qubit, a pulse of zero amplitude and negative detuning is applied. Here, the values of the detuning are normalized in terms of the maximum absolute value of the diagonal terms and subtracted from 1. For each qubit ii the value is:

DMM=1(wi/wmax)DMM = 1 - (w_i/w_{max})

This way, the qubits with lower weights receive higher detuning values, whilst the ones with higher weights receive lower values.

import torch
from qubosolver import QUBOInstance
from qubosolver.config import SolverConfig, PulseShapingConfig
from qoolqit._solvers.types import BackendType, DeviceType
from qubosolver.solver import QuboSolver
from qubosolver.qubo_types import PulseType
Q = torch.tensor([
[-63.9423, 0.0000, 73.6471, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 55.2853],
[ 0.0000, -44.1916, 0.0000, 0.0000, 0.0000, 0.0000, 58.9307, 0.0000, 0.0000, 0.0000],
[ 73.6471, 0.0000, -89.8861, 51.0382, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 51.0382, -63.7618, 0.0000, 0.0000, 33.9093, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, -94.4426, 18.7963, 0.0000, 0.0000, 14.3994, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 18.7963, -60.7545, 0.0000, 0.0000, 0.0000, 96.9903],
[ 0.0000, 58.9307, 0.0000, 33.9093, 0.0000, 0.0000, -71.3241, 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000, -38.2094, 59.3175, 0.0000],
[ 0.0000, 0.0000, 0.0000, 0.0000, 14.3994, 0.0000, 0.0000, 59.3175, -94.5790, 18.0653],
[ 55.2853, 0.0000, 0.0000, 0.0000, 0.0000, 96.9903, 0.0000, 0.0000, 18.0653, -97.3174]
])
instance = QUBOInstance(Q)
default_config = SolverConfig(
use_quantum = True, pulse_shaping=PulseShapingConfig(pulse_shaping_method=PulseType.ADIABATIC)
)
solver = QuboSolver(instance, default_config)
solution = solver.solve()
print(solution)
QUBOSolution(bitstrings=tensor([[0., 1., 1., 0., 0., 0., 0., 0., 0., 1.], [0., 1., 1., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 1., 0., 0., 0., 1., 0., 0.], [1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]]), costs=tensor([-231.3951, -95.7631, -89.7809, 242.3500]), counts=tensor([ 1, 319, 1, 179], dtype=torch.int32), probabilities=tensor([0.0020, 0.6380, 0.0020, 0.3580]), solution_status=) This will return a QUBOSolution instance, which comprehends the solution bitstrings, the counts of each bitstring, their probabilities and costs.

Obs.: The ADIABATIC method is the default one, it's explicit in pulse_shaping_method for ilustration purposes.