Skip to content

Commit

Permalink
Extend get_parameters
Browse files Browse the repository at this point in the history
  • Loading branch information
goerz committed Mar 23, 2024
1 parent 570ed0a commit 68025fa
Show file tree
Hide file tree
Showing 18 changed files with 11,979 additions and 117 deletions.
5 changes: 4 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"

[weakdeps]
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"
RecursiveArrayTools = "731186ca-8d62-57ce-b412-fbd966d074cd"

[extensions]
QuantumPropagatorsODEExt = "OrdinaryDiffEq"
QuantumPropagatorsRecursiveArrayToolsExt = "RecursiveArrayTools"

[compat]
OrdinaryDiffEq = "6.59"
OffsetArrays = "1"
OrdinaryDiffEq = "6.59"
ProgressMeter = "1"
Random = "1"
RecursiveArrayTools = "3.12"
SpecialFunctions = "1, 2"
StaticArrays = "1"
TimerOutputs = "0.5.23"
Expand Down
23 changes: 21 additions & 2 deletions docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,36 @@ if endswith(VERSION, "dev")
end

links = InterLinks(
"Julia" => (
"https://docs.julialang.org/en/v1/",
"https://docs.julialang.org/en/v1/objects.inv",
joinpath(@__DIR__, "src", "inventories", "Julia.toml"),
),
"TimerOutputs" => (
"https://github.com/KristofferC/TimerOutputs.jl",
joinpath(@__DIR__, "src", "inventories", "TimerOutputs.toml")
joinpath(@__DIR__, "src", "inventories", "TimerOutputs.toml"),
),
# We'll use `@extref` for links from docstrings to sections so that the
# docstrings can also be rendered as part of the QuantumControl
# documentation.
"QuantumPropagators" => "https://juliaquantumcontrol.github.io/QuantumPropagators.jl/$DEV_OR_STABLE",
"QuantumControlBase" => "https://juliaquantumcontrol.github.io/QuantumControlBase.jl/$DEV_OR_STABLE",
"ComponentArrays" => (
"https://jonniedie.github.io/ComponentArrays.jl/stable/",
"https://jonniedie.github.io/ComponentArrays.jl/stable/objects.inv",
joinpath(@__DIR__, "src", "inventories", "ComponentArrays.toml")
),
"RecursiveArrayTools" => (
"https://docs.sciml.ai/RecursiveArrayTools/stable/",
"https://docs.sciml.ai/RecursiveArrayTools/stable/objects.inv",
joinpath(@__DIR__, "src", "inventories", "RecursiveArrayTools.toml")
),
)

externals = ExternalFallbacks("Trajectory" => "@extref QuantumControlBase.Trajectory")
externals = ExternalFallbacks(
"Trajectory" => "@extref QuantumControlBase.Trajectory",
"ParameterizedFunction" => "@extref `QuantumPropagators.Controls.ParameterizedFunction`"
)

println("Starting makedocs")

