How-to Guides
Contents
- How to define a functional $J_T$ that depends on more than just target states
- How to deal with long-running calculations
Also see the following how-to guides from the QuantumPropagators documentation:
- How to implement a new propagation method
- How to specify the spectral range for a Chebychev propagation
- How to define a parameterized control
How to define a functional $J_T$ that depends on more than just target states
All of the optimization methods in the JuliaQuantumControl organization target a final-time functional $J_T$ via an argument J_T, see QuantumControl.optimize, that has the interface
J_T: A functionJ_T(Ψ, trajectories)that evaluates the final time functional from a listΨof forward-propagated states andproblem.trajectories. The functionJ_Tmay also take a keyword argumenttau. If it does, a vector containing the complex overlaps of the target states (target_stateproperty of each trajectory inproblem.trajectories) with the propagated states will be passed toJ_T.
If the functional does not depend solely on a set of states Ψ and a set of corresponding target states, that raises the question of how to include additional information in J_T, within the constraints of the API that does not allow for additional arguments to J_T. For example, we might want to reference an operator in J_T whose expectation value should be maximized or minimized. There are three fundamental approaches:
- Hard-code the relevant data inside the definition of
J_T. This is the most straightforward, but not very flexible. - Attach the data to the function
J_T. This makes sense when the data is independent of thetrajectories. Typically, this is done via a closure, e.g., via amake_J_T(op)function that returns a functionJ_T(Ψ, trajectories)that referencesJ_T, or, in trivial cases, with an anonymous function for the keyword argumentJ_Tofoptimize. This is often the most flexible approach, but be aware of the performance implications of closures. - Attach the data to the
trajectories. EachTrajectorytakes arbitrary keyword arguments that can be used to attach any data as attributes that a customJ_Tfunction may then reference. This makes sense when the data is unique to eachtrajectory. In fact, the standard (but optional!)target_stateitself is an example of this; for functionals where atarget_statedoes not make sense, it can be omitted and replaced by arbitrary other data, like maybe atarget_op. Note that if thattarget_opis the same for all trajectories, it would be less redundant to associate it withJ_T, see item 2.
How to deal with long-running calculations
For any calculation that runs for more than a couple of minutes, use the QuantumControl.run_or_load function. A particular case of a long-running calculation is a call to QuantumControl.optimize for a system of non-trivial size. For optimizations in particular, there is QuantumControl.@optimize_or_load that uses run_or_load around optimize, and stores the optimization result together with the (truncated) output from the optimization.
As an alternative to QuantumControl.run_or_load, you might also consider the use of the DrWatson package, which provides DrWatson.produce_or_load. It has a slightly more opinionated approach to saving and uses automatic file names based on parameters in a config data structure. In contrast, QuantumControl.run_or_load gives more control over the filename and does not force you to organize parameters in a config.