@@ -1657,6 +1657,79 @@ function test_parametric_objective_type_cubic_error()
16571657 return
16581658end
16591659
1660+ # ============================================================================
1661+ # Contribution of objective parameters in duals
1662+ # ============================================================================
1663+
1664+ function test_cubic_dual_ppp_terms ()
1665+ # min x + p^3 s.t. x >= 1, p = 2
1666+ # Optimal: x = 1, obj = 1 + 8 = 9
1667+ # ∂(p^3)/∂p = 3p^2 = 12
1668+ model = Model (() -> POI. Optimizer (HiGHS. Optimizer ()))
1669+ set_silent (model)
1670+ @variable (model, x)
1671+ @variable (model, p in MOI. Parameter (2.0 ))
1672+ @constraint (model, x >= 1 )
1673+ @objective (model, Min, x + p^ 3 )
1674+ optimize! (model)
1675+ @test termination_status (model) in (OPTIMAL, LOCALLY_SOLVED)
1676+ @test dual (ParameterRef (p)) ≈ 12.0 atol = ATOL
1677+ return
1678+ end
1679+
1680+ function test_cubic_dual_ppv_terms ()
1681+ # min p1*p2*x + x^2 s.t. x >= 0, p1 = 1, p2 = -2
1682+ # ppv is multiplicative → dual query should error
1683+ model = Model (() -> POI. Optimizer (HiGHS. Optimizer ()))
1684+ set_silent (model)
1685+ @variable (model, x >= 0 )
1686+ @variable (model, p1 in MOI. Parameter (1.0 ))
1687+ @variable (model, p2 in MOI. Parameter (- 2.0 ))
1688+ @objective (model, Min, p1 * p2 * x + x^ 2 )
1689+ optimize! (model)
1690+ @test termination_status (model) in (OPTIMAL, LOCALLY_SOLVED)
1691+ @test value (x) ≈ 1.0 atol = ATOL
1692+ @test_throws ErrorException dual (ParameterRef (p1))
1693+ @test_throws ErrorException dual (ParameterRef (p2))
1694+ return
1695+ end
1696+
1697+ function test_cubic_dual_pvv_terms ()
1698+ # min p*x^2 - 3x s.t. 0 <= x <= 10, p = 1
1699+ # pvv is multiplicative → dual query should error
1700+ model = Model (() -> POI. Optimizer (HiGHS. Optimizer ()))
1701+ set_silent (model)
1702+ @variable (model, 0 <= x <= 10 )
1703+ @variable (model, p in MOI. Parameter (1.0 ))
1704+ @objective (model, Min, p * x^ 2 - 3 * x)
1705+ optimize! (model)
1706+ @test termination_status (model) in (OPTIMAL, LOCALLY_SOLVED)
1707+ @test value (x) ≈ 1.5 atol = ATOL
1708+ @test_throws ErrorException dual (ParameterRef (p))
1709+ return
1710+ end
1711+
1712+ function test_cubic_dual_ppp_three_distinct ()
1713+ # min x + p1*p2*p3 s.t. x >= 1, p1=2, p2=3, p3=4
1714+ # ∂/∂p1 = p2*p3 = 12
1715+ # ∂/∂p2 = p1*p3 = 8
1716+ # ∂/∂p3 = p1*p2 = 6
1717+ model = Model (() -> POI. Optimizer (HiGHS. Optimizer ()))
1718+ set_silent (model)
1719+ @variable (model, x)
1720+ @variable (model, p1 in MOI. Parameter (2.0 ))
1721+ @variable (model, p2 in MOI. Parameter (3.0 ))
1722+ @variable (model, p3 in MOI. Parameter (4.0 ))
1723+ @constraint (model, x >= 1 )
1724+ @objective (model, Min, x + p1 * p2 * p3)
1725+ optimize! (model)
1726+ @test termination_status (model) in (OPTIMAL, LOCALLY_SOLVED)
1727+ @test dual (ParameterRef (p1)) ≈ 12.0 atol = ATOL
1728+ @test dual (ParameterRef (p2)) ≈ 8.0 atol = ATOL
1729+ @test dual (ParameterRef (p3)) ≈ 6.0 atol = ATOL
1730+ return
1731+ end
1732+
16601733end # module
16611734
16621735TestCubic. runtests ()
0 commit comments