Skip to content

Commit 521a8b6

Browse files
authored
Merge pull request #52 from hdavid16:ext_dict
use extension dictionary
2 parents a5c6d6e + 88867e4 commit 521a8b6

File tree

10 files changed

+38
-75
lines changed

10 files changed

+38
-75
lines changed

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DisjunctiveProgramming"
22
uuid = "0d27d021-0159-4c7d-b4a7-9ccb5d9366cf"
33
authors = ["hdavid16 <[email protected]>"]
4-
version = "0.3.0"
4+
version = "0.3.1"
55

66
[deps]
77
IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253"

examples/ex1.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ m = Model()
1111
name=:y
1212
)
1313
choose!(m, 1, m[:y]...; mode = :exactly, name = "XOR") #XOR constraint
14-
@proposition(m, y[1] y[2]) #this is a redundant proposition
14+
@proposition(m, y[1] y[2], name = "prop") #this is a redundant proposition
1515

1616
print(m)
1717

examples/ex2.jl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ m = Model()
1818
choose!(m, 1, m[:y]...; mode = :exactly, name = "XOR") #XOR constraint
1919
print(m)
2020

21-
# ┌ Warning: [con1[1] : x[1] in [0.0, 3.0], con1[2] : x[2] in [0.0, 4.0]] uses the `MOI.Interval` set. Each instance of the interval set has been split into two constraints, one for each bound.
22-
# ┌ Warning: [con2[1] : x[1] in [5.0, 9.0], con2[2] : x[2] in [4.0, 6.0]] uses the `MOI.Interval` set. Each instance of the interval set has been split into two constraints, one for each bound.
2321
# Feasibility
2422
# Subject to
2523
# XOR(disj_y) : y[1] + y[2] == 1.0 <- XOR constraint

src/bigm.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function big_m_reformulation!(constr::NonlinearConstraintRef, bin_var, M, i, j,
3333
gx = gx - M*(1-λ) #add bigM
3434

3535
#update constraint
36-
replace_constraint(constr, gx, op, rhs)
36+
replace_constraint(constr, bin_var, gx, op, rhs)
3737
end
3838
big_m_reformulation!(constr::AbstractArray{<:ConstraintRef}, bin_var, M, i, j, k) =
3939
big_m_reformulation(constr[k], bin_var, M, i, j, k)

src/constraint.jl

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,7 @@ function check_constraint!(m::Model, constr::ConstraintRef)
4141
if isnothing(new_constr)
4242
new_constr = constr
4343
else
44-
constr_name = gen_constraint_name(constr)
45-
delete_constraint!(m, constr, constr_name)
46-
m[constr_name] = new_constr
47-
m.ext[:object_dict][constr_name] = new_constr
44+
delete(m, constr)
4845
end
4946
return new_constr
5047
end
@@ -64,10 +61,7 @@ function check_constraint!(m::Model, constr::AbstractArray{<:ConstraintRef})
6461
]...
6562
))
6663
new_constr = Containers.SparseAxisArray(constr_dict)
67-
constr_name = gen_constraint_name(constr)
68-
delete_constraint!.(m, constr, constr_name)
69-
m[constr_name] = new_constr
70-
m.ext[:object_dict][constr_name] = new_constr
64+
delete(m, constr)
7165
end
7266
return new_constr
7367
end
@@ -166,11 +160,11 @@ function parse_constraint(constr::ConstraintRef)
166160
end
167161

168162
"""
169-
replace_constraint(constr::ConstraintRef, sym_expr, op, rhs)
163+
replace_constraint(constr::ConstraintRef, bin_var::Symbol, sym_expr, op, rhs)
170164
171165
Replace nonlinear or quadratic constraint with its hull reformulation.
172166
"""
173-
function replace_constraint(constr::ConstraintRef, sym_expr, op, rhs)
167+
function replace_constraint(constr::ConstraintRef, bin_var::Symbol, sym_expr, op, rhs)
174168
#convert symbolic function to expression
175169
op = eval(op)
176170
expr = Base.remove_linenums!(build_function(op(sym_expr,rhs))).args[2].args[1]
@@ -179,12 +173,6 @@ function replace_constraint(constr::ConstraintRef, sym_expr, op, rhs)
179173
replace_JuMPvars!(expr, m)
180174
replace_operators!(expr)
181175
#replace constraint with prespective function
182-
constr_name = gen_constraint_name(constr)
183-
delete_constraint!(m, constr, constr_name)
184-
m[constr_name] = add_nonlinear_constraint(m, expr)
185-
end
186-
187-
function delete_constraint!(m, constr, constr_name)
176+
push!(m.ext[bin_var], add_nonlinear_constraint(m, expr))
188177
delete(m, constr)
189-
unregister(m, constr_name)
190178
end

