Skip to content

Commit 0846150

Browse files
committed
Add Flow(ocp) and augment=true tests to CTFlows reexports
- Add 4 new testsets for Flow(ocp) and augment=true functionality - Test Flow from Control-Free OCP: verify callable and return types - Test augment=true: verify 3-value return (state, costate, variable costate) - Test Manual vs Automatic Hamiltonian: compare manual H_aug vs Flow(ocp) - Test Analytical Solution Check: simple λ=0 constant solution case - Add using OrdinaryDiffEq dependency for Flow functionality - Fix applicable() test instead of isa Function for OptimalControlFlow objects - All tests pass (98/98) with proper signature freezing
1 parent 8120478 commit 0846150

2 files changed

Lines changed: 124 additions & 2 deletions

File tree

docs/src/example-control-free.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ nothing # hide
5858
### Direct method
5959

6060
```@example main-growth
61-
direct_sol = solve(ocp; display=false)
61+
direct_sol = solve(ocp; grid_size=20, display=false)
6262
println("Estimated growth rate: λ = ", variable(direct_sol))
6363
println("Objective value: ", objective(direct_sol))
6464
nothing # hide
@@ -225,7 +225,7 @@ nothing # hide
225225
### [Direct method](@id example-control-free-direct-2)
226226

227227
```@example main-harmonic
228-
direct_sol = solve(ocp; display=false)
228+
direct_sol = solve(ocp; grid_size=20, display=false)
229229
println("Optimal pulsation: ω = ", variable(direct_sol))
230230
println("Objective value: ω² = ", objective(direct_sol))
231231
println("Expected: ω = π/2 ≈ 1.5708, ω² ≈ 2.4674")

test/suite/reexport/test_ctflows.jl

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module TestCtflows
1010
using Test: Test
1111
using OptimalControl # using is mandatory since we test exported symbols
1212
using CTFlows: CTFlows # needed for abstract type checks
13+
using OrdinaryDiffEq
1314

1415
const VERBOSE = isdefined(Main, :TestOptions) ? Main.TestOptions.VERBOSE : true
1516
const SHOWTIMING = isdefined(Main, :TestOptions) ? Main.TestOptions.SHOWTIMING : true
@@ -357,6 +358,127 @@ function test_ctflows()
357358
Test.@test dg(3, [1, 2], [4, 5]) 6
358359
end
359360
end
361+
362+
# ====================================================================
363+
# FLOW FROM OCP AND AUGMENT TESTS
364+
# ====================================================================
365+
# These tests verify the Flow(ocp) construction for control-free problems
366+
# and the augment=true feature for automatic costate computation.
367+
368+
Test.@testset "Flow from OCP and augment" begin
369+
Test.@testset "Flow from Control-Free OCP" begin
370+
# Define a simple control-free OCP (exponential growth)
371+
t0 = 0
372+
tf = 1
373+
x0 = 1.0
374+
375+
ocp = @def begin
376+
λ R, variable
377+
t [t0, tf], time
378+
x R, state
379+
x(t0) == x0
380+
(t) == λ * x(t)
381+
(x(t)^2) min
382+
end
383+
384+
# Test: Flow(ocp) works for control-free problems
385+
f = Flow(ocp)
386+
387+
# Test: basic call returns 2 values (state, costate)
388+
λ_val = 0.5
389+
p0 = 1.0
390+
Test.@test applicable(f, t0, x0, p0, tf, λ_val)
391+
xf, pf = f(t0, x0, p0, tf, λ_val)
392+
Test.@test xf isa Real
393+
Test.@test pf isa Real
394+
end
395+
396+
Test.@testset "Flow with augment=true" begin
397+
# Same OCP as above
398+
t0 = 0
399+
tf = 1
400+
x0 = 1.0
401+
402+
ocp = @def begin
403+
λ R, variable
404+
t [t0, tf], time
405+
x R, state
406+
x(t0) == x0
407+
(t) == λ * x(t)
408+
(x(t)^2) min
409+
end
410+
411+
f = Flow(ocp)
412+
λ_val = 0.5
413+
p0 = 1.0
414+
415+
# Test: augment=true returns 3 values (state, costate, variable costate)
416+
xf, pf, pλ = f(t0, x0, p0, tf, λ_val; augment=true)
417+
Test.@test xf isa Real
418+
Test.@test pf isa Real
419+
Test.@testisa Real # The new one: costate of λ
420+
end
421+
422+
Test.@testset "Manual vs Automatic Hamiltonian" begin
423+
# Define OCP
424+
t0 = 0
425+
tf = 1
426+
x0 = 1.0
427+
λ_val = 0.5
428+
p0 = 1.0
429+
430+
ocp = @def begin
431+
λ R, variable
432+
t [t0, tf], time
433+
x R, state
434+
x(t0) == x0
435+
(t) == λ * x(t)
436+
(x(t)^2) min
437+
end
438+
439+
# Manual Hamiltonian construction
440+
H(x, p, λ) = p * λ * x - x^2
441+
function H_aug(x_, p_)
442+
x, λ = x_
443+
p, _ = p_
444+
return H(x, p, λ)
445+
end
446+
f_manual = Flow(OptimalControl.Hamiltonian(H_aug))
447+
448+
# Automatic Flow from OCP
449+
f_auto = Flow(ocp)
450+
451+
# Test: both give similar results
452+
xf_manual, pf_manual = f_manual(t0, [x0, λ_val], [p0, 0.0], tf)
453+
xf_auto, pf_auto = f_auto(t0, x0, p0, tf, λ_val)
454+
455+
Test.@test xf_manual[1] xf_auto rtol=1e-6
456+
Test.@test pf_manual[1] pf_auto rtol=1e-6
457+
end
458+
459+
Test.@testset "Analytical Solution Check" begin
460+
# For λ=0, x(t) = x0 (constant)
461+
t0 = 0
462+
tf = 1
463+
x0 = 1.0
464+
465+
ocp = @def begin
466+
λ R, variable
467+
t [t0, tf], time
468+
x R, state
469+
x(t0) == x0
470+
(t) == λ * x(t)
471+
(x(t)^2) min
472+
end
473+
474+
f = Flow(ocp)
475+
λ_zero = 0.0
476+
p0 = 1.0
477+
478+
xf, pf = f(t0, x0, p0, tf, λ_zero)
479+
Test.@test xf x0 rtol=1e-10 # x remains constant
480+
end
481+
end
360482
end
361483
end
362484

0 commit comments

Comments
 (0)