Class | ConstraintSolver::ConstraintSolver |
In: |
lib/ConstraintSolver.rb
|
Parent: | Object |
log | [R] |
Attempts to solve the constraint satisfaction problem and returns a list of all solutions. If there are no solutions, an empty list is returned. Requires the problem to solve as an argument.
# File lib/ConstraintSolver.rb, line 21 def solve(problem) @problem = problem @constraintChecks = 0 @nodeChecks = 0 @solutions = Array.new assignNextVariable(@problem.variables.sort { |a,b| b.merit <=> a.merit }) return @solutions, @nodeChecks, @constraintChecks end
Attempts to assign a value that is consistent with all constraints to the next variable. Returns true iff a solution to the constraint satisfaction problem was found; i.e. before the call there was only one unassigned variable and a value that is consistent with all constraints was found in its domain. This method calls itself recursively if not all variables have values assigned to them.
# File lib/ConstraintSolver.rb, line 38 def assignNextVariable(variables) retval = false unassigned = variables.first values = unassigned.domain.sort { |a,b| (@problem.meritMap.has_key?(b) ? @problem.meritMap[b] : 0) <=> (@problem.meritMap.has_key?(a) ? @problem.meritMap[a] : 0) } values.each { |value| unassigned.value = value @nodeChecks += 1 @log.debug("Checking node " + unassigned.to_s) revisedDomains, wipeout = reviseConstraints(unassigned) if not wipeout # if a domain was wiped out we can skip the rest of the subtree if variables.size == 1 solution = Solution.new(@problem.variables, @problem.meritMap) @log.info("Found solution " + solution.to_s) @solutions << solution retval = true else retval = assignNextVariable(variables.rest) end end revisedDomains.each { |domain| domain.undoPruning } #break if retval } unassigned.reset return retval end
Revises all constraints that involve variable. Returns the list of domains that have been revised and a boolean indicating whether a domain was wiped out during pruning.
# File lib/ConstraintSolver.rb, line 70 def reviseConstraints(variable) revisedDomains = Array.new wipeout = false queue = @problem.constraints.notAllAssignedWithVariable(variable) begin while not queue.empty? revisedConstraint = queue.shift @log.debug("Revising constraint " + revisedConstraint.to_s) revisedVariables, checks = revisedConstraint.revise @constraintChecks += checks revisedVariables.each { |variable| revisedDomains << variable.domain @problem.constraints.notAllAssignedWithVariable(variable).each { |constraint| queue << constraint unless queue.include?(constraint) or constraint == revisedConstraint } } end rescue DomainWipeoutException wipeout = true end return revisedDomains, wipeout end