Skip to content

Commit 3c0bd3e

Browse files
committed
2 parents afd934a + fcf3844 commit 3c0bd3e

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed

test/linear_constraint_tests.jl

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
using Test
2+
using JuMP
3+
using DisjunctiveProgramming
4+
using Symbolics
5+
6+
@testset "linear constraints" begin
7+
8+
function minimal()
9+
m = Model()
10+
@variable(m, -1<=x<=10)
11+
12+
@constraint(m, con1, x<=3)
13+
@constraint(m, con2, 0<=x)
14+
@constraint(m, con3, x<=9)
15+
@constraint(m, con4, 5<=x)
16+
17+
@disjunction(m,(con1,con2),con3,con4,reformulation=:CHR,name=:y)
18+
19+
@test true
20+
end
21+
22+
function simple_example(reform)
23+
m = Model()
24+
@variable(m, -10<=x<=10)
25+
@constraint(m, con1, x<=-1)
26+
@constraint(m, con2, 1<=x)
27+
28+
if (reform == :BMR)
29+
@disjunction(m, con1, con2, reformulation=:BMR, name=:y)
30+
elseif (reform == :CHR)
31+
@disjunction(m, con1, con2, reformulation=:CHR, name=:y)
32+
end
33+
return m
34+
end
35+
36+
function robustness()
37+
unreg = m -> unregister(m, :original_model_variables)
38+
39+
function fresh_model()
40+
m = Model()
41+
@variable(m, -10<=x<=10)
42+
@constraint(m, con1, x<=-1)
43+
@constraint(m, con2, 1<=x)
44+
return m, con1, con2
45+
end
46+
47+
# not enough constraints
48+
m = fresh_model()[1]
49+
# @test_throws DomainError @disjunction(m, (con1, con2), reformulation=:BMR, name=:y)
50+
unreg(m)
51+
# @test_throws DomainError @disjunction(m, con1, reformulation=:BMR, name=:y)
52+
53+
# Big-M reformulation without variable bounds defined
54+
# should only work if user specifies M value
55+
m = Model()
56+
@variable(m, x)
57+
@constraint(m, con1, x<=-1)
58+
@constraint(m, con2, 1<=x)
59+
@test @disjunction(m, con1, con2, reformulation=:BMR, name=:y, M=11) == nothing
60+
unreg(m)
61+
@test_throws ErrorException @disjunction(m, con1, con2, reformulation=:BMR, name=:y)
62+
63+
# CHR reformulation without variable bounds defined should fail
64+
m = Model()
65+
@variable(m, x)
66+
@constraint(m, con1, x<=-1)
67+
@constraint(m, con2, 1<=x)
68+
@test_throws AssertionError @disjunction(m, con1, con2, reformulation=:CHR, name=:y)
69+
70+
# empty constraints on one side of disjunction
71+
m, con1, con2 = fresh_model()
72+
@test @disjunction(m, con1, nothing, reformulation=:BMR, name=:y) == nothing
73+
m, con1, con2 = fresh_model()
74+
@test @disjunction(m, nothing, con2, reformulation=:CHR, name=:z) == nothing
75+
m, con1, con2 = fresh_model()
76+
@test @disjunction(m, (con1, con2), nothing, reformulation=:BMR, name=:y) == nothing
77+
78+
end
79+
80+
function model_BMR_valid(m)
81+
# Expecting to see following constraints:
82+
# x <= -1 + 11 * (1 - y1)
83+
# -x <= -1 + 11 * (1 - y2)
84+
# y1 + y2 = 1
85+
# -10<=x<=10
86+
cons = (L -> all_constraints(m, L...)).(list_of_constraint_types(m))
87+
@test sum(length.(cons)) == 5 + 2 # add 2 for y1/y2 binary statements
88+
89+
con_strings = replace.(constraints_string(REPLMode, m), "[" => "",
90+
"]" => "", "+ y" => "+y", " y" => "* y",
91+
"con1 :" => "", "con2 :" => "")
92+
cons_actual = Meta.parse.(con_strings[1:5])
93+
cons_expected = [:(y1 + y2 == 1), :(x + 11 * y1 <= 10),
94+
:(-x + 11 * y2 <= 10), :(x >= -10), :(x <= 10)]
95+
matches = sum(map(i->isequal(i[1], i[2]),
96+
Base.product(cons_expected, cons_actual)))
97+
@test matches == length(cons_actual)
98+
end
99+
100+
function model_CHR_valid(m)
101+
# Expecting to see following constraints:
102+
# x_y1 <= -1 * y1
103+
# -x_y2 <= -1 * y2
104+
# y1 + y2 = 1
105+
# x = x_y1 + x_y2
106+
# -10 * y1 <= x_y1 <= 10 * y1
107+
# -10 * y2 <= x_y2 <= 10 * y2
108+
# -10 <= x <= 10
109+
# -10 <= x_y1 <= 10
110+
# -10 <= x_y2 <= 10
111+
cons = (L -> all_constraints(m, L...)).(list_of_constraint_types(m))
112+
@test sum(length.(cons)) == 14 + 2 # add 2 for y1/y2 binary statements
113+
114+
con_strings = replace.(constraints_string(REPLMode, m), "[" => "",
115+
"]" => "", "+ y" => "+y", " y" => "* y",
116+
"con1 :" => "", "con2 :" => "")
117+
println.(con_strings)
118+
cons_expected = [:(y1 + y2 == 1), :(x - x_1 - x_2 == 0), :(x >= -10),
119+
:(x_1 + y1 <= 0), :(-x_2 + y2 <= 0), :(x <= 10),
120+
:(x_1 >= -10), :(x_1 <= 10), :(x_2 >= -10), :(x_2 <= 10),
121+
:(-10 * y1 - x_1 <= 0), :(-10 * y1 + x_1 <= 0),
122+
:(-10 * y2 - x_2 <= 0), :(-10 * y2 + x_2 <= 0)]
123+
cons_actual = Meta.parse.(con_strings[1:14])
124+
matches = sum(map(i->isequal(i[1], i[2]),
125+
Base.product(cons_expected, cons_actual)))
126+
@test matches == length(cons_actual)
127+
end
128+
129+
robustness()
130+
131+
m1 = simple_example(:BMR)
132+
model_BMR_valid(m1)
133+
134+
m2 = simple_example(:CHR)
135+
model_CHR_valid(m2)
136+
137+
end

0 commit comments

Comments
 (0)