gecoder 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +11 -0
- data/README +12 -1
- data/example/example_helper.rb +1 -0
- data/example/magic_sequence.rb +43 -0
- data/example/queens.rb +43 -0
- data/example/raw_bindings.rb +42 -0
- data/example/send_more_money.rb +43 -0
- data/example/sudoku.rb +65 -0
- data/ext/missing.cpp +15 -21
- data/ext/missing.h +14 -20
- data/ext/vararray.cpp +14 -20
- data/ext/vararray.h +18 -22
- data/lib/gecoder/bindings/bindings.rb +1979 -1969
- data/lib/gecoder/interface/binding_changes.rb +123 -2
- data/lib/gecoder/interface/constraints/bool/boolean.rb +80 -65
- data/lib/gecoder/interface/constraints/bool_enum/boolean.rb +59 -0
- data/lib/gecoder/interface/constraints/bool_enum_constraints.rb +8 -0
- data/lib/gecoder/interface/constraints/bool_var_constraints.rb +42 -0
- data/lib/gecoder/interface/constraints/int/arithmetic.rb +21 -44
- data/lib/gecoder/interface/constraints/int/domain.rb +6 -4
- data/lib/gecoder/interface/constraints/int_enum/arithmetic.rb +18 -44
- data/lib/gecoder/interface/constraints/int_enum/count.rb +3 -18
- data/lib/gecoder/interface/constraints/int_enum/distinct.rb +4 -16
- data/lib/gecoder/interface/constraints/int_enum/element.rb +9 -20
- data/lib/gecoder/interface/constraints/int_var_constraints.rb +28 -0
- data/lib/gecoder/interface/constraints/set/cardinality.rb +56 -0
- data/lib/gecoder/interface/constraints/set/domain.rb +66 -0
- data/lib/gecoder/interface/constraints/set/relation.rb +125 -0
- data/lib/gecoder/interface/constraints/set_var_constraints.rb +37 -0
- data/lib/gecoder/interface/constraints.rb +229 -65
- data/lib/gecoder/interface/enum_wrapper.rb +42 -11
- data/lib/gecoder/interface/model.rb +75 -0
- data/lib/gecoder/interface/search.rb +4 -9
- data/lib/gecoder/interface/variables.rb +36 -2
- data/lib/gecoder/version.rb +1 -1
- data/specs/bool_var.rb +58 -0
- data/specs/constraints/arithmetic.rb +91 -90
- data/specs/constraints/bool_enum.rb +130 -0
- data/specs/constraints/boolean.rb +95 -2
- data/specs/constraints/cardinality.rb +127 -0
- data/specs/constraints/constraint_helper.rb +91 -0
- data/specs/constraints/constraints.rb +31 -0
- data/specs/constraints/element.rb +43 -72
- data/specs/constraints/{domain.rb → int_domain.rb} +4 -0
- data/specs/constraints/{relation.rb → int_relation.rb} +0 -0
- data/specs/constraints/set_domain.rb +165 -0
- data/specs/constraints/set_relation.rb +181 -0
- data/specs/enum_wrapper.rb +13 -2
- data/specs/int_var.rb +33 -1
- data/specs/model.rb +80 -0
- data/specs/set_var.rb +39 -0
- data/specs/spec_helper.rb +35 -0
- data/specs/tmp +11 -124
- data/tasks/distribution.rake +1 -1
- data/vendor/rust/rust/class.rb +10 -10
- data/vendor/rust/rust/constants.rb +1 -1
- data/vendor/rust/rust/function.rb +5 -5
- data/vendor/rust/rust/type.rb +1 -1
- data/vendor/rust/test/constants.rb +1 -0
- data/vendor/rust/test/cppclass.cc +5 -0
- data/vendor/rust/test/cppclass.hh +4 -0
- data/vendor/rust/test/lib/extension-test.rb +1 -1
- data/vendor/rust/test/operators.cc +41 -0
- data/vendor/rust/test/operators.hh +39 -0
- data/vendor/rust/test/operators.rb +39 -0
- data/vendor/rust/test/test-cwrapper.rb +3 -0
- data/vendor/rust/test/test-operators.rb +42 -0
- metadata +31 -4
@@ -45,4 +45,95 @@ describe 'constraint with options', :shared => true do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
it_should_behave_like 'constraint with strength option'
|
48
|
+
end
|
49
|
+
|
50
|
+
# This requires that the constraint spec has the instance variable
|
51
|
+
# @expect_relation which takes a relation and right hand side as arguments and
|
52
|
+
# sets up the corresponding expectations. It also requires @invoke_relation and
|
53
|
+
# @invoke_negated_relation with the same arguments. The spec is also required to
|
54
|
+
# provide an int var @target.
|
55
|
+
describe 'composite constraint', :shared => true do
|
56
|
+
Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
|
57
|
+
it "should translate #{relation} with constant target" do
|
58
|
+
@expect_relation.call(type, 1, false)
|
59
|
+
@invoke_relation.call(relation, 1, false)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
|
64
|
+
it "should translate #{relation} with variable target" do
|
65
|
+
@expect_relation.call(type, @target, false)
|
66
|
+
@invoke_relation.call(relation, @target, false)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
|
71
|
+
it "should translate negated #{relation} with constant target" do
|
72
|
+
@expect_relation.call(type, 1, true)
|
73
|
+
@invoke_relation.call(relation, 1, true)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
|
78
|
+
it "should translate negated #{relation} with variable target" do
|
79
|
+
@expect_relation.call(type, @target, true)
|
80
|
+
@invoke_relation.call(relation, @target, true)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should raise error if the target is of the wrong type' do
|
85
|
+
lambda do
|
86
|
+
@invoke_relation.call(:==, 'hello', false)
|
87
|
+
end.should raise_error(TypeError)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Requires @invoke_options and @model.
|
92
|
+
describe 'non-reifiable set constraint', :shared => true do
|
93
|
+
it 'should not accept strength option' do
|
94
|
+
lambda do
|
95
|
+
@invoke_options.call(:strength => :default)
|
96
|
+
end.should raise_error(ArgumentError)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should not accept reification option' do
|
100
|
+
bool = @model.bool_var
|
101
|
+
lambda do
|
102
|
+
@invoke_options.call(:reify => bool)
|
103
|
+
end.should raise_error(ArgumentError)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Requires @invoke_options, @expect_options and @model.
|
108
|
+
describe 'reifiable set constraint', :shared => true do
|
109
|
+
it 'should not accept strength option' do
|
110
|
+
lambda do
|
111
|
+
@invoke_options.call(:strength => :default)
|
112
|
+
end.should raise_error(ArgumentError)
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should accept reification option' do
|
116
|
+
bool = @model.bool_var
|
117
|
+
@expect_options.call(nil, bool)
|
118
|
+
@invoke_options.call(:reify => bool)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Help methods for the GecodeR specs.
|
123
|
+
module GecodeR::Specs
|
124
|
+
module SetHelper
|
125
|
+
module_function
|
126
|
+
|
127
|
+
# Returns the arguments that should be used in a partial mock to expect the
|
128
|
+
# specified constant set (possibly an array of arguments).
|
129
|
+
def expect_constant_set(constant_set)
|
130
|
+
if constant_set.kind_of? Range
|
131
|
+
return constant_set.first, constant_set.last
|
132
|
+
elsif constant_set.kind_of? Fixnum
|
133
|
+
constant_set
|
134
|
+
else
|
135
|
+
an_instance_of(Gecode::Raw::IntSet)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
48
139
|
end
|
@@ -17,6 +17,18 @@ describe Gecode::Constraints::IntEnum::Expression do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
describe Gecode::Constraints::Int::CompositeStub, ' (not subclassed)' do
|
21
|
+
before do
|
22
|
+
@con = Gecode::Constraints::Int::CompositeStub.new(Gecode::Model.new, {})
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should raise error when calling #constrain_equal' do
|
26
|
+
lambda do
|
27
|
+
@con.instance_eval{ constrain_equal(nil, {}) }
|
28
|
+
end.should raise_error(NoMethodError)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
20
32
|
describe Gecode::Constraints::Constraint, ' (not subclassed)' do
|
21
33
|
before do
|
22
34
|
@con = Gecode::Constraints::Constraint.new(Gecode::Model.new, {})
|
@@ -25,4 +37,23 @@ describe Gecode::Constraints::Constraint, ' (not subclassed)' do
|
|
25
37
|
it 'should raise error when calling #post because it\'s not overridden' do
|
26
38
|
lambda{ @con.post }.should raise_error(NoMethodError)
|
27
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe Gecode::Constraints::Util do
|
43
|
+
it 'should raise error when giving incorrect set to #constant_set_to_params' do
|
44
|
+
lambda do
|
45
|
+
Gecode::Constraints::Util.constant_set_to_params('hello')
|
46
|
+
end.should raise_error(TypeError)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe Gecode::Constraints::CompositeExpression do
|
51
|
+
it 'should raise error if a method doesn\'t exist' do
|
52
|
+
expression = Gecode::Constraints::CompositeExpression.new(
|
53
|
+
Gecode::Constraints::Int::Expression, Gecode::FreeIntVar,
|
54
|
+
Gecode::Model.new, {:lhs => nil, :negate => false}){}
|
55
|
+
lambda do
|
56
|
+
expression.this_method_does_not_exist
|
57
|
+
end.should raise_error(NoMethodError)
|
58
|
+
end
|
28
59
|
end
|
@@ -21,92 +21,58 @@ describe Gecode::Constraints::IntEnum::Element do
|
|
21
21
|
before do
|
22
22
|
@model = ElementSampleProblem.new
|
23
23
|
@prices = @model.prices
|
24
|
-
@price = @model.price
|
24
|
+
@target = @price = @model.price
|
25
25
|
@store = @model.store
|
26
26
|
@fixnum_prices = @model.fixnum_prices
|
27
27
|
|
28
|
-
#
|
29
|
-
@
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
@expect_options = lambda do |strength, reif_var|
|
28
|
+
# Creates an expectation corresponding to the specified input.
|
29
|
+
@expect = lambda do |element, relation, target, strength, reif_var, negated|
|
30
|
+
target = target.bind if target.respond_to? :bind
|
31
|
+
element = element.bind if element.respond_to? :bind
|
34
32
|
if reif_var.nil?
|
35
|
-
Gecode::Raw
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
if !negated and relation == Gecode::Raw::IRT_EQ and
|
34
|
+
target.kind_of? Gecode::Raw::IntVar
|
35
|
+
Gecode::Raw.should_receive(:element).once.with(@model.active_space,
|
36
|
+
an_instance_of(Gecode::Raw::IntVarArray),
|
37
|
+
element, target, strength)
|
38
|
+
else
|
39
|
+
Gecode::Raw.should_receive(:element).once.with(@model.active_space,
|
40
|
+
an_instance_of(Gecode::Raw::IntVarArray),
|
41
|
+
element, an_instance_of(Gecode::Raw::IntVar), strength)
|
42
|
+
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
43
|
+
an_instance_of(Gecode::Raw::IntVar), relation, target, strength)
|
44
|
+
end
|
42
45
|
else
|
43
46
|
Gecode::Raw.should_receive(:element).once.with(@model.active_space,
|
44
47
|
an_instance_of(Gecode::Raw::IntVarArray),
|
45
|
-
an_instance_of(Gecode::Raw::IntVar),
|
46
|
-
an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
|
48
|
+
element, an_instance_of(Gecode::Raw::IntVar), strength)
|
47
49
|
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
48
|
-
an_instance_of(Gecode::Raw::IntVar),
|
49
|
-
an_instance_of(Gecode::Raw::IntVar),
|
50
|
+
an_instance_of(Gecode::Raw::IntVar), relation, target,
|
50
51
|
an_instance_of(Gecode::Raw::BoolVar), strength)
|
51
52
|
end
|
52
53
|
end
|
53
|
-
end
|
54
|
-
|
55
|
-
Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
|
56
|
-
it "should translate #{relation} with variable right hand side" do
|
57
|
-
Gecode::Raw.should_receive(:element).once.with(@model.active_space,
|
58
|
-
an_instance_of(Gecode::Raw::IntVarArray),
|
59
|
-
an_instance_of(Gecode::Raw::IntVar),
|
60
|
-
an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::ICL_DEF)
|
61
|
-
unless type == Gecode::Raw::IRT_EQ
|
62
|
-
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
63
|
-
an_instance_of(Gecode::Raw::IntVar), type,
|
64
|
-
an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
|
65
|
-
end
|
66
|
-
@prices[@store].must.send(relation, @price)
|
67
|
-
@model.solve!
|
68
|
-
end
|
69
|
-
end
|
70
54
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
an_instance_of(Gecode::Raw::IntVarArray),
|
75
|
-
an_instance_of(Gecode::Raw::IntVar),
|
76
|
-
an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::ICL_DEF)
|
77
|
-
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
78
|
-
an_instance_of(Gecode::Raw::IntVar), type,
|
79
|
-
an_instance_of(Gecode::Raw::IntVar), an_instance_of(Fixnum))
|
80
|
-
@prices[@store].must_not.send(relation, @price)
|
55
|
+
# For constraint option spec.
|
56
|
+
@invoke_options = lambda do |hash|
|
57
|
+
@prices[@store].must_be.greater_than(@price, hash)
|
81
58
|
@model.solve!
|
82
59
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
60
|
+
@expect_options = lambda do |strength, reif_var|
|
61
|
+
@expect.call(@store, Gecode::Raw::IRT_GR, @price, strength, reif_var,
|
62
|
+
false)
|
63
|
+
end
|
64
|
+
|
65
|
+
# For composite spec.
|
66
|
+
@invoke_relation = lambda do |relation, target, negated|
|
67
|
+
if negated
|
68
|
+
@prices[@store].must_not.send(relation, target)
|
69
|
+
else
|
70
|
+
@prices[@store].must.send(relation, target)
|
94
71
|
end
|
95
|
-
@prices[@store].must.send(relation, 5)
|
96
72
|
@model.solve!
|
97
73
|
end
|
98
|
-
|
99
|
-
|
100
|
-
Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
|
101
|
-
it "should translate negated #{relation} with constant right hand side" do
|
102
|
-
Gecode::Raw.should_receive(:element).once.with(@model.active_space,
|
103
|
-
an_instance_of(Gecode::Raw::IntVarArray),
|
104
|
-
an_instance_of(Gecode::Raw::IntVar),
|
105
|
-
an_instance_of(Gecode::Raw::IntVar), Gecode::Raw::ICL_DEF)
|
106
|
-
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
107
|
-
an_instance_of(Gecode::Raw::IntVar), type, 5, an_instance_of(Fixnum))
|
108
|
-
@prices[@store].must_not.send(relation, 5)
|
109
|
-
@model.solve!
|
74
|
+
@expect_relation = lambda do |relation, target, negated|
|
75
|
+
@expect.call(@store, relation, target, Gecode::Raw::ICL_DEF, nil, negated)
|
110
76
|
end
|
111
77
|
end
|
112
78
|
|
@@ -119,10 +85,15 @@ describe Gecode::Constraints::IntEnum::Element do
|
|
119
85
|
@fixnum_prices[@store].must == @fixnum_prices[2]
|
120
86
|
@model.solve!.store.val.should equal(2)
|
121
87
|
end
|
122
|
-
|
123
|
-
it 'should
|
124
|
-
|
88
|
+
|
89
|
+
it 'should translate reification when using equality' do
|
90
|
+
bool_var = @model.bool_var
|
91
|
+
@expect.call(@store, Gecode::Raw::IRT_EQ, @target, Gecode::Raw::ICL_DEF,
|
92
|
+
bool_var, false)
|
93
|
+
@prices[@store].must_be.equal_to(@target, :reify => bool_var)
|
94
|
+
@model.solve!
|
125
95
|
end
|
126
96
|
|
97
|
+
it_should_behave_like 'composite constraint'
|
127
98
|
it_should_behave_like 'constraint with options'
|
128
99
|
end
|
@@ -52,5 +52,9 @@ describe Gecode::Constraints::Int::Domain do
|
|
52
52
|
@x.should have_domain(@domain.to_a - @range_domain.to_a)
|
53
53
|
end
|
54
54
|
|
55
|
+
it 'should raise error if the right hand side is not an enumeration' do
|
56
|
+
lambda{ @x.must_be.in 'hello' }.should raise_error(TypeError)
|
57
|
+
end
|
58
|
+
|
55
59
|
it_should_behave_like 'constraint with options'
|
56
60
|
end
|
File without changes
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/constraint_helper'
|
3
|
+
|
4
|
+
describe Gecode::Constraints::Set::Domain do
|
5
|
+
include GecodeR::Specs::SetHelper
|
6
|
+
|
7
|
+
before do
|
8
|
+
@model = Gecode::Model.new
|
9
|
+
@glb = [0]
|
10
|
+
@lub = 0..3
|
11
|
+
@set = @model.set_var(@glb, @lub)
|
12
|
+
@range = 0..1
|
13
|
+
@non_range = [0, 2]
|
14
|
+
@singleton = 0
|
15
|
+
|
16
|
+
@expect = lambda do |relation_type, rhs, reif_var, negated|
|
17
|
+
if reif_var.nil? and !negated
|
18
|
+
Gecode::Raw.should_receive(:dom).once.with(@model.active_space,
|
19
|
+
@set.bind, relation_type, *expect_constant_set(rhs))
|
20
|
+
else
|
21
|
+
params = [@model.active_space, @set.bind, relation_type]
|
22
|
+
params << expect_constant_set(rhs)
|
23
|
+
params << an_instance_of(Gecode::Raw::BoolVar)
|
24
|
+
Gecode::Raw.should_receive(:dom).once.with(*params.flatten)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# For options spec.
|
29
|
+
@invoke_options = lambda do |hash|
|
30
|
+
@set.must_be.superset_of(@non_range, hash)
|
31
|
+
@model.solve!
|
32
|
+
end
|
33
|
+
@expect_options = lambda do |strength, reif_var|
|
34
|
+
@expect.call(Gecode::Raw::SRT_SUP, @non_range, reif_var, false)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Gecode::Constraints::Util::SET_RELATION_TYPES.each_pair do |relation, type|
|
39
|
+
next if relation == :==
|
40
|
+
|
41
|
+
it "should translate #{relation} with constant range to domain constraint" do
|
42
|
+
@expect.call(type, @range, nil, false)
|
43
|
+
@set.must.send(relation, @range)
|
44
|
+
@model.solve!
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should translate #{relation} with constant non-range to domain constraint" do
|
48
|
+
@expect.call(type, @non_range, nil, false)
|
49
|
+
@set.must.send(relation, @non_range)
|
50
|
+
@model.solve!
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should translate #{relation} with constant singleton to domain constraint" do
|
54
|
+
@expect.call(type, @singleton, nil, false)
|
55
|
+
@set.must.send(relation, @singleton)
|
56
|
+
@model.solve!
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should translate negated #{relation} with constant range to domain constraint" do
|
60
|
+
@expect.call(type, @range, nil, true)
|
61
|
+
@set.must_not.send(relation, @range)
|
62
|
+
@model.solve!
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should translate negated #{relation} with constant non-range to domain constraint" do
|
66
|
+
@expect.call(type, @non_range, nil, true)
|
67
|
+
@set.must_not.send(relation, @non_range)
|
68
|
+
@model.solve!
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should translate negated #{relation} with constant singleton to domain constraint" do
|
72
|
+
@expect.call(type, @singleton, nil, true)
|
73
|
+
@set.must_not.send(relation, @singleton)
|
74
|
+
@model.solve!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it_should_behave_like 'reifiable set constraint'
|
79
|
+
end
|
80
|
+
|
81
|
+
describe Gecode::Constraints::Set::Domain, ' (equality)' do
|
82
|
+
include GecodeR::Specs::SetHelper
|
83
|
+
|
84
|
+
before do
|
85
|
+
@model = Gecode::Model.new
|
86
|
+
@glb = [0]
|
87
|
+
@lub = 0..3
|
88
|
+
@set = @model.set_var(@glb, @lub)
|
89
|
+
@range = 0..1
|
90
|
+
@non_range = [0, 2]
|
91
|
+
@singleton = 0
|
92
|
+
|
93
|
+
@expect = lambda do |relation_type, rhs, reif_var|
|
94
|
+
if reif_var.nil?
|
95
|
+
Gecode::Raw.should_receive(:dom).once.with(@model.active_space,
|
96
|
+
@set.bind, relation_type, *expect_constant_set(rhs))
|
97
|
+
else
|
98
|
+
params = [@model.active_space, @set.bind, relation_type]
|
99
|
+
params << expect_constant_set(rhs)
|
100
|
+
params << an_instance_of(Gecode::Raw::BoolVar)
|
101
|
+
Gecode::Raw.should_receive(:dom).once.with(*params.flatten)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# For options spec.
|
106
|
+
@invoke_options = lambda do |hash|
|
107
|
+
@set.must_be.equal_to(@non_range, hash)
|
108
|
+
@model.solve!
|
109
|
+
end
|
110
|
+
@expect_options = lambda do |strength, reif_var|
|
111
|
+
@expect.call(Gecode::Raw::SRT_EQ, @non_range, reif_var)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should translate equality with constant range to domain constraint' do
|
116
|
+
@expect.call(Gecode::Raw::SRT_EQ, @range, nil)
|
117
|
+
@set.must == @range
|
118
|
+
@model.solve!
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'should translate equality with constant non-range to domain constraint' do
|
122
|
+
@expect.call(Gecode::Raw::SRT_EQ, @non_range, nil)
|
123
|
+
@set.must == @non_range
|
124
|
+
@model.solve!
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should translate equality with constant singleton to domain constraint' do
|
128
|
+
@expect.call(Gecode::Raw::SRT_EQ, @singleton, nil)
|
129
|
+
@set.must == @singleton
|
130
|
+
@model.solve!
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'should translate negated equality with constant range to domain constraint' do
|
134
|
+
@expect.call(Gecode::Raw::SRT_NQ, @range, nil)
|
135
|
+
@set.must_not == @range
|
136
|
+
@model.solve!
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should translate negated equality with constant non-range to domain constraint' do
|
140
|
+
@expect.call(Gecode::Raw::SRT_NQ, @non_range, nil)
|
141
|
+
@set.must_not == @non_range
|
142
|
+
@model.solve!
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'should translate negated equality with constant singleton to domain constraint' do
|
146
|
+
@expect.call(Gecode::Raw::SRT_NQ, @singleton, nil)
|
147
|
+
@set.must_not == @singleton
|
148
|
+
@model.solve!
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should constrain the domain with equality' do
|
152
|
+
@set.must == @singleton
|
153
|
+
@model.solve!
|
154
|
+
@set.should be_assigned
|
155
|
+
@set.should include(@singleton)
|
156
|
+
@set.val_size.should == 1
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'should constrain the domain with inequality' do
|
160
|
+
@set.must_not == @singleton
|
161
|
+
@model.solve!.should be_nil
|
162
|
+
end
|
163
|
+
|
164
|
+
it_should_behave_like 'reifiable set constraint'
|
165
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/constraint_helper'
|
3
|
+
|
4
|
+
describe Gecode::Constraints::Set::Relation do
|
5
|
+
include GecodeR::Specs::SetHelper
|
6
|
+
|
7
|
+
before do
|
8
|
+
@model = Gecode::Model.new
|
9
|
+
@set = @model.set_var([0], 0..3)
|
10
|
+
@set2 = @model.set_var([1], 0..3)
|
11
|
+
|
12
|
+
@expect = lambda do |relation_type, rhs, reif_var, negated|
|
13
|
+
if reif_var.nil? and !negated
|
14
|
+
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
15
|
+
@set.bind, relation_type, @set2.bind)
|
16
|
+
else
|
17
|
+
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
18
|
+
@set.bind, relation_type, @set2.bind,
|
19
|
+
an_instance_of(Gecode::Raw::BoolVar))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# For options spec.
|
24
|
+
@invoke_options = lambda do |hash|
|
25
|
+
@set.must_be.superset_of(@set2, hash)
|
26
|
+
@model.solve!
|
27
|
+
end
|
28
|
+
@expect_options = lambda do |strength, reif_var|
|
29
|
+
@expect.call(Gecode::Raw::SRT_SUP, @set2, reif_var, false)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Gecode::Constraints::Util::SET_RELATION_TYPES.each_pair do |relation, type|
|
34
|
+
next if relation == :==
|
35
|
+
|
36
|
+
it "should translate #{relation} with set to relation constraint" do
|
37
|
+
@expect.call(type, @set2, nil, false)
|
38
|
+
@set.must.send(relation, @set2)
|
39
|
+
@model.solve!
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should translate negated #{relation} with set to relation constraint" do
|
43
|
+
@expect.call(type, @set2, nil, true)
|
44
|
+
@set.must_not.send(relation, @set2)
|
45
|
+
@model.solve!
|
46
|
+
end
|
47
|
+
end
|
48
|
+
it_should_behave_like 'reifiable set constraint'
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Gecode::Constraints::Set::Relation, ' (equality)' do
|
52
|
+
include GecodeR::Specs::SetHelper
|
53
|
+
|
54
|
+
before do
|
55
|
+
@model = Gecode::Model.new
|
56
|
+
@set = @model.set_var([0], 0..1)
|
57
|
+
@set2 = @model.set_var([1], 0..1)
|
58
|
+
|
59
|
+
@expect = lambda do |relation_type, rhs, reif_var|
|
60
|
+
if reif_var.nil?
|
61
|
+
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
62
|
+
@set.bind, relation_type, @set2.bind)
|
63
|
+
else
|
64
|
+
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
65
|
+
@set.bind, relation_type, @set2.bind,
|
66
|
+
an_instance_of(Gecode::Raw::BoolVar))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# For options spec.
|
71
|
+
@invoke_options = lambda do |hash|
|
72
|
+
@set.must_be.equal_to(@set2, hash)
|
73
|
+
@model.solve!
|
74
|
+
end
|
75
|
+
@expect_options = lambda do |strength, reif_var|
|
76
|
+
@expect.call(Gecode::Raw::SRT_EQ, @set2, reif_var)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should translate equality with set to relation constraint' do
|
81
|
+
@expect.call(Gecode::Raw::SRT_EQ, @set2, nil)
|
82
|
+
@set.must == @set2
|
83
|
+
@model.solve!
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should translate negated equality with set to domain constraint' do
|
87
|
+
@expect.call(Gecode::Raw::SRT_NQ, @set2, nil)
|
88
|
+
@set.must_not == @set2
|
89
|
+
@model.solve!
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should constrain sets to be equality when not negated' do
|
93
|
+
@set.must == @set2
|
94
|
+
@model.solve!
|
95
|
+
@set.should have_bounds(0..1, 0..1)
|
96
|
+
@set2.should have_bounds(0..1, 0..1)
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should constrain sets to not be equal when negated' do
|
100
|
+
@set.must_not == @set2
|
101
|
+
union = @model.set_var([0, 1], [0, 1])
|
102
|
+
@set.must_not == union
|
103
|
+
@set2.must_not == union
|
104
|
+
@model.solve!
|
105
|
+
@set.should have_bounds([0], [0])
|
106
|
+
@set2.should have_bounds([1], [1])
|
107
|
+
end
|
108
|
+
|
109
|
+
it_should_behave_like 'reifiable set constraint'
|
110
|
+
end
|
111
|
+
|
112
|
+
describe Gecode::Constraints::Set::Relation, ' (elements)' do
|
113
|
+
include GecodeR::Specs::SetHelper
|
114
|
+
|
115
|
+
before do
|
116
|
+
@model = Gecode::Model.new
|
117
|
+
@set = @model.set_var([0], 0..2)
|
118
|
+
@int_var = @model.int_var(0..2)
|
119
|
+
@int_constant = 2
|
120
|
+
@model.branch_on @model.wrap_enum([@set])
|
121
|
+
@expect = lambda do |relation_type, rhs|
|
122
|
+
if rhs.kind_of? Fixnum
|
123
|
+
rhs = an_instance_of(Gecode::Raw::IntVar)
|
124
|
+
end
|
125
|
+
rhs = rhs.bind if rhs.respond_to? :bind
|
126
|
+
Gecode::Raw.should_receive(:rel).once.with(@model.active_space,
|
127
|
+
@set.bind, relation_type, rhs)
|
128
|
+
end
|
129
|
+
|
130
|
+
@invoke_options = lambda do |hash|
|
131
|
+
@set.elements.must_be.equal_to(@int_var, hash)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
Gecode::Constraints::Util::RELATION_TYPES.each_pair do |relation, type|
|
136
|
+
it "should translate #{relation} with variable to relation constraint" do
|
137
|
+
@expect.call(type, @int_var)
|
138
|
+
@set.elements.must.send(relation, @int_var)
|
139
|
+
@model.solve!
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should translate #{relation} with constant to relation constraint" do
|
143
|
+
@expect.call(type, @int_constant)
|
144
|
+
@set.elements.must.send(relation, @int_constant)
|
145
|
+
@model.solve!
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
Gecode::Constraints::Util::NEGATED_RELATION_TYPES.each_pair do |relation, type|
|
150
|
+
it "should translate negated #{relation} with variable to relation constraint" do
|
151
|
+
@expect.call(type, @int_var)
|
152
|
+
@set.elements.must_not.send(relation, @int_var)
|
153
|
+
@model.solve!
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should translate negated #{relation} with constant to relation constraint" do
|
157
|
+
@expect.call(type, @int_constant)
|
158
|
+
@set.elements.must_not.send(relation, @int_constant)
|
159
|
+
@model.solve!
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should constrain the elements of the set' do
|
164
|
+
@set.elements.must <= @int_var
|
165
|
+
@int_var.must == 0
|
166
|
+
@model.solve!
|
167
|
+
@set.should be_assigned
|
168
|
+
@set.should include(0)
|
169
|
+
@set.should_not include(1,2)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should constrain the elements of the set (constant parameter)' do
|
173
|
+
@set.elements.must <= 0
|
174
|
+
@model.solve!
|
175
|
+
@set.should be_assigned
|
176
|
+
@set.should include(0)
|
177
|
+
@set.should_not include(1,2)
|
178
|
+
end
|
179
|
+
|
180
|
+
it_should_behave_like 'non-reifiable set constraint'
|
181
|
+
end
|
data/specs/enum_wrapper.rb
CHANGED
@@ -80,11 +80,22 @@ end
|
|
80
80
|
describe Gecode::BoolEnumMethods do
|
81
81
|
before do
|
82
82
|
@model = Gecode::Model.new
|
83
|
-
@
|
83
|
+
@bool_enum = @model.bool_var_array(3)
|
84
84
|
end
|
85
85
|
|
86
86
|
it 'should convert to a bool var array' do
|
87
|
-
@
|
87
|
+
@bool_enum.to_bool_var_array.should be_kind_of(Gecode::Raw::BoolVarArray)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe Gecode::SetEnumMethods do
|
92
|
+
before do
|
93
|
+
@model = Gecode::Model.new
|
94
|
+
@set_enum = @model.set_var_array(3, [0], 0..1)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should convert to a set var array' do
|
98
|
+
@set_enum.to_set_var_array.should be_kind_of(Gecode::Raw::SetVarArray)
|
88
99
|
end
|
89
100
|
end
|
90
101
|
|