lib/gecoder/interface/search.rb in gecoder-0.8.3 vs lib/gecoder/interface/search.rb in gecoder-0.9.0
- old
+ new
@@ -1,35 +1,47 @@
module Gecode
+ # An exception raised when a search failed because there are no
+ # solutions.
+ class NoSolutionError < RuntimeError
+ def initialize #:nodoc:
+ super('No solution could be found.')
+ end
+ end
+
class Model
# Finds the first solution to the modelled problem and updates the variables
- # to that solution. Returns the model if a solution was found, nil
- # otherwise.
+ # to that solution. The found solution is also returned. Raises
+ # Gecode::NoSolutionError if no solution can be found.
def solve!
dfs = dfs_engine
space = dfs.next
@statistics = dfs.statistics
- return nil if space.nil?
+ raise Gecode::NoSolutionError if space.nil?
self.active_space = space
return self
end
- # Returns to the original state, before any search was made (but propagation
- # might have been performed). Returns the reset model.
+ # Returns to the original state, before any search was made (but
+ # propagation might have been performed). Returns the reset model.
def reset!
self.active_space = base_space
@statistics = nil
return self
end
# Yields the first solution (if any) to the block. If no solution is found
# then the block is not used. Returns the result of the block (nil in case
# the block wasn't run).
def solution(&block)
- solution = self.solve!
- res = yield solution unless solution.nil?
- self.reset!
- return res
+ begin
+ solution = self.solve!
+ res = yield solution
+ self.reset!
+ return res
+ rescue Gecode::NoSolutionError
+ return nil
+ end
end
# Yields each solution that the model has.
def each_solution(&block)
dfs = dfs_engine
@@ -42,11 +54,11 @@
self.reset!
end
# Returns search statistics providing various information from Gecode about
# the search that resulted in the model's current variable state. If the
- # model's variables have not undegone any search then nil is returned. The
+ # model's variables have not undergone any search then nil is returned. The
# statistics is a hash with the following keys:
# [:propagations] The number of propagation steps performed.
# [:failures] The number of failed nodes in the search tree.
# [:clones] The number of clones created.
# [:commits] The number of commit operations performed.
@@ -72,11 +84,11 @@
#
# model.optimize! do |model, best_so_far|
# model.price.must < best_so_far.price.val
# end
#
- # Returns nil if there is no solution.
+ # Raises Gecode::NoSolutionError if no solution can be found.
def optimize!(&block)
# Execute constraints.
perform_queued_gecode_interactions
# Set the method used for constrain calls by the BAB-search.
@@ -104,28 +116,28 @@
end
@statistics = bab.statistics
# Reset the method used constrain calls and return the result.
Model.constrain_proc = nil
- return nil if result.nil?
+ raise Gecode::NoSolutionError if result.nil?
# Switch to the result.
self.active_space = result
return self
end
# Finds the solution that maximizes a given integer variable. The name of
# the method that accesses the variable from the model should be given. To
- # for instance maximize a variable named "profit", that's accessible through
- # the model, one would use the following.
+ # for instance maximize a variable named "profit", that's accessible
+ # through the model, one would use the following.
#
# model.maximize! :profit
#
- # Returns nil if there is no solution.
+ # Raises Gecode::NoSolutionError if no solution can be found.
def maximize!(var)
variable = self.method(var).call
- unless variable.kind_of? Gecode::FreeIntVar
+ unless variable.kind_of? Gecode::IntVar
raise ArgumentError.new("Expected integer variable, got #{variable.class}.")
end
optimize! do |model, best_so_far|
model.method(var).call.must > best_so_far.method(var).call.value
@@ -137,13 +149,13 @@
# for instance minimize a variable named "cost", that's accessible through
# the model, one would use the following.
#
# model.minimize! :cost
#
- # Returns nil if there is no solution.
+ # Raises Gecode::NoSolutionError if no solution can be found.
def minimize!(var)
variable = self.method(var).call
- unless variable.kind_of? Gecode::FreeIntVar
+ unless variable.kind_of? Gecode::IntVar
raise ArgumentError.new("Expected integer variable, got #{variable.class}.")
end
optimize! do |model, best_so_far|
model.method(var).call.must < best_so_far.method(var).call.value