I am having some difficulties trying to implement the recursive version of conflict-directed-backjumping algorithm for the rlfa problem (https://miat.inrae.fr/schiex/rlfap.shtml) using aimacode (https://github.com/aimacode/aima-python/blob/master/csp.py).
My code:
class RlfapCSP(CSP):
def __init__(self, variables, domains, neighbors, constraints):
super().__init__(variables, domains, neighbors, constraints)
self.conflicts = {}
self.constraint_pairs = self.get_constraint_pairs()
self.weights = {pair:1 for list in self.constraint_pairs.values() for pair in list}
self.constraints_checked = 0
def get_constraint_pairs(self):
constraint_pairs = {}
for var in self.variables:
constraint_pairs[var] = []
for neighbor in self.neighbors[var]:
constraint_pairs[var].append((var, neighbor))
return constraint_pairs
def forward_checking(csp, var, value, assignment, removals):
"""Prune neighbor values inconsistent with var=value."""
csp.support_pruning()
for B in csp.neighbors[var]:
if B not in assignment:
for b in csp.curr_domains[B][:]:
csp.constraints_checked+=1
if not csp.constraints(var, value, B, b):
csp.prune(B, b, removals)
if B not in csp.conflicts:
csp.conflicts[B] = []
csp.conflicts[B].append(var)
if not csp.curr_domains[B]:
csp.weights[(var, B)] += 1
csp.weights[(B,var)] += 1
if var not in csp.conflicts:
csp.conflicts[var] = []
csp.conflicts[var].extend(csp.conflicts[B])
return False
return True
# search
def backjumping_search(csp, select_unassigned_variable,
order_domain_values, inference):
def backjumping(assignment):
if len(assignment) == len(csp.variables):
return assignment, None
var = select_unassigned_variable(assignment, csp)
for value in order_domain_values(var, assignment, csp):
if 0 == csp.nconflicts(var, value, assignment):
csp.assign(var, value, assignment)
removals = csp.suppose(var, value)
temp_conflicts = csp.conflicts.copy()
if inference(csp, var, value, assignment, removals):
result, last_conflicted_var = backjumping(assignment)
if result is not None:
return result, None
if last_conflicted_var and last_conflicted_var != var:
return None, last_conflicted_var
csp.restore(removals)
csp.conflicts = temp_conflicts.copy()
csp.unassign(var, assignment)
return None, csp.conflicts[var].pop() if var in csp.conflicts else None
result, x = backjumping({})
assert result is None or csp.goal_test(result)
return result, csp.nassigns, csp.constraints_checked
What I have done so far is keep track of the conflicts of each variable and when a value for the current variable cannot be found backjump not to the previous variable, but to the last variable that is in conflict with the current variable. I am using a global conflict set to keep track of the conflicts and I also, when it is time to backjump to the last variable in current variable's conflict set, return this conflict variable with the result.
My best guess is that I am updating the conflict set wrong, but I can't seem to find what exactly it is.