gecoder-with-gecode 0.8.2 → 0.8.3

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.
Files changed (38) hide show
  1. data/CHANGES +14 -0
  2. data/ext/gecoder.cpp +181 -0
  3. data/ext/gecoder.h +94 -0
  4. data/ext/vararray.cpp +3 -3
  5. data/lib/gecoder/bindings/bindings.rb +104 -46
  6. data/lib/gecoder/interface/binding_changes.rb +1 -301
  7. data/lib/gecoder/interface/branch.rb +15 -11
  8. data/lib/gecoder/interface/constraints.rb +38 -0
  9. data/lib/gecoder/interface/constraints/bool/boolean.rb +56 -52
  10. data/lib/gecoder/interface/constraints/bool/channel.rb +1 -16
  11. data/lib/gecoder/interface/constraints/bool_enum/channel.rb +13 -8
  12. data/lib/gecoder/interface/constraints/bool_enum/extensional.rb +48 -0
  13. data/lib/gecoder/interface/constraints/extensional_regexp.rb +101 -0
  14. data/lib/gecoder/interface/constraints/int/channel.rb +1 -13
  15. data/lib/gecoder/interface/constraints/int_enum/channel.rb +15 -35
  16. data/lib/gecoder/interface/constraints/int_enum/extensional.rb +130 -0
  17. data/lib/gecoder/interface/constraints/set/channel.rb +54 -0
  18. data/lib/gecoder/interface/constraints/set_enum/channel.rb +37 -6
  19. data/lib/gecoder/interface/constraints/set_var_constraints.rb +1 -0
  20. data/lib/gecoder/interface/model.rb +110 -85
  21. data/lib/gecoder/interface/variables.rb +3 -21
  22. data/lib/gecoder/version.rb +1 -1
  23. data/specs/branch.rb +16 -1
  24. data/specs/constraints/bool_enum_relation.rb +6 -6
  25. data/specs/constraints/boolean.rb +31 -25
  26. data/specs/constraints/channel.rb +102 -4
  27. data/specs/constraints/extensional.rb +185 -2
  28. data/specs/constraints/reification_sugar.rb +2 -46
  29. data/specs/model.rb +85 -7
  30. data/tasks/dependencies.txt +1 -0
  31. data/vendor/rust/rust/class.rb +33 -35
  32. data/vendor/rust/rust/templates/ClassDeclarations.rusttpl +1 -1
  33. data/vendor/rust/rust/templates/CxxClassDefinitions.rusttpl +10 -1
  34. metadata +707 -706
  35. data/example/raw_bindings.rb +0 -44
  36. data/ext/missing.cpp +0 -328
  37. data/ext/missing.h +0 -120
  38. data/specs/binding_changes.rb +0 -76
@@ -1,23 +1,8 @@
1
1
  module Gecode::Constraints::Bool
2
2
  class Expression
3
- alias_method :pre_channel_equals, :==
4
-
5
3
  # Constrains the boolean variable to be equal to the specified integer
6
4
  # variable.
7
- def ==(int, options = {})
8
- unless @params[:lhs].kind_of?(Gecode::FreeBoolVar) and
9
- int.kind_of?(Gecode::FreeIntVar)
10
- return pre_channel_equals(int, options)
11
- end
12
-
13
- # Provide commutivity to the corresponding int variable constraint.
14
- if @params[:negate]
15
- int.must_not.equal(@params[:lhs], options)
16
- else
17
- int.must.equal(@params[:lhs], options)
18
- end
19
- end
20
-
5
+ provide_commutivity(:==){ |rhs, _| rhs.kind_of?(Gecode::FreeIntVar) }
21
6
  alias_comparison_methods
22
7
  end
23
8
  end
@@ -6,7 +6,7 @@ module Gecode::Constraints::BoolEnum
6
6
  #
7
7
  # [:offset] Specifies an offset for the integer variable. If the offset is
8
8
  # set to k then the integer variable takes value i+k exactly
9
- # when the variable at index i in the boolean enumration is true
9
+ # when the variable at index i in the boolean enumeration is true
10
10
  # and the rest are false.
