4
4
Add disjunction macro.
5
5
"""
6
6
macro disjunction (m, args... )
7
- # get disjunction (pos_args) and keyword arguments
8
- pos_args, kw_args, _ = Containers. _extract_kw_args (args)
9
- @assert length (pos_args) > 1 " At least 2 disjuncts must be included. If there is an empty disjunct, use `nothing`."
7
+ # get disjunction (args) and keyword arguments
8
+ disjuncts, kwargs, _ = Containers. _extract_kw_args (args)
10
9
11
- # get kw_args and set defaults if missing
12
- reformulation = filter (i -> i. args[1 ] == :reformulation , kw_args)
13
- if ! isempty (reformulation)
14
- reformulation = reformulation[1 ]. args[2 ]
15
- reformulation_kind = eval (reformulation)
16
- @assert reformulation_kind in [:big_m , :hull ] " Invalid reformulation method passed to keyword argument `:reformulation`. Valid options are :big_m (Big-M Reformulation) and :hull (Hull Reformulation)."
17
- if reformulation_kind == :big_m
18
- M = filter (i -> i. args[1 ] == :M , kw_args)
19
- param = ! isempty (M) ? M[1 ]. args[2 ] : :(missing )
20
- elseif reformulation_kind == :hull
21
- ϵ = filter (i -> i. args[1 ] == :ϵ , kw_args)
22
- param = ! isempty (ϵ) ? ϵ[1 ]. args[2 ] : :(1e-6 )
23
- else
24
- end
25
- else
26
- throw (UndefKeywordError (:reformulation ))
27
- end
28
- name = filter (i -> i. args[1 ] == :name , kw_args)
29
- if ! isempty (name)
30
- name = name[1 ]. args[2 ]
31
- disj_name = Symbol (" disj_" ,eval (name))
32
- else
33
- name = :(Symbol (" disj" ,gensym ()))
34
- disj_name = eval (name)
35
- end
10
+ # get kwargs and set defaults if missing
11
+ reformulation_kwarg = filter (i -> i. args[1 ] == :reformulation , kwargs)
12
+ reformulation = isempty (reformulation_kwarg) ? throw (UndefKeywordError (:reformulation )) : reformulation_kwarg[1 ]. args[2 ]
13
+ M_kwarg = filter (i -> i. args[1 ] == :M , kwargs)
14
+ M = isempty (M_kwarg) ? :missing : M_kwarg[1 ]. args[2 ]
15
+ ϵ_kwarg = filter (i -> i. args[1 ] == :ϵ , kwargs)
16
+ ϵ = isempty (ϵ_kwarg) ? :(1e-6 ) : ϵ_kwarg[1 ]. args[2 ]
17
+ name_kwarg = filter (i -> i. args[1 ] == :name , kwargs)
18
+ name = isempty (name_kwarg) ? Symbol (" disj_" ,gensym ()) : name_kwarg[1 ]. args[2 ]
19
+ disj_name = isempty (name_kwarg) ? name : Symbol (" disj_" ,eval (name))
36
20
37
21
# create constraints for each disjunction
38
- disj_names = [Symbol (" $(disj_name) [$i ]" ) for i in eachindex (pos_args )]
22
+ disj_names = [Symbol (" $(disj_name) [$i ]" ) for i in eachindex (disjuncts )]
39
23
disjunction = []
40
- for (d,dname) in zip (pos_args ,disj_names)
24
+ for (d,dname) in zip (disjuncts ,disj_names)
41
25
if Meta. isexpr (d, :tuple )
42
26
for (j,di) in enumerate (d. args)
43
- i = findfirst (x -> x == d, pos_args )
27
+ i = findfirst (x -> x == d, disjuncts )
44
28
dname_j = Symbol (" $(disj_name) [$i ,$j ]" )
45
29
d. args[j] = add_disjunction_constraint (m, di, dname_j)
46
30
end
@@ -49,17 +33,10 @@ macro disjunction(m, args...)
49
33
push! (disjunction, add_disjunction_constraint (m, d, dname))
50
34
end
51
35
end
52
-
53
- # #XOR constraint name
54
- # xor_con = Symbol("XOR($disj_name)")
55
36
56
37
# build disjunction
57
38
code = quote
58
- if ! in ($ name, keys (object_dictionary ($ m)))
59
- $ m[$ name] = @variable ($ m, [eachindex ($ disjunction)], Bin, base_name = string ($ name))
60
- end
61
- # @constraint($m, $xor_con, sum($m[$name]) == 1)
62
- DisjunctiveProgramming. reformulate_disjunction ($ m, $ (disjunction... ); bin_var = $ name, reformulation = $ reformulation, param = $ param)
39
+ DisjunctiveProgramming. add_disjunction! ($ m, $ (disjunction... ); reformulation = $ reformulation, M = $ M, ϵ = $ ϵ, name = $ name)
63
40
end
64
41
65
42
return esc (code)
@@ -110,7 +87,7 @@ function add_disjunction!(m::Model,disj...;reformulation::Symbol,M=missing,ϵ=1e
110
87
@assert reformulation in [:big_m , :hull ] " Invalid reformulation method passed to keyword argument `:reformulation`. Valid options are :big_m (Big-M Reformulation) and :hull (Hull Reformulation)."
111
88
@assert length (disj) > 1 " At least 2 disjuncts must be included. If there is an empty disjunct, use `nothing`."
112
89
113
- # get kw_args and set defaults if missing
90
+ # get kwargs and set defaults if missing
114
91
param = reformulation == :big_m ? M : ϵ
115
92
bin_var = ismissing (name) ? Symbol (" disj" ,gensym ()) : name
116
93
0 commit comments