Mixing of LockedAmplitude and ShapedAmplitude #82
-
I have an optimization problem where I have three time-dependent fields. The first field is my control, the second is a LockedAmplitude (not optimized), and the third should be the product of the two. However, it is not clear to me how I should define that? As an example, it could be: Tend = 10
times = range(0, Tend, step=0.01)
shape(t) = QuantumControl.Shapes.flattop(t, T=Tend, t_rise=0.3, func=:blackman);
optimized_field = QuantumControl.Controls.ShapedAmplitude(t -> 1, times; shape) #Should be optimized
constant_ampl = QuantumControl.Controls.LockedAmplitude(t->t^2, times) #Amplitude that should not be optimized. In reality the time dependence is more complicated
#Cross term that is the product of the two fields
cross_term = optimized_field*constant_ampl #This obviously does not work, but I am unsure how to define an equivalent function.
#The Hamiltonian should look like
H = hamiltonian((h1,constant_ampl),(h2,optimized_field),(h3,cross_term)) I considered whether I should refer to optimized_field.control, since this vector is mutated in the optimization, but it is not entirely clear to me whether this will work. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 7 replies
-
If we call your The product
Note that I didn't include |
Beta Was this translation helpful? Give feedback.
-
I see that makes a lot of sense! The Hamiltonian I am currently interested in optimizing has the following form: We are thus considering a certain amount of photonic modes (with the associated creation and annihilation operator I have sketched out an implementation of this squareroot product of two functions below, which passes both checks. I haven't tested whether it works in an optimization yet. Do you have any comments on how it was implemented? using QuantumControl
using QuantumPropagators
abstract type SqrtProductAmplitude <: QuantumPropagators.Amplitudes.ControlAmplitude end
function SqrtProductAmplitude(control1,control2)
if (control1 isa Vector{Float64}) && (control2 isa Vector{Float64})
return SqrtProductAmplitudePulse((control1, control2))
else
try
ϵ_t = control1(0.0)
catch
error(
"SqrtProductAmplitude control 1 must either be a vector of values or a callable"
)
end
try
ϵ_t = control2(0.0)
catch
error("SqrtProductAmplitude control 2 must either be a vector of values or a callable")
end
return SqrtProductAmplitudeContinuous((control1, control2))
end
end
struct SqrtProductAmplitudePulse <: SqrtProductAmplitude
controls # vector of controls
end
struct SqrtProductAmplitudeContinuous <: SqrtProductAmplitude
controls # vector of controls
end
Base.Array(ampl::SqrtProductAmplitudePulse ) = sqrt.(ampl.controls[1] .*ampl.controls[2] )
(ampl::SqrtProductAmplitudeContinuous)(t::Float64) = sqrt(ampl.controls[1](t) * ampl.controls[2](t))
function QuantumPropagators.Controls.evaluate(ampl::SqrtProductAmplitude, args...; vals_dict=IdDict())
S_t = QuantumPropagators.Controls.evaluate(ampl.controls[1], args...; vals_dict)
ϵ_t = QuantumPropagators.Controls.evaluate(ampl.controls[2], args...; vals_dict)
return sqrt.(S_t .* ϵ_t)
end
function Base.show(io::IO, ampl::SqrtProductAmplitude)
print(io, "SqrtProductAmplitude(::$(typeof(ampl.controls[1])),::$(typeof(ampl.controls[2]))")
end
function QuantumControl.Controls.get_control_deriv(ampl::SqrtProductAmplitudePulse,control)
if control ≡ ampl.controls[1]
return QuantumControl.Amplitudes.LockedAmplitude(.- 1 ./ (2 .* sqrt(ampl.controls[1] .* ampl.controls[2])) .* ampl.controls[2])
elseif control ≡ ampl.controls[2]
return QuantumControl.Amplitudes.LockedAmplitude(.- 1 ./ (2 .* sqrt(ampl.controls[1] .* ampl.controls[2])) .* ampl.controls[1])
else
0
end
end
function QuantumControl.Controls.get_control_deriv(ampl::SqrtProductAmplitudeContinuous,control)
if control ≡ ampl.controls[1]
return QuantumControl.Amplitudes.LockedAmplitude(t->-1/(2*sqrt(ampl.controls[1](t)*ampl.controls[2](t)))*ampl.controls[2](t))
elseif control ≡ ampl.controls[2]
return QuantumControl.Amplitudes.LockedAmplitude(t->-1/(2*sqrt(ampl.controls[1](t)*ampl.controls[2](t)))*ampl.controls[1](t))
else
0
end
end
QuantumControl.Controls.get_controls(a::SqrtProductAmplitude) = a.controls
function QuantumPropagators.Controls.substitute(ampl::CT, replacements) where {CT<:SqrtProductAmplitude}
if ampl in keys(replacements)
return replacements[ampl]
else
control1 = QuantumPropagators.Controls.substitute(ampl.controls[1], replacements)
control2 = QuantumPropagators.Controls.substitute(ampl.controls[2], replacements)
CT((control1, control2))
end
end
ϵ1(t) = 1.0
ϵ2(t) = 1.0
field = SqrtProductAmplitude(ϵ1, ϵ2)
dt = 0.1
T = 10
tlist = collect(range(0, T, step=dt))
QuantumPropagators.Interfaces.check_amplitude(field; tlist, quiet=false)
QuantumControl.Interfaces.check_amplitude(field; tlist, quiet=false) As for the constant factor in a Hamiltonian, lets say we have This is exactly the sum over n of |
Beta Was this translation helpful? Give feedback.
If we call your$\Gamma(t)$ , the constant $S(t)$ and the actual control $\epsilon(t)$ , it seems to me your Hamiltonian is
constant_ampl
shape
in theoptimized_field
t -> 1
The product$\Gamma(t) S(t)$ is just another shape function for a
ShapedAmplitude
. So this should be totally fine, as something like: