GRAPE's method in Quantum Control (GRAPE.jl)

Hi. I’m working with QuantumControl.jl and I’m trying to learn about GRAPE method in this package. There is an example of Optimization of a State-to-State Transfer in a Two-Level-System. I can run this code but I need to access to the controls in each iteration It should be a list containing 4 arrays with 499 elements.
In krotov module in python there is a same list named all_pulses for this particular example.
Would you please help me how can I find this list in QuantumControl.jl package?

You should probably tag me directly for any questions about QuantumControl.jl, or ask questions like this at Discussions · JuliaQuantumControl/QuantumControl.jl · GitHub. Not that there’s anything wrong with Discourse, but I might not see the question.

The way to get any kind of data out of each iteration in the optimization is to use a custom info_hook (let’s call it store_pulses) and pass that to the optimize function (see the documentation about the info_hook parameter). In the specific example you link to, you’d be adding store_pulses to the existing hooks (where you see chain_infohooks). The store_pulses should return a tuple of the optimized pulses. These will then be available in result.records, where result is the object returned by the optimize routine.

Something like this should do it (not tested):

function store_pulses(wrk, iteration, _...)
    L = length(wrk.controls)
    ϵ_opt = reshape(wrk.pulsevals, L, :)
    opt_pulses = [discretize_on_midpoints(ϵ_opt[l, :], res.tlist) for l=1:L]
    return Tuple(opt_pulses)
end

I realize the documentation didn’t tell you which parameters the store_pulses should get, or which properties wrk has. Hopefully, that will get better in future versions. In the meantime, custom info_hooks probably will require looking at the source code of the package.

I should also mention that probably in the next major release of GRAPE.jl, the layout of wrk.pulsevals will be transposed, so you’d have to reshape it as reshape(wrk.pulsevals, :, L) and then access ϵ_opt[:, l].

You could use discretize instead of discretize_on_midpoints if you want to get the optimized controls on the points of the time grid instead of the “pulses” defined on the midpoints of the time grid, but that would introduce additional overhead to do the conversion in each iteration. Or, you could also just return a tuple with wrk.pulsevals as the only element, and then sort it out later.

Since what you’re trying to do is probably quite common, we should include this information in the documentation: Add a Howto on how to access the optimized pulses in each iteration · Issue #18 · JuliaQuantumControl/QuantumControl.jl · GitHub

1 Like

Thanks for your response.
I tried to follow these steps. But I have some questions as I faced some errors.

  1. Is wrk= GRAPE.GrapeWrk(problem;) ?
  2. What dose the “iteration” that you defined in the “store_pulses(wrk, iteration, _…)” do?
  1. Is wrk= GRAPE.GrapeWrk(problem;)

Yes, exactly.

  1. What does the “iteration” that you defined in the store_pulses(wrk, iteration, _…) do

That’s just the iteration number (as an integer)

In general, you can temporarily put e.g. @show iteration or @show typeof(wrk) somewhere in your store_pulses function. Julia is very good at “print-debugging”.

I wrote this:

function store_pulses(wrk)
    L = length(wrk.controls)
    ϵ_opt = reshape(wrk.pulsevals, L, :)
    opt_pulses = [QuantumPropagators.Controls.discretize_on_midpoints(ϵ_opt[l, :], tlist) for l=1:L]
    return Tuple(opt_pulses)
end

and it is the optimization part:

opt_result_LBFGSB, file = @optimize_or_load(
    datadir("TLS"),
    problem,
    method = :grape,
    force = true,
    filename = "opt_result_LBFGSB.jld2",
    info_hook = chain_infohooks(
        GRAPELinesearchAnalysis.plot_linesearch(datadir("TLS", "Linesearch", "LBFGSB")),
        QuantumControl.GRAPE.print_table,
        store_pulses(wrk)
    )
);

and I got this error: MethodError: objects of type Tuple{Vector{Float64}} are not callable

There’s two points where you didn’t follow my instructions :wink: :

  1. You’re not using the correct signature for store_pulses. It has to be store_pulses(wrk, iteration, _...)
  2. You’re not passing store_pulses as an info_hook, but the result of store_pulses(wrk), which is where your error originates.

Here is a complete working example:

I appreciate the information you have provided me with, and I appreciate your prompt reply.

1 Like