11
11
  def channel(int_var, options = {})
12
12
  if @params[:negate]
@@ -25,28 +25,33 @@ module Gecode::Constraints::BoolEnum
25
25
  @params.update(Gecode::Constraints::Util.decode_options(options))
26
26
  @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
27
27
  end
28
+
29
+ # Adds a channel constraint on the variables in the enum with the specified
30
+ # set variable.
31
+ provide_commutivity(:channel){ |rhs, _| rhs.kind_of? Gecode::FreeSetVar }
28
32
  end
29
33
 
30
34
  # A module that gathers the classes and modules used in channel constraints
31
35
  # involving one boolean enum and one integer variable.
32
36
  module Channel #:nodoc:
33
- # Describes a channel constraint that "channels" an enumerations of
37
+ # Describes a channel constraint that "channels" an enumeration of
34
38
  # boolean variables with an integer variable. This constrains the integer
35
39
  # variable to take value i exactly when the variable at index i in the
36
40
  # boolean enumeration is true and the others are false.
37
41
  #
38
- # Neither reification nor negation is supported.
42
+ # Neither reification nor negation is supported. The int variable
43
+ # and the enumeration can be interchanged.
39
44
  #
40
45
  # == Examples
41
46
  #
42
- # # Constrains the enumeration called +selected_option+ to be false in the
47
+ # # Constrains the enumeration called +option_is_selected+ to be false in the
43
48
  # # first four positions and have exactly one true variable in the other.
44
- # selected_option.must.channel selected_option_index
49
+ # option_is_selected.must.channel selected_option_index
45
50
  # selected_option_index.must_be > 3
46
51
  #
47
- # # Constrains the enumeration called +selected_option+ to be false in the
52
+ # # Constrains the enumeration called +option_is_selected+ to be false in the
48
53
  # # first five positions and have exactly one true variable in the other.
49
- # selected_option.must.channel(selected_option_index, :offset => 1)
54
+ # selected_option_index.must.channel(option_is_selected, :offset => 1)
50
55
  # selected_option_index.must_be > 3
51
56
  class ChannelConstraint < Gecode::Constraints::Constraint
52
57
  def post
@@ -56,4 +61,4 @@ module Gecode::Constraints::BoolEnum
56
61
  end
57
62
  end
58
63
  end
59
- end
64
+ end
@@ -25,6 +25,27 @@ module Gecode::Constraints::BoolEnum
25
25
  @model.add_constraint Extensional::TupleConstraint.new(@model,
26
26
  @params.update(Gecode::Constraints::Util.decode_options(options)))
27
27
  end
28
+
29
+ # Adds a constraint that forces the enumeration to match the
30
+ # specified regular expression over the boolean domain. The regular
31
+ # expression is expressed using arrays and boolean values (or
32
+ # integers). See BoolEnum::Extensional::RegexpConstraint for more information
33
+ # and examples of such regexps.
34
+ def match(regexp, options = {})
35
+ if @params[:negate]
36
+ raise Gecode::MissingConstraintError, 'A negated regexp constraint ' +
37
+ 'is not implemented.'
38
+ end
39
+ unless options[:reify].nil?
40
+ raise ArgumentError, 'Reification is not supported by the regexp ' +
41
+ 'constraint.'
42
+ end
43
+
44
+ @params[:regexp] =
45
+ Gecode::Constraints::Util::Extensional.parse_regexp regexp
46
+ @params.update Gecode::Constraints::Util.decode_options(options)
47
+ @model.add_constraint Extensional::RegexpConstraint.new(@model, @params)
48
+ end
28
49
  end
29
50
 
30
51
  # A module that gathers the classes and modules used in extensional
@@ -60,5 +81,32 @@ module Gecode::Constraints::BoolEnum
60
81
  *propagation_options)
61
82
  end
62
83
  end
84
+
85
+ # Describes a regexp constraint, which constrains the enumeration of
86
+ # boolean variables to match a specified regexp in the boolean
87
+ # domain. Neither negation nor reification is supported.
88
+ #
89
+ # The regular expressions are specified as described in
90
+ # IntEnum::Extensional::RegexpConstraint but true and false can be
91
+ # used instead of integers.
92
+ #
93
+ # == Example
94
+ #
95
+ # # Constrains the two boolean variables in +bools+ to be false
96
+ # # and true respectively.
97
+ # bools.must.match [false, true]
98
+ #
99
+ # # Constrains the boolean variables in +bools+ to be false,
100
+ # # except for three consecutive variables which should be true
101
+ # # followed by false followed by true.
102
+ # bools.must.match [repeat(false), true, false, true, repeat(false)]]
103
+ #
104
+ class RegexpConstraint < Gecode::Constraints::Constraint
105
+ def post
106
+ lhs, regexp = @params.values_at(:lhs, :regexp)
107
+ Gecode::Raw::extensional(@model.active_space, lhs.to_bool_var_array,
108
+ regexp, *propagation_options)
109
+ end
110
+ end
63
111
  end
64
112
  end
@@ -0,0 +1,101 @@
1
+ module Gecode
2
+ class Model
3
+ # Specifies an integer regexp that matches +regexp+ repeated between
4
+ # +at_least+ and +at_most+ times (inclusive). If +at_most+ is
5
+ # omitted then no upper bound is placed. If both +at_least+ and
6
+ # +at_most+ are omitted then no bounds are placed.
7
+ #
8
+ # See Constraints::IntEnum::Extensional::RegexpConstraint for the
9
+ # allowed syntax of +regexp+.
10
+ def repeat(regexp, at_least = nil, at_most = nil)
11
+ unless at_least.nil? or at_least.kind_of? Fixnum
12
+ raise TypeError,
13
+ "Expected the at_least argument to be a Fixnum, got #{at_least.class}"
14
+ end
15
+ unless at_most.nil? or at_most.kind_of?(Fixnum)
16
+ raise TypeError,
17
+ "Expected the at_most argument to be a Fixnum, got #{at_most.class}"
18
+ end
19
+
20
+ reg = Constraints::Util::Extensional.parse_regexp regexp
21
+ if at_most.nil?
22
+ if at_least.nil?
23
+ reg.send '*'
24
+ else
25
+ reg.send('()', at_least)
26
+ end
27
+ else
28
+ reg.send('()', at_least, at_most)
29
+ end
30
+ end
31
+
32
+ # Matches +regexp+ repeated zero or one time (i.e. like '?' in normal
33
+ # regexps). Produces the same result as calling
34
+ #
35
+ # repeat(regexp, 0, 1)
36
+ def at_most_once(regexp)
37
+ repeat(regexp, 0, 1)
38
+ end
39
+
40
+ # Matches +regexp+ repeated at least one time (i.e. like '+' in normal
41
+ # regexps). Produces the same result as calling
42
+ #
43
+ # repeat(regexp, 1)
44
+ def at_least_once(regexp)
45
+ repeat(regexp, 1)
46
+ end
47
+
48
+ # Matches any of the specified +regexps+.
49
+ def any(*regexps)
50
+ regexps.inject(Gecode::Raw::REG.new) do |result, regexp|
51
+ result | Constraints::Util::Extensional.parse_regexp(regexp)
52
+ end
53
+ end
54
+ end
55
+
56
+ module Constraints::Util::Extensional
57
+ module_function
58
+
59
+ # Parses a regular expression over the integer domain, returning
60
+ # an instance of Gecode::REG .
61
+ #
62
+ # Pseudo-BNF of the integer regexp representation:
63
+ # regexp ::= <Fixnum> | <TrueClass> | <FalseClass> | <Gecode::Raw::REG>
64
+ # | [<regexp>, ...]
65
+ def parse_regexp(regexp)
66
+ # Check the involved types.
67
+ unless regexp.kind_of? Enumerable
68
+ regexp = [regexp]
69
+ end
70
+ regexp.to_a.flatten.each do |element|
71
+ unless element.kind_of?(Fixnum) or element.kind_of?(Gecode::Raw::REG) or
72
+ element.kind_of?(TrueClass) or element.kind_of?(FalseClass)
73
+ raise TypeError,
74
+ "Can't translate #{element.class} into integer or boolean regexp."
75
+ end
76
+ end
77
+
78
+ # Convert it into a regexp.
79
+ internal_parse_regexp(regexp)
80
+ end
81
+
82
+ private
83
+
84
+ # Recursively converts arg into an instance of Gecode::REG. It is
85
+ # assumed that arg is of kind Gecode::Raw::REG, Fixnum, TrueClass,
86
+ # FalseClass or Enumerable.
87
+ def self.internal_parse_regexp(arg)
88
+ case arg
89
+ when Gecode::Raw::REG: arg
90
+ when Fixnum: Gecode::Raw::REG.new(arg)
91
+ when TrueClass: Gecode::Raw::REG.new(1)
92
+ when FalseClass: Gecode::Raw::REG.new(0)
93
+ when Enumerable
94
+ # Recursively convert the elements of the arg.
95
+ arg.inject(Gecode::Raw::REG.new) do |regexp, element|
96
+ regexp += internal_parse_regexp(element)
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -35,19 +35,7 @@ module Gecode::Constraints::Int
35
35
  # set to k then the integer variable takes value i+k exactly