src/hull.jl

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function hull_reformulation!(constr::ConstraintRef, bin_var, eps, i, j, k)
6363
pers_func = substitute(pers_func, Dict(FSG1 => (1-ϵ)*λ+ϵ,
6464
FSG2 => ϵ*(1-λ)))
6565
pers_func = simplify(pers_func)
66-
replace_constraint(constr, pers_func, op, rhs)
66+
replace_constraint(constr, bin_var, pers_func, op, rhs)
6767
end
6868
hull_reformulation!(constr::AbstractArray{<:ConstraintRef}, bin_var, eps, i, j, k) =
6969
hull_reformulation!(constr[k], bin_var, eps, i, j, k)
@@ -93,14 +93,20 @@ function disaggregate_variables(m::Model, disj, bin_var)
9393
#apply bounding constraints on disaggregated variable
9494
var_i_lb = "$(var_name_i)_lb"
9595
var_i_ub = "$(var_name_i)_ub"
96-
m[Symbol(var_i_lb)] = @constraint(m, LB * m[bin_var][i] .- m[var_name_i] .<= 0, base_name = var_i_lb)
97-
m[Symbol(var_i_ub)] = @constraint(m, m[var_name_i] .- UB * m[bin_var][i] .<= 0, base_name = var_i_ub)
96+
push!(
97+
m.ext[bin_var],
98+
@constraint(m, LB * m[bin_var][i] .- m[var_name_i] .<= 0, base_name = var_i_lb),
99+
@constraint(m, m[var_name_i] .- UB * m[bin_var][i] .<= 0, base_name = var_i_ub)
100+
)
98101
#update disaggregated sum expression
99102
add_to_expression!(sum_vars, 1, m[var_name_i])
100103
end
101104
#sum disaggregated variables
102105
aggr_con = "$(var)_$(bin_var)_aggregation"
103-
m[Symbol(aggr_con)] = @constraint(m, var == sum_vars, base_name = aggr_con)
106+
push!(
107+
m.ext[bin_var],
108+
@constraint(m, var == sum_vars, base_name = aggr_con)
109+
)
104110
end
105111
end
106112

