Skip to content

Commit ad813ad

Browse files
authored
Merge pull request #92 from hdavid16/proposition_single_variable
Disallow logical propositions with only 1 logical variable
2 parents b26e1ed + 79c54c0 commit ad813ad

File tree

2 files changed

+18
-47
lines changed

2 files changed

+18
-47
lines changed

src/constraints.jl

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,14 +493,23 @@ end
493493

494494
# Check that logical expression is valid
495495
function _check_logical_expression(ex)
496+
_check_logical_expression_literal(ex)
497+
_check_logical_expression_operator(ex)
498+
end
499+
function _check_logical_expression_literal(ex::_LogicalExpr)
500+
if _isa_literal(ex)
501+
error("Cannot define constraint on single logical variable, use `fix` instead.")
502+
end
503+
end
504+
function _check_logical_expression_operator(ex)
496505
return
497506
end
498-
function _check_logical_expression(ex::_LogicalExpr)
507+
function _check_logical_expression_operator(ex::_LogicalExpr)
499508
if !(ex.head in _LogicalOperatorHeads)
500509
error("Unrecognized logical operator `$(ex.head)`.")
501510
end
502511
for a in ex.args
503-
_check_logical_expression(a)
512+
_check_logical_expression_operator(a)
504513
end
505514
return
506515
end

test/constraints/proposition.jl

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ function test_proposition_add_fail()
99
m = GDPModel()
1010
@variable(m, y[1:3], Logical)
1111
@test_throws ErrorException @constraint(m, y[1] := true)
12+
@test_throws ErrorException @constraint(m, ¬y[1] := true)
13+
@test_throws ErrorException @constraint(m, logical_not(y[1]) := true)
1214
@test_throws ErrorException @constraint(Model(), logical_or(y...) := true)
1315
@test_throws ErrorException @constraint(m, logical_or(y...) == 2)
1416
@test_throws ErrorException @constraint(m, logical_or(y...) <= 1)
@@ -22,33 +24,6 @@ function test_proposition_add_fail()
2224
@test_throws AssertionError add_constraint(m, ScalarConstraint(logical_or(y...), MOI.LessThan(42)))
2325
end
2426

25-
function test_negation_add_success()
26-
model = GDPModel()
27-
@variable(model, y, Logical)
28-
c1 = @constraint(model, logical_not(y) := true)
29-
@constraint(model, c2, ¬y := true)
30-
@test is_valid(model, c1)
31-
@test is_valid(model, c2)
32-
@test owner_model(c1) == model
33-
@test owner_model(c2) == model
34-
@test name(c1) == ""
35-
@test name(c2) == "c2"
36-
@test index(c1) == LogicalConstraintIndex(1)
37-
@test index(c2) == LogicalConstraintIndex(2)
38-
@test haskey(DP._logical_constraints(model), index(c1))
39-
@test haskey(DP._logical_constraints(model), index(c2))
40-
@test DP._logical_constraints(model)[index(c1)] == DP._constraint_data(c1)
41-
@test constraint_object(c1).func isa DP._LogicalExpr
42-
@test constraint_object(c2).func isa DP._LogicalExpr
43-
@test constraint_object(c1).func.head ==
44-
constraint_object(c2).func.head == :!
45-
@test constraint_object(c1).func.args ==
46-
constraint_object(c2).func.args == Any[y]
47-
@test constraint_object(c1).set ==
48-
constraint_object(c2).set == MOI.EqualTo{Bool}(true)
49-
@test c1 == copy(c1)
50-
end
51-
5227
function test_implication_add_success()
5328
model = GDPModel()
5429
@variable(model, y[1:2], Logical)
@@ -168,18 +143,6 @@ function test_proposition_delete()
168143
@test !DP._ready_to_optimize(model)
169144
end
170145

171-
function test_negation_reformulation()
172-
model = GDPModel()
173-
@variable(model, y, Logical)
174-
@constraint(model, ¬y := true)
175-
reformulate_model(model, DummyReformulation())
176-
ref_con = DP._reformulation_constraints(model)[1]
177-
@test is_valid(model, ref_con)
178-
ref_con_obj = constraint_object(ref_con)
179-
@test ref_con_obj.set == MOI.GreaterThan(0.0)
180-
@test ref_con_obj.func == -DP._indicator_to_binary(model)[y]
181-
end
182-
183146
function test_implication_reformulation()
184147
model = GDPModel()
185148
@variable(model, y[1:2], Logical)
@@ -222,17 +185,18 @@ end
222185
function test_intersection_reformulation()
223186
model = GDPModel()
224187
@variable(model, y[1:2], Logical)
225-
@constraint(model, (y[1], y[2]) := true)
188+
@constraint(model, y[1] ¬y[2] := true)
226189
reformulate_model(model, DummyReformulation())
227190
ref_cons = DP._reformulation_constraints(model)
228191
@test all(is_valid.(model, ref_cons))
229192
ref_con_objs = constraint_object.(ref_cons)
230-
@test ref_con_objs[1].set ==
231-
ref_con_objs[2].set == MOI.GreaterThan(1.0)
193+
sets = [ref_con_objs[1].set, ref_con_objs[2].set]
194+
@test MOI.GreaterThan(1.0) in sets
195+
@test MOI.GreaterThan(0.0) in sets
232196
bvars = DP._indicator_to_binary(model)
233197
funcs = [ref_con_objs[1].func, ref_con_objs[2].func]
234198
@test 1bvars[y[1]] in funcs
235-
@test 1bvars[y[2]] in funcs
199+
@test -1bvars[y[2]] in funcs
236200
end
237201

238202
function test_implication_reformulation()
@@ -530,7 +494,6 @@ end
530494
end
531495
@testset "Add Proposition" begin
532496
test_proposition_add_fail()
533-
test_negation_add_success()
534497
test_implication_add_success()
535498
test_equivalence_add_success()
536499
test_intersection_and_flatten_add_success()
@@ -540,7 +503,6 @@ end
540503
test_proposition_add_sparse_axis()
541504
end
542505
@testset "Reformulate Proposition" begin
543-
test_negation_reformulation()
544506
test_implication_reformulation()
545507
test_implication_reformulation_fail()
546508
test_equivalence_reformulation()

0 commit comments

Comments
 (0)