Skip to content

Commit e719b96

Browse files
committed
more tests
1 parent e1288d6 commit e719b96

File tree

2 files changed

+186
-1
lines changed

2 files changed

+186
-1
lines changed

src/feasibility.jl

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,39 @@ function _dual_point_to_dual_model_ref(
983983
new_dual_point = Dict{MOI.VariableIndex,Number}()
984984
dual_var_to_primal_con = Dict{MOI.VariableIndex,MOI.ConstraintIndex}()
985985
dual_con_to_primal_con = Dict{MOI.ConstraintIndex,MOI.ConstraintIndex}()
986+
for (F, S) in MOI.get(primal_model, MOI.ListOfConstraintTypesPresent())
987+
list = MOI.get(primal_model, MOI.ListOfConstraintIndices{F,S}())
988+
for primal_con in list
989+
dual_vars = Dualization._get_dual_variables(map, primal_con)
990+
val = get(dual_point, primal_con, nothing)
991+
if !isnothing(val)
992+
if length(dual_vars) != length(val)
993+
error(
994+
"The dual point entry for constraint $primal_con has " *
995+
"length $(length(val)) but the dual variable " *
996+
"length is $(length(dual_vars)).",
997+
)
998+
end
999+
for (idx, dual_var) in enumerate(dual_vars)
1000+
new_dual_point[dual_var] = val[idx]
1001+
end
1002+
end
1003+
for dual_var in dual_vars
1004+
dual_var_to_primal_con[dual_var] = primal_con
1005+
end
1006+
dual_con = Dualization._get_dual_constraint(map, primal_con)
1007+
if dual_con !== nothing
1008+
dual_con_to_primal_con[dual_con] = primal_con
1009+
# else
1010+
# if !(primal_con isa MOI.ConstraintIndex{MOI.VariableIndex,<:MOI.EqualTo} ||
1011+
# primal_con isa MOI.ConstraintIndex{MOI.VectorOfVariables,MOI.Zeros}
1012+
# SAF in EQ, etc...
1013+
#)
1014+
# error("Problem with dualization, see: $primal_con")
1015+
# end
1016+
end
1017+
end
1018+
end
9861019
for (primal_con, val) in dual_point
9871020
dual_vars = Dualization._get_dual_variables(map, primal_con)
9881021
if length(dual_vars) != length(val)
@@ -1247,7 +1280,9 @@ function _analyze_objectives!(model::MOI.ModelLike, dual_model, map, data)
12471280
)
12481281
end
12491282