36
36
  # when the variable at index i in the boolean enumration is true
37
37
  # and the rest are false.
38
- def channel(bool_enum, options = {})
39
- unless bool_enum.respond_to? :to_bool_var_array
40
- raise TypeError, 'Expected an enumration of boolean variables, got ' +
41
- "#{bool_enum.class}."
42
- end
43
-
44
- # Just provide commutivity with the boolean enum channel constraint.
45
- if @params[:negate]
46
- bool_enum.must_not.channel(@params[:lhs], options)
47
- else
48
- bool_enum.must.channel(@params[:lhs], options)
49
- end
50
- end
38
+ provide_commutivity(:channel){ |rhs, _| rhs.respond_to? :to_bool_var_array }
51
39
  end
52
40
 
53
41
  # A module that gathers the classes and modules used in channel constraints
@@ -7,23 +7,20 @@ module Gecode::Constraints::IntEnum
7
7
  raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
8
8
  'is not implemented.'
9
9
  end
10
- unless enum.respond_to?(:to_int_var_array) or
11
- enum.respond_to?(:to_set_var_array)
12
- raise TypeError, "Expected int or set enum, got #{enum.class}."
10
+ unless enum.respond_to?(:to_int_var_array)
11
+ raise TypeError, "Expected int enum, got #{enum.class}."
13
12
  end
14
- if enum.respond_to? :to_set_var_array
15
- if options.has_key? :reify
16
- raise ArgumentError, 'The channel constraints does not support the ' +
17
- 'reification option.'
18
- end
19
- @params.update(Gecode::Constraints::Set::Util.decode_options(options))
20
- else
21
- @params.update(Gecode::Constraints::Util.decode_options(options))
13
+ if options.has_key? :reify
14
+ raise ArgumentError, 'The channel constraints does not support the ' +
15
+ 'reification option.'
22
16
  end
23
17
 
18
+ @params.update(Gecode::Constraints::Util.decode_options(options))
24
19
  @params.update(:rhs => enum)
25
20
  @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
26
21
  end
22
+
23
+ provide_commutivity(:channel){ |rhs, _| rhs.respond_to? :to_set_var_array }
27
24
  end
28
25
 
29
26
  # A module that gathers the classes and modules used in channel constraints.
@@ -33,14 +30,12 @@ module Gecode::Constraints::IntEnum
33
30
  # enumeration of set variables. Channel constraints are used to give
34
31
  # access to multiple viewpoints when modelling.
35
32
  #
36
- # When used on two integer enumeration, the channel constraint can be
37
- # thought of as constraining the arrays to be each other's inverses. When
38
- # used with an enumeration of sets the i:th set includes the value of the
39
- # j:th integer.
33
+ # The channel constraint can be thought of as constraining the arrays to
34
+ # be each other's inverses. I.e. if the i:th value in the first enumeration
35
+ # is j, then the j:th value in the second enumeration is constrained to be
36
+ # i.
40
37
  #
