Skip to content

Commit 92687ad

Browse files
committed
Merge #109 from branch J-a-avg-zero
2 parents 493f59a + b693ae8 commit 92687ad

2 files changed

Lines changed: 87 additions & 1 deletion

File tree

src/functionals.jl

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module Functionals
22

33
export J_T_ss, J_T_sm, J_T_re
4-
export J_a_fluence
4+
export J_a_fluence, J_a_avg_zero
55
export gate_functional
66
export make_gate_chi
77
export J_b
@@ -973,6 +973,60 @@ end
973973
make_analytic_grad_J_a(::typeof(J_a_fluence), tlist) = grad_J_a_fluence
974974

975975

976+
@doc raw"""Running cost penalizing a non-zero pulse area.
977+
978+
```julia
979+
J_a = J_a_avg_zero(pulsevals, tlist)
980+
```
981+
982+
calculates
983+
984+
```math
985+
J_a = \sum_l \left(\int_0^T ϵ_l(t)\, dt\right)^2 \approx \sum_l A_l^2\,,
986+
\quad A_l = \sum_n ϵ_{nl}\, dt_n\,,
987+
```
988+
989+
where ``ϵ_{nl}`` and ``dt_n`` are as in [`J_a_fluence`](@ref). The functional
990+
is zero when every control integrates to zero over the time grid, and positive
991+
otherwise.
992+
993+
In conjunction with [`QuantumPropagators.Amplitudes.GuidedAmplitude`](@ref),
994+
this enables an optimization that preserves the pulse area of a given `guide`.
995+
996+
# See also
997+
998+
* [`grad_J_a_avg_zero`](@ref) — analytic (automatic) gradient
999+
"""
1000+
function J_a_avg_zero(pulsevals, tlist)
1001+
N_T = length(tlist) - 1
1002+
dt = diff(tlist) # (N_T,)
1003+
pv = reshape(pulsevals, N_T, :) # (N_T, N_L), no copy
1004+
A = vec(dt' * pv) # (N_L,): time integral per control
1005+
return sum(abs2.(A))
1006+
end
1007+
1008+
1009+
"""Analytic derivative for [`J_a_avg_zero`](@ref).
1010+
1011+
```julia
1012+
∇J_a = grad_J_a_avg_zero(pulsevals, tlist)
1013+
```
1014+
1015+
returns `∇J_a` with elements ``2 A_l\\, dt_n``, where
1016+
``A_l = \\sum_n ϵ_{nl}\\, dt_n`` is the time integral of control `l`.
1017+
"""
1018+
function grad_J_a_avg_zero(pulsevals, tlist)
1019+
N_T = length(tlist) - 1
1020+
dt = diff(tlist) # (N_T,)
1021+
pv = reshape(pulsevals, N_T, :) # (N_T, N_L), no copy
1022+
A = vec(dt' * pv) # (N_L,): time integral per control
1023+
return vec(2 .* reshape(dt, :, 1) .* reshape(A, 1, :))
1024+
end
1025+
1026+
1027+
make_analytic_grad_J_a(::typeof(J_a_avg_zero), tlist) = grad_J_a_avg_zero
1028+
1029+
9761030
"""
9771031
Return a function that calculates ``|ξ_k(t_n)⟩ = -∂g_b/∂⟨Ψ_k(t_n)|``.
9781032

test/test_functionals.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ using QuantumControl.Functionals:
77
J_T_ss,
88
J_a_fluence,
99
grad_J_a_fluence,
10+
J_a_avg_zero,
11+
grad_J_a_avg_zero,
1012
make_grad_J_a,
1113
make_chi,
1214
make_xi,
@@ -148,6 +150,36 @@ end
148150
end
149151

150152

153+
@testset "J_a_avg_zero" begin
154+
155+
# Two controls on a non-uniform grid
156+
tlist_nu = [0.0, 0.1, 0.3, 0.6, 1.0]
157+
dt_nu = [0.1, 0.2, 0.3, 0.4] # diff(tlist_nu)
158+
pv1 = [1.0, -2.0, 3.0, -1.0] # A₁ = 0.1 - 0.4 + 0.9 - 0.4 = 0.2
159+
pv2 = [2.0, -1.0, -1.0, 0.0] # A₂ = 0.2 - 0.2 - 0.3 + 0.0 = -0.3
160+
pulsevals_nu = vcat(pv1, pv2)
161+
162+
A1 = dot(pv1, dt_nu)
163+
A2 = dot(pv2, dt_nu)
164+
@test J_a_avg_zero(pulsevals_nu, tlist_nu) A1^2 + A2^2
165+
166+
# Zero when each control integrates to zero:
167+
# 1*0.1 + 0*0.2 + 0*0.3 + (-0.25)*0.4 = 0.1 - 0.1 = 0
168+
pv_zeroA = [1.0, 0.0, 0.0, -0.25]
169+
@test J_a_avg_zero(vcat(pv_zeroA, pv_zeroA), tlist_nu) 0.0 atol = 1e-15
170+
171+
# Analytic gradient matches manual calculation
172+
G_expected = vcat(2 * A1 .* dt_nu, 2 * A2 .* dt_nu)
173+
@test grad_J_a_avg_zero(pulsevals_nu, tlist_nu) G_expected
174+
175+
# Analytic gradient matches Zygote
176+
grad_J_a_zygote =
177+
make_grad_J_a(J_a_avg_zero, tlist_nu; mode = :automatic, automatic = Zygote)
178+
@test norm(grad_J_a_zygote(pulsevals_nu, tlist_nu) - G_expected) < 1e-12
179+
180+
end
181+
182+
151183
@testset "J_T without analytic derivative" begin
152184

153185
QuantumControl.set_default_ad_framework(nothing; quiet = true)

0 commit comments

Comments
 (0)