Skip to content

Commit c788b10

Browse files
committed
add tests
1 parent 0daa695 commit c788b10

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

src/hull.jl

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ function _disaggregate_variable(model::Model, lvref::LogicalVariableRef, vref::V
2727
#get binary indicator variable
2828
bvref = _indicator_to_binary(model)[lvref]
2929
#temp storage
30-
if !haskey(method.disjunction_variables, vref)
30+
if !haskey(method.disjunction_variables, vref) #NOTE: not needed because _Hull disjunction_variables is initialized with all the variables in the disjunction
3131
method.disjunction_variables[vref] = Vector{VariableRef}()
3232
end
3333
push!(method.disjunction_variables[vref], dvref)
@@ -66,7 +66,7 @@ end
6666
# variable
6767
function _disaggregate_expression(model::Model, vref::VariableRef, bvref::VariableRef, method::_Hull)
6868
if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged
69-
return vref
69+
return vref #NOTE: not needed because nested constraint of the form `vref in MOI.AbstractScalarSet` gets reformulated to an affine expression.
7070
else #replace with disaggregated form
7171
return method.disjunct_variables[vref, bvref]
7272
end
@@ -105,17 +105,20 @@ function _disaggregate_nl_expression(model::Model, c::Number, ::VariableRef, met
105105
end
106106
# variable in NonlinearExpr
107107
function _disaggregate_nl_expression(model::Model, vref::VariableRef, bvref::VariableRef, method::_Hull)
108-
ϵ = method.value
109-
dvref = method.disjunct_variables[vref, bvref]
110-
new_var = dvref / ((1-ϵ)*bvref+ϵ)
111-
return new_var
108+
if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged
109+
return vref
110+
else #replace with disaggregated form
111+
ϵ = method.value
112+
dvref = method.disjunct_variables[vref, bvref]
113+
return dvref / ((1-ϵ)*bvref+ϵ)
114+
end
112115
end
113116
# affine expression in NonlinearExpr
114117
function _disaggregate_nl_expression(model::Model, aff::AffExpr, bvref::VariableRef, method::_Hull)
115118
new_expr = aff.constant
116119
ϵ = method.value
117120
for (vref, coeff) in aff.terms
118-
if is_binary(vref) #keep any binary variables undisaggregated
121+
if is_binary(vref) || !haskey(method.disjunct_variables, (vref, bvref)) #keep any binary variables or nested disaggregated variables unchanged
119122
dvref = vref
120123
else #replace other vars with disaggregated form
121124
dvref = method.disjunct_variables[vref, bvref]
@@ -125,6 +128,8 @@ function _disaggregate_nl_expression(model::Model, aff::AffExpr, bvref::Variable
125128
return new_expr
126129
end
127130
# quadratic expression in NonlinearExpr
131+
# TODO review what happens when there are bilinear terms with binary variables involved since these are not being disaggregated
132+
# (e.g., complementarity constraints; though likely irrelevant)...
128133
function _disaggregate_nl_expression(model::Model, quad::QuadExpr, bvref::VariableRef, method::_Hull)
129134
#get affine part
130135
new_expr = _disaggregate_nl_expression(model, quad.aff, bvref, method)

src/logic.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ function _reformulate_proposition(model::Model, lexpr::_LogicalExpr)
248248
end
249249
elseif expr.head in (:||, :!) && all(_isa_literal.(expr.args))
250250
_add_reformulated_proposition(model, expr)
251-
else
251+
else #NOTE: should never enter the `else` section
252252
error("Expression $expr was not converted to proper Conjunctive Normal Form.")
253253
end
254254
end

test/constraints/hull.jl

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ function test_disaggregate_variables()
3939
@variable(model, 10 <= x <= 100)
4040
@variable(model, y, Bin)
4141
@variable(model, z, Logical)
42-
vrefs = Set([x,y])
42+
vrefs = Set{VariableRef}() #initialize empty set to check if method.disjunct_variables has variables added to it in _disaggregate_variable call
4343
DP._reformulate_logical_variables(model)
4444
method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), vrefs)
45+
vrefs = Set([x,y])
4546
DP._disaggregate_variables(model, z, vrefs, method)
4647

4748
refvars = DP._reformulation_variables(model)
@@ -76,6 +77,38 @@ function test_aggregate_variable()
7677
@test refcons[1].set == MOI.EqualTo(0.)
7778
end
7879

80+
function test_disaggregate_expression_var_binary()
81+
model = GDPModel()
82+
@variable(model, x, Bin)
83+
@variable(model, z, Logical)
84+
DP._reformulate_logical_variables(model)
85+
bvrefs = DP._indicator_to_binary(model)
86+
87+
vrefs = Set([x])
88+
method = DP._Hull(Hull(1e-3, Dict(x => (0., 1.))), vrefs)
89+
DP._disaggregate_variables(model, z, vrefs, method)
90+
@test isnothing(variable_by_name(model, "x_z"))
91+
92+
refexpr = DP._disaggregate_expression(model, x, bvrefs[z], method)
93+
@test refexpr == x
94+
end
95+
96+
function test_disaggregate_expression_var()
97+
model = GDPModel()
98+
@variable(model, 10 <= x <= 100)
99+
@variable(model, z, Logical)
100+
DP._reformulate_logical_variables(model)
101+
bvrefs = DP._indicator_to_binary(model)
102+
103+
vrefs = Set([x])
104+
method = DP._Hull(Hull(1e-3, Dict(x => (0., 100.))), vrefs)
105+
DP._disaggregate_variables(model, z, vrefs, method)
106+
107+
refexpr = DP._disaggregate_expression(model, x, bvrefs[z], method)
108+
x_z = variable_by_name(model, "x_z")
109+
@test refexpr == x_z
110+
end
111+
79112
function test_disaggregate_expression_affine()
80113
model = GDPModel()
81114
@variable(model, 10 <= x <= 100)
@@ -131,6 +164,21 @@ function test_disaggregate_nl_expression_c()
131164
@test refexpr == 1
132165
end
133166

167+
function test_disaggregate_nl_expression_var_binary()
168+
model = GDPModel()
169+
@variable(model, x, Bin)
170+
@variable(model, z, Logical)
171+
DP._reformulate_logical_variables(model)
172+
bvrefs = DP._indicator_to_binary(model)
173+
174+
vrefs = Set([x])
175+
method = DP._Hull(Hull(1e-3, Dict(x => (0., 1.))), vrefs)
176+
DP._disaggregate_variables(model, z, vrefs, method)
177+
178+
refexpr = DP._disaggregate_nl_expression(model, x, bvrefs[z], method)
179+
@test refexpr == x
180+
end
181+
134182
function test_disaggregate_nl_expression_var()
135183
model = GDPModel()
136184
@variable(model, 10 <= x <= 100)
@@ -548,9 +596,12 @@ end
548596
test_query_variable_bounds_error2()
549597
test_disaggregate_variables()
550598
test_aggregate_variable()
599+
test_disaggregate_expression_var_binary()
600+
test_disaggregate_expression_var()
551601
test_disaggregate_expression_affine()
552602
test_disaggregate_expression_quadratic()
553603
test_disaggregate_nl_expression_c()
604+
test_disaggregate_nl_expression_var_binary()
554605
test_disaggregate_nl_expression_var()
555606
test_disaggregate_nl_expression_aff()
556607
test_disaggregate_nl_expression_quad()

0 commit comments

Comments
 (0)