Skip to content

Commit c9ff1f1

Browse files
committed
feat: add improved display function test suite
- Add .extras/test_display.jl with improved display functionality - Add .extras/Project.toml for testing dependencies - Update .gitignore to include .extras/ - Features: * Forced order: discretizer → modeler → solver * Component IDs from actual objects using CTBase.remove() * Options display with sources (user/default) * Modern formatting with colors and compact layout * Support for additional method options in parentheses
1 parent 90c1ce7 commit c9ff1f1

File tree

3 files changed

+359
-1
lines changed

3 files changed

+359
-1
lines changed

.extras/Project.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[deps]
2+
ADNLPModels = "54578032-b7ea-4c30-94aa-7cbd1cce6c9a"
3+
CTBase = "54762871-cc72-4466-b8e8-f6c8b58076cd"
4+
CTDirect = "790bbbee-bee9-49ee-8912-a9de031322d5"
5+
CTModels = "34c4fa32-2049-4079-8329-de33c2a22e2d"
6+
CTSolvers = "d3e8d392-8e4b-4d9b-8e92-d7d4e3650ef6"
7+
ExaModels = "1037b233-b668-4ce9-9b63-f9f681f55dd2"
8+
MadNLP = "2621e9c9-9eb4-46b1-8089-e8c72242dfb6"
9+
MadNLPMumps = "3b83494e-c0a4-4895-918b-9157a7a085a1"
10+
NLPModelsIpopt = "f4238b75-b362-5c4c-b852-0801c9a21d71"
11+
OptimalControl = "5f98b655-cc9a-415a-b60e-744165666948"

.extras/test_display.jl