41
- # Neither reification nor negation is supported. Selecting strength is only
42
- # supported when using the constraint between two integer enumerations,
43
- # it's not supported when a set enumeration is used.
38
+ # Neither reification nor negation is supported.
44
39
  #
45
40
  # == Example
46
41
  #
@@ -82,26 +77,11 @@ module Gecode::Constraints::IntEnum
82
77
  #
83
78
  # elements.must.channel positions
84
79
  #
85
- # == Example (sets)
86
- #
87
- # # +set_enum+ is constrained to channel +int_enum+.
88
- # int_enum.must.channel set_enum
89
- #
90
- # # This is another way of saying the above.
91
- # set_enum.must.channel int_enum
92
80
  class ChannelConstraint < Gecode::Constraints::Constraint
93
81
  def post
94
82
  lhs, rhs = @params.values_at(:lhs, :rhs)
95
-
96
- lhs = lhs.to_int_var_array
97
- if rhs.respond_to? :to_int_var_array
98
- # Int var array.
99
- Gecode::Raw::channel(@model.active_space, lhs, rhs.to_int_var_array,
100
- *propagation_options)
101
- else
102
- # Set var array, no propagation options.
103
- Gecode::Raw::channel(@model.active_space, lhs, rhs.to_set_var_array)
104
- end
83
+ Gecode::Raw::channel(@model.active_space, lhs.to_int_var_array,
84
+ rhs.to_int_var_array, *propagation_options)
105
85
  end
106
86
  end
107
87
  end
@@ -26,6 +26,27 @@ module Gecode::Constraints::IntEnum
26
26
  @model.add_constraint Extensional::TupleConstraint.new(@model,
27
27
  @params.update(util.decode_options(options)))
28
28
  end
29
+
30
+ # Adds a constraint that forces the enumeration to match the
31
+ # specified regular expression over the integer domain. The regular
32
+ # expression is expressed using arrays and integers. See
33
+ # IntEnum::Extensional::RegexpConstraint for more information and examples of
34
+ # such regexps.
35
+ def match(regexp, options = {})
36
+ if @params[:negate]
37
+ raise Gecode::MissingConstraintError, 'A negated regexp constraint ' +
38
+ 'is not implemented.'
39
+ end
40
+ unless options[:reify].nil?
41
+ raise ArgumentError, 'Reification is not supported by the regexp ' +
42
+ 'constraint.'
43
+ end
44
+
45
+ @params[:regexp] =
46
+ Gecode::Constraints::Util::Extensional.parse_regexp regexp
47
+ @params.update Gecode::Constraints::Util.decode_options(options)
48
+ @model.add_constraint Extensional::RegexpConstraint.new(@model, @params)
49
+ end
29
50
  end
30
51
 
31
52
  # A module that gathers the classes and modules used in extensional
@@ -60,5 +81,114 @@ module Gecode::Constraints::IntEnum
60
81
  *propagation_options)
61
82
  end
62
83
  end