1250-
if !isapprox(obj_val, dual_obj_val; atol = data.atol)
1283+
if !isapprox(obj_val, dual_obj_val; atol = data.atol) &&
1284+
!isnan(dual_obj_val) &&
1285+
!isnan(obj_val)
12511286
push!(
12521287
data.primal_dual_mismatch,
12531288
PrimalDualMismatch(obj_val, dual_obj_val),

test/feasibility.jl

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,156 @@ function test_lowlevel_mismatch()
796796
return
797797
end
798798

799+
function test_skip_missing_primal()
800+
model = Model()
801+
set_silent(model)
802+
@variable(model, x >= 0)
803+
@variable(model, y >= 0)
804+
@constraint(model, c, x + y >= 0)
805+
@objective(model, Min, x)
806+
807+
@test_throws ErrorException ModelAnalyzer.analyze(
808+
ModelAnalyzer.Feasibility.Analyzer(),
809+
model,
810+
primal_point = Dict(JuMP.index(x) => 1.0),
811+
# dual_point = Dict(JuMP.index(c) => 1.0),
812+
skip_missing = false,
813+
dual_check = false,
814+
)
815+
data = ModelAnalyzer.analyze(
816+
ModelAnalyzer.Feasibility.Analyzer(),
817+
model,
818+
primal_point = Dict(JuMP.index(x) => 1.0),
819+
# dual_point = Dict(JuMP.index(c) => 1.0),
820+
skip_missing = true,
821+
dual_check = false,
822+
)
823+
list = ModelAnalyzer.list_of_issue_types(data)
824+
@test length(list) == 0
825+
return
826+
end
827+
828+
function test_skip_missing_primal_var_not_in_con()
829+
model = Model()
830+
set_silent(model)
831+
@variable(model, x)
832+
@variable(model, y)
833+
@constraint(model, c, x >= 0)
834+
@objective(model, Min, x + y)
835+
836+
@test_throws ErrorException ModelAnalyzer.analyze(
837+
ModelAnalyzer.Feasibility.Analyzer(),
838+
model,
839+
primal_point = Dict(JuMP.index(x) => 0.0),
840+
# dual_point = Dict(JuMP.index(c) => 1.0),
841+
skip_missing = false,
842+
dual_check = false,
843+
)
844+
data = ModelAnalyzer.analyze(
845+
ModelAnalyzer.Feasibility.Analyzer(),
846+
model,
847+
primal_point = Dict(JuMP.index(x) => 0.0),
848+
# dual_point = Dict(JuMP.index(c) => 1.0),
849+
skip_missing = true,
850+
dual_check = false,
851+
)
852+
list = ModelAnalyzer.list_of_issue_types(data)
853+
@test length(list) == 0
854+
return
855+
end
856+
857+
function test_skip_missing_primal_empty_con()
858+
model = Model()
859+
set_silent(model)
860+
@variable(model, x)
861+
@constraint(model, c, 1 >= 0)
862+
@constraint(model, c2, x >= 0)
863+
@objective(model, Min, x)
864+
865+
@test_throws ErrorException ModelAnalyzer.analyze(
866+
ModelAnalyzer.Feasibility.Analyzer(),
867+
model,
868+
primal_point = Dict(JuMP.index(x) => 0.0),
869+
dual_point = Dict(JuMP.index(c2) => 1.0),
870+
skip_missing = false,
871+
dual_check = true,
872+
)
873+
data = ModelAnalyzer.analyze(
874+
ModelAnalyzer.Feasibility.Analyzer(),
875+
model,
876+
primal_point = Dict(JuMP.index(x) => 0.0),
877+
dual_point = Dict(JuMP.index(c2) => 1.0),
878+
skip_missing = true,
879+
dual_check = true,
880+
)
881+
@show list = ModelAnalyzer.list_of_issue_types(data)
882+
@test length(list) == 0
883+
return
884+
end
885+
886+
function test_skip_missing_dual()
887+
model = Model()
888+
set_silent(model)
889+
@variable(model, x)
890+
@constraint(model, c1, x >= 0)
891+
@constraint(model, c2, x >= 2)
892+
@objective(model, Min, x)
893+
894+
@test_throws ErrorException ModelAnalyzer.analyze(
895+
ModelAnalyzer.Feasibility.Analyzer(),
896+
model,
897+
primal_point = Dict(JuMP.index(x) => 2.0),
898+
dual_point = Dict(JuMP.index(c1) => 1.0),
899+
skip_missing = false,
900+
dual_check = true,
901+
)
902+
data = ModelAnalyzer.analyze(
903+
ModelAnalyzer.Feasibility.Analyzer(),
904+
model,
905+
primal_point = Dict(JuMP.index(x) => 2.0),
906+
dual_point = Dict(JuMP.index(c1) => 0.0),
907+
skip_missing = true,
908+
dual_check = true,
909+
)
910+
@show list = ModelAnalyzer.list_of_issue_types(data)
911+
@test length(list) == 0
912+
return
913+
end
914+
915+
function test_dual_bad_size()
916+
model = Model()
917+
set_silent(model)
918+
@variable(model, x)
919+
@constraint(model, c1, x >= 0)
920+
@objective(model, Min, x)
921+
922+
@test_throws ErrorException ModelAnalyzer.analyze(
923+
ModelAnalyzer.Feasibility.Analyzer(),
924+
model,
925+
primal_point = Dict(JuMP.index(x) => 2.0),
926+
dual_point = Dict(JuMP.index(c1) => [1.0, 2.0]),
927+
)
928+
return
929+
end
930+
931+
function test_dual_vector()
932+
model = Model()
933+
set_silent(model)
934+
@variable(model, x)
935+
@constraint(model, c1, [x, 2x - 1] in Nonnegatives())
936+
@objective(model, Min, x)
937+
938+
data = ModelAnalyzer.analyze(
939+
ModelAnalyzer.Feasibility.Analyzer(),
940+
model,
941+
primal_point = Dict(JuMP.index(x) => 0.5),
942+
dual_point = Dict(JuMP.index(c1) => [0.0, 0.5]),
943+
)
944+
@show list = ModelAnalyzer.list_of_issue_types(data)
945+
@test length(list) == 0
946+
return
947+
end
948+
799949
end # module
800950

801951
TestDualFeasibilityChecker.runtests()

0 commit comments

Comments
 (0)