Lines changed: 347 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,347 @@
1+
try
2+
using Revise
3+
catch
4+
println("🔧 Revise not found - continuing without hot reload")
5+
end
6+
7+
using Pkg
8+
Pkg.activate(@__DIR__)
9+
10+
# Add OptimalControl in development mode
11+
if !haskey(Pkg.project().dependencies, "OptimalControl")
12+
Pkg.develop(path=joinpath(@__DIR__, ".."))
13+
end
14+
15+
using OptimalControl
16+
using NLPModelsIpopt
17+
import MadNLP
18+
import MadNLPMumps
19+
20+
# Include shared test problems via TestProblems module
21+
# include(joinpath(@__DIR__, "..", "test", "problems", "TestProblems.jl"))
22+
# using .TestProblems
23+
24+
# Create test arguments similar to test_canonical.jl
25+
function create_test_components()
26+
# Discretizer
27+
discretizer = OptimalControl.Collocation(grid_size=100, scheme=:midpoint)
28+
29+
# Modeler
30+
modeler = OptimalControl.ADNLPModeler()
31+
32+
# Solver - use real Ipopt solver
33+
solver = OptimalControl.IpoptSolver(print_level=0)
34+
35+
# Method tuple
36+
method = (:collocation, :adnlp, :ipopt)
37+
38+
return method, discretizer, modeler, solver
39+
end
40+
41+
# Create additional test configurations
42+
function create_test_variants()
43+
variants = []
44+
45+
# Variant 1: Different discretizer
46+
discretizer1 = OptimalControl.Collocation(grid_size=50, scheme=:trapeze)
47+
modeler1 = OptimalControl.ADNLPModeler()
48+
solver1 = OptimalControl.IpoptSolver(print_level=0)
49+
method1 = (:collocation, :ipopt, :adnlp)
50+
push!(variants, ("Trapezoidal Grid", method1, discretizer1, modeler1, solver1))
51+
52+
# Variant 2: Different modeler
53+
discretizer2 = OptimalControl.Collocation(grid_size=75, scheme=:midpoint)
54+
modeler2 = OptimalControl.ExaModeler()
55+
solver2 = OptimalControl.IpoptSolver(print_level=0)
56+
method2 = (:exa, :collocation, :cpu, :ipopt)
57+
push!(variants, ("ExaModeler", method2, discretizer2, modeler2, solver2))
58+
59+
# Variant 3: Different solver
60+
discretizer3 = OptimalControl.Collocation(grid_size=80, scheme=:midpoint)
61+
modeler3 = OptimalControl.ADNLPModeler()
62+
solver3 = OptimalControl.MadNLPSolver(print_level=MadNLP.ERROR)
63+
method3 = (:collocation, :optimized, :adnlp, :gpu, :madnlp)
64+
push!(variants, ("MadNLP Solver", method3, discretizer3, modeler3, solver3))
65+
66+
return variants
67+
end
68+
69+
# Copy the ORIGINAL display function from solve.jl
70+
function original_display_ocp_method(
71+
io::IO,
72+
method::Tuple,
73+
discretizer,
74+
modeler,
75+
solver;
76+
display::Bool,
77+
)
78+
display || return nothing
79+
80+
version_str = string(Base.pkgversion(OptimalControl))
81+
82+
print(io, "▫ This is OptimalControl version v", version_str, " running with: ")
83+
for (i, m) in enumerate(method)
84+
sep = i == length(method) ? ".\n\n" : ", "
85+
printstyled(io, string(m) * sep; color=:cyan, bold=true)
86+
end
87+
88+
# Package information using id()
89+
model_pkg = OptimalControl.id(typeof(modeler))
90+
solver_pkg = OptimalControl.id(typeof(solver))
91+
92+
println(
93+
io,
94+
" ┌─ The NLP is modelled with ",
95+
model_pkg,
96+
" and solved with ",
97+
solver_pkg,
98+
".",
99+
)
100+
println(io, "")
101+
102+
# Options section
103+
disc_opts = OptimalControl.options(discretizer)
104+
mod_opts = OptimalControl.options(modeler)
105+
sol_opts = OptimalControl.options(solver)
106+
107+
has_disc = !isempty(propertynames(disc_opts))
108+
has_mod = !isempty(propertynames(mod_opts))
109+
has_sol = !isempty(propertynames(sol_opts))
110+
111+
if has_disc || has_mod || has_sol
112+
println(io, " Options:")
113+
114+
if has_disc
115+
println(io, " ├─ Discretizer:")
116+
for name in propertynames(disc_opts)
117+
println(io, "", name, " = ", getproperty(disc_opts, name))
118+
end
119+
end
120+
121+
if has_mod
122+
println(io, " ├─ Modeler:")
123+
for name in propertynames(mod_opts)
124+
println(io, "", name, " = ", getproperty(mod_opts, name))
125+
end
126+
end
127+
128+
if has_sol
129+
println(io, " └─ Solver:")
130+
for name in propertynames(sol_opts)
131+
println(io, " ", name, " = ", getproperty(sol_opts, name))
132+
end
133+
end
134+
end
135+
136+
println(io)
137+
return nothing
138+
end
139+
140+
function original_display_ocp_method(
141+
method,
142+
discretizer,
143+
modeler,
144+
solver;
145+
display::Bool,
146+
)
147+
return original_display_ocp_method(
148+
stdout, method, discretizer, modeler, solver; display=display
149+
)
150+
end
151+
152+
# Copy the display function here for testing and improvement
153+
function improved_display_ocp_method(
154+
io::IO,
155+
method::Tuple,
156+
discretizer,
157+
modeler,
158+
solver;
159+
display::Bool,
160+
show_options::Bool=true,
161+
show_sources::Bool=false,
162+
)
163+
display || return nothing
164+
165+
# Get version info
166+
version_str = string(Base.pkgversion(OptimalControl))
167+
168+
# Header with method
169+
print(io, "▫ OptimalControl v", version_str, " solving with: ")
170+
171+
# First, get the strategy IDs from the actual components
172+
discretizer_id = OptimalControl.id(typeof(discretizer))
173+
modeler_id = OptimalControl.id(typeof(modeler))
174+
solver_id = OptimalControl.id(typeof(solver))
175+
176+
# Always show: discretizer → modeler → solver using IDs
177+
printstyled(io, discretizer_id; color=:cyan, bold=true)
178+
print(io, "")
179+
printstyled(io, modeler_id; color=:cyan, bold=true)
180+
print(io, "")
181+
printstyled(io, solver_id; color=:cyan, bold=true)
182+
183+
# Clean the method by removing strategy IDs and show remaining options
184+
cleaned_method = CTBase.remove(method, (discretizer_id, modeler_id, solver_id))
185+
if !isempty(cleaned_method)
186+
print(io, " (")
187+
for (i, m) in enumerate(cleaned_method)
188+
sep = i == length(cleaned_method) ? "" : ", "
189+
printstyled(io, string(m) * sep; color=:cyan, bold=true)
190+
end
191+
print(io, ")")
192+
end
193+
194+
println(io)
195+
196+
# Package information using id()
197+
println(io, "")
198+
println(io, " 📦 Configuration:")
199+
200+
model_pkg = OptimalControl.id(typeof(modeler))
201+
solver_pkg = OptimalControl.id(typeof(solver))
202+
203+
print(io, " ├─ Modeler: ")
204+
printstyled(io, model_pkg; color=:cyan, bold=true)
205+
println(io)
206+
print(io, " └─ Solver: ")
207+
printstyled(io, solver_pkg; color=:cyan, bold=true)
208+
println(io)
209+
210+
# Options section
211+
if show_options
212+
disc_opts = OptimalControl.options(discretizer)
213+
mod_opts = OptimalControl.options(modeler)
214+
sol_opts = OptimalControl.options(solver)
215+
216+
println(io, "")
217+
println(io, " ⚙️ Options:")
218+
219+
has_disc = !isempty(propertynames(disc_opts.options))
220+
has_mod = !isempty(propertynames(mod_opts.options))
221+
has_sol = !isempty(propertynames(sol_opts.options))
222+
223+
if has_disc
224+
print(io, " ├─ ")
225+
printstyled(io, "Discretizer"; color=:cyan, bold=true)
226+
print(io, ": ")
227+
228+
# Extract individual options from StrategyOptions
229+
items = collect(pairs(disc_opts.options))
230+
for (i, (key, opt)) in enumerate(items)
231+
sep = i == length(items) ? "" : ", "
232+
print(io, string(key), " = ", opt.value, " (", opt.source, ")", sep)
233+
end
234+
println(io)
235+
end
236+
237+
if has_mod
238+
print(io, " ├─ ")
239+
printstyled(io, "Modeler"; color=:cyan, bold=true)
240+
print(io, ": ")
241+
242+
items = collect(pairs(mod_opts.options))
243+
for (i, (key, opt)) in enumerate(items)
244+
sep = i == length(items) ? "" : ", "
245+
print(io, string(key), " = ", opt.value, " (", opt.source, ")", sep)
246+
end
247+
println(io)
248+
end
249+
250+
if has_sol
251+
print(io, " └─ ")
252+
printstyled(io, "Solver"; color=:cyan, bold=true)
253+
print(io, ": ")
254+
255+
items = collect(pairs(sol_opts.options))
256+
for (i, (key, opt)) in enumerate(items)
257+
sep = i == length(items) ? "" : ", "
258+
print(io, string(key), " = ", opt.value, " (", opt.source, ")", sep)
259+
end
260+
println(io)
261+
end
262+
end
263+
264+
println(io)
265+
println(io, "🎯 Ready to solve!")
266+
return nothing
267+
end
268+
269+
function improved_display_ocp_method(
270+
method,
271+
discretizer,
272+
modeler,
273+
solver;
274+
display::Bool,
275+
kwargs...
276+
)
277+
return improved_display_ocp_method(
278+
stdout, method, discretizer, modeler, solver; display=display, kwargs...
279+
)
280+
end
281+
282+
# Simple fallback for original display testing
283+
function test_display_ocp_method(
284+
method,
285+
discretizer,
286+
modeler,
287+
solver;
288+
display::Bool,
289+
)
290+
display || return nothing
291+
292+
println("▫ Original display (simplified):")
293+
println(" Method: ", method)
294+
println(" Discretizer: ", typeof(discretizer))
295+
println(" Modeler: ", typeof(modeler))
296+
println(" Solver: ", typeof(solver))
297+
return nothing
298+
end
299+
300+
# Create simple test problem
301+
struct SimpleProblem
302+
x0::Vector{Float64}
303+
xf::Vector{Float64}
304+
end
305+
306+
# Test problem
307+
problem = SimpleProblem([0.0, 0.0], [1.0, 1.0])
308+
309+
# Create components
310+
method, discretizer, modeler, solver = create_test_components()
311+
variants = create_test_variants()
312+
313+
println("🧪 Testing ORIGINAL vs IMPROVED display functions:")
314+
println("=" ^ 60)
315+
316+
println("\n📋 ORIGINAL DISPLAY:")
317+
println("-" ^ 30)
318+
# Call the ORIGINAL display function
319+
original_display_ocp_method(
320+
method, discretizer, modeler, solver; display=true
321+
)
322+
323+
println("\n📋 IMPROVED DISPLAY:")
324+
println("-" ^ 30)
325+
# Call the IMPROVED display function
326+
improved_display_ocp_method(
327+
method, discretizer, modeler, solver; display=true
328+
)
329+
330+
println("\n📋 IMPROVED DISPLAY (minimal):")
331+
println("-" ^ 30)
332+
# Call with minimal options
333+
improved_display_ocp_method(
334+
method, discretizer, modeler, solver; display=true, show_options=false
335+
)
336+
337+
println("\n📋 TESTING DIFFERENT CONFIGURATIONS:")
338+
println("-" ^ 30)
339+
for (name, meth, disc, mod, solv) in variants
340+
println("\n🔸 Configuration: ", name)
341+
improved_display_ocp_method(
342+
meth, disc, mod, solv; display=true, show_options=true
343+
)
344+
end
345+
346+
println("=" ^ 60)
347+
println("✅ Display comparison completed!")

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,6 @@ Manifest.toml
4141

4242
#
4343
.tmp/
44-
.extras/
44+
#.extras/
4545
#.save/
4646
.windsurf/

0 commit comments

Comments
 (0)