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
@@ -0,0 +1,54 @@
1
+ module Gecode::Constraints::Set
2
+ class Expression
3
+ # Adds a channel constraint on the set variable with the specified enum of
4
+ # boolean variables.
5
+ def channel(bool_enum, options = {})
6
+ if @params[:negate]
7
+ raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
8
+ 'is not implemented.'
9
+ end
10
+ if options.has_key? :reify
11
+ raise ArgumentError, 'The channel constraint does not support the ' +
12
+ 'reification option.'
13
+ end
14
+ unless bool_enum.respond_to? :to_bool_var_array
15
+ raise TypeError, 'Expected an enum of bool variables, ' +
16
+ "got #{bool_enum.class}."
17
+ end
18
+
19
+ @params.update(:rhs => bool_enum)
20
+ @params.update Gecode::Constraints::Set::Util.decode_options(options)
21
+ @model.add_constraint Channel::ChannelConstraint.new(@model, @params)
22
+ end
23
+ end
24
+
25
+ # A module that gathers the classes and modules used in channel constraints
26
+ # involving one set variable and a boolean enum.
27
+ module Channel #:nodoc:
28
+ # Describes a channel constraint that "channels" a set variable and an
29
+ # enumerations of boolean variables. This constrains the set variable to
30
+ # include value i exactly when the variable at index i in the boolean
31
+ # enumeration is true.
32
+ #
33
+ # Neither reification nor negation is supported. The boolean enum and set
34
+ # can be interchanged.
35
+ #
36
+ # == Examples
37
+ #
38
+ # # Constrains the enumeration of boolean variables called +bools+ to at
39
+ # # least have the first and third variables set to true
40
+ # set.must_be.superset_of [0, 2]
41
+ # set.must.channel bools
42
+ #
43
+ # # An alternative way of writing the above.
44
+ # set.must_be.superset_of [0, 2]
45
+ # bools.must.channel set
46
+ class ChannelConstraint < Gecode::Constraints::Constraint
47
+ def post
48
+ lhs, rhs = @params.values_at(:lhs, :rhs)
49
+ Gecode::Raw::channel(@model.active_space, rhs.to_bool_var_array,
50
+ lhs.bind)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -2,16 +2,47 @@ module Gecode::Constraints::SetEnum
2
2
  class Expression
3
3
  # Posts a channel constraint on the variables in the enum with the specified
4
4
  # int enum.
5
- def channel(enum)
5
+ def channel(enum, options = {})
6
6
  unless enum.respond_to? :to_int_var_array
7
7
  raise TypeError, "Expected integer variable enum, for #{enum.class}."
8
8
  end
9
-
10
- # Just provide commutativity to the corresponding int enum constraint.
11
9
  if @params[:negate]
12
- enum.must_not.channel(@params[:lhs])
13
- else
14
- enum.must.channel(@params[:lhs])
10
+ raise Gecode::MissingConstraintError, 'A negated channel constraint ' +
11
+ 'is not implemented.'
12
+ end
13
+ if options.has_key? :reify
14
+ raise ArgumentError, 'The channel constraints does not support the ' +
15
+ 'reification option.'
16
+ end
17
+
18
+ @params.update(Gecode::Constraints::Set::Util.decode_options(options))
19
+ @params.update(:rhs => enum)
20
+ @model.add_constraint Channel::IntChannelConstraint.new(@model, @params)
21
+ end
22
+ end
23
+
24
+ # A module that gathers the classes and modules used in channel constraints.
25
+ module Channel #:nodoc:
26
+ # Describes a channel constraint which "channels" one enumeration of
27
+ # integer variables with one enumeration of set variables. The i:th set
28
+ # in the enumeration of set variables is constrainde to includes the value
29
+ # of the j:th integer variable.
30
+ #
31
+ # Neither reification nor negation is supported.
32
+ #
33
+ # == Examples
34
+ #
35
+ # # +set_enum+ is constrained to channel +int_enum+.
36
+ # int_enum.must.channel set_enum
37
+ #
38
+ # # This is another way of saying the above.
39
+ # set_enum.must.channel int_enum
40
+ #
41
+ class IntChannelConstraint < Gecode::Constraints::Constraint
42
+ def post
43
+ lhs, rhs = @params.values_at(:lhs, :rhs)
44
+ Gecode::Raw::channel(@model.active_space, rhs.to_int_var_array,
45
+ lhs.to_set_var_array)
15
46
  end
16
47
  end
17
48
  end
@@ -75,3 +75,4 @@ require 'gecoder/interface/constraints/set/relation'
75
75
  require 'gecoder/interface/constraints/set/cardinality'
76
76
  require 'gecoder/interface/constraints/set/connection'
77
77
  require 'gecoder/interface/constraints/set/operation'
78
+ require 'gecoder/interface/constraints/set/channel'
@@ -1,117 +1,109 @@
1
1
  module Gecode
2
2
  # Model is the base class that all models must inherit from.
3
3
  class Model
4
+ # The largest integer allowed in the domain of an integer variable.
5
+ MAX_INT = Gecode::Raw::IntLimits::MAX
6
+ # The smallest integer allowed in the domain of an integer variable.
7
+ MIN_INT = Gecode::Raw::IntLimits::MIN
8
+
9
+ # The largest integer allowed in the domain of a set variable.
10
+ SET_MAX_INT = Gecode::Raw::SetLimits::MAX
11
+ # The smallest integer allowed in the domain of a set variable.
12
+ SET_MIN_INT = Gecode::Raw::SetLimits::MIN
13
+
14
+ # The largest possible domain for an integer variable.
15
+ LARGEST_INT_DOMAIN = MIN_INT..MAX_INT
16
+ # The largest possible domain, without negative integers, for an
17
+ # integer variable.
18
+ NON_NEGATIVE_INT_DOMAIN = 0..MAX_INT
19
+
20
+ # The largest possible bound for a set variable.
21
+ LARGEST_SET_BOUND = SET_MIN_INT..SET_MAX_INT
22
+
4
23
  # Creates a new integer variable with the specified domain. The domain can
5
24
  # either be a range, a single element, or an enumeration of elements. If no
6
25
  # domain is specified then the largest possible domain is used.
7
- def int_var(domain =
8
- Gecode::Raw::IntLimits::MIN..Gecode::Raw::IntLimits::MAX)
9
- enum = domain_enum(domain)
10
- index = variable_creation_space.new_int_vars(enum).first
11
- FreeIntVar.new(self, index)
26
+ def int_var(domain = LARGEST_INT_DOMAIN)
27
+ args = domain_arguments(domain)
28
+ FreeIntVar.new(self, variable_creation_space.new_int_var(*args))
12
29
  end
13
30
 
14
31
  # Creates an array containing the specified number of integer variables
15
32
  # with the specified domain. The domain can either be a range, a single
16
- # element, or an enumeration of elements.
17
- def int_var_array(count, domain)
18
- enum = domain_enum(domain)
19
- variables = []
20
- variable_creation_space.new_int_vars(enum, count).each do |index|
21
- variables << FreeIntVar.new(self, index)
33
+ # element, or an enumeration of elements. If no domain is specified then
34
+ # the largest possible domain is used.
35
+ def int_var_array(count, domain = LARGEST_INT_DOMAIN)
36
+ args = domain_arguments(domain)
37
+ build_var_array(count) do
38
+ FreeIntVar.new(self, variable_creation_space.new_int_var(*args))
22
39
  end
23
- return wrap_enum(variables)
24
40
  end
25
41
 
26
42
  # Creates a matrix containing the specified number rows and columns of
27
43
  # integer variables with the specified domain. The domain can either be a
28
- # range, a single element, or an enumeration of elements.
29
- def int_var_matrix(row_count, col_count, domain)
30
- enum = domain_enum(domain)
31
- indices = variable_creation_space.new_int_vars(enum, row_count*col_count)
32
- rows = []
33
- row_count.times do |i|
34
- rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
35
- FreeIntVar.new(self, index)
36
- end
44
+ # range, a single element, or an enumeration of elements. If no domain
45
+ # is specified then the largest possible domain is used.
46
+ def int_var_matrix(row_count, col_count, domain = LARGEST_INT_DOMAIN)
47
+ args = domain_arguments(domain)
48
+ build_var_matrix(row_count, col_count) do
49
+ FreeIntVar.new(self, variable_creation_space.new_int_var(*args))
37
50
  end
38
- return wrap_enum(Util::EnumMatrix.rows(rows, false))
39
51
  end
40
52
 
41
53
  # Creates a new boolean variable.
42
54
  def bool_var
43
- index = variable_creation_space.new_bool_vars.first
44
- FreeBoolVar.new(self, index)
55
+ FreeBoolVar.new(self, variable_creation_space.new_bool_var)
45
56
  end
46
57
 
47
58
  # Creates an array containing the specified number of boolean variables.
48
59
  def bool_var_array(count)
49
- variables = []
50
- variable_creation_space.new_bool_vars(count).each do |index|
51
- variables << FreeBoolVar.new(self, index)
60
+ build_var_array(count) do
61
+ FreeBoolVar.new(self, variable_creation_space.new_bool_var)
52
62
  end
53
- return wrap_enum(variables)
54
63
  end
55
64
 
56
65
  # Creates a matrix containing the specified number rows and columns of
57
66
  # boolean variables.
58
67
  def bool_var_matrix(row_count, col_count)
59
- indices = variable_creation_space.new_bool_vars(row_count*col_count)
60
- rows = []
61
- row_count.times do |i|
62
- rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
63
- FreeBoolVar.new(self, index)
64
- end
68
+ build_var_matrix(row_count, col_count) do
69
+ FreeBoolVar.new(self, variable_creation_space.new_bool_var)
65
70
  end
66
- return wrap_enum(Util::EnumMatrix.rows(rows, false))
67
71
  end
68
72
 
69
73
  # Creates a set variable with the specified domain for greatest lower bound
70
74
  # and least upper bound (specified as either a fixnum, range or enum). If
71
- # no bounds are specified then the empty set is used as greates lower bound
72
- # and the universe as least upper bound. A range for the allowed cardinality
73
- # of the set can also be specified, if none is specified, or nil is given,
74
- # then the default range (anything) will be used. If only a single Fixnum is
75
+ # no bounds are specified then the empty set is used as greatest lower
76
+ # bound and the largest possible set as least upper bound.
77
+ #
78
+ # A range for the allowed cardinality of the set can also be
79
+ # specified, if none is specified, or nil is given, then the default
80
+ # range (anything) will be used. If only a single Fixnum is
75
81
  # specified as cardinality_range then it's used as lower bound.
76
- def set_var(glb_domain = [], lub_domain =
77
- Gecode::Raw::SetLimits::MIN..Gecode::Raw::SetLimits::MAX,
82
+ def set_var(glb_domain = [], lub_domain = LARGEST_SET_BOUND,
78
83
  cardinality_range = nil)
79
- check_set_bounds(glb_domain, lub_domain)
80
-
81
- index = variable_creation_space.new_set_vars(glb_domain, lub_domain,
82
- to_set_cardinality_range(cardinality_range)).first
83
- FreeSetVar.new(self, index)
84
+ args = set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
85
+ FreeSetVar.new(self, variable_creation_space.new_set_var(*args))
84
86
  end
85
87
 
86
88
  # Creates an array containing the specified number of set variables. The
87
89
  # parameters beyond count are the same as for #set_var .
88
- def set_var_array(count, glb_domain, lub_domain, cardinality_range = nil)
89
- check_set_bounds(glb_domain, lub_domain)
90
-
91
- variables = []
92
- variable_creation_space.new_set_vars(glb_domain, lub_domain,
93
- to_set_cardinality_range(cardinality_range), count).each do |index|
94
- variables << FreeSetVar.new(self, index)
90
+ def set_var_array(count, glb_domain = [], lub_domain = LARGEST_SET_BOUND,
91
+ cardinality_range = nil)
92
+ args = set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
93
+ build_var_array(count) do
94
+ FreeSetVar.new(self, variable_creation_space.new_set_var(*args))
95
95
  end
96
- return wrap_enum(variables)
97
96
  end
98
97
 
99
98
  # Creates a matrix containing the specified number of rows and columns
100
99
  # filled with set variables. The parameters beyond row and column counts are
101
100
  # the same as for #set_var .
102
- def set_var_matrix(row_count, col_count, glb_domain, lub_domain,
103
- cardinality_range = nil)
104
- check_set_bounds(glb_domain, lub_domain)
105
-
106
- indices = variable_creation_space.new_set_vars(glb_domain, lub_domain,
107
- to_set_cardinality_range(cardinality_range), row_count*col_count)
108
- rows = []
109
- row_count.times do |i|
110
- rows << indices[(i*col_count)...(i.succ*col_count)].map! do |index|
111
- FreeSetVar.new(self, index)
112
- end
101
+ def set_var_matrix(row_count, col_count, glb_domain = [],
102
+ lub_domain = LARGEST_SET_BOUND, cardinality_range = nil)
103
+ args = set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
104
+ build_var_matrix(row_count, col_count) do
105
+ FreeSetVar.new(self, variable_creation_space.new_set_var(*args))
113
106
  end
114
- return wrap_enum(Util::EnumMatrix.rows(rows, false))
115
107
  end
116
108
 
117
109
  # Retrieves the currently used space. Calling this method is only allowed
@@ -176,20 +168,49 @@ module Gecode
176
168
 
177
169
  private
178
170
 
179
- # Returns an enumeration of the specified domain arguments, which can
180
- # either be given as a range, a single number, or an enumerable of elements.
181
- def domain_enum(domain)
171
+ # Creates an array containing the specified number of variables, all
172
+ # constructed using the provided block..
173
+ def build_var_array(count, &block)
174
+ variables = []
175
+ count.times do
176
+ variables << yield
177
+ end
178
+ return wrap_enum(variables)
179
+ end
180
+
181
+ # Creates a matrix containing the specified number rows and columns of
182
+ # variables, all constructed using the provided block.
183
+ def build_var_matrix(row_count, col_count, &block)
184
+ rows = []
185
+ row_count.times do |i|
186
+ row = []
187
+ col_count.times do |j|
188
+ row << yield
189
+ end
190
+ rows << row
191
+ end
192
+ return wrap_enum(Util::EnumMatrix.rows(rows, false))
193
+ end
194
+
195
+ # Returns the array of arguments that correspond to the specified
196
+ # domain when given to Gecode. The domain can be given as a range,
197
+ # a single number, or an enumerable of elements.
198
+ def domain_arguments(domain)
182
199
  if domain.respond_to?(:first) and domain.respond_to?(:last) and
183
200
  domain.respond_to?(:exclude_end?)
184
201
  if domain.exclude_end?
185
- return domain.first..(domain.last - 1)
202
+ return [domain.first, (domain.last - 1)]
186
203
  else
187
- return domain
204
+ return [domain.first, domain.last]
188
205
  end
189
206
  elsif domain.kind_of? Enumerable
190
- return domain
207
+ array = domain.to_a
208
+ return [Gecode::Raw::IntSet.new(array, array.size)]
209
+ elsif domain.kind_of? Fixnum
210
+ return [domain, domain]
191
211
  else
192
- return domain..domain
212
+ raise TypeError, 'The domain must be given as an instance of ' +
213
+ "Enumerable or Fixnum, but #{domain.class} was given."
193
214
  end
194
215
  end
195
216
 
@@ -204,6 +225,21 @@ module Gecode
204
225
  end
205
226
  end
206
227
 
228
+ # Converts the specified set var domain to parameters accepted by
229
+ # Gecode. The bounds can be specified as a fixnum, range or # enum.
230
+ # The parameters are returned as an array.
231
+ def set_bounds_to_parameters(glb_domain, lub_domain, cardinality_range)
232
+ check_set_bounds(glb_domain, lub_domain)
233
+ args = []
234
+ args << Gecode::Constraints::Util.constant_set_to_int_set(glb_domain)
235
+ args << Gecode::Constraints::Util.constant_set_to_int_set(lub_domain)
236
+ card_range = to_set_cardinality_range(cardinality_range)
237
+ if card_range.nil?
238
+ card_range = 0..Gecode::Raw::SetLimits::CARD
239
+ end
240
+ args << card_range.first << card_range.last
241
+ end
242
+
207
243
  # Checks whether the specified greatest lower bound is a subset of least
208
244
  # upper bound. Raises ArgumentError if that is not the case.
209
245
  def check_set_bounds(glb, lub)
@@ -243,15 +279,6 @@ module Gecode
243
279
  @variable_creation_space || selected_space
244
280
  end
245
281
 
246
- # Refreshes all cached variables. This should be called if the variables
247
- # in an existing space were changed.
248
- def refresh_variables
249
- return if @variables.nil?
250
- @variables.each do |variable|
251
- variable.refresh if variable.cached?
252
- end
253
- end
254
-
255
282
  # Executes any interactions with Gecode still waiting in the queue
256
283
  # (emptying the queue) in the process.
257
284
  def perform_queued_gecode_interactions
@@ -266,8 +293,6 @@ module Gecode
266
293
  # assigned directly.
267
294
  def active_space=(new_space)
268
295
  @active_space = new_space
269
- new_space.refresh
270
- refresh_variables
271
296
  end
272
297
  end
273
- end
298
+ end
@@ -8,21 +8,9 @@ module Gecode
8
8
  def initialize(model, index)
9
9
  @model = model
10
10
  @index = index
11
- @bound_space = @bound_var = nil
12
11
  model.track_variable(self)
13
12
  end
14
-
15
- # Checks whether the variable is cached, i.e. whether it needs to be
16
- # rebound after changes to a space.
17
- def cached?
18
- not @bound_space.nil?
19
- end
20
-
21
- # Forces the variable to refresh itself.
22
- def refresh
23
- @bound_space = nil
24
- end
25
-
13
+
26
14
  def inspect
27
15
  if assigned?
28
16
  "#<#{self.class} #{domain}>"
@@ -54,13 +42,7 @@ module Gecode
54
42
  # Binds the int variable to the currently active space of the model,
55
43
  # returning the bound int variable.
56
44
  def bind
57
- space = active_space
58
- unless @bound_space == space
59
- # We have not bound the variable to this space, so we do it now.
60
- @bound = space.method(:#{space_bind_method}).call(@index)
61
- @bound_space = space
62
- end
63
- return @bound
45
+ active_space.method(:#{space_bind_method}).call(@index)
64
46
  end
65
47
 
66
48
  private
@@ -251,4 +233,4 @@ module Gecode
251
233
  end
252
234
  end
253
235
  end
254
- end
236
+ end
@@ -1,4 +1,4 @@
1
1
  module GecodeR
2
2
  # A string representation of the Gecode/R version.
3
- VERSION = '0.8.2'
3
+ VERSION = '0.8.3'
4
4
  end
data/specs/branch.rb CHANGED
@@ -37,6 +37,16 @@ describe Gecode::Model, ' (integer branch)' do
37
37
  @model.solve!.bools.each{ |var| var.should be_assigned }
38
38
  end
39
39
 
40
+ it 'should allow branching on a single integer variable' do
41
+ @model.branch_on @vars.first
42
+ @model.solve!.vars.first.should be_assigned
43
+ end
44
+
45
+ it 'should allow branching on a single boolean variable' do
46
+ @model.branch_on @bools.first
47
+ @model.solve!.bools.first.should be_assigned
48
+ end
49
+
40
50
  supported_var_selectors = {
41
51
  :none => Gecode::Raw::INT_VAR_NONE,
42
52
  :smallest_min => Gecode::Raw::INT_VAR_MIN_MIN,
@@ -120,6 +130,11 @@ describe Gecode::Model, ' (set branch)' do
120
130
  @model.branch_on @sets
121
131
  @model.solve!.sets.each{ |var| var.should be_assigned }
122
132
  end
133
+
134
+ it 'should allow branching on a single set variable' do
135
+ @model.branch_on @sets.first
136
+ @model.solve!.sets.first.should be_assigned
137
+ end
123
138
 
124
139
  supported_var_selectors = {
125
140
  :none => Gecode::Raw::SET_VAR_NONE,
@@ -167,4 +182,4 @@ describe Gecode::Model, ' (set branch)' do
167
182
  @model.branch_on @sets, :foo => 5
168
183
  end.should raise_error(ArgumentError)
169
184
  end
170
- end
185
+ end