qutip/qutip-qtrl

Separate bounds on each control for GRAPE

Opened this issue · 0 comments

Can GRAPE have different bounds on each control?

The docstring for pulseoptim.create_pulse_optimizer states that amp_lbound and amp_ubound can be a list specifying different bounds for each of the controls. But this does not work with the default alg='GRAPE' because when the pulse_generator is created in lines 2087-2097 in pulseoptim.py, a single pulse_generator is used for all controls, but the bounds are still set with amp_lbound and amp_ubound as lists. This will fail because the PulseGen class expects the bounds to be floats, e.g., when bounds checking in _apply_bounds_and_offset. Having a single pulse generator also does not conceptually align with having different bounds on each control. None of this is an issue if amp_lbound and amp_ubound are specified as a single float for all controls, or if alg='CRAB' is used instead because a pulse_generator is created for each control.

The coding fix is simple, but it is unclear whether instantiating a pulse generator for each control, like in CRAB, is still valid for GRAPE.

Below is a simple example that will fail:

from qutip import identity, sigmax, sigmay, sigmaz
from qutip_qip.operations import hadamard_transform
import qutip_qtrl.pulseoptim as cpo

# Drift
H_d = sigmaz()

# Control
H_c = [sigmax(), sigmay()]

# Initial unitary
U_0 = identity(2)

# Target unitary
U_targ = hadamard_transform(N=1)

# Number of time slots
n_ts = 10

# Total time
evo_time = 10

# Bounds
amp_lbound = [-1 for _ in range(len(H_c))]
amp_ubound = [1 for _ in range(len(H_c))]

result = cpo.optimize_pulse_unitary(H_d, H_c, U_0, U_targ, n_ts, evo_time,
                amp_lbound=amp_lbound, amp_ubound=amp_ubound,
                alg='GRAPE')