def __init__(self, nodes, edges, cf=lambda x, y: x != y): """ Constructor for VCProblem :param nodes: nodes in the VC-problem :param edges: edges between the nodes in the VC-problem """ self.constraints = {} for from_node, to_node in edges: if from_node not in self.constraints: self.constraints[from_node] = [] self.constraints[from_node].append(to_node) if to_node not in self.constraints: self.constraints[to_node] = [] self.constraints[to_node].append(from_node) self.gac = GAC(csp_state=CSPState(nodes), cnet=self.constraints, cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state self.goal_node = None # TODO: Check for contradiction or solution h = self.heuristic(self.initial_state) if h == 0: log("Found solution for VCProblem after first domain filtering loop" ) print( "Found solution for VCProblem after first domain filtering loop" ) # Should add debug flag here!
def __init__(self, nodes, edges, cf=lambda x, y: x != y): """ Constructor for VCProblem :param nodes: nodes in the VC-problem :param edges: edges between the nodes in the VC-problem """ self.constraints = {} for from_node, to_node in edges: if from_node not in self.constraints: self.constraints[from_node] = [] self.constraints[from_node].append(to_node) if to_node not in self.constraints: self.constraints[to_node] = [] self.constraints[to_node].append(from_node) self.gac = GAC(csp_state=CSPState(nodes), cnet=self.constraints, cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state self.goal_node = None # TODO: Check for contradiction or solution h = self.heuristic(self.initial_state) if h == 0: log("Found solution for VCProblem after first domain filtering loop") print("Found solution for VCProblem after first domain filtering loop") # Should add debug flag here!
def __init__(self, path): """ Constructor for the NonogramProblem Will set up the grid and create all nodes with all possible permutations as domains """ self.nodes = {} with open(path) as f: cols, rows = map(int, f.readline().split()) self.grid = [[False] * cols] * rows self.total_rows = rows self.total_cols = cols r_reversed = [] for row in range(rows): r_reversed.append(list(map(int, f.readline().split()))) for row, counts in enumerate(reversed(r_reversed)): self.nodes[row] = [(row, p) for p in self.gen_patterns(counts, cols)] for col in range(cols): counts = list(map(int, f.readline().split())) self.nodes[rows + col] = [ (col, p) for p in self.gen_patterns(counts, rows) ] if DEBUG: for x in range(rows + cols): print(self.nodes[x]) self.constraints = {} self.generate_constraints() def cf(a, b): r, domain_a = a c, domain_b = b return domain_a[c] == domain_b[r] self.gac = GAC(cnet=self.constraints, csp_state=CSPState(self.nodes), cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state log('NonogramProblem initialized with %dx%d grid' % (rows, cols))
def __init__(self, path): """ Constructor for the NonogramProblem Will set up the grid and create all nodes with all possible permutations as domains """ self.nodes = {} with open(path) as f: cols, rows = map(int, f.readline().split()) self.grid = [[False]*cols]*rows self.total_rows = rows self.total_cols = cols r_reversed = [] for row in range(rows): r_reversed.append(list(map(int, f.readline().split()))) for row, counts in enumerate(reversed(r_reversed)): self.nodes[row] = [(row, p) for p in self.gen_patterns(counts, cols)] for col in range(cols): counts = list(map(int, f.readline().split())) self.nodes[rows + col] = [(col, p) for p in self.gen_patterns(counts, rows)] if DEBUG: for x in range(rows + cols): print(self.nodes[x]) self.constraints = {} self.generate_constraints() def cf(a, b): r, domain_a = a c, domain_b = b return domain_a[c] == domain_b[r] self.gac = GAC(cnet=self.constraints, csp_state=CSPState(self.nodes), cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state log('NonogramProblem initialized with %dx%d grid' % (rows, cols))
class NonogramProblem(AStarProblem): def __init__(self, path): """ Constructor for the NonogramProblem Will set up the grid and create all nodes with all possible permutations as domains """ self.nodes = {} with open(path) as f: cols, rows = map(int, f.readline().split()) self.grid = [[False]*cols]*rows self.total_rows = rows self.total_cols = cols r_reversed = [] for row in range(rows): r_reversed.append(list(map(int, f.readline().split()))) for row, counts in enumerate(reversed(r_reversed)): self.nodes[row] = [(row, p) for p in self.gen_patterns(counts, cols)] for col in range(cols): counts = list(map(int, f.readline().split())) self.nodes[rows + col] = [(col, p) for p in self.gen_patterns(counts, rows)] if DEBUG: for x in range(rows + cols): print(self.nodes[x]) self.constraints = {} self.generate_constraints() def cf(a, b): r, domain_a = a c, domain_b = b return domain_a[c] == domain_b[r] self.gac = GAC(cnet=self.constraints, csp_state=CSPState(self.nodes), cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state log('NonogramProblem initialized with %dx%d grid' % (rows, cols)) @staticmethod def gen_patterns(counts, cols): """ Generates pattern permutations for a given number of segments :param counts: A sequence of segment sizes :param cols: The number of columns in the matrix :return: A pattern matrix """ if len(counts) == 0: return [[False for i in range(cols)]] permutations = [] for start in range(cols - counts[0] + 1): permutation = [] permutation.extend([False for i in range(start)]) permutation.extend([True for i in range(start, start + counts[0])]) x = start + counts[0] if x < cols: permutation.append(False) x += 1 if x == cols and len(counts) == 0: permutations.append(permutation) break sub_start = x sub_rows = NonogramProblem.gen_patterns(counts[1:len(counts)], cols - sub_start) for sub_row in sub_rows: sub_permutation = deepcopy(permutation) sub_permutation.extend([sub_row[x - sub_start] for x in range(sub_start, cols)]) permutations.append(sub_permutation) return permutations def generate_constraints(self): """ Generates constraint network for the problem In this problem it is implemented as a dictionary with a given row/col index as a key The respective value is a list with the index for all possible rows/columns the row/col has constraints against More specific this means a list of all intersecting cells between a row and a column. """ for row in range(self.total_rows): self.constraints[row] = [i for i in range(self.total_rows, self.total_rows + self.total_cols)] for col in range(self.total_cols): self.constraints[self.total_rows + col] = [i for i in range(0, self.total_rows)] def get_start_node(self): """ Returns the start node for this problem instance :return: the initial state in this specific problem """ return self.initial_state def heuristic(self, astar_state): """ Calculates the heuristic for a given state In this problem the heuristic is calculated from the sum of all domains in the variables list :param astar_state: The state to calculate h for :return: The h value """ h = sum((len(domains) - 1) for domains in astar_state.state.nodes.values()) if h == 0: astar_state.is_goal = True astar_state.h = h return h def arc_cost(self, node): """ Returns the arc cost for a given node :param node: The node to get arc cost for :return: The arc cost, 1 in this implementation """ return 1 def get_goal_node(self): """ Returns the goal node for the problem instance Not implemented for this problem :return: None in this instance """ return None def get_all_successor_nodes(self, astar_state): """ Fetches all successor nodes from a given CSP state In this spesific problem that means all states with a domain length greater than 1 for a random node :return: The generated successor nodes """ csp_state = astar_state.state successor_nodes = [] for node, domains in csp_state.nodes.items(): if len(domains) > 1: for d in range(len(domains)): child_state = deepcopy(csp_state) child_state.nodes[node] = [list(domains)[d]] if DEBUG: print("Domain for %s is now %s" % (node, str(child_state.nodes[node]))) self.gac.csp_state = child_state self.gac.run_again(node) if not child_state.contradiction: astar_state = AStarState() astar_state.state = child_state successor_nodes.append(astar_state) return successor_nodes def get_node(self, x, y): """ Returnes a given node in the grid representation It used the x and y coordinates to achieve this :param x: x-coordinate :param y: y-coordinate :return: """ a = AStarState(index=0, x=x, y=y) a.state = self.grid[y][x] return a
class VCProblem(AStarProblem): def __init__(self, nodes, edges, cf=lambda x, y: x != y): """ Constructor for VCProblem :param nodes: nodes in the VC-problem :param edges: edges between the nodes in the VC-problem """ self.constraints = {} for from_node, to_node in edges: if from_node not in self.constraints: self.constraints[from_node] = [] self.constraints[from_node].append(to_node) if to_node not in self.constraints: self.constraints[to_node] = [] self.constraints[to_node].append(from_node) self.gac = GAC(csp_state=CSPState(nodes), cnet=self.constraints, cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state self.goal_node = None # TODO: Check for contradiction or solution h = self.heuristic(self.initial_state) if h == 0: log("Found solution for VCProblem after first domain filtering loop") print("Found solution for VCProblem after first domain filtering loop") # Should add debug flag here! def get_start_node(self): """ Get the initital state (start node) for this specific problem :return: The state """ return self.initial_state def get_goal_node(self): """ Get the final state for this problem, if and only if it exists :return: The state """ return self.goal_node def get_all_successor_nodes(self, astar_state): """ Fetches all successor nodes from a given CSP state In this spesific problem that means all states with a domain length greater than 1 for a random node :return: The generated successor nodes """ csp_state = astar_state.state successor_nodes = [] for node, domains in csp_state.nodes.items(): if len(domains) > 1: for d in range(len(domains)): child_state = deepcopy(csp_state) child_state.nodes[node] = {list(domains)[d]} if DEBUG: print("Domain for %s is now %s" % (node, str(child_state.nodes[node]))) self.gac.csp_state = child_state self.gac.run_again(node) if not child_state.contradiction: astar_state = AStarState() astar_state.state = child_state successor_nodes.append(astar_state) return successor_nodes def heuristic(self, astar_state): """" From the problem description: A simple heuristic involves calculating the size of each domain minus one, then summing all those values to produce a very rough estimate of the distance to the goal. Devising a good, and admissible, heuristic, is more of a challenge, since it is very hard to estimate the extent of domain reduction incurred by any run of the Domain-filtering loop. :param: The state to calculate the heuristic on :return: The heuristic for the given state """ h = sum((len(domains) - 1) for domains in astar_state.state.nodes.values()) if h == 0: self.goal_node = astar_state astar_state.is_goal = True if DEBUG: print("Heuristic for %s is %d" % (astar_state, h)) astar_state.h = h return h def arc_cost(self, astar_state): """ Returns the arc cost for a given state. Always returning 1 in this problem :param astar_state: The state to calculate on :return: The calculated arc cost """ return 1
class VCProblem(AStarProblem): def __init__(self, nodes, edges, cf=lambda x, y: x != y): """ Constructor for VCProblem :param nodes: nodes in the VC-problem :param edges: edges between the nodes in the VC-problem """ self.constraints = {} for from_node, to_node in edges: if from_node not in self.constraints: self.constraints[from_node] = [] self.constraints[from_node].append(to_node) if to_node not in self.constraints: self.constraints[to_node] = [] self.constraints[to_node].append(from_node) self.gac = GAC(csp_state=CSPState(nodes), cnet=self.constraints, cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state self.goal_node = None # TODO: Check for contradiction or solution h = self.heuristic(self.initial_state) if h == 0: log("Found solution for VCProblem after first domain filtering loop" ) print( "Found solution for VCProblem after first domain filtering loop" ) # Should add debug flag here! def get_start_node(self): """ Get the initital state (start node) for this specific problem :return: The state """ return self.initial_state def get_goal_node(self): """ Get the final state for this problem, if and only if it exists :return: The state """ return self.goal_node def get_all_successor_nodes(self, astar_state): """ Fetches all successor nodes from a given CSP state In this spesific problem that means all states with a domain length greater than 1 for a random node :return: The generated successor nodes """ csp_state = astar_state.state successor_nodes = [] for node, domains in csp_state.nodes.items(): if len(domains) > 1: for d in range(len(domains)): child_state = deepcopy(csp_state) child_state.nodes[node] = {list(domains)[d]} if DEBUG: print("Domain for %s is now %s" % (node, str(child_state.nodes[node]))) self.gac.csp_state = child_state self.gac.run_again(node) if not child_state.contradiction: astar_state = AStarState() astar_state.state = child_state successor_nodes.append(astar_state) return successor_nodes def heuristic(self, astar_state): """" From the problem description: A simple heuristic involves calculating the size of each domain minus one, then summing all those values to produce a very rough estimate of the distance to the goal. Devising a good, and admissible, heuristic, is more of a challenge, since it is very hard to estimate the extent of domain reduction incurred by any run of the Domain-filtering loop. :param: The state to calculate the heuristic on :return: The heuristic for the given state """ h = sum( (len(domains) - 1) for domains in astar_state.state.nodes.values()) if h == 0: self.goal_node = astar_state astar_state.is_goal = True if DEBUG: print("Heuristic for %s is %d" % (astar_state, h)) astar_state.h = h return h def arc_cost(self, astar_state): """ Returns the arc cost for a given state. Always returning 1 in this problem :param astar_state: The state to calculate on :return: The calculated arc cost """ return 1
class NonogramProblem(AStarProblem): def __init__(self, path): """ Constructor for the NonogramProblem Will set up the grid and create all nodes with all possible permutations as domains """ self.nodes = {} with open(path) as f: cols, rows = map(int, f.readline().split()) self.grid = [[False] * cols] * rows self.total_rows = rows self.total_cols = cols r_reversed = [] for row in range(rows): r_reversed.append(list(map(int, f.readline().split()))) for row, counts in enumerate(reversed(r_reversed)): self.nodes[row] = [(row, p) for p in self.gen_patterns(counts, cols)] for col in range(cols): counts = list(map(int, f.readline().split())) self.nodes[rows + col] = [ (col, p) for p in self.gen_patterns(counts, rows) ] if DEBUG: for x in range(rows + cols): print(self.nodes[x]) self.constraints = {} self.generate_constraints() def cf(a, b): r, domain_a = a c, domain_b = b return domain_a[c] == domain_b[r] self.gac = GAC(cnet=self.constraints, csp_state=CSPState(self.nodes), cf=cf) self.gac.initialize() self.gac.domain_filtering_loop() self.initial_state = AStarState() self.initial_state.state = self.gac.csp_state log('NonogramProblem initialized with %dx%d grid' % (rows, cols)) @staticmethod def gen_patterns(counts, cols): """ Generates pattern permutations for a given number of segments :param counts: A sequence of segment sizes :param cols: The number of columns in the matrix :return: A pattern matrix """ if len(counts) == 0: return [[False for i in range(cols)]] permutations = [] for start in range(cols - counts[0] + 1): permutation = [] permutation.extend([False for i in range(start)]) permutation.extend([True for i in range(start, start + counts[0])]) x = start + counts[0] if x < cols: permutation.append(False) x += 1 if x == cols and len(counts) == 0: permutations.append(permutation) break sub_start = x sub_rows = NonogramProblem.gen_patterns(counts[1:len(counts)], cols - sub_start) for sub_row in sub_rows: sub_permutation = deepcopy(permutation) sub_permutation.extend( [sub_row[x - sub_start] for x in range(sub_start, cols)]) permutations.append(sub_permutation) return permutations def generate_constraints(self): """ Generates constraint network for the problem In this problem it is implemented as a dictionary with a given row/col index as a key The respective value is a list with the index for all possible rows/columns the row/col has constraints against More specific this means a list of all intersecting cells between a row and a column. """ for row in range(self.total_rows): self.constraints[row] = [ i for i in range(self.total_rows, self.total_rows + self.total_cols) ] for col in range(self.total_cols): self.constraints[self.total_rows + col] = [i for i in range(0, self.total_rows)] def get_start_node(self): """ Returns the start node for this problem instance :return: the initial state in this specific problem """ return self.initial_state def heuristic(self, astar_state): """ Calculates the heuristic for a given state In this problem the heuristic is calculated from the sum of all domains in the variables list :param astar_state: The state to calculate h for :return: The h value """ h = sum( (len(domains) - 1) for domains in astar_state.state.nodes.values()) if h == 0: astar_state.is_goal = True astar_state.h = h return h def arc_cost(self, node): """ Returns the arc cost for a given node :param node: The node to get arc cost for :return: The arc cost, 1 in this implementation """ return 1 def get_goal_node(self): """ Returns the goal node for the problem instance Not implemented for this problem :return: None in this instance """ return None def get_all_successor_nodes(self, astar_state): """ Fetches all successor nodes from a given CSP state In this spesific problem that means all states with a domain length greater than 1 for a random node :return: The generated successor nodes """ csp_state = astar_state.state successor_nodes = [] for node, domains in csp_state.nodes.items(): if len(domains) > 1: for d in range(len(domains)): child_state = deepcopy(csp_state) child_state.nodes[node] = [list(domains)[d]] if DEBUG: print("Domain for %s is now %s" % (node, str(child_state.nodes[node]))) self.gac.csp_state = child_state self.gac.run_again(node) if not child_state.contradiction: astar_state = AStarState() astar_state.state = child_state successor_nodes.append(astar_state) return successor_nodes def get_node(self, x, y): """ Returnes a given node in the grid representation It used the x and y coordinates to achieve this :param x: x-coordinate :param y: y-coordinate :return: """ a = AStarState(index=0, x=x, y=y) a.state = self.grid[y][x] return a