Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/src/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ lines = ["* [$(DocInventories.dispname(item))]($(DocInventories.uri(inventory, D
Markdown.parse(join(lines, "\n"))
```

## How to define a functional ``J_T`` that depends on more than just target states

All of the optimization methods in the [JuliaQuantumControl organization](https://github.com/JuliaQuantumControl) target a final-time functional ``J_T`` via an argument `J_T`, see [`QuantumControl.optimize`](@ref), that has the interface

> `J_T`: A function `J_T(Ψ, trajectories)` that evaluates the final time functional from a list `Ψ` of forward-propagated states and `problem.trajectories`. The function `J_T` may also take a keyword argument `tau`. If it does, a vector containing the complex overlaps of the target states (`target_state` property of each trajectory in `problem.trajectories`) with the propagated states will be passed to `J_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:

1. Hard-code the relevant data inside the definition of `J_T`. This is the most straightforward, but not very flexible.
2. Attach the data to the function `J_T`. This makes sense when the data is independent of the `trajectories`. Typically, this is done via a [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)), e.g., via a `make_J_T(op)` function that returns a function `J_T(Ψ, trajectories)` that references `J_T`, or, in trivial cases, with an [anonymous function](@extref Julia :label:`man-anonymous-functions`) for the keyword argument `J_T` of [`optimize`](@ref). This is often the most flexible approach, but be aware of the [performance implications of closures](https://discourse.julialang.org/t/can-someone-explain-closures-to-me/105605).
3. Attach the data to the `trajectories`. Each [`Trajectory`](@ref) takes arbitrary keyword arguments that can be used to attach any data as attributes that a custom `J_T` function may then reference. This makes sense when the data is unique to each `trajectory`. In fact, the standard (but optional!) `target_state` itself is an example of this; for functionals where a `target_state` does not make sense, it can be omitted and replaced by arbitrary other data, like maybe a `target_op`. Note that if that `target_op` is the same for all trajectories, it would be less redundant to associate it with `J_T`, see item 2.


## How to deal with long-running calculations

Expand Down