Expand All @@ -51,6 +69,7 @@ makedocs(;
# Link checking is disabled in REPL, see `devrepl.jl`.
linkcheck=(get(ENV, "DOCUMENTER_CHECK_LINKS", "1") != "0"),
warnonly,
doctest=false, # doctests run as part of test suite
format=Documenter.HTML(;
prettyurls=true,
canonical="https://juliaquantumcontrol.github.io/QuantumPropagators.jl",
Expand Down
4 changes: 2 additions & 2 deletions docs/src/benchmarks/profiling.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ using BenchmarkTools
using QuantumPropagators
using QuantumPropagators: Cheby
@benchmark propagate($Ψ₀, $H, $tlist; method=Cheby) samples=10
@benchmark propagate($Ψ₀, $H, $tlist; method=Cheby, check=false) samples=10
```

### Newton propagation
Expand All @@ -39,7 +39,7 @@ Or, the same propagation with the Newton method:
```@example profiling
using QuantumPropagators: Newton
@benchmark propagate($Ψ₀, $H, $tlist; method=Newton) samples=10
@benchmark propagate($Ψ₀, $H, $tlist; method=Newton, check=false) samples=10
```

The result in this case illustrates the significant advantage of the Chebychev method for systems of moderate to small size and unitary dynamics.
Expand Down
97 changes: 97 additions & 0 deletions docs/src/howto.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,100 @@ A propagation with [`method=Cheby`](@ref method_cheby) requires that the dynamic
By default, the Chebychev propagator uses heuristics to estimate this spectral envelope. If the spectral envelope is known (either analytically of via a separate numerical exploration of the eigenvalues over the full range of possible controls), the minimum and maximum eigenvalues of ``\op{H}(t)`` can be passed as keyword arguments `E_min` and `E_max` to [`propagate`](@ref) or [`init_prop`](@ref). Since the Chebychev method is only defined for Hermitian generators, `E_min` and `E_max` must be real values. Both values must be given.

Manually specifying `E_min` and `E_max` works with the default `specrange_method=:auto` as well as with the explicit `specrange_method=:manual`. When calculating the Chebychev coefficients, the given values may still be enlarged by the default `specrange_buffer` keyword argument in [`init_prop`](@ref). If `E_min` and `E_max` should be used *exactly*, pass `specrange_buffer=0`.


## [How to define a parameterized control](@id howto_parameterized)

Parameterized controls are [function-like objects](@extref Julia Function-like-objects) with an associated vector of parameter values that must be accessible via [`QuantumPropagators.Controls.get_parameters`](@ref).

It is recommended to define a parameterized control as a subtype of [`QuantumPropagators.Controls.ParameterizedFunction`](@ref). The packages [`ComponentArrays`](https://github.com/jonniedie/ComponentArrays.jl) and [`UnPack`](https://github.com/mauro3/UnPack.jl) might be useful in the implementing of a suitable type . For example,


```jldoctest
using ComponentArrays
using UnPack: @unpack
using QuantumPropagators.Controls: ParameterizedFunction, get_parameters
struct GaussianControl <: ParameterizedFunction
parameters::ComponentVector{Float64,Vector{Float64},Tuple{Axis{(A=1, t0=2, sigma=3)}}}
end
function GaussianControl(; A=1.0, t0=0.0, sigma=1.0)
return GaussianControl(ComponentVector(; A, t0, sigma))
end
function (control::GaussianControl)(t)
@unpack A, t0, sigma = control.parameters
return A * exp(- (t - t0)^2 / (2 * sigma^2))
end
# usage
gaussian = GaussianControl(A=2.0, sigma=0.5)
gaussian.parameters.t0 = 5 # shift center from original 0.0
@show get_parameters(gaussian)
println("gaussian(4.5) = $(round(gaussian(4.5); digits=3))")
# output
get_parameters(gaussian) = (A = 2.0, t0 = 5.0, sigma = 0.5)
gaussian(4.5) = 1.213
```


We could put some extra effort into giving direct property access to all
parameters and to provide unicode-aliases for all parameters:


```jldoctest
using ComponentArrays
using QuantumPropagators.Controls: ParameterizedFunction, get_parameters
struct GaussianControl <: ParameterizedFunction
parameters::ComponentVector{Float64,Vector{Float64},Tuple{Axis{(A=1, t0=2, sigma=3)}}}
end
function GaussianControl(; A=1.0, t0=0.0, t₀=t0, sigma=1.0, σ=sigma)
return GaussianControl(ComponentVector(; A, t0=t₀, sigma=σ))
end
function Base.propertynames(g::GaussianControl, private::Bool=false)
names = (:A, :t0, :t₀, :sigma, :σ)
return private ? Tuple(union(names, fieldnames(GaussianControl))) : names
end
function Base.getproperty(g::GaussianControl, name::Symbol)
unicode_aliases = Dict(:σ => :sigma, :t₀ => :t0)
getproperty(get_parameters(g), get(unicode_aliases, name, name))
end
function Base.setproperty!(g::GaussianControl, name::Symbol, value)
unicode_aliases = Dict(:σ => :sigma, :t₀ => :t0)
setproperty!(
get_parameters(g),
get(unicode_aliases, name, name),
value
)
end
function (control::GaussianControl)(t)
A, t₀, σ = get_parameters(control)
return A * exp(- (t - t₀)^2 / (2 * σ^2))
end
# usage
gaussian = GaussianControl(A=2.0, σ=0.5)
gaussian.t₀ = 5 # shift center from original 0.0
@show get_parameters(gaussian)
println("gaussian(4.5) = $(round(gaussian(4.5); digits=3))")
# output
get_parameters(gaussian) = (A = 2.0, t0 = 5.0, sigma = 0.5)
gaussian(4.5) = 1.213
```

The [`QuantumPropagators.Interfaces.check_parameterized_function`](@ref) can be used to verify the implementation of a [`ParameterizedFunction`](@ref).
193 changes: 193 additions & 0 deletions docs/src/inventories/ComponentArrays.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
# DocInventory version 1
project = "ComponentArrays.jl"
version = "0.15.11"

[[jl.method]]
name = "ComponentArrays.getaxes-Tuple{ComponentArray}"
uri = "api/#ComponentArrays.getaxes-Tuple%7BComponentArray%7D"
[[jl.method]]
name = "ComponentArrays.getdata-Tuple{ComponentArray}"
uri = "api/#ComponentArrays.getdata-Tuple%7BComponentArray%7D"
[[jl.method]]
name = "ComponentArrays.label2index-Tuple{ComponentVector{T, A, Axes} where {T, A, Axes}, Any}"
uri = "api/#ComponentArrays.label2index-Tuple%7BComponentVector%7BT%2C%20A%2C%20Axes%7D%20where%20%7BT%2C%20A%2C%20Axes%7D%2C%20Any%7D"
[[jl.method]]
name = "ComponentArrays.labels-Tuple{ComponentVector{T, A, Axes} where {T, A, Axes}}"
uri = "api/#ComponentArrays.labels-Tuple%7BComponentVector%7BT%2C%20A%2C%20Axes%7D%20where%20%7BT%2C%20A%2C%20Axes%7D%7D"
[[jl.method]]
name = "ComponentArrays.valkeys-Tuple{AbstractAxis}"
uri = "api/#ComponentArrays.valkeys-Tuple%7BAbstractAxis%7D"

[[jl.type]]
name = "ComponentArrays.Axis"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.ComponentArray"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.ComponentMatrix"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.ComponentVector"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.KeepIndex"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.LazyArray"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.PartitionedAxis"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.ShapedAxis"
uri = "api/#$"
[[jl.type]]
name = "ComponentArrays.ViewAxis"
uri = "api/#$"

[[std.doc]]
dispname = "API"
name = "api"
uri = "api/"
[[std.doc]]
dispname = "Neural ODEs with DiffEqFlux"
name = "examples/DiffEqFlux"
uri = "examples/DiffEqFlux/"
[[std.doc]]
dispname = "ODE with Jacobian"
name = "examples/ODE_jac"
uri = "examples/ODE_jac/"
[[std.doc]]
dispname = "Model Reference Adaptive Control"
name = "examples/adaptive_control"
uri = "examples/adaptive_control/"
[[std.doc]]
dispname = "Home"
name = "index"
uri = ""
[[std.doc]]
dispname = "Indexing Behavior"
name = "indexing_behavior"
uri = "indexing_behavior/"
[[std.doc]]
dispname = "Quick Start"
name = "quickstart"
uri = "quickstart/"
[[std.doc]]
dispname = "Unpacking to StaticArrays"
name = "static_unpack"
uri = "static_unpack/"

[[std.label]]
dispname = "A sliding block with two different friction models"
name = "A-sliding-block-with-two-different-friction-models"
uri = "examples/coulomb_control/#$"
[[std.label]]
name = "API"
uri = "api/#$"
[[std.label]]
dispname = "Closed-Loop Response"
name = "Closed-Loop-Response"
uri = "examples/coulomb_control/#$"
[[std.label]]
dispname = "Component Functions"
name = "Component-Functions"
uri = "examples/coulomb_control/#$"
[[std.label]]
name = "ComponentArrays.jl"
uri = "#$"
[[std.label]]
dispname = "Control of a sliding block"
name = "Control-of-a-sliding-block"
uri = "examples/coulomb_control/#$"
[[std.label]]
dispname = "Derivative Functions"
name = "Derivative-Functions"
uri = "examples/adaptive_control/#$"
[[std.label]]
name = "Example"
uri = "static_unpack/#$"
[[std.label]]
dispname = "General use"
name = "General-use"
uri = "quickstart/#$"
[[std.label]]
dispname = "Helper Functions"
name = "Helper-Functions"
uri = "examples/adaptive_control/#$"
[[std.label]]
dispname = "Indexing Behavior"
name = "Indexing-Behavior"
uri = "indexing_behavior/#$"
[[std.label]]
dispname = "Indexing with multiple symbols"
name = "Indexing-with-multiple-symbols"
uri = "indexing_behavior/#$"
[[std.label]]
dispname = "Insufficient Excitation and Rohr's Example"
name = "Insufficient-Excitation-and-Rohr's-Example"
uri = "examples/adaptive_control/#Insufficient-Excitation-and-Rohr%27s-Example"
[[std.label]]
dispname = "Laplace Domain Model Specification"
name = "Laplace-Domain-Model-Specification"
uri = "examples/adaptive_control/#$"
[[std.label]]
dispname = "Model Reference Adaptive Control"
name = "Model-Reference-Adaptive-Control"
uri = "examples/adaptive_control/#$"
[[std.label]]
name = "Motivation"
uri = "examples/adaptive_control/#$"
[[std.label]]
dispname = "Neural ODEs with DiffEqFlux"
name = "Neural-ODEs-with-DiffEqFlux"
uri = "examples/DiffEqFlux/#$"
[[std.label]]
dispname = "ODE with Jacobian"
name = "ODE-with-Jacobian"
uri = "examples/ODE_jac/#$"
[[std.label]]
dispname = "Open-Loop Response"
name = "Open-Loop-Response"
uri = "examples/coulomb_control/#$"
[[std.label]]
dispname = "PID feedback control"
name = "PID-feedback-control"
uri = "examples/coulomb_control/#$"
[[std.label]]
dispname = "Problem Setup"
name = "Problem-Setup"
uri = "examples/coulomb_control/#$"
[[std.label]]
dispname = "Quick Start"
name = "Quick-Start"
uri = "quickstart/#$"
[[std.label]]
dispname = "Retaining component labels through index operations"
name = "Retaining-component-labels-through-index-operations"
uri = "indexing_behavior/#$"
[[std.label]]
dispname = "Set Up Simulation"
name = "Set-Up-Simulation"
uri = "examples/adaptive_control/#$"
[[std.label]]
dispname = "Simulation Inputs"
name = "Simulation-Inputs"
uri = "examples/adaptive_control/#$"
[[std.label]]
dispname = "Unmodeled Dynamics"
name = "Unmodeled-Dynamics"
uri = "examples/adaptive_control/#$"
[[std.label]]
dispname = "Unpacking to StaticArrays"
name = "Unpacking-to-StaticArrays"
uri = "static_unpack/#$"
[[std.label]]
dispname = "Views and slices"
name = "Views-and-slices"
uri = "indexing_behavior/#$"
[[std.label]]
dispname = "Why not just have static ComponentArrays?"
name = "Why-not-just-have-static-ComponentArrays?"
uri = "static_unpack/#Why-not-just-have-static-ComponentArrays%3F"
Loading

0 comments on commit 68025fa

Please sign in to comment.