84
+
85
+ # Describes a regexp constraint, which constrains the enumeration of
86
+ # integer variables to match a specified regexp in the integer
87
+ # domain. Neither negation nor reification is supported.
88
+ #
89
+ # == Regexp syntax
90
+ #
91
+ # The regular expressions are specified using arrays, integers and a
92
+ # few methods provided by Model. Arrays are used to group the
93
+ # integers in sequences that must be matched. The following array
94
+ # describes a regular expression matching a 1 followed by a 7.
95
+ #
96
+ # [1, 7]
97
+ #
98
+ # Arrays can be nested or left out when not needed. I.e. the above
99
+ # is semantically equal to
100
+ #
101
+ # [[[1], 7]]
102
+ #
103
+ # A couple of methods provided by Model are used to express patterns
104
+ # beyond mere sequences:
105
+ #
106
+ # [Model#repeat] Used for specifying patterns that include patterns
107
+ # that may be repeated a given number of times. The
108
+ # number of times to repeat a pattern can be specified
109
+ # using a lower and upper bound, but the bounds can be
110
+ # omitted to for instance allow an expression to be
111
+ # repeated any number of times.
112
+ # [Model#any] Used for specifying alternatives.
113
+ #
114
+ # Additionally Model#at_least_once and Model#at_most_once are
115
+ # provided as convenience methods.
116
+ #
117
+ # === Examples
118
+ #
119
+ # # Matches 1 followed by any number of 2s.
120
+ # [1, repeat(2)]
121
+ #
122
+ # # Semantically the same as above. It just has a bunch of
123
+ # # needless brackets thrown in.
124
+ # [[1], [repeat([2])]]
125
+ #
126
+ # # Matches 1 followed by [a 2 followed by a 3] at least two times.
127
+ # # Matches e.g. 1, 2, 3, 2, 3
128
+ # [1, repeat([2, 3], 2)]
129
+ #
130
+ # # Matches between one and two [2 followed by [at least three 1]]
131
+ # # followed by between three and four 3. Matches e.g.
132
+ # # 2, 1, 1, 1, 2, 1, 1, 1, 3, 3, 3
133
+ # [repeat([2, repeat(1, 3], 1, 2), repeat(3, 3, 4)]
134
+ #
135
+ # # Matches [1, 2 or 3] followed by 4. Matches e.g. 2, 4
136
+ # [any(1, 2, 3), 4]
137
+ #
138
+ # # Matches 0 followed by [[1 followed by 2] or [3 followed by 5]].
139
+ # # Matches e.g. 0, 1, 2 as well as 0, 3, 5
140
+ # [0, any([1, 2], [3, 5])]
141
+ #
142
+ # # Matches 0 followed by [[[1 followed by 7] at least two times]
143
+ # # or [[8, 9], at most two times]. Matches e.g.
144
+ # # 0, 1, 7, 1, 7, 1, 7 as well as 0, 8, 9
145
+ # [0, any(repeat([1, 7], 2), repeat([8, 9], 0, 2)]
146
+ #
147
+ # # Matches 0 followed by at least one 1.
148
+ # [0, at_least_once(1)]
149
+ #
150
+ # # Exactly the same as the above.
151
+ # [0, repeat(1, 1)]
152
+ #
153
+ # # Matches 0 followed by at least one [[1 followed by 7] or [3
154
+ # # followed by 2]]. Matches e.g. 0, 1, 7, 3, 2, 1, 7
155
+ # [0, at_least_once(any([1, 7], [3, 2]]
156
+ #
157
+ # # Matches 0 followed by at either [[1 followed by 7] at least once]
158
+ # # or [[3 followed by 2] at least once]. Matches e.g.
159
+ # # 0, 1, 7, 1, 7 but does _not_ match 0, 1, 7, 3, 2, 1, 7
160
+ # [0, any(at_least_once([1, 7]), at_least_once([3, 2])]
161
+ #
162
+ # # Matches 0, followed by at most one 1. Matches 0 as well as
163
+ # # 0, 1
164
+ # [0, at_most_once(1)]
165
+ #
166
+ # # Exactly the same as the above.
167
+ # [0, repeat(1, 0, 1)]
168
+ #
169
+ # == Example
170
+ #
171
+ # # Constrains the two integer variables in +numbers+ to have
172
+ # # values 1 and 7.
173
+ # numbers.must.match [1, 7]
174
+ #
175
+ # # Constrains the integer variables in +numbers+ to contain the
176
+ # # value 47 followed by 11, with all other values set to -1.
177
+ # numbers.must.match [repeat(-1), 47, 11, repeat(-1)]
178
+ #
179
+ # # Constrains exactly three of the integer variables in +numbers+ to
180
+ # # contain 47 or 11, each followed by at least two
181
+ # # variables set to -1. All other variables are constrained to
182
+ # # equal -1.
183
+ # numbers.must.match repeat([repeat(-1), any(11, 47),
184
+ # repeat(-1, 2)], 3, 3)
185
+ #
186
+ class RegexpConstraint < Gecode::Constraints::Constraint
187
+ def post
188
+ lhs, regexp = @params.values_at(:lhs, :regexp)
189
+ Gecode::Raw::extensional(@model.active_space, lhs.to_int_var_array,
190
+ regexp, *propagation_options)
191
+ end
192
+ end
63
193
  end
64
194
  end