Recursive implementation of Conflict-Directed-Backjumping algorithm

61 views Asked by At

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.

0

There are 0 answers