src/logic.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ function add_selection!(m::Model, n, vars::VariableRef...; mode::Symbol, name::S
2828
end
2929

3030
"""
31-
add_proposition!(m::Model, expr::Expr)
31+
add_proposition!(m::Model, expr::Expr; name::String = "")
3232
3333
Convert logical proposition expression into conjunctive normal form.
3434
"""
35-
function add_proposition!(m::Model, expr::Expr)
36-
expr_name = Symbol("{$expr}") #get name to register reformulated logical proposition
35+
function add_proposition!(m::Model, expr::Expr; name::String = "")
36+
if isempty(name)
37+
name = "{$expr}" #get name to register reformulated logical proposition
38+
end
3739
replace_Symvars!(expr, m; logical_proposition = true) #replace all JuMP variables with Symbolic variables
3840
clause_list = to_cnf!(expr)
3941
#replace symbolic variables with JuMP variables and boolean operators with their algebraic counterparts
@@ -47,9 +49,9 @@ function add_proposition!(m::Model, expr::Expr)
4749
unique!(lhs)
4850
#generate JuMP constraints for the logical proposition
4951
if length(lhs) == 1
50-
m[expr_name] = @constraint(m, lhs[1] >= 1, base_name = string(expr_name))
52+
m[Symbol(name)] = @constraint(m, lhs[1] >= 1, base_name = name)
5153
else
52-
m[expr_name] = @constraint(m, [i = eachindex(lhs)], lhs[i] >= 1, base_name = string(expr_name))
54+
m[Symbol(name)] = @constraint(m, [i = eachindex(lhs)], lhs[i] >= 1, base_name = name)
5355
end
5456
end
5557

src/macros.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,13 @@ end
106106
107107
Add logical proposition macro.
108108
"""
109-
macro proposition(m, expr)
109+
macro proposition(m, args...)
110+
expr, kwargs, _ = Containers._extract_kw_args(args)
111+
name_kwarg = filter(i -> i.args[1] == :name, kwargs)
112+
name = isempty(name_kwarg) ? Symbol("") : name_kwarg[1].args[2]
110113
#get args
111114
expr = QuoteNode(expr)
112-
code = :(DisjunctiveProgramming.add_proposition!($m, $expr))
115+
code = :(DisjunctiveProgramming.add_proposition!($m, $expr[1]; name = $name))
113116

114117
return esc(code)
115118
end

src/reformulate.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ Reformulate disjunction on a JuMP model.
88
Reformulate disjunction.
99
"""
1010
function reformulate_disjunction(m::Model, disj...; bin_var, reformulation, param)
11-
m.ext[:object_dict] = copy(object_dictionary(m))
11+
#placeholder to store new constraints (reformulated)
12+
m.ext[bin_var] = []
1213
#check disj
1314
disj = [check_constraint!(m, constr) for constr in disj]#check_disjunction!(m, disj)
1415
#run reformulation
1516
if reformulation == :hull
1617
disaggregate_variables(m, disj, bin_var)
1718
end
1819
reformulate_disjunction(disj, bin_var, reformulation, param)
20+
push!(m.ext[bin_var], Iterators.flatten(filter(i -> is_constraint(m, i), disj))...)
1921
end
2022
function reformulate_disjunction(disj, bin_var, reformulation, param)
2123
for (i,constr) in enumerate(disj)

src/utils.jl

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -57,46 +57,6 @@ function get_constraint_variables(m::Model, disjunction)
5757
)
5858
end
5959

60-
"""
61-
gen_constraint_name(constr)
62-
63-
Generate constraint name for a constraint to be split (Interval or EqualTo).
64-
"""
65-
function gen_constraint_name(constr::ConstraintRef)
66-
constr_name = name(constr)
67-
if isempty(constr_name)
68-
constr_name = gensym("constraint")
69-
end
70-
71-
return Symbol(constr_name)
72-
end
73-
function gen_constraint_name(constr::NonlinearConstraintRef)
74-
constr_name = findfirst(==(constr), constr.model.ext[:object_dict])
75-
if isnothing(constr_name)
76-
constr_name = gensym("constraint")
77-
end
78-
79-
return Symbol(constr_name)
80-
end
81-
function gen_constraint_name(constr::AbstractArray{<:NonlinearConstraintRef})
82-
constr_name = findfirst(==(constr), first(constr).model.ext[:object_dict])
83-
if isnothing(constr_name)
84-
constr_name = gensym("constraint")
85-
end
86-
87-
return Symbol(constr_name)
88-
end
89-
function gen_constraint_name(constr::AbstractArray{<:ConstraintRef})
90-
constr_name_set = union(first.(split.(string.(gen_constraint_name.(constr)), "[")))
91-
if length(constr_name_set) == 1
92-
constr_name = constr_name_set[1]
93-
else
94-
constr_name = gensym("constraint")
95-
end
96-
97-
return Symbol(constr_name)
98-
end
99-
10060
function replace_Symvars!(expr, model; logical_proposition = false)
10161
#replace JuMP variables with symbolic variables
10262
name = join(split(string(expr)," "))
@@ -191,4 +151,8 @@ function constraint_variables!(expr, model, var_list=[])
191151
constraint_variables!(expr.args[i], model, var_list)
192152
end
193153
end
194-
end
154+
end
155+
156+
is_constraint(m::Model, constr::ConstraintRef) = is_valid(m,constr)
157+
is_constraint(m::Model, constr::AbstractArray{<:ConstraintRef}) = all(is_valid.(m,constr))
158+
is_constraint(m::Model, constr::Tuple) = all([is_constraint(m,i) for i in constr])

0 commit comments

Comments
 (0)