gecoder-with-gecode 0.8.0-mswin32 → 0.8.1-mswin32

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 CHANGED
@@ -1,8 +1,18 @@
1
+ == Version 0.8.1
2
+ This release adds tuple constraints along with a couple of minor features. It
3
+ also fixes a bug introduced in the previous version.
4
+
5
+ * [#19435] Fixed a bug causing inconsistencies during BAB-search. The bug stopped the send+more=money example from working correctly.
6
+ * Fixed the "raw_bindings" and "sudoku-set" examples, which were broken by the 0.8.0 release.
7
+ * Integers can now be used to specify singleton lower and upper bounds when creating set variables.
8
+ * Added convenience methods Model#maximize! and Model#minimize! for optimizing single variables.
9
+ * Added tuple constraints for enumerations of integer and boolean variables.
10
+
1
11
  == Version 0.8.0
2
12
  This release makes the jump from using Gecode 1.3.1 to using Gecode 2.1.1 .
3
13
  The following changes have been made to the interface as a result of the jump.
4
14
 
5
- * The distinct constraint for sets has been removed.
15
+ * Removed the distinct constraint for sets.
6
16
  * Added the propagation kind option to the non-set constraints.
7
17
 
8
18
  == Version 0.7.1
data/Rakefile CHANGED
@@ -4,10 +4,11 @@ require 'rake/rdoctask'
4
4
  require 'rake/gempackagetask'
5
5
 
6
6
  require 'tasks/all_tasks'
7
- task :default => [:verify_rcov]
7
+ task :default => [:verify_rcov, :example_specs]
8
8
 
9
9
  desc 'Performs the tasks necessary when releasing'
10
- task :release => [:publish_website, :publish_packages, :tag]
10
+ task :release => [:clobber, :verify_rcov, :example_specs, :publish_website,
11
+ :publish_packages, :tag]
11
12
 
12
13
  desc 'Runs all the tests'
13
14
  task :test => :specs
@@ -12,14 +12,16 @@ s, e, n, d, m, o, r, y = (0..7).to_a.map{ |i| letters.at(i) }
12
12
  Gecode::Raw::post(space, (s * 1000 + e * 100 + n * 10 + d +
13
13
  m * 1000 + o * 100 + r * 10 + e).
14
14
  equal(m * 10000 + o * 1000 + n * 100 + e * 10 + y ),
15
- Gecode::Raw::ICL_DEF)
16
- Gecode::Raw::rel(space, s, Gecode::Raw::IRT_NQ, 0, Gecode::Raw::ICL_DEF)
17
- Gecode::Raw::rel(space, m, Gecode::Raw::IRT_NQ, 0, Gecode::Raw::ICL_DEF)
18
- Gecode::Raw::distinct(space, letters, Gecode::Raw::ICL_DEF)
15
+ Gecode::Raw::ICL_DEF, Gecode::Raw::PK_DEF)
16
+ Gecode::Raw::rel(space, s, Gecode::Raw::IRT_NQ, 0, Gecode::Raw::ICL_DEF,
17
+ Gecode::Raw::PK_DEF)
18
+ Gecode::Raw::rel(space, m, Gecode::Raw::IRT_NQ, 0, Gecode::Raw::ICL_DEF,
19
+ Gecode::Raw::PK_DEF)
20
+ Gecode::Raw::distinct(space, letters, Gecode::Raw::ICL_DEF, Gecode::Raw::PK_DEF)
19
21
 
20
22
  # Branching.
21
23
  Gecode::Raw::branch(space, letters,
22
- Gecode::Raw::BVAR_SIZE_MIN, Gecode::Raw::BVAL_MIN)
24
+ Gecode::Raw::INT_VAR_SIZE_MIN, Gecode::Raw::INT_VAL_MIN)
23
25
 
24
26
  # Search
25
27
  COPY_DIST = 16
@@ -61,9 +61,6 @@ class SudokuSet < Gecode::Model
61
61
  @sets[i].must_be.disjoint_with @sets[j]
62
62
  end
63
63
  end
64
- # The above implies that the sets must be distinct (since cardinality 0 is
65
- # not allowed), but we also explicitly add the distinctness constraint.
66
- @sets.must_be.distinct(:size => n)
67
64
 
68
65
  # The sets must intersect in exactly one element with each row column and
69
66
  # block. I.e. an assignable number must be assigned exactly once in each
data/lib/gecode.dll CHANGED
Binary file
@@ -149,7 +149,7 @@ Rust::Bindings::create_bindings Rust::Bindings::LangCxx, "gecode" do |b|
149
149
  enum.add_value "SRT_CMPL"
150
150
  end
151
151
 
152
- ns.add_enum "SetOpType " do |enum|
152
+ ns.add_enum "SetOpType" do |enum|
153
153
  enum.add_value "SOT_UNION"
154
154
  enum.add_value "SOT_DUNION"
155
155
  enum.add_value "SOT_INTER"
@@ -337,6 +337,20 @@ Rust::Bindings::create_bindings Rust::Bindings::LangCxx, "gecode" do |b|
337
337
  klass.add_method "debug"
338
338
  end
339
339
 
340
+ ns.add_cxx_class "TupleSet" do |klass|
341
+ klass.add_constructor
342
+
343
+ klass.add_method "add" do |method|
344
+ method.add_parameter "Gecode::IntArgs", "tuple"
345
+ end
346
+
347
+ klass.add_method "finalize"
348
+
349
+ klass.add_method "finalized", "bool"
350
+
351
+ klass.add_method "tuples", "int"
352
+ end
353
+
340
354
  ns.add_cxx_class "MBranchingDesc" do |klass|
341
355
  klass.bindname = "BranchingDesc"
342
356
  klass.add_constructor
@@ -1207,6 +1221,26 @@ Rust::Bindings::create_bindings Rust::Bindings::LangCxx, "gecode" do |b|
1207
1221
  func.add_parameter "Gecode::PropKind", "pk"
1208
1222
  end
1209
1223
 
