1+ using OptimizationBase, Test, DifferentiationInterface
2+ using ADTypes, ForwardDiff, ReverseDiff, Zygote
3+
4+ @testset " Lagrangian Hessian with σ = 0" begin
5+ # Test that lag_h works correctly when σ = 0
6+ # This is a regression test for the bug where lag_h! would fail when
7+ # cons_h was not generated but lag_h needed to compute constraint Hessians
8+
9+ x0 = [0.5 , 0.5 ]
10+ rosenbrock (x, p = nothing ) = (1 - x[1 ])^ 2 + 100 * (x[2 ] - x[1 ]^ 2 )^ 2
11+
12+ # Single constraint
13+ cons1 = (res, x, p) -> (res[1 ] = x[1 ]^ 2 + x[2 ]^ 2 ; return nothing )
14+
15+ # Two constraints
16+ cons2 = (res, x, p) -> begin
17+ res[1 ] = x[1 ]^ 2 + x[2 ]^ 2
18+ res[2 ] = x[2 ] * sin (x[1 ]) - x[1 ]
19+ return nothing
20+ end
21+
22+ @testset " Single constraint with σ = 0" begin
23+ # Create optimization function WITHOUT cons_h but WITH lag_h
24+ optf = OptimizationFunction (
25+ rosenbrock,
26+ SecondOrder (AutoForwardDiff (), AutoForwardDiff ()),
27+ cons = cons1
28+ )
29+
30+ optprob = OptimizationBase. instantiate_function (
31+ optf, x0,
32+ SecondOrder (AutoForwardDiff (), AutoForwardDiff ()),
33+ nothing , 1 ,
34+ g = true , h = true ,
35+ cons_j = true ,
36+ cons_h = false , # Don't generate cons_h!
37+ lag_h = true # Only generate lag_h!
38+ )
39+
40+ # Test with σ = 0 - this should compute only constraint Hessians
41+ H_lag = Array {Float64} (undef, 2 , 2 )
42+ λ = [2.0 ] # arbitrary multiplier
43+ σ = 0.0
44+
45+ # This should work and compute H = λ[1] * ∇²c₁
46+ optprob. lag_h (H_lag, x0, σ, λ)
47+
48+ # Expected: constraint Hessian is [2 0; 0 2] for c(x) = x₁² + x₂²
49+ # Scaled by λ[1] = 2.0 gives [4 0; 0 4]
50+ @test H_lag ≈ [4.0 0.0 ; 0.0 4.0 ]
51+
52+ # Test with σ ≠ 0 for comparison
53+ σ = 1.0
54+ optprob. lag_h (H_lag, x0, σ, λ)
55+
56+ # Expected objective Hessian at x0 = [0.5, 0.5]
57+ H_obj = zeros (2 , 2 )
58+ H_obj[1 , 1 ] = 2.0 - 400.0 * x0[2 ] + 1200.0 * x0[1 ]^ 2
59+ H_obj[1 , 2 ] = - 400.0 * x0[1 ]
60+ H_obj[2 , 1 ] = - 400.0 * x0[1 ]
61+ H_obj[2 , 2 ] = 200.0
62+
63+ # Should be σ * H_obj + λ[1] * H_cons
64+ @test H_lag ≈ H_obj + [4.0 0.0 ; 0.0 4.0 ]
65+ end
66+
67+ @testset " Two constraints with σ = 0" begin
68+ optf = OptimizationFunction (
69+ rosenbrock,
70+ SecondOrder (AutoForwardDiff (), AutoForwardDiff ()),
71+ cons = cons2
72+ )
73+
74+ optprob = OptimizationBase. instantiate_function (
75+ optf, x0,
76+ SecondOrder (AutoForwardDiff (), AutoForwardDiff ()),
77+ nothing , 2 ,
78+ g = true , h = true ,
79+ cons_j = true ,
80+ cons_h = false , # Don't generate cons_h!
81+ lag_h = true # Only generate lag_h!
82+ )
83+
84+ # Test with σ = 0
85+ H_lag = Array {Float64} (undef, 2 , 2 )
86+ λ = [1.5 , - 0.5 ]
87+ σ = 0.0
88+
89+ # This should compute H = λ[1] * ∇²c₁ + λ[2] * ∇²c₂
90+ optprob. lag_h (H_lag, x0, σ, λ)
91+
92+ # Expected constraint Hessians:
93+ # ∇²c₁ = [2 0; 0 2] for c₁(x) = x₁² + x₂²
94+ # ∇²c₂ = [-sin(x₁)*x₂ cos(x₁); cos(x₁) 0] for c₂(x) = x₂*sin(x₁) - x₁
95+ # At x0 = [0.5, 0.5]:
96+ H_c2 = zeros (2 , 2 )
97+ H_c2[1 , 1 ] = - sin (x0[1 ]) * x0[2 ]
98+ H_c2[1 , 2 ] = cos (x0[1 ])
99+ H_c2[2 , 1 ] = cos (x0[1 ])
100+ H_c2[2 , 2 ] = 0.0
101+
102+ expected = λ[1 ] * [2.0 0.0 ; 0.0 2.0 ] + λ[2 ] * H_c2
103+ @test H_lag ≈ expected rtol= 1e-6
104+ end
105+
106+ @testset " Different AD backends with σ = 0" begin
107+ # Test with AutoReverseDiff
108+ optf = OptimizationFunction (
109+ rosenbrock,
110+ SecondOrder (AutoForwardDiff (), AutoReverseDiff ()),
111+ cons = cons1
112+ )
113+
114+ optprob = OptimizationBase. instantiate_function (
115+ optf, x0,
116+ SecondOrder (AutoForwardDiff (), AutoReverseDiff ()),
117+ nothing , 1 ,
118+ g = true , h = true ,
119+ cons_j = true ,
120+ cons_h = false ,
121+ lag_h = true
122+ )
123+
124+ H_lag = Array {Float64} (undef, 2 , 2 )
125+ λ = [3.0 ]
126+ σ = 0.0
127+
128+ optprob. lag_h (H_lag, x0, σ, λ)
129+ @test H_lag ≈ [6.0 0.0 ; 0.0 6.0 ] # 3.0 * [2 0; 0 2]
130+
131+ # Test with AutoZygote
132+ optf = OptimizationFunction (
133+ rosenbrock,
134+ SecondOrder (AutoForwardDiff (), AutoZygote ()),
135+ cons = cons1
136+ )
137+
138+ optprob = OptimizationBase. instantiate_function (
139+ optf, x0,
140+ SecondOrder (AutoForwardDiff (), AutoZygote ()),
141+ nothing , 1 ,
142+ g = true , h = true ,
143+ cons_j = true ,
144+ cons_h = false ,
145+ lag_h = true
146+ )
147+
148+ H_lag = Array {Float64} (undef, 2 , 2 )
149+ λ = [0.5 ]
150+ σ = 0.0
151+
152+ optprob. lag_h (H_lag, x0, σ, λ)
153+ @test H_lag ≈ [1.0 0.0 ; 0.0 1.0 ] # 0.5 * [2 0; 0 2]
154+ end
155+
156+ @testset " Edge cases" begin
157+ optf = OptimizationFunction (
158+ rosenbrock,
159+ SecondOrder (AutoForwardDiff (), AutoForwardDiff ()),
160+ cons = cons2
161+ )
162+
163+ optprob = OptimizationBase. instantiate_function (
164+ optf, x0,
165+ SecondOrder (AutoForwardDiff (), AutoForwardDiff ()),
166+ nothing , 2 ,
167+ g = true , h = true ,
168+ cons_j = true ,
169+ cons_h = false ,
170+ lag_h = true
171+ )
172+
173+ H_lag = Array {Float64} (undef, 2 , 2 )
174+
175+ # Test with all λ = 0 and σ = 0 (should give zero matrix)
176+ λ = [0.0 , 0.0 ]
177+ σ = 0.0
178+ optprob. lag_h (H_lag, x0, σ, λ)
179+ @test all (H_lag .≈ 0.0 )
180+
181+ # Test with some λ = 0 (should skip those constraints)
182+ λ = [2.0 , 0.0 ]
183+ σ = 0.0
184+ optprob. lag_h (H_lag, x0, σ, λ)
185+ @test H_lag ≈ [4.0 0.0 ; 0.0 4.0 ] # Only first constraint contributes
186+ end
187+ end
0 commit comments