1
+ """
2
+ choose!(m::Model, n::Int, vars::VariableRef...; mode)
3
+
4
+ Add constraint to select n elements from the list of variables. Options for mode
5
+ are `:at_least`, `:at_most`, `:exactly`.
6
+ """
7
+ function choose! (m:: Model , n:: Int , vars:: VariableRef... ; mode= :exactly )
8
+ @assert length (vars) >= n " Not enough variables passed."
9
+ @assert all (is_valid .(m, vars)) " Invalid VariableRefs passed."
10
+ add_selection! (m, n, vars... ; mode)
11
+ end
12
+ function choose! (m:: Model , vars:: VariableRef... ; mode= :exactly )
13
+ @assert all (is_valid .(m, vars)) " Invalid VariableRefs passed."
14
+ n = vars[1 ] # first variable is the n
15
+ add_selection! (m, n, vars... ; mode)
16
+ end
17
+ function add_selection! (m:: Model , n, vars:: VariableRef... ; mode:: Symbol )
18
+ display (n)
19
+ if mode == :exactly
20
+ display (@constraint (m, sum (vars) == n))
21
+ elseif mode == :at_least
22
+ @constraint (m, sum (vars) ≥ n)
23
+ elseif mode == :at_most
24
+ @constraint (m, sum (vars) ≥ n)
25
+ end
26
+ end
27
+
1
28
"""
2
29
to_cnf!(m::Model, expr::Expr)
3
30
4
31
Convert logical proposition expression into conjunctive normal form.
5
32
"""
6
33
function to_cnf! (m:: Model , expr:: Expr )
7
- expr_name = Symbol (expr) # get name to register reformulated logical proposition
34
+ expr_name = Symbol (" { $ expr} " ) # get name to register reformulated logical proposition
8
35
replace_Symvars! (expr, m; logical_proposition = true ) # replace all JuMP variables with Symbolic variables
9
- check_logical_proposition (expr) # check that valid boolean symbols and variables are used in the logical proposition
10
- eliminate_equivalence! (expr) # eliminate ⇔
11
- eliminate_implication! (expr) # eliminmate ⇒
12
- move_negations_inwards! (expr) # expand ¬
13
- clause_list = distribute_and_over_or_recursively! (expr) # distribute ∧ over ∨ recursively
14
- @assert ! isempty (clause_list) " Conversion to CNF failed."
36
+ clause_list = to_cnf! (expr)
15
37
# replace symbolic variables with JuMP variables and boolean operators with their algebraic counterparts
16
38
for clause in clause_list
17
39
replace_JuMPvars! (clause, m)
@@ -29,6 +51,22 @@ function to_cnf!(m::Model, expr::Expr)
29
51
end
30
52
end
31
53
54
+ """
55
+ to_cnf!(expr::Expr)
56
+
57
+ Convert an expression of symbolic Boolean variables and operators to CNF.
58
+ """
59
+ function to_cnf! (expr:: Expr )
60
+ check_logical_proposition (expr) # check that valid boolean symbols and variables are used in the logical proposition
61
+ eliminate_equivalence! (expr) # eliminate ⇔
62
+ eliminate_implication! (expr) # eliminmate ⇒
63
+ move_negations_inwards! (expr) # expand ¬
64
+ clause_list = distribute_and_over_or_recursively! (expr) # distribute ∧ over ∨ recursively
65
+ @assert ! isempty (clause_list) " Conversion to CNF failed."
66
+
67
+ return clause_list
68
+ end
69
+
32
70
"""
33
71
check_logical_proposition(expr::Expr)
34
72
@@ -53,11 +91,13 @@ function eliminate_equivalence!(expr)
53
91
if expr isa Expr
54
92
if expr. args[1 ] == :⇔
55
93
@assert length (expr. args) == 3 " Double implication cannot have more than two clauses."
56
- A = expr. args[2 ]
57
- B = expr. args[3 ]
94
+ A1 = expr. args[2 ]
95
+ B1 = expr. args[3 ]
96
+ A2 = A1 isa Expr ? copy (A1) : A1
97
+ B2 = B1 isa Expr ? copy (B1) : B1
58
98
expr. args[1 ] = :∧
59
- expr. args[2 ] = :($ A ⇒ $ B )
60
- expr. args[3 ] = :($ B ⇒ $ A )
99
+ expr. args[2 ] = :($ A1 ⇒ $ B1 )
100
+ expr. args[3 ] = :($ B2 ⇒ $ A2 )
61
101
end
62
102
for i in eachindex (expr. args)
63
103
expr. args[i] = eliminate_equivalence! (expr. args[i])
0 commit comments