1224
+ ns.add_function "extensional", "void" do |func|
1225
+ func.add_parameter "Gecode::MSpace*", "home"
1226
+ func.add_parameter "Gecode::MIntVarArray *", "x" do |param|
1227
+ param.custom_conversion = "*ruby2Gecode_MIntVarArrayPtr(argv[1], 2)->ptr()"
1228
+ end
1229
+ func.add_parameter "Gecode::TupleSet", "t"
1230
+ func.add_parameter "Gecode::IntConLevel", "icl"
1231
+ func.add_parameter "Gecode::PropKind", "pk"
1232
+ end
1233
+
1234
+ ns.add_function "extensional", "void" do |func|
1235
+ func.add_parameter "Gecode::MSpace*", "home"
1236
+ func.add_parameter "Gecode::MBoolVarArray *", "x" do |param|
1237
+ param.custom_conversion = "*ruby2Gecode_MBoolVarArrayPtr(argv[1], 2)->ptr()"
1238
+ end
1239
+ func.add_parameter "Gecode::TupleSet", "t"
1240
+ func.add_parameter "Gecode::IntConLevel", "icl"
1241
+ func.add_parameter "Gecode::PropKind", "pk"
1242
+ end
1243
+
1210
1244
  # ns.add_function "regular", "void" do |func|
1211
1245
  # func.add_parameter "Gecode::MSpace*", "home"
1212
1246
  # func.add_parameter "Gecode::MIntVarArray *", "x" do |param|
@@ -291,15 +291,11 @@ module Gecode
291
291
 
292
292
  private
293
293
 
294
- # Transforms a lub or glb domain given as a range or enumeration into one
295
- # or more parameters that describe the domain to Gecode::Raw::SetVar .
294
+ # Transforms a lub or glb domain given as a fixnum, range or enumeration
295
+ # into one or more parameters that describe the domain to
296
+ # Gecode::Raw::SetVar .
296
297
  def domain_to_args(domain)
297
- if domain.kind_of? Range
298
- return domain.first, domain.last
299
- else
300
- elements = domain.to_a
301
- return Gecode::Raw::IntSet.new(domain, domain.size)
302
- end
298
+ Gecode::Constraints::Util.constant_set_to_int_set(domain)
303
299
  end
304
300
 
305
301
  # Creates a new storage array for bool variables.
@@ -0,0 +1,63 @@
1
+ module Gecode::Constraints::BoolEnum
2
+ class Expression
3
+ # Posts an equality constraint on the variables in the enum.
4
+ def in(tuples, options = {})
5
+ if @params[:negate]
6
+ raise Gecode::MissingConstraintError, 'A negated tuple constraint is ' +
7
+ 'not implemented.'
8
+ end
9
+ unless options[:reify].nil?
10
+ raise ArgumentError, 'Reification is not supported by the tuple ' +
11
+ 'constraint.'
12
+ end
13
+ unless tuples.respond_to?(:each) and
14
+ tuples.all?{ |tuple| tuple.respond_to?(:each) }
15
+ raise TypeError, 'Expected an enumeration with tuples, got ' +
16
+ "#{tuples.class}."
17
+ end
18
+ unless tuples.all?{ |tuple|
19
+ tuple.all?{ |x| x.kind_of?(TrueClass) or x.kind_of?(FalseClass) }}
20
+ raise TypeError, 'All tuples must contain booleans.'
21
+ end
22
+
23
+ @params[:tuples] = tuples
24
+ @model.add_constraint Extensional::TupleConstraint.new(@model,
25
+ @params.update(Gecode::Constraints::Util.decode_options(options)))
26
+ end
27
+ end
28
+
29
+ # A module that gathers the classes and modules used in extensional
30
+ # constraints.
31
+ module Extensional #:nodoc:
32
+ # Describes a tuple constraint, which constrains the variables in an
33
+ # boolean enumeration to be equal to one of the specified tuples. Neither
34
+ # negation nor reification is supported.
35
+ #
36
+ # == Example
37
+ #
38
+ # # Constrains the three boolean variables in +bools+ to either
39
+ # # be true, false, true, or false, false, true.
40
+ # bools.must_be.in [[true, false, true], [false, false, true]]
41
+ #
42
+ # # The same as above, but preferring speed over low memory usage.
43
+ # bools.must_be.in([[true, false, true], [false, false, true]],
44
+ # :kind => :speed)
45
+ class TupleConstraint < Gecode::Constraints::Constraint
46
+ def post
47
+ # Bind lhs.
48
+ lhs = @params[:lhs].to_bool_var_array
49
+
50
+ # Create the tuple set.
51
+ tuple_set = Gecode::Raw::TupleSet.new
52
+ @params[:tuples].each do |tuple|
53
+ tuple_set.add tuple.map{ |b| b ? 1 : 0 }
54
+ end
55
+ tuple_set.finalize
56
+
57
+ # Post the constraint.
58
+ Gecode::Raw::extensional(@model.active_space, lhs, tuple_set,
59
+ *propagation_options)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -3,21 +3,23 @@ module Gecode
3
3
  # Produces an expression that can be handled as if it was a variable
4
4
  # representing the conjunction of all boolean variables in the enumeration.
5
5
  def conjunction
6
- return Gecode::Constraints::BoolEnum::ConjunctionStub.new(
6
+ return Gecode::Constraints::BoolEnum::Relation::ConjunctionStub.new(
7
7
  @model, :lhs => self)
8
8
  end
9
9
 
10
10
  # Produces an expression that can be handled as if it was a variable
11
11
  # representing the disjunction of all boolean variables in the enumeration.
12
12
  def disjunction
13
- return Gecode::Constraints::BoolEnum::DisjunctionStub.new(
13
+ return Gecode::Constraints::BoolEnum::Relation::DisjunctionStub.new(
14
14
  @model, :lhs => self)
15
15
  end
16
16
  end
17
-
17
+ end
18
+
19
+ module Gecode::Constraints::BoolEnum
18
20
  # A module that gathers the classes and modules used by boolean enumeration
19
- # constraints.
20
- module Constraints::BoolEnum
21
+ # relation constraints.
22
+ module Relation #:nodoc:
21
23
  # Describes a CompositeStub for the conjunction constraint, which constrain
22
24
  # the conjunction of all boolean variables in an enumeration.
23
25
  #
@@ -83,4 +85,4 @@ module Gecode
83
85
  end
84
86
  end
85
87
  end
86
- end
88
+ end
@@ -1,8 +1,32 @@
1
- module Gecode
1
+ module Gecode
2
+ module BoolEnumMethods
3
+ include Gecode::Constraints::LeftHandSideMethods
4
+
5
+ private
6
+
7
+ # Produces an expression for the lhs module.
8
+ def expression(params)
9
+ params.update(:lhs => self)
10
+ Constraints::BoolEnum::Expression.new(@model, params)
11
+ end
12
+ end
13
+
2
14
  # A module containing constraints that have enumerations of boolean variables
3
15
  # as left hand side.
4
16
  module Constraints::BoolEnum
17
+ # Expressions with bool enums as left hand sides.
18
+ class Expression < Gecode::Constraints::Expression #:nodoc:
19
+ # Raises TypeError unless the left hand side is a bool enum.
20
+ def initialize(model, params)
21
+ super
22
+
23
+ unless params[:lhs].respond_to? :to_bool_var_array
24
+ raise TypeError, 'Must have bool enum as left hand side.'
25
+ end
26
+ end
27
+ end
5
28
  end
6
29
  end
7
30
 
8
- require 'gecoder/interface/constraints/bool_enum/boolean'
31
+ require 'gecoder/interface/constraints/bool_enum/relation'
32
+ require 'gecoder/interface/constraints/bool_enum/extensional'
@@ -0,0 +1,61 @@
1
+ module Gecode::Constraints::IntEnum
2
+ class Expression
3
+ # Posts an equality constraint on the variables in the enum.
4
+ def in(tuples, options = {})
5
+ if @params[:negate]
6
+ raise Gecode::MissingConstraintError, 'A negated tuple constraint is ' +
7
+ 'not implemented.'
8
+ end
9
+ unless options[:reify].nil?
10
+ raise ArgumentError, 'Reification is not supported by the tuple ' +
11
+ 'constraint.'
12
+ end
13
+ unless tuples.respond_to?(:each) and
14
+ tuples.all?{ |tuple| tuple.respond_to?(:each) }
15
+ raise TypeError, 'Expected an enumeration with tuples, got ' +
16
+ "#{tuples.class}."
17
+ end
18
+ unless tuples.all?{ |tuple| tuple.all?{ |x| x.kind_of? Fixnum }}
19
+ raise TypeError, 'All tuples must contain Fixnum.'
20
+ end
21
+
22
+ @params[:tuples] = tuples
23
+ @model.add_constraint Extensional::TupleConstraint.new(@model,
24
+ @params.update(Gecode::Constraints::Util.decode_options(options)))
25
+ end
26
+ end
27
+
28
+ # A module that gathers the classes and modules used in extensional
29
+ # constraints.
30
+ module Extensional #:nodoc:
31
+ # Describes a tuple constraint, which constrains all the variables in an
32
+ # enumeration of integer variables to be equal to one of the specified
33
+ # tuples. Neither negation nor reification is supported.
34
+ #
35
+ # == Example
36
+ #
37
+ # # Constrains the two integer variables in +numbers+ to either have
38
+ # # values 1 and 7, or values 47 and 11.
39
+ # numbers.must_be.in [[1,7], [47,11]]
40
+ #
41
+ # # The same as above, but preferring speed over low memory usage.
42
+ # numbers.must_be.in([[1,7], [47,11]], :kind => :speed)
43
+ class TupleConstraint < Gecode::Constraints::Constraint
44
+ def post
45
+ # Bind lhs.
46
+ lhs = @params[:lhs].to_int_var_array
47
+
48
+ # Create the tuple set.
49
+ tuple_set = Gecode::Raw::TupleSet.new
50
+ @params[:tuples].each do |tuple|
51
+ tuple_set.add tuple
52
+ end
53
+ tuple_set.finalize
54
+
55
+ # Post the constraint.
56
+ Gecode::Raw::extensional(@model.active_space, lhs, tuple_set,
57
+ *propagation_options)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -35,3 +35,4 @@ require 'gecoder/interface/constraints/int_enum/element'
35
35
  require 'gecoder/interface/constraints/int_enum/count'
36
36
  require 'gecoder/interface/constraints/int_enum/sort'
37
37
  require 'gecoder/interface/constraints/int_enum/arithmetic'
38
+ require 'gecoder/interface/constraints/int_enum/extensional'
@@ -67,11 +67,11 @@ module Gecode
67
67
  end
68
68
 
69
69
  # Creates a set variable with the specified domain for greatest lower bound
70
- # and least upper bound (specified as either a range or enum). If no bounds
71
- # are specified then the empty set is used as greates lower bound and the
72
- # universe as least upper bound. A range for the allowed cardinality of the
73
- # set can also be specified, if none is specified, or nil is given, then the
74
- # default range (anything) will be used. If only a single Fixnum is
70
+ # 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
75
  # specified as cardinality_range then it's used as lower bound.
76
76
  def set_var(glb_domain = [], lub_domain =
77
77
  Gecode::Raw::SetLimits::MIN..Gecode::Raw::SetLimits::MAX,
@@ -220,6 +220,8 @@ module Gecode
220
220
  if glb.kind_of?(Range) and lub.kind_of?(Range)
221
221
  glb.first >= lub.first and glb.last <= lub.last
222
222
  else
223
+ glb = [glb] if glb.kind_of?(Fixnum)
224
+ lub = [lub] if lub.kind_of?(Fixnum)
223
225
  (glb.to_a - lub.to_a).empty?
224
226
  end
225
227
  end
@@ -232,7 +234,8 @@ module Gecode
232
234
  # Retrieves the currently selected space, the one which constraints and
233
235
  # variables should be bound to.
234
236
  def selected_space
235
- @active_space ||= base_space
237
+ return @active_space unless @active_space.nil?
238
+ self.active_space = base_space
236
239
  end
237
240
 
238
241
  # Retrieves the space that should be used for variable creation.
@@ -243,9 +246,28 @@ module Gecode
243
246
  # Refreshes all cached variables. This should be called if the variables
244
247
  # in an existing space were changed.
245
248
  def refresh_variables
249
+ return if @variables.nil?
246
250
  @variables.each do |variable|
247
251
  variable.refresh if variable.cached?
248
252
  end
249
253
  end
254
+
255
+ # Executes any interactions with Gecode still waiting in the queue
256
+ # (emptying the queue) in the process.
257
+ def perform_queued_gecode_interactions
258
+ allow_space_access do
259
+ gecode_interaction_queue.each{ |con| con.call }
260
+ gecode_interaction_queue.clear # Empty the queue.
261
+ end
262
+ end
263
+
264
+ # Switches the active space used (the space from which variables are read
265
+ # and to which constraints are posted). @active_space should never be
266
+ # assigned directly.
267
+ def active_space=(new_space)
268
+ @active_space = new_space
269
+ new_space.refresh
270
+ refresh_variables
271
+ end
250
272
  end
251
273
  end
@@ -6,14 +6,14 @@ module Gecode
6
6
  def solve!
7
7
  space = dfs_engine.next
8
8
  return nil if space.nil?
9
- @active_space = space
9
+ self.active_space = space
10
10
  return self
11
11
  end
12
12
 
13
13
  # Returns to the original state, before any search was made (but propagation
14
14
  # might have been performed). Returns the reset model.
15
15
  def reset!
16
- @active_space = base_space
16
+ self.active_space = base_space
17
17
  return self
18
18
  end
19
19
 
@@ -30,7 +30,9 @@ module Gecode
30
30
  # Yields each solution that the model has.
31
31
  def each_solution(&block)
32
32
  dfs = dfs_engine
33
- while not (@active_space = dfs.next).nil?
33
+ next_solution = nil
34
+ while not (next_solution = dfs.next).nil?
35
+ self.active_space = next_solution
34
36
  yield self
35
37
  end
36
38
  self.reset!
@@ -54,10 +56,10 @@ module Gecode
54
56
 
55
57
  # Set the method used for constrain calls by the BAB-search.
56
58
  Model.constrain_proc = lambda do |home_space, best_space|
57
- @active_space = best_space
59
+ self.active_space = best_space
58
60
  @variable_creation_space = home_space
59
61
  yield(self, self)
60
- @active_space = home_space
62
+ self.active_space = home_space
61
63
  @variable_creation_space = nil
62
64
 
63
65
  perform_queued_gecode_interactions
@@ -74,13 +76,49 @@ module Gecode
74
76
  Model.constrain_proc = nil
75
77
  return nil if result.nil?
76
78
 
77
- # Refresh the solution.
78
- result.refresh
79
- refresh_variables
80
- @active_space = result
79
+ # Switch to the result.
80
+ self.active_space = result
81
81
  return self
82
82
  end
83
83
 
84
+ # Finds the solution that maximizes a given integer variable. The name of
85
+ # the method that accesses the variable from the model should be given. To
86
+ # for instance maximize a variable named "profit", that's accessible through
87
+ # the model, one would use the following.
88
+ #
89
+ # model.maximize! :profit
90
+ #
91
+ # Returns nil if there is no solution.
92
+ def maximize!(var)
93
+ variable = self.method(var).call
94
+ unless variable.kind_of? Gecode::FreeIntVar
95
+ raise ArgumentError.new("Expected integer variable, got #{variable.class}.")
96
+ end
97
+
98
+ optimize! do |model, best_so_far|
99
+ model.method(var).call.must > best_so_far.method(var).call.value
100
+ end
101
+ end
102
+
103
+ # Finds the solution that minimizes a given integer variable. The name of
104
+ # the method that accesses the variable from the model should be given. To
105
+ # for instance minimize a variable named "cost", that's accessible through
106
+ # the model, one would use the following.
107
+ #
108
+ # model.minimize! :cost
109
+ #
110
+ # Returns nil if there is no solution.
111
+ def minimize!(var)
112
+ variable = self.method(var).call
113
+ unless variable.kind_of? Gecode::FreeIntVar
114
+ raise ArgumentError.new("Expected integer variable, got #{variable.class}.")
115
+ end
116
+
117
+ optimize! do |model, best_so_far|
118
+ model.method(var).call.must < best_so_far.method(var).call.value
119
+ end
120
+ end
121
+
84
122
  class <<self
85
123
  # Sets the proc that should be used to handle constrain requests.
86
124
  def constrain_proc=(proc) #:nodoc:
@@ -111,14 +149,5 @@ module Gecode
111
149
  Gecode::Raw::Search::Config::ADAPTIVE_DISTANCE,
112
150
  nil)
113
151
  end
114
-
115
- # Executes any interactions with Gecode still waiting in the queue
116
- # (emptying the queue) in the process.
117
- def perform_queued_gecode_interactions
118
- allow_space_access do
119
- gecode_interaction_queue.each{ |con| con.call }
120
- gecode_interaction_queue.clear # Empty the queue.
121
- end
122
- end
123
152
  end
124
153
  end
@@ -1,4 +1,4 @@
1
1
  module GecodeR
2
2
  # A string representation of the Gecode/R version.
3
- VERSION = '0.8.0'
3
+ VERSION = '0.8.1'
4
4
  end
@@ -17,7 +17,7 @@ end
17
17
 
18
18
  # Expects @stub, which contains the started constraint and @compute_result which
19
19
  # computes whether the left hand side is true or not.
20
- describe 'bool enum constraint', :shared => true do
20
+ describe 'bool enum relation constraint', :shared => true do
21
21
  it 'should handle being constrained to be true' do
22
22
  @stub.must_be.true
23
23
  @model.solve!
@@ -67,7 +67,7 @@ describe 'bool enum constraint', :shared => true do
67
67
  end
68
68
  end
69
69
 
70
- describe Gecode::Constraints::BoolEnum, ' (conjunction)' do
70
+ describe Gecode::Constraints::BoolEnum::Relation, ' (conjunction)' do
71
71
  before do
72
72
  @model = BoolEnumSampleProblem.new
73
73
  @bools = @model.bools
@@ -109,11 +109,11 @@ describe Gecode::Constraints::BoolEnum, ' (conjunction)' do
109
109
  @compute_result = lambda{ @bools.all?{ |b| b.value } }
110
110
  end
111
111
 
112
- it_should_behave_like 'bool enum constraint'
112
+ it_should_behave_like 'bool enum relation constraint'
113
113
  it_should_behave_like 'reifiable constraint'
114
114
  end
115
115
 
116
- describe Gecode::Constraints::BoolEnum, ' (disjunction)' do
116
+ describe Gecode::Constraints::BoolEnum::Relation, ' (disjunction)' do
117
117
  before do
118
118
  @model = BoolEnumSampleProblem.new
119
119
  @bools = @model.bools
@@ -155,6 +155,6 @@ describe Gecode::Constraints::BoolEnum, ' (disjunction)' do
155
155
  @compute_result = lambda{ @bools.any?{ |b| b.value } }
156
156
  end
157
157
 
158
- it_should_behave_like 'bool enum constraint'
158
+ it_should_behave_like 'bool enum relation constraint'
159
159
  it_should_behave_like 'reifiable constraint'
160
160
  end
@@ -17,6 +17,15 @@ describe Gecode::Constraints::IntEnum::Expression do
17
17
  end
18
18
  end
19
19
 
20
+ describe Gecode::Constraints::BoolEnum::Expression do
21
+ it 'should raise error unless lhs is a bool enum' do
22
+ lambda do
23
+ Gecode::Constraints::BoolEnum::Expression.new(Gecode::Model.new,
24
+ :lhs => 'foo', :negate => false)
25
+ end.should raise_error(TypeError)
26
+ end
27
+ end
28
+
20
29
  describe Gecode::Constraints::SetEnum::Expression do
21
30
  it 'should raise error unless lhs is a set enum' do
22
31
  lambda do
@@ -0,0 +1,106 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require File.dirname(__FILE__) + '/constraint_helper'
3
+
4
+ describe Gecode::Constraints::IntEnum::Extensional do
5
+ before do
6
+ @model = Gecode::Model.new
7
+ @tuples = [[1,7], [5,1]]
8
+ @digits = @model.int_var_array(2, 0..9)
9
+ @model.branch_on @digits
10
+
11
+ @invoke_options = lambda do |hash|
12
+ @digits.must_be.in(@tuples, hash)
13
+ @model.solve!
14
+ end
15
+ @expect_options = option_expectation do |strength, kind, reif_var|
16
+ Gecode::Raw.should_receive(:extensional).once.with(
17
+ an_instance_of(Gecode::Raw::Space),
18
+ an_instance_of(Gecode::Raw::IntVarArray),
19
+ an_instance_of(Gecode::Raw::TupleSet), strength, kind)
20
+ end
21
+ end
22
+
23
+ it 'should constrain the domain of all variables' do
24
+ @digits.must_be.in @tuples
25
+
26
+ found_solutions = []
27
+ @model.each_solution do |m|
28
+ found_solutions << @digits.values
29
+ end
30
+
31
+ found_solutions.size.should == 2
32
+ (found_solutions - @tuples).should be_empty
33
+ end
34
+
35
+ it 'should not allow negation' do
36
+ lambda do
37
+ @digits.must_not_be.in @tuples
38
+ end.should raise_error(Gecode::MissingConstraintError)
39
+ end
40
+
41
+ it 'should raise error if the right hand side is not an enumeration' do
42
+ lambda{ @digits.must_be.in 4711 }.should raise_error(TypeError)
43
+ end
44
+
45
+ it 'should raise error if the right hand side does not contain tuples' do
46
+ lambda{ @digits.must_be.in [17, 4711] }.should raise_error(TypeError)
47
+ end
48
+
49
+ it 'should raise error if the right hand side does not contain integer tuples' do
50
+ lambda{ @digits.must_be.in ['hello'] }.should raise_error(TypeError)
51
+ end
52
+
53
+ it_should_behave_like 'non-reifiable constraint'
54
+ end
55
+
56
+ describe Gecode::Constraints::BoolEnum::Extensional do
57
+ before do
58
+ @model = Gecode::Model.new
59
+ @tuples = [[true, false, true], [false, false, true]]
60
+ @bools = @model.bool_var_array(3)
61
+ @model.branch_on @bools
62
+
63
+ @invoke_options = lambda do |hash|
64
+ @bools.must_be.in(@tuples, hash)
65
+ @model.solve!
66
+ end
67
+ @expect_options = option_expectation do |strength, kind, reif_var|
68
+ Gecode::Raw.should_receive(:extensional).once.with(
69
+ an_instance_of(Gecode::Raw::Space),
70
+ an_instance_of(Gecode::Raw::BoolVarArray),
71
+ an_instance_of(Gecode::Raw::TupleSet), strength, kind)
72
+ end
73
+ end
74
+
75
+ it 'should constrain the domain of all variables' do
76
+ @bools.must_be.in @tuples
77
+
78
+ found_solutions = []
79
+ @model.each_solution do |m|
80
+ found_solutions << @bools.values
81
+ end
82
+
83
+ found_solutions.size.should == 2
84
+ (found_solutions - @tuples).should be_empty
85
+ end
86
+
87
+ it 'should not allow negation' do
88
+ lambda do
89
+ @bools.must_not_be.in @tuples
90
+ end.should raise_error(Gecode::MissingConstraintError)
91
+ end
92
+
93
+ it 'should raise error if the right hand side is not an enumeration' do
94
+ lambda{ @bools.must_be.in true }.should raise_error(TypeError)
95
+ end
96
+
97
+ it 'should raise error if the right hand side does not contain tuples' do
98
+ lambda{ @bools.must_be.in [true, false] }.should raise_error(TypeError)
99
+ end
100
+
101
+ it 'should raise error if the right hand side does not contain boolean tuples' do
102
+ lambda{ @bools.must_be.in ['hello'] }.should raise_error(TypeError)
103
+ end
104
+
105
+ it_should_behave_like 'non-reifiable constraint'
106
+ end
data/specs/examples.rb ADDED
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+ require 'open3'
3
+
4
+ # This spec checks that the examples are still working.
5
+ files = Dir["#{File.dirname(__FILE__)}/../example/*.rb"]
6
+ files.delete_if do |file|
7
+ file =~ /example_helper.rb/
8
+ end
9
+
10
+ files.each do |example|
11
+ describe "Example (#{File.basename(example)})" do
12
+ it 'should not output errors' do
13
+ _, _, stderr = Open3.popen3("ruby #{example} 1> /dev/null")
14
+ stderr.gets.should be_nil
15
+ end
16
+ end
17
+ end
data/specs/search.rb CHANGED
@@ -205,6 +205,66 @@ describe Gecode::Model, '(optimization search)' do
205
205
  solution.z.value.should == 25
206
206
  end
207
207
 
208
+ it 'should support maximizing singe variables given as symbols' do
209
+ solution = SampleOptimizationProblem.new.maximize! :z
210
+ solution.should_not be_nil
211
+ solution.x.value.should == 5
212
+ solution.y.value.should == 5
213
+ solution.z.value.should == 25
214
+ end
215
+
216
+ it 'should support maximizing singe variables given as strings' do
217
+ solution = SampleOptimizationProblem.new.maximize! 'z'
218
+ solution.should_not be_nil
219
+ solution.x.value.should == 5
220
+ solution.y.value.should == 5
221
+ solution.z.value.should == 25
222
+ end
223
+
224
+ it 'should raise error if maximize! is given a non-existing method' do
225
+ lambda do
226
+ SampleOptimizationProblem.new.maximize! :does_not_exist
227
+ end.should raise_error(NameError)
228
+ end
229
+
230
+ it 'should raise error if maximize! is given a method that does not return an integer variable' do
231
+ lambda do
232
+ SampleOptimizationProblem.new.maximize! :object_id
233
+ end.should raise_error(ArgumentError)
234
+ end
235
+
236
+ it 'should support minimizing singe variables given as symbols' do
237
+ problem = SampleOptimizationProblem.new
238
+ problem.z.must > 2
239
+ solution = problem.minimize! :x
240
+ solution.should_not be_nil
241
+ solution.x.value.should == 1
242
+ solution.y.value.should == 3
243
+ solution.z.value.should == 3
244
+ end
245
+
246
+ it 'should support minimizing singe variables given as strings' do
247
+ problem = SampleOptimizationProblem.new
248
+ problem.z.must > 2
249
+ solution = problem.minimize! 'x'
250
+ solution.should_not be_nil
251
+ solution.x.value.should == 1
252
+ solution.y.value.should == 3
253
+ solution.z.value.should == 3
254
+ end
255
+
256
+ it 'should raise error if minimize! is given a non-existing method' do
257
+ lambda do
258
+ SampleOptimizationProblem.new.minimize! :does_not_exist
259
+ end.should raise_error(NameError)
260
+ end
261
+
262
+ it 'should raise error if minimize! is given a method that does not return an integer variable' do
263
+ lambda do
264
+ SampleOptimizationProblem.new.minimize! :object_id
265
+ end.should raise_error(ArgumentError)
266
+ end
267
+
208
268
  it 'should not be bothered by garbage collecting' do
209
269
  # This goes through 400+ spaces.
210
270
  solution = SampleOptimizationProblem2.new.optimize! do |model, best_so_far|
data/specs/set_var.rb CHANGED
@@ -47,7 +47,7 @@ end
47
47
  describe Gecode::FreeSetVar, '(assigned)' do
48
48
  before do
49
49
  model = Gecode::Model.new
50
- @var = model.set_var([1], [1])
50
+ @var = model.set_var(1, 1)
51
51
  model.solve!
52
52
  end
53
53
 
@@ -7,6 +7,7 @@ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
7
7
  PKG_FILE_NAME_WITH_GECODE = "#{PKG_NAME_WITH_GECODE}-#{PKG_VERSION}"
8
8
  # The location where the precompiled DLL should be placed.
9
9
  DLL_LOCATION = 'lib/gecode.dll'
10
+ EXT_DIR = 'ext'
10
11
 
11
12
  desc 'Generate RDoc'
12
13
  rd = Rake::RDocTask.new do |rdoc|
@@ -16,14 +17,19 @@ rd = Rake::RDocTask.new do |rdoc|
16
17
  rdoc.rdoc_files.include('README', 'CHANGES', 'LGPL-LICENSE', 'lib/**/*.rb')
17
18
  end
18
19
 
20
+ TMP_DIR = 'doc/tmp/rdoc_dev'
19
21
  desc 'Generate RDoc, ignoring nodoc'
20
- Rake::RDocTask.new(:rdoc_dev) do |rdoc|
22
+ Rake::RDocTask.new(:rdoc_dev => :prepare_rdoc_dev) do |rdoc|
21
23
  rdoc.rdoc_dir = 'doc/output/rdoc_dev'
22
24
  rdoc.options << '--title' << 'Gecode/R Developers RDoc' << '--line-numbers' <<
23
25
  '--inline-source' << '--accessor' << 'delegate'
24
-
26
+
27
+ rdoc.rdoc_files.include("#{TMP_DIR}/**/*.rb")
28
+ end
29
+
30
+ desc 'Copies the files that RDoc should parse, removing #:nodoc:'
31
+ task :prepare_rdoc_dev do
25
32
  # Copy the rdoc and remove all #:nodoc: .
26
- TMP_DIR = 'doc/tmp/rdoc_dev'
27
33
  Dir['lib/**/*.rb'].each do |source_name|
28
34
  destination_name = source_name.sub('lib', TMP_DIR)
29
35
  File.makedirs File.dirname(destination_name)
@@ -33,8 +39,6 @@ Rake::RDocTask.new(:rdoc_dev) do |rdoc|
33
39
  end
34
40
  destination.close
35
41
  end
36
-
37
- rdoc.rdoc_files.include("#{TMP_DIR}/**/*.rb")
38
42
  end
39
43
 
40
44
  spec = Gem::Specification.new do |s|
@@ -122,43 +126,55 @@ end
122
126
  desc 'Removes generated distribution files'
123
127
  task :clobber do
124
128
  rm DLL_LOCATION if File.exists? DLL_LOCATION
129
+ FileList[
130
+ "#{EXT_DIR}/*.o",
131
+ "#{EXT_DIR}/gecode.{cc,hh}",
132
+ "#{EXT_DIR}/Makefile",
133
+ "#{EXT_DIR}/mkmf.log"
134
+ ].to_a.each{ |file| rm file if File.exists? file }
125
135
  end
126
136
 
127
137
  desc 'Publish packages on RubyForge'
128
138
  task :publish_packages => [:publish_gecoder_packages,
129
- :publish_gecoder_with_gecode_packages]
130
-
139
+ :publish_gecoder_with_gecode_packages,
140
+ :publish_gecoder_with_gecode_mswin32_packages]
141
+
142
+ # Files included in the vanilla Gecode/R release.
143
+ vanilla_release_files = [
144
+ "pkg/#{PKG_FILE_NAME}.gem",
145
+ "pkg/#{PKG_FILE_NAME}.tgz",
146
+ "pkg/#{PKG_FILE_NAME}.zip"
147
+ ]
131
148
  desc 'Publish Gecode/R packages on RubyForge'
132
- task :publish_gecoder_packages => [:verify_user, :package] do
133
- release_files = FileList[
134
- "pkg/#{PKG_FILE_NAME}.gem",
135
- "pkg/#{PKG_FILE_NAME}.tgz",
136
- "pkg/#{PKG_FILE_NAME}.zip"
137
- ]
149
+ task :publish_gecoder_packages => [:verify_user] + vanilla_release_files do
138
150
  require 'meta_project'
139
151
  require 'rake/contrib/xforge'
140
152
 
141
153
  Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new(PROJECT_NAME)) do |xf|
142
154
  xf.user_name = ENV['RUBYFORGE_USER']
143
- xf.files = release_files.to_a
155
+ xf.files = vanilla_release_files.to_a
144
156
  xf.release_name = "Gecode/R #{PKG_VERSION}"
157
+ xf.package_name = PKG_NAME
145
158
  end
146
159
  end
147
160
 
161
+ # Files included in the release with Gecode.
162
+ gecode_release_files = [
163
+ "pkg/#{PKG_FILE_NAME_WITH_GECODE}.gem",
164
+ #"pkg/#{PKG_FILE_NAME_WITH_GECODE}.tgz",
165
+ #"pkg/#{PKG_FILE_NAME_WITH_GECODE}.zip",
166
+ "pkg/#{PKG_FILE_NAME_WITH_GECODE}-mswin32.gem"
167
+ ]
148
168
  desc 'Publish Gecode/R with Gecode packages on RubyForge'
149
- task :publish_gecoder_with_gecode_packages => [:verify_user, :package] do
150
- release_files = FileList[
151
- "pkg/#{PKG_FILE_NAME_WITH_GECODE}*.gem",
152
- "pkg/#{PKG_FILE_NAME_WITH_GECODE}*.tgz",
153
- "pkg/#{PKG_FILE_NAME_WITH_GECODE}*.zip"
154
- ]
155
-
169
+ task :publish_gecoder_with_gecode_packages =>
170
+ [:verify_user] + gecode_release_files do
156
171
  require 'meta_project'
157
172
  require 'rake/contrib/xforge'
158
173
 
159
174
  Rake::XForge::Release.new(MetaProject::Project::XForge::RubyForge.new(PROJECT_NAME)) do |xf|
160
175
  xf.user_name = ENV['RUBYFORGE_USER']
161
- xf.files = release_files.to_a
176
+ xf.files = gecode_release_files.to_a
162
177
  xf.release_name = "Gecode/R with Gecode #{PKG_VERSION}"
178
+ xf.package_name = PKG_NAME_WITH_GECODE
163
179
  end
164
180
  end
data/tasks/rcov.rake CHANGED
@@ -3,9 +3,10 @@ require 'spec/rake/verify_rcov'
3
3
 
4
4
  RCOV_DIR = "#{File.dirname(__FILE__)}/../doc/output/coverage"
5
5
 
6
- desc "Run all specs with rcov"
6
+ desc "Run all specs (except examples) with rcov"
7
7
  Spec::Rake::SpecTask.new(:rcov) do |t|
8
8
  t.spec_files = FileList['specs/**/*.rb']
9
+ t.spec_files.exclude 'examples.rb'
9
10
  t.rcov = true
10
11
  t.rcov_opts = ['--exclude examples', '--exclude specs']
11
12
  t.rcov_dir = RCOV_DIR
@@ -14,4 +15,4 @@ end
14
15
  RCov::VerifyTask.new(:verify_rcov => :rcov) do |t|
15
16
  t.threshold = 100.0
16
17
  t.index_html = "#{RCOV_DIR}/index.html"
17
- end
18
+ end
data/tasks/specs.rake CHANGED
@@ -3,13 +3,19 @@ require 'spec/rake/spectask'
3
3
  spec_files = FileList['specs/**/*.rb']
4
4
 
5
5
  desc 'Run all specs'
6
- Spec::Rake::SpecTask.new('specs') do |t|
6
+ Spec::Rake::SpecTask.new(:specs) do |t|
7
7
  t.libs = ['lib']
8
8
  t.spec_files = spec_files
9
9
  end
10
10
 
11
+ desc 'Run specs for the examples'
12
+ Spec::Rake::SpecTask.new(:example_specs) do |t|
13
+ t.libs = ['lib']
14
+ t.spec_files = FileList['specs/examples.rb']
15
+ end
16
+
11
17
  desc 'Generate an rspec html report'
12
- Spec::Rake::SpecTask.new('spec_html') do |t|
18
+ Spec::Rake::SpecTask.new(:spec_html) do |t|
13
19
  t.spec_files = spec_files
14
20
  t.spec_opts = ['--format html:doc/output/rspec.html','--backtrace']
15
- end
21
+ end
data/tasks/svn.rake CHANGED
@@ -2,10 +2,13 @@ require 'lib/gecoder/version'
2
2
 
3
3
  desc "Tag the release in svn"
4
4
  task :tag do
5
- from = `svn info`.match(/Repository Root: (.*)/n)[1] + '/trunk'
6
- to = from.gsub(/trunk/, "tags/gecoder-#{GecodeR::VERSION}")
5
+ base_url = `svn info`.match(/Repository Root: (.*)/n)[1]
6
+ base_url.gsub!('rubyforge', "#{ENV['RUBYFORGE_USER']}@rubyforge")
7
+ from = base_url + '/trunk'
8
+ to = base_url + "/tags/gecoder-#{GecodeR::VERSION}"
9
+ options = "-m \"Tag release Gecode/R #{GecodeR::VERSION}\""
7
10
 
8
11
  puts "Creating tag in SVN"
9
- tag_cmd = "svn cp #{from} #{to} -m \"Tag release Gecode/R #{GecodeR::VERSION}\""
12
+ tag_cmd = "svn cp #{from} #{to} #{options}"
10
13
  `#{tag_cmd}` ; raise "ERROR: #{tag_cmd}" unless $? == 0
11
14
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: gecoder-with-gecode
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.8.0
7
- date: 2008-04-10 00:00:00 +02:00
6
+ version: 0.8.1
7
+ date: 2008-04-20 00:00:00 +02:00
8
8
  summary: Ruby interface to Gecode, an environment for constraint programming.
9
9
  require_paths:
10
10
  - lib
@@ -34,7 +34,8 @@ files:
34
34
  - COPYING
35
35
  - README
36
36
  - LGPL-LICENSE
37
- - lib/gecoder/interface/constraints/bool_enum/boolean.rb
37
+ - lib/gecoder/interface/constraints/bool_enum/extensional.rb
38
+ - lib/gecoder/interface/constraints/bool_enum/relation.rb
38
39
  - lib/gecoder/interface/constraints/set_enum/operation.rb
39
40
  - lib/gecoder/interface/constraints/set_enum/distinct.rb
40
41
  - lib/gecoder/interface/constraints/set_enum/selection.rb
@@ -56,6 +57,7 @@ files:
56
57
  - lib/gecoder/interface/constraints/int_enum/count.rb
57
58
  - lib/gecoder/interface/constraints/int_enum/arithmetic.rb
58
59
  - lib/gecoder/interface/constraints/int_enum/element.rb
60
+ - lib/gecoder/interface/constraints/int_enum/extensional.rb
59
61
  - lib/gecoder/interface/constraints/int_enum_constraints.rb
60
62
  - lib/gecoder/interface/constraints/bool_enum_constraints.rb
61
63
  - lib/gecoder/interface/constraints/set_enum_constraints.rb
@@ -156,7 +158,6 @@ files:
156
158
  - tasks/dependencies.txt
157
159
  - specs/constraints
158
160
  - specs/constraints/boolean.rb
159
- - specs/constraints/bool_enum.rb
160
161
  - specs/constraints/int_domain.rb
161
162
  - specs/constraints/distinct.rb
162
163
  - specs/constraints/set_domain.rb
@@ -176,6 +177,8 @@ files:
176
177
  - specs/constraints/channel.rb
177
178
  - specs/constraints/linear.rb
178
179
  - specs/constraints/set_operation.rb
180
+ - specs/constraints/extensional.rb
181
+ - specs/constraints/bool_enum_relation.rb
179
182
  - specs/branch.rb
180
183
  - specs/model.rb
181
184
  - specs/binding_changes.rb
@@ -188,6 +191,7 @@ files:
188
191
  - specs/enum_matrix.rb
189
192
  - specs/spec_helper.rb
190
193
  - specs/distribution.rb
194
+ - specs/examples.rb
191
195
  - vendor/gecode/win32/lib/libgecodeint.dll
192
196
  - vendor/gecode/win32/lib/libgecodekernel.dll
193
197
  - vendor/gecode/win32/lib/libgecodeminimodel.dll
@@ -197,7 +201,6 @@ files:
197
201
  - lib/gecode.dll
198
202
  test_files:
199
203
  - specs/constraints/boolean.rb
200
- - specs/constraints/bool_enum.rb
201
204
  - specs/constraints/int_domain.rb
202
205
  - specs/constraints/distinct.rb
203
206
  - specs/constraints/set_domain.rb
@@ -217,6 +220,8 @@ test_files:
217
220
  - specs/constraints/channel.rb
218
221
  - specs/constraints/linear.rb
219
222
  - specs/constraints/set_operation.rb
223
+ - specs/constraints/extensional.rb
224
+ - specs/constraints/bool_enum_relation.rb
220
225
  - specs/branch.rb
221
226
  - specs/model.rb
222
227
  - specs/binding_changes.rb
@@ -229,6 +234,7 @@ test_files:
229
234
  - specs/enum_matrix.rb
230
235
  - specs/spec_helper.rb
231
236
  - specs/distribution.rb
237
+ - specs/examples.rb
232
238
  rdoc_options:
233
239
  - --title
234
240
  - Gecode/R
@@ -242,7 +248,8 @@ extra_rdoc_files:
242
248
  - README
243
249
  - CHANGES
244
250
  - LGPL-LICENSE
245
- - lib/gecoder/interface/constraints/bool_enum/boolean.rb
251
+ - lib/gecoder/interface/constraints/bool_enum/extensional.rb
252
+ - lib/gecoder/interface/constraints/bool_enum/relation.rb
246
253
  - lib/gecoder/interface/constraints/set_enum/operation.rb
247
254
  - lib/gecoder/interface/constraints/set_enum/distinct.rb
248
255
  - lib/gecoder/interface/constraints/set_enum/selection.rb
@@ -264,6 +271,7 @@ extra_rdoc_files:
264
271
  - lib/gecoder/interface/constraints/int_enum/count.rb
265
272
  - lib/gecoder/interface/constraints/int_enum/arithmetic.rb
266
273
  - lib/gecoder/interface/constraints/int_enum/element.rb
274
+ - lib/gecoder/interface/constraints/int_enum/extensional.rb
267
275
  - lib/gecoder/interface/constraints/int_enum_constraints.rb
268
276
  - lib/gecoder/interface/constraints/bool_enum_constraints.rb
269
277
  - lib/gecoder/interface/constraints/set_enum_constraints.rb