From 63d96c27258bd3f5a096c57812caad65d9ca0f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 17 Apr 2025 10:13:12 +0200 Subject: [PATCH 1/6] Pass attributes through Objective.FunctionConversionBridge --- src/bridges.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/bridges.jl b/src/bridges.jl index 2b0eb46b4..367fc2bf5 100644 --- a/src/bridges.jl +++ b/src/bridges.jl @@ -3,6 +3,23 @@ # Use of this source code is governed by an MIT-style license that can be found # in the LICENSE.md file or at https://opensource.org/licenses/MIT. +function MOI.get( + model::MOI.ModelLike, + attr::ObjectiveFunctionAttribute{ReverseObjectiveFunction,G}, + bridge::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, +) where {T,F,G} + return MOI.get(model, ObjectiveFunctionAttribute{ReverseObjectiveFunction,F}(attr.attr)) +end + +function MOI.set( + model::MOI.ModelLike, + attr::ObjectiveFunctionAttribute{ReverseObjectiveFunction,G}, + bridge::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, + value, +) where {T,F,G} + return MOI.set(model, ObjectiveFunctionAttribute{ReverseObjectiveFunction,F}(attr.attr), value) +end + function MOI.get( model::MOI.ModelLike, ::ObjectiveFunctionAttribute{ReverseObjectiveFunction}, From c254bc19aa36d51f39ddbe0b8a1c294df39425b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Fri, 18 Apr 2025 09:18:41 +0200 Subject: [PATCH 2/6] Fix --- src/bridges.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bridges.jl b/src/bridges.jl index 367fc2bf5..f40d6b217 100644 --- a/src/bridges.jl +++ b/src/bridges.jl @@ -6,18 +6,18 @@ function MOI.get( model::MOI.ModelLike, attr::ObjectiveFunctionAttribute{ReverseObjectiveFunction,G}, - bridge::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, + ::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, ) where {T,F,G} return MOI.get(model, ObjectiveFunctionAttribute{ReverseObjectiveFunction,F}(attr.attr)) end function MOI.set( model::MOI.ModelLike, - attr::ObjectiveFunctionAttribute{ReverseObjectiveFunction,G}, - bridge::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, + attr::ObjectiveFunctionAttribute{ForwardObjectiveFunction,G}, + ::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, value, ) where {T,F,G} - return MOI.set(model, ObjectiveFunctionAttribute{ReverseObjectiveFunction,F}(attr.attr), value) + return MOI.set(model, ObjectiveFunctionAttribute{ForwardObjectiveFunction,F}(attr.attr), value) end function MOI.get( From 2dd9e1d84ca55d630a4b1abc036db6eec78ed42d Mon Sep 17 00:00:00 2001 From: joaquimg Date: Mon, 19 May 2025 12:52:18 -0700 Subject: [PATCH 3/6] add test --- src/bridges.jl | 11 +++++++++-- test/jump.jl | 20 ++++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/bridges.jl b/src/bridges.jl index f40d6b217..a56717b3c 100644 --- a/src/bridges.jl +++ b/src/bridges.jl @@ -8,7 +8,10 @@ function MOI.get( attr::ObjectiveFunctionAttribute{ReverseObjectiveFunction,G}, ::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, ) where {T,F,G} - return MOI.get(model, ObjectiveFunctionAttribute{ReverseObjectiveFunction,F}(attr.attr)) + return MOI.get( + model, + ObjectiveFunctionAttribute{ReverseObjectiveFunction,F}(attr.attr), + ) end function MOI.set( @@ -17,7 +20,11 @@ function MOI.set( ::MOI.Bridges.Objective.FunctionConversionBridge{T,F,G}, value, ) where {T,F,G} - return MOI.set(model, ObjectiveFunctionAttribute{ForwardObjectiveFunction,F}(attr.attr), value) + return MOI.set( + model, + ObjectiveFunctionAttribute{ForwardObjectiveFunction,F}(attr.attr), + value, + ) end function MOI.get( diff --git a/test/jump.jl b/test/jump.jl index 8055f1f10..4ba7a6c1a 100644 --- a/test/jump.jl +++ b/test/jump.jl @@ -31,6 +31,26 @@ function runtests() return end +function test_single_variable_objective() + model = Model(() -> DiffOpt.diff_optimizer(SCS.Optimizer)) + @variable(model, x[1:7] >= 0) + @constraint(model, c1, sum(x[i] for i in 1:6) == 10) + @constraint(model, c2, x[7] == 10) + @constraint( + model, + c3, + LinearAlgebra.Symmetric([ + x[7] 0.0 + 0.0 x[1] + ]) in PSDCone() + ) + @objective(model, Max, x[7]) + optimize!(model) + MOI.set(model, DiffOpt.ForwardObjectiveFunction(), sum(x)) + DiffOpt.forward_differentiate!(model) + @test MOI.get(model, DiffOpt.ForwardVariablePrimal(), x[7]) == 0 +end + function test_forward_on_trivial_qp() # using example on https://osqp.org/docs/examples/setup-and-solve.html Q = [4.0 1.0; 1.0 2.0] From 2d325b38f62e4f6a842c258531d9c92d6d273157 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Mon, 19 May 2025 12:54:46 -0700 Subject: [PATCH 4/6] fix tol --- test/jump.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jump.jl b/test/jump.jl index 4ba7a6c1a..a6266f1d9 100644 --- a/test/jump.jl +++ b/test/jump.jl @@ -48,7 +48,7 @@ function test_single_variable_objective() optimize!(model) MOI.set(model, DiffOpt.ForwardObjectiveFunction(), sum(x)) DiffOpt.forward_differentiate!(model) - @test MOI.get(model, DiffOpt.ForwardVariablePrimal(), x[7]) == 0 + @test MOI.get(model, DiffOpt.ForwardVariablePrimal(), x[7]) == 0 atol = ATOL end function test_forward_on_trivial_qp() From 0bd8d0cdae0629d540a0fb172d8265b1ce089106 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Mon, 19 May 2025 12:55:39 -0700 Subject: [PATCH 5/6] fix test --- test/jump.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jump.jl b/test/jump.jl index a6266f1d9..fce1876c2 100644 --- a/test/jump.jl +++ b/test/jump.jl @@ -48,7 +48,7 @@ function test_single_variable_objective() optimize!(model) MOI.set(model, DiffOpt.ForwardObjectiveFunction(), sum(x)) DiffOpt.forward_differentiate!(model) - @test MOI.get(model, DiffOpt.ForwardVariablePrimal(), x[7]) == 0 atol = ATOL + @test MOI.get(model, DiffOpt.ForwardVariablePrimal(), x[7]) ≈ 0 atol = ATOL end function test_forward_on_trivial_qp() From 25a0fbed2f6cdad132cdb31a1576087b1b0ebd83 Mon Sep 17 00:00:00 2001 From: joaquimg Date: Mon, 19 May 2025 16:18:23 -0700 Subject: [PATCH 6/6] add reverse test --- test/jump.jl | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/test/jump.jl b/test/jump.jl index fce1876c2..bdb031b73 100644 --- a/test/jump.jl +++ b/test/jump.jl @@ -31,7 +31,7 @@ function runtests() return end -function test_single_variable_objective() +function test_single_variable_objective_forward() model = Model(() -> DiffOpt.diff_optimizer(SCS.Optimizer)) @variable(model, x[1:7] >= 0) @constraint(model, c1, sum(x[i] for i in 1:6) == 10) @@ -49,6 +49,29 @@ function test_single_variable_objective() MOI.set(model, DiffOpt.ForwardObjectiveFunction(), sum(x)) DiffOpt.forward_differentiate!(model) @test MOI.get(model, DiffOpt.ForwardVariablePrimal(), x[7]) ≈ 0 atol = ATOL + return +end + +function test_single_variable_objective_reverse() + model = Model(() -> DiffOpt.diff_optimizer(SCS.Optimizer)) + @variable(model, x[1:7] >= 0) + @constraint(model, c1, sum(x[i] for i in 1:6) == 10) + @constraint(model, c2, x[7] == 10) + @constraint( + model, + c3, + LinearAlgebra.Symmetric([ + x[7] 0.0 + 0.0 x[1] + ]) in PSDCone() + ) + @objective(model, Max, x[7]) + optimize!(model) + MOI.set(model, DiffOpt.ReverseVariablePrimal(), x[7], 1.0) + DiffOpt.reverse_differentiate!(model) + func = MOI.get(model, DiffOpt.ReverseObjectiveFunction()) + @test JuMP.coefficient(func, x[7]) ≈ 0.0 atol = ATOL rtol = RTOL + return end function test_forward_on_trivial_qp()