diff --git a/examples/training.jl b/examples/training.jl index fe5da594085eb21cb72e3d414cfd307aaf801e0f..b108b3f6e5769c8536bf0f4f4b53042b7606d25f 100644 --- a/examples/training.jl +++ b/examples/training.jl @@ -51,6 +51,9 @@ import ProgressMeter using Printf using Plots +# %% +product = Iterators.product + # %% using Logging @@ -392,6 +395,9 @@ plot!(ks[end:end], as[end:end], line = nothing, marker = :dot, label = "") plot(plt_a, plt_b, plt_c, plt_d) +# %% [markdown] +# **TODO**: Can the R-dependence be obtained directly? + # %% ks = range(a+1, 100, length=200) plot() @@ -508,12 +514,10 @@ plot(kps, xaxis = "Steps", yaxis = "k_p") plot(kds, xaxis = "Steps", yaxis = "k_d") # %% -function train(kp, kd) +function train(kp, kd; n_iters = 250) λs = [] kps = [] kds = [] - n_iters = 250 - # pm = Progress(n_iters) @time for iter in 1:n_iters (λ, ∂kp, ∂kd) = conv_grad(ζ, ω, kp, kd) step = 1e-1 * 1/sqrt(∂kp^2 + ∂kd^2) * 1/sqrt(iter) @@ -522,15 +526,14 @@ function train(kp, kd) push!(λs, λ) push!(kps, kp) push!(kds, kd) - # next!(pm, showvalues=[(:λ, λ), (:kp, kp), (:kd, kd)]) end (λs, kps, kds) end # %% ress = Dict([]) -@time for kp in [1, 0, -1], kd in [1, 0, -1] - (λs, kps, kds) = train(kp, kd) +for (kp, kd) in product([1, 0, -1], [1, 0, -1]) + @time (λs, kps, kds) = train(kp, kd, n_iters = 50) ress[(kp,kd)] = (kps, kds) plt_a = plot(λs, label = "", yaxis = "conv_rate", xaxis = "steps") plt_b = plot(kps, label = "", yaxis = "kp", xaxis = "steps") @@ -570,8 +573,7 @@ ys = [] us = [] vs = [] -@showprogress for kp in kps - for kd in kds +@showprogress for (kp, kd) in product(kps, kds) (λ, ∂kp, ∂kd) = conv_grad(ζ, ω, kp, kd) push!(xs, kp) push!(ys, kd) @@ -877,7 +879,7 @@ function real_conv_rate(ζ, ω, kp, kd) (2ζ*ω+kd)/2 end end - + # %% @time contourf(kps, kds, (kp, kd) -> real_conv_rate(.1, 1, kp, kd)) @@ -1212,4 +1214,239 @@ plot!(kps[end:end], kds[end:end], line=nothing, marker=:dot, label = "") # %% plot(τs) +# %% [markdown] +# # Gain Bound of PD-controlled Second Order System, with shift + +# %% +function _gain_grad(ζ_val, ω_val, kp_val, kd_val; margin = 1e-3, R = 0.0) + + sys = DynamicSystem(opt = Hypatia.Optimizer) + kp = @IQC.parameter sys kp kp_val + kd = @IQC.parameter sys kd kd_val + ζ = @IQC.parameter sys ζ ζ_val + ω = @IQC.parameter sys ω ω_val + + @signals sys begin + x, 1 + dx, 1 + u, 1 + w, 1 + end + + @equalities sys begin + 0 = u+kp*x+kd*dx + end + + @tfs sys begin + x = (1/(s^2+2*ζ*ω*s+ω^2))*(u+w) + dx = s*x + end + + τ = gen_τ(sys, IQC.Scalar(), minimize=true, nonneg=true) + @target sys begin + x^2 + R*u^2 <= τ*w^2 + end + + + λ = IQC.convergence_rate(sys, margin=margin, ϵ = 1e-2) + λ = clamp(λ, -Inf, 0.0) + (success, P, feas_prob) = solve!(sys, λ=λ, margin=margin, req_PSD_P=true, silent=true) + IQC.set_param!(sys, τ, IQC.value(sys, τ)) + @assert success + + grads = IQC.gradient(sys, τ, λ=λ, margin=margin) + (IQC.value(sys, τ), grads[kp], grads[kd]) +end + + +function gain_grad(ζ_val, ω_val, kp_val, kd_val; margin = 1e-3, R=0.0, n_tries = 10) + n_failed = 0 + done = false + ret_val = nothing + while n_failed < n_tries && !done + try + ret_val = _gain_grad(ζ_val, ω_val, kp_val, kd_val, margin=margin, R=0.0) + done = true + catch e + n_failed += 1 + end + end + ret_val +end + +# %% +ζ = .1 +ω = 1 +kp = 0.5 +kd = 0.5 + +for _ in 1:20 + try + @show _gain_grad(ζ, ω, kp, kd, margin=1e-3) + catch e + @show e + end +end + +# %% +ζ = .1 +ω = 1 +kp = 0.5 +kd = 0.5 + + +for _ in 1:20 + try + @show _gain_grad(ζ, ω, kp, kd, margin=1e-6) + catch e + @show e + end +end + +# %% +ζ = .1 +ω = 1 +kp = 0.0 +kd = 0.0 + + +for _ in 1:20 + try + @show _gain_grad(ζ, ω, kp, kd, margin=1e-6) + catch e + @show e + end +end + +# %% [markdown] +# Now, the gain bound varies a lot between runs. This is definitely a problem. + +# %% +ζ = -.1 +ω = 1 +kp = -.5 +kd = -.1 +∂kp = 0 +∂kd = 0 +τ = 0 + +τs = [] +kps = [] +kds = [] +n_iters = 10^2 +pm = Progress(n_iters) +for iter in 1:n_iters + (τ, ∂kp, ∂kd) = gain_grad(ζ, ω, kp, kd, margin=1e-6) + step = 1e-1/sqrt(iter) + kp -= step*∂kp + kd -= step*∂kd + push!(τs, τ) + push!(kps, kp) + push!(kds, kd) + next!(pm, showvalues=[(:τ, τ), (:kp, kp), (:kd, kd)]) +end + +# %% +plot(τs, yaxis = ("Gain Bound", :log10), xaxis = "Gradient Steps") + +# %% +plot(kps, kds, xaxis = "kp", yaxis = "kd", label = "") +plot!(kps[end:end], kds[end:end], line=nothing, marker=:dot, label = "") + +# %% +ζ = .1 +ω = 1 +kp = .5 +kd = .5 +∂kp = 0 +∂kd = 0 +τ = 0 + +τs = [] +kps = [] +kds = [] +n_iters = 10^2 +pm = Progress(n_iters) +for iter in 1:n_iters + (τ, ∂kp, ∂kd) = gain_grad(ζ, ω, kp, kd, margin=1e-6, R = 1.0) + step = 1e-1/sqrt(iter) + kp -= step*sign(∂kp) + kd -= step*sign(∂kd) + push!(τs, τ) + push!(kps, kp) + push!(kds, kd) + next!(pm, showvalues=[(:τ, τ), (:kp, kp), (:kd, kd)]) +end + +# %% +plot(τs, yaxis = ("Gain Bound", :log10), xaxis = "Gradient Steps") + +# %% +plot(plot(kps, xaxis = "Steps", yaxis = "kp", label=""),plot(kds, xaxis = "Steps", yaxis = "kp", label = "")) + +# %% +plot(kps, kds, xaxis = "kp", yaxis = "kd", label = "") +plot!(kps[end:end], kds[end:end], line=nothing, marker=:dot, label = "") + +# %% [markdown] +# For sufficiently large $R$, I expect the optimal $kp$ to be finite, but I seem to get large $kp$. Matlab should be able to tell me what the answer is, and then I should try to interpret the result. + +# %% + +# %% +ζ = .1 +ω = 1 +kp = 1 +kd = 1 +∂kp = 0 +∂kd = 0 +τ = 0 + +τs = [] +kps = [] +kds = [] +n_iters = 10^3 +pm = Progress(n_iters) +for iter in 1:n_iters + (τ, ∂kp, ∂kd) = conv_grad(ζ, ω, kp, kd, margin=1e-6) + step = 1e-1 * 1/sqrt(∂kp^2 + ∂kd^2) * 1/sqrt(iter) + kp += step*∂kp + kd += step*∂kd + push!(τs, τ) + push!(kps, kp) + push!(kds, kd) + next!(pm, showvalues=[(:τ, τ), (:kp, kp), (:kd, kd)]) +end + +# %% +plot(kps, kds, xaxis = "kp", yaxis = "kd", label = "") +plot!(kps[end:end], kds[end:end], line=nothing, marker=:dot, label = "") + +# %% +plot(τs) + +# %% +τs = [] + +for iter in 1:n_iters + (τ, ∂kp, ∂kd) = gain_grad(ζ, ω, kp, kd, R = 1.0) + step = 1e-1/sqrt(iter) + kp -= step*∂kp + kd -= step*∂kd + push!(τs, τ) + push!(kps, kp) + push!(kds, kd) + next!(pm, showvalues=[(:τ, τ), (:kp, kp), (:kd, kd)]) +end + +# %% +plot(kps, kds, xaxis = "kp", yaxis = "kd", label = "") +plot!(kps[end:end], kds[end:end], line=nothing, marker=:dot, label = "") + +# %% +plot(τs) + +# %% [markdown] +# # Shift, and then do gain bound gradients + # %%