def main(argv: List[str]) -> None: size: int = 0 try: opts: List[Tuple[str, str]] args: List[str] opts, args = getopt.getopt(argv, 'hs:', ['size=']) except getopt.GetoptError: print('queens.py -s <size>') sys.exit(2) opt: str arg: str for opt, arg in opts: if opt == '-h': print('queens.py -s <size>') sys.exit(2) elif opt in ('-s', '--size'): try: size = int(arg) except ValueError: print('Error: size must be int. queens.py -s <size>') sys.exit(2) columns: List[int] = list(range(size)) rows: Dict[int, List[int]] = {} for column in columns: rows[column] = list(range(size)) csp: CSP[int, int] = CSP(columns, rows) for i in range(len(columns) - 1): for j in range(i + 1, len(columns)): csp.add_constraint(QueenArcConstraint(i, j)) min_conflict: MinConflict[int, int] = MinConflict( csp, State[int, int]({i: 0 for i in range(size)}), 1000) solution, steps = min_conflict.solve() if solution is None: print("No solution found!") else: print(solution.assignment)
def create_n_queens_csp(n=8): """Create an N-Queen problem on the board of size n * n. You should call csp.add_variable() and csp.add_binary_factor(). Args: n: int, number of queens, or the size of one dimension of the board. Returns csp: A CSP problem with correctly configured factor tables such that it can be solved by a weighted CSP solver """ csp = CSP() # TODO: Problem a # TODO: BEGIN_YOUR_CODE for i in range(n): csp.add_variable('Q' + str(i), list(range(n))) # the position of a queen in each row (from 0 to n-1) for i in range(n-1): for j in range(i+1, n): csp.add_binary_factor('Q' + str(i), 'Q' + str(j), lambda x, y: x != y) csp.add_binary_factor('Q' + str(i), 'Q' + str(j), lambda x, y: abs(x-y) != abs(j-i)) # TODO: END_YOUR_CODE return csp
def nQueens(n, tableCnstr): '''Return an n-queens CSP, optionally use tableContraints''' i = 0 dom = [] for i in range(n): dom.append(i+1) vars = [] for i in dom: vars.append(Variable('Q{}'.format(i), dom)) cons = [] for qi in range(len(dom)): for qj in range(qi+1, len(dom)): if tableCnstr: con = QueensTableConstraint("C(Q{},Q{})".format(qi+1,qj+1), vars[qi], vars[qj], qi+1, qj+1) else: con = QueensConstraint("C(Q{},Q{})".format(qi+1,qj+1), vars[qi], vars[qj], qi+1, qj+1) cons.append(con) csp = CSP("{}-Queens".format(n), vars, cons) return csp
def scheduling(courses, faculties, times, rooms, assigned_faculty): domains = {} # to append all possible courses' cases to domains for course in courses: domains[course] = list() for faculty in faculties: for time in times: for room in rooms: domains[course].append([faculty, time, room]) # Pairing two courses each. neighbors = parse_neighbors( """cs108: cs112; cs112: cs212; cs212: cs214; cs214: cs384; cs384: cs232; cs232: cs344; cs344: cs108""", courses) for type in [courses]: for A in type: for B in type: if A != B: if B not in neighbors[A]: neighbors[A].append(B) if A not in neighbors[B]: neighbors[B].append(A) def scheduling_constraint(A, a, B, b, recurse=0): # each course should be offered exactly once by the assigned faculty member. if assigned_faculty[A] != a[0] and assigned_faculty[B] != b[0]: return False # a faculty member can only teach one thing at a time. if a[0] == b[0] and a[1] == b[1]: return False # a room can only have one class at each time. if a[1] == b[1] and a[2] == b[2]: return False return True return CSP(courses, domains, neighbors, scheduling_constraint)
def main(): GRID_SIZE = 9 CB = CircuitBoard(GRID_SIZE) boxes = ( # From Book "44", "33", "22", "61", "25", # More Squares "31", "17", "23", "11", "41", "32", "51", "14", # 9x9 area is full ) locations = {} for box in boxes: locations[box] = CB.generate_domain(int(box[0]), int(box[1])) csp = CSP(boxes, locations) csp.add_constraint(CircuitBoardConstraint(boxes)) solution = csp.backtracking_search() if solution is None: print("No Solution Found") else: for box, grid_locations in solution.items(): print( f"Box: {box}," f"Grid Location: {[gl.__str__() for gl in grid_locations]}," f"Area: {len(grid_locations)}\n" ) print_grid(solution, GRID_SIZE)
def create_n_queens_csp(n=8): """Create an N-Queen problem on the board of size n * n. You should call csp.add_variable() and csp.add_binary_factor(). Args: n: int, number of queens, or the size of one dimension of the board. Returns csp: A CSP problem with correctly configured factor tables such that it can be solved by a weighted CSP solver """ csp = CSP() # TODO: Problem a # TODO: BEGIN_YOUR_CODE vars = [] for i in range(1, n + 1): # we suppose that on a board, we put in queens with order. # In other words, Xi is fixed for each queen, # we only have to consider Yi for each queen varName = 'Y' + str(i) csp.add_variable(varName, range(1, n + 1)) vars.append(varName) rule1 = lambda x, y: x != y for var in vars: for anotherVar in vars: if var != anotherVar: # csp.add_binary_factor(var, anotherVar, lambda y1, y2: y1 != y2) dist = abs(vars.index(anotherVar) - vars.index(var)) csp.add_binary_factor( var, anotherVar, lambda y1, y2: y1 != y2 and abs(y1 - y2) != dist) # raise NotImplementedError # TODO: END_YOUR_CODE return csp
def nQueens(n, model): '''Return an n-queens CSP, optionally use tableContraints''' #your implementation for Question 4 changes this function #implement handling of model == 'alldiff' if not model in ['table', 'alldiff', 'row']: print("Error wrong sudoku model specified {}. Must be one of {}").format( model, ['table', 'alldiff', 'row']) i = 0 dom = [] for i in range(n): dom.append(i+1) vars = [] for i in dom: vars.append(Variable('Q{}'.format(i), dom)) cons = [] if model == 'alldiff': for qi in range(len(dom)): for qj in range(qi+1, len(dom)): con = NeqConstraint("C(Q{},Q{})".format(qi+1,qj+1), [vars[qi], vars[qj]], qi+1, qj+1) cons.append(con) cons.append(AllDiffConstraint("C(Q{})".format(n),vars)) else: constructor = QueensTableConstraint if model == 'table' else QueensConstraint for qi in range(len(dom)): for qj in range(qi+1, len(dom)): con = constructor("C(Q{},Q{})".format(qi+1,qj+1), vars[qi], vars[qj], qi+1, qj+1) cons.append(con) csp = CSP("{}-Queens".format(n), vars, cons) return csp
def ClassSchedulingCSP(): """Queens problem for the class scheduling problem. I've used the classes as the variables and combinations of time, professor, and classroom as the domains for each variable. The constraints are that no prof can teach two classes at the same time, no class can be in the same room at the same time as another class, and each course should be offered exactly once. """ """Initialize data structures for the class scheduling problem.""" classes = ['CS108', 'CS112', 'CS214', 'CS212', 'CS232', 'CS344'] faculty = ['dschuurman', 'kvlinden', 'adams', 'norman'] time_slots = ['mwf900', 'mwf1030', 'tth900', 'tth1030'] classrooms = ['nh253', 'sb382'] combination = [faculty, time_slots, classrooms] variables = classes domain = list(itertools.product(*combination)) domains = {} neighbors = {} for var in variables: domains[var] = domain neighbors[var] = [x for x in variables if x != var] def constraints(A, a, B, b): # check if it's the same time if a[1] == b[1]: # check if profs are the same if a[0] == b[0]: return False # check if rooms are the same elif a[2] == b[2]: return False else: return True else: return True return CSP(variables, domains, neighbors, constraints)
def min_conflict_solve(): req_data = request.get_json() k: int = req_data['k'] init_state: List[int] = req_data['initState'] iteration: int = req_data['iteration'] columns: List[int] = list(range(k)) rows: Dict[int, List[int]] = {} for column in columns: rows[column] = list(range(k)) csp: CSP[int, int] = CSP(columns, rows) for i in range(len(columns) - 1): for j in range(i + 1, len(columns)): csp.add_constraint(QueenArcConstraint(i, j)) min_conflict: MinConflict[int, int] = MinConflict( csp, State[int, int]({i: x for i, x in enumerate(init_state)}), iteration) solution, steps, time = min_conflict.solve() response = app.response_class(response=json.dumps({ "steps": steps, "time": time }), status=200, mimetype='application/json') return response
def run_experiment(): kenken = KenKen(6, difficult) csp = CSP() csp.solve(kenken) print('RESULTS of AC3 Only') csp.print_solution() print('\nNow, try searching to reduce domains') A1domain = csp.variables['A1'].domain A2domain = csp.variables['A2'].domain A3domain = csp.variables['A3'].domain for i in A1domain: kenken.variables['A1'].domain = [i] kenken.variables['A2'].domain = A2domain kenken.variables['A3'].domain = A3domain answer = csp.solve(kenken) if answer == None: print('A1=', i, ' No Solution Found.') continue for j in A2domain: kenken.variables['A2'].domain = [j] kenken.variables['A3'].domain = A3domain answer = csp.solve(kenken) if answer == None: print('A1=', i, ' A2=', j, ' No Solution Found.') continue for k in A3domain: kenken.variables['A3'].domain = [k] answer = csp.solve(kenken) if answer == None: print('A1=', i, ' A2=', j, ' A3=', k, ' No Solution Found.') else: # This is a viable combination print('A1=', i, ' A2=', j, ' A3=', k) csp.print_solution() print("\n")
# 모든 변수에 숫자를 할당해서 계싼이 맞는지 확인한다 if len(assignment) == len(self.letters): s: int = assignment["S"] e: int = assignment["E"] n: int = assignment["N"] d: int = assignment["D"] m: int = assignment["M"] o: int = assignment["O"] r: int = assignment["R"] y: int = assignment["Y"] send: int = s * 1000 + e * 100 + n * 10 + d more: int = m * 1000 + o * 100 + r * 10 + e money: int = m * 10000 + o * 1000 + n * 100 + e * 10 + y return send + more == money return True if __name__ == "__main__": letters: List[str] = ["S", "E", "N", "D", "M", "O", "R", "Y"] possible_digits: Dict[str, List[int]] = {} for letter in letters: possible_digits[letter] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] possible_digits["M"] = [1] # 답은 0으로 시작하지 않는다 csp: CSP[str, int] = CSP(letters, possible_digits) csp.add_constraint(SendMoreMoneyConstraint(letters)) solution: Optional[Dict[str, int]] = csp.backtracking_search() if solution is None: print("답을 찾을 수 없습니다") else: print(solution)
def solve_planes(planes_problem, algo, allsolns, variableHeuristic='mrv', silent=False, trace=False): # Your implementation for Question 6 goes here. # # Do not but do not change the functions signature # (the autograder will twig out if you do). # If the silent parameter is set to True # you must ensure that you do not execute any print statements # in this function. # (else the output of the autograder will become confusing). # So if you have any debugging print statements make sure you # only execute them "if not silent". (The autograder will call # this function with silent=True, plane_scheduling.py will call # this function with silent=False) # You can optionally ignore the trace parameter # If you implemented tracing in your FC and GAC implementations # you can set this argument to True for debugging. # # Once you have implemented this function you should be able to # run plane_scheduling.py to solve the test problems (or the autograder). # # '''This function takes a planes_problem (an instance of PlaneProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solutions it constructs a list of lists specifying a schedule for each plane and returns that list of lists The required format is the list of lists is: For each plane P the list of lists contains a list L. L[0] == P (i.e., the first item of the list is the plane) and L[1], ..., L[k] (i.e., L[1:]) is the sequence of flights assigned to P. The returned list of lists should contain a list for every plane. ''' # BUILD your CSP here and store it in the varable csp variables = [] constraints = [] legal_order = [[f1, f2] for f1, f2 in planes_problem.can_follow] legal_order += [[f, 'None'] for f in planes_problem.flights] legal_order += [['None', 'None']] maintenance_flights = [f for f in planes_problem.maintenance_flights] maintenance_flights += ['None'] for p in planes_problem.planes: legal_flights = planes_problem.can_fly(p) domain = [f for f in legal_flights] + ['None'] flight_sequence = [ Variable(p + '_%d' % i, domain) for i in range(1, len(legal_flights)) ] flight_sequence = [ Variable(p + '_0', planes_problem.can_start(p) + ['None']) ] + flight_sequence variables += flight_sequence # Flight order for i in range(0, len(flight_sequence) - 1): f1, f2 = flight_sequence[i], flight_sequence[i + 1] constraints.append( TableConstraint(p + '_order%d' % i, [f1, f2], legal_order)) # Flight maintenance if len(flight_sequence) >= planes_problem.min_maintenance_frequency: for i in range( 0, len(flight_sequence) - planes_problem.min_maintenance_frequency + 1): fs = flight_sequence[i:i + planes_problem.min_maintenance_frequency] constraints.append( NValuesConstraint(p + '_maintenance%d' % i, fs, maintenance_flights, 1, len(flight_sequence))) # Every flight taken for f in planes_problem.flights: constraints.append(NValuesConstraint('flights', variables, [f], 1, 1)) csp = CSP('plane_scheduling', variables, constraints) # invoke search with the passed parameters solutions, num_nodes = bt_search(algo, csp, variableHeuristic, allsolns, trace) # Convert each solution into a list of lists specifying a schedule # for each plane in the format described above. # then return a list containing all converted solutions # (i.e., a list of lists of lists) all_solutions = [] for s_raw in solutions: s = {p: [] for p in planes_problem.planes} for var, f in s_raw: if f == 'None': continue p, order = var.name().split('_') order = int(order) s[p].append((order, f)) s = {p: sorted(s[p]) for p in s} s = [[p] + [f[1] for f in s[p]] for p in s] all_solutions.append(s) return all_solutions
def satisfied(self, assignment: Dict[str, str]) -> bool: # If either place is not in the assignment, then it is not # yet possible for their colors to be conflicting if self.place1 not in assignment or self.place2 not in assignment: return True # check the color assigned to place1 is not the same as the # color assigned to place2 return assignment[self.place1] != assignment[self.place2] if __name__ == "__main__": variables: List[str] = ["MA", "PI", "CE", "RN", "PB", "PE", "AL", "SE", "BA"] domains: Dict[str, List[str]] = {} for variable in variables: domains[variable] = ["red", "green", "blue"] csp: CSP[str, str] = CSP(variables, domains) csp.add_constraint(MapColoringConstraint("MA", "PI")) csp.add_constraint(MapColoringConstraint("PI", "CE")) csp.add_constraint(MapColoringConstraint("PI", "PE")) csp.add_constraint(MapColoringConstraint("PI", "BA")) csp.add_constraint(MapColoringConstraint("CE", "RN")) csp.add_constraint(MapColoringConstraint("CE", "PB")) csp.add_constraint(MapColoringConstraint("CE", "PE")) csp.add_constraint(MapColoringConstraint("RN", "PB")) csp.add_constraint(MapColoringConstraint("PB", "PE")) csp.add_constraint(MapColoringConstraint("PE", "AL")) csp.add_constraint(MapColoringConstraint("PE", "BA")) csp.add_constraint(MapColoringConstraint("AL", "SE")) csp.add_constraint(MapColoringConstraint("AL", "BA")) csp.add_constraint(MapColoringConstraint("SE", "BA"))
def question_3(): print_title(2) tested[2] = True fails = [False, False, False, False, False, False, False, False] v1 = Variable('V1', [1, 2]) v2 = Variable('V2', [1, 2]) v3 = Variable('V3', [1, 2, 3, 4, 5]) v4 = Variable('V4', [1, 2, 3, 4, 5]) v5 = Variable('V5', [1, 2, 3, 4, 5]) v6 = Variable('V6', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v7 = Variable('V7', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v8 = Variable('V8', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v9 = Variable('V9', [1, 2, 3, 4, 5, 6, 7, 8, 9]) vars = [v1, v2, v3, v4, v5, v6, v7, v8, v9] ac = AllDiffConstraint('test9', vars) testcsp = CSP('test', vars, [ac]) GacEnforce([ac], testcsp, None, None) #v1.pruneValue(1, None, None) test1 = " v1 = Variable('V1', [1, 2])\n\ v2 = Variable('V2', [1, 2])\n\ v3 = Variable('V3', [1, 2, 3, 4, 5])\n\ v4 = Variable('V4', [1, 2, 3, 4, 5])\n\ v5 = Variable('V5', [1, 2, 3, 4, 5])\n\ v6 = Variable('V6', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v7 = Variable('V7', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v8 = Variable('V8', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v9 = Variable('V9', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ vars = [v1, v2, v3, v4, v5, v6, v7, v8, v9]\n\ ac = AllDiffConstraint('test9', vars)\n\ testcsp = CSP('test', vars, [ac])\n\ GacEnforce([ac], testcsp, None, None)" soln_doms = [ set([1, 2]), set([1, 2]), set([3, 4, 5]), set([3, 4, 5]), set([3, 4, 5]), set([6, 7, 8, 9]), set([6, 7, 8, 9]), set([6, 7, 8, 9]), set([6, 7, 8, 9]) ] for i, v in enumerate(vars): if set(v.curDomain()) != soln_doms[i]: fails[0] = True print "Error: {}.curDomain() == {}".format(v.name(), v.curDomain()) print "Correct curDomin should be == {}".format(list(soln_doms[i])) if fails[0]: print "\nFail Q3 test 1\nErrors were generated on the following code:" print test1 else: print "Pass Q3 test 1" print_sep() v1 = Variable('V1', [1, 2]) v2 = Variable('V2', [1, 2]) v3 = Variable('V3', [1, 2, 3, 4, 5]) v4 = Variable('V4', [1, 2, 3, 4, 5]) v5 = Variable('V5', [1, 2, 3, 4, 5]) v6 = Variable('V6', [1, 3, 4, 5]) v7 = Variable('V7', [1, 3, 4, 5]) ac1 = AllDiffConstraint('1', [v1, v2, v3]) ac2 = AllDiffConstraint('1', [v1, v2, v4]) ac3 = AllDiffConstraint('1', [v1, v2, v5]) ac4 = AllDiffConstraint('1', [v3, v4, v5, v6]) ac5 = AllDiffConstraint('1', [v3, v4, v5, v7]) vars = [v1, v2, v3, v4, v5, v6, v7] cnstrs = [ac1, ac2, ac3, ac4, ac5] testcsp = CSP('test2', vars, cnstrs) GacEnforce(cnstrs, testcsp, None, None) test2 = " v1 = Variable('V1', [1, 2])\n\ v2 = Variable('V2', [1, 2])\n\ v3 = Variable('V3', [1, 2, 3, 4, 5])\n\ v4 = Variable('V4', [1, 2, 3, 4, 5])\n\ v5 = Variable('V5', [1, 2, 3, 4, 5])\n\ v6 = Variable('V6', [1, 3, 4, 5])\n\ v7 = Variable('V7', [1, 3, 4, 5])\n\ ac1 = AllDiffConstraint('1', [v1,v2,v3])\n\ ac2 = AllDiffConstraint('1', [v1,v2,v4])\n\ ac3 = AllDiffConstraint('1', [v1,v2,v5])\n\ ac4 = AllDiffConstraint('1', [v3,v4,v5,v6])\n\ ac5 = AllDiffConstraint('1', [v3,v4,v5,v7])\n\ vars = [v1, v2, v3, v4, v5, v6, v7]\n\ cnstrs = [ac1,ac2,ac3,ac4,ac5]\n\ testcsp = CSP('test2', vars, cnstrs)\n\ GacEnforce(cnstrs, testcsp, None, None)" soln_doms = [ set([1, 2]), set([1, 2]), set([3, 4, 5]), set([3, 4, 5]), set([3, 4, 5]), set([1]), set([1]) ] #v1.pruneValue(1, None, None) for i, v in enumerate(vars): if set(v.curDomain()) != soln_doms[i]: fails[1] = True print "Error: {}.curDomain() == {}".format(v.name(), v.curDomain()) print "Correct curDomin should be == {}".format(list(soln_doms[i])) if fails[1]: print "\nFail Q3 test 2\nErrors were generated on the following code:" print test2 else: print "Pass Q3 test 2" print_sep() csp = sudokuCSP(b1, 'neq') GacEnforce(csp.constraints(), csp, None, None) vars = csp.variables() vars.sort(key=lambda var: var.name()) soln_doms = [ set([3]), set([1]), set([2]), set([5]), set([9]), set([8]), set([7]), set([6]), set([4]), set([9]), set([4]), set([6]), set([7]), set([3]), set([1]), set([2]), set([5]), set([8]), set([8]), set([7]), set([5]), set([4]), set([2]), set([6]), set([9]), set([1]), set([3]), set([5]), set([6]), set([7]), set([8]), set([4]), set([2]), set([3]), set([9]), set([1]), set([4]), set([8]), set([1]), set([3]), set([6]), set([9]), set([5]), set([7]), set([2]), set([2]), set([9]), set([3]), set([1]), set([7]), set([5]), set([4]), set([8]), set([6]), set([1]), set([3]), set([8]), set([2]), set([5]), set([7]), set([6]), set([4]), set([9]), set([6]), set([5]), set([4]), set([9]), set([1]), set([3]), set([8]), set([2]), set([7]), set([7]), set([2]), set([9]), set([6]), set([8]), set([4]), set([1]), set([3]), set([5]) ] #vars[0].pruneValue(3, None, None) for i, v in enumerate(vars): if set(v.curDomain()) != soln_doms[i]: fails[2] = True print "Error: {}.curDomain() == {}".format(v.name(), v.curDomain()) print "Correct curDomin should be == {}".format(list(soln_doms[i])) if fails[2]: print "\nFail Q3 test 3\nErrors were generated on the following code:" print "python2.7 sudoku.py -e -m neq 1" else: print "Pass Q3 test 3" print_sep() csp = sudokuCSP(b5, 'neq') GacEnforce(csp.constraints(), csp, None, None) vars = csp.variables() vars.sort(key=lambda var: var.name()) soln_doms = [ set([2, 4, 5, 8]), set([6]), set([2, 4, 5, 8]), set([1]), set([2, 5, 8]), set([3, 8]), set([7, 9]), set([3, 5, 7, 8]), set([3, 7, 8, 9]), set([1, 2, 5, 8]), set([1, 2, 5, 8]), set([7]), set([2, 3, 9]), set([2, 5, 6, 8]), set([3, 6, 8]), set([1, 6, 9]), set([3, 5, 6, 8]), set([4]), set([1, 5, 8]), set([9]), set([3]), set([4]), set([7]), set([6, 8]), set([1, 6]), set([5, 6, 8]), set([2]), set([2, 4, 8]), set([2, 4, 7, 8]), set([1]), set([6]), set([3]), set([9]), set([2, 4, 7]), set([2, 4, 7]), set([5]), set([5, 9]), set([5, 7]), set([5, 6, 9]), set([8]), set([4]), set([2]), set([1, 6, 7, 9]), set([3, 6, 7]), set([1, 3, 6, 7, 9]), set([3]), set([2, 4]), set([2, 4, 6, 9]), set([5]), set([1]), set([7]), set([8]), set([2, 4, 6]), set([6, 9]), set([6]), set([2, 4, 5, 8]), set([2, 4, 5, 8]), set([2, 7]), set([9]), set([4, 8]), set([3]), set([1]), set([7, 8]), set([7]), set([1, 2, 3, 4, 8]), set([2, 4, 8, 9]), set([2, 3]), set([2, 6, 8]), set([1, 3, 4, 6, 8]), set([5]), set([2, 4, 6, 8]), set([6, 8]), set([1, 2, 4, 8]), set([1, 2, 3, 4, 8]), set([2, 4, 8]), set([2, 3, 7]), set([2, 6, 8]), set([5]), set([2, 4, 6, 7]), set([9]), set([6, 7, 8]) ] #vars[0].pruneValue(2, None, None) for i, v in enumerate(vars): if set(v.curDomain()) != soln_doms[i]: fails[3] = True print "Error: {}.curDomain() == {}".format(v.name(), v.curDomain()) print "Correct curDomin should be == {}".format(list(soln_doms[i])) if fails[3]: print "\nFail Q3 test 4\nErrors were generated on the following code:" print "python2.7 sudoku.py -e -m neq 5" else: print "Pass Q3 test 4" print_sep() v1 = Variable('V1', [1, 2]) v2 = Variable('V2', [1, 2]) v3 = Variable('V3', [1, 2, 3, 4, 5]) v4 = Variable('V4', [1, 2, 3, 4, 5]) v5 = Variable('V5', [1, 2, 3, 4, 5]) v6 = Variable('V6', [1, 3, 4, 5]) v7 = Variable('V7', [1, 3, 4, 5]) ac1 = AllDiffConstraint('1', [v1, v2, v3]) ac2 = AllDiffConstraint('1', [v1, v2, v4]) ac3 = AllDiffConstraint('1', [v1, v2, v5]) ac4 = AllDiffConstraint('1', [v3, v4, v5, v6]) ac5 = AllDiffConstraint('1', [v3, v4, v5, v7]) neq = NeqConstraint('2', [v6, v7]) vars = [v1, v2, v3, v4, v5, v6, v7] cnstrs = [ac1, ac2, ac3, ac4, ac5, neq] testcsp = CSP('test2', vars, cnstrs) val = GacEnforce(cnstrs, testcsp, None, None) test5 = " v1 = Variable('V1', [1, 2])\n\ v2 = Variable('V2', [1, 2])\n\ v3 = Variable('V3', [1, 2, 3, 4, 5])\n\ v4 = Variable('V4', [1, 2, 3, 4, 5])\n\ v5 = Variable('V5', [1, 2, 3, 4, 5])\n\ v6 = Variable('V6', [1, 3, 4, 5])\n\ v7 = Variable('V7', [1, 3, 4, 5])\n\ ac1 = AllDiffConstraint('1', [v1,v2,v3])\n\ ac2 = AllDiffConstraint('1', [v1,v2,v4])\n\ ac3 = AllDiffConstraint('1', [v1,v2,v5])\n\ ac4 = AllDiffConstraint('1', [v3,v4,v5,v6])\n\ ac5 = AllDiffConstraint('1', [v3,v4,v5,v7])\n\ neq = NeqConstraint('2', [v6,v7])\n\ vars = [v1, v2, v3, v4, v5, v6, v7]\n\ cnstrs = [ac1,ac2,ac3,ac4,ac5]\n\ testcsp = CSP('test2', vars, cnstrs)\n\ val = GacEnforce(cnstrs, testcsp, None, None)" #val = 'fo' if val != "DWO": fails[4] = True print "Error: GacEnforce failed to return \"DWO\" returned {} instead".format( val) if fails[4]: print "\nFail Q3 test 5\nErrors were generated on the following code:" print test5 else: print "Pass Q3 test 5" print_sep() csp = nQueens(8, False) solutions, num_nodes = bt_search('GAC', csp, 'fixed', False, False) errors = csp.check(solutions) if len(errors) > 0: fails[5] = True print "Fail Q3 test 6: invalid solution(s) returned by GAC" for err in errors: print_soln(err[0]) print "\n", err[1] if len(solutions) != 1: fails[5] = True print "Fail Q3 test 6: GAC failed to return only one solution" print " returned: " for s in solutions: print_soln(s) print "" ok = True for v in csp.variables(): if set(v.curDomain()) != set(v.domain()): fails[5] = True print "Fail Q3 test 6: GAC failed to restore domains of variables" if not fails[5]: print "Pass Q3 test 6" print_sep() csp = nQueens(8, False) solutions, num_nodes = bt_search('GAC', csp, 'fixed', True, False) errors = csp.check(solutions) if len(errors) > 0: fails[6] = True print "Fail Q3 test 7: invalid solution(s) returned by GAC" for err in errors: print_soln(err[0]) print "\n", err[1] if len(solutions) != 92: fails[6] = True print "Fail Q3 test 7: GAC failed to return 92 solutions" print " returned {} solutions".format(len(solutions)) ok = True for v in csp.variables(): if set(v.curDomain()) != set(v.domain()): fails[6] = True print "Fail Q3 test 7: GAC failed to restore domains of variables" if not fails[7]: print "Pass Q3 test 7" print_sep() grades[2] = 0 if sum(fails[:4]) == 0: grades[2] += 3 if not fails[4]: grades[2] += 1 if grades[2] >= 3: if sum([fails[5], fails[6]]) == 0: grades[2] += 3
m = assignment['M'] o = assignment['O'] r = assignment['R'] y = assignment['Y'] send = s * 1000 + e * 100 + n * 10 + d more = m * 1000 + o * 100 + r * 10 + e money = m * 10000 + o * 1000 + n * 100 + e * 10 + y return send + more == money # No conflict, ensures partial solution can continue to be worked on return True if __name__ == '__main__': letters = list('SENDMORY') possible_digits = {} for letter in letters: possible_digits[letter] = list(range(10)) possible_digits['M'] = [1] # So we don't get answers starting with a 0 csp = CSP(letters, possible_digits) csp.add_constraint(SendMoreMoneyConstraint(letters)) solution = csp.backtracking_search() if solution is None: print('No solution found!') else: print(solution)
def satisfied(self, assignment: Dict[str, List[GridLocation]]) -> bool: # if there are any duplicates grid locations then there is an overlap all_locations = [ locs for values in assignment.values() for locs in values ] return len(set(all_locations)) == len(all_locations) if __name__ == "__main__": grid: Grid = generate_grid(9, 9) words: List[str] = ["MATTHEW", "JOE", "MARY", "SARAH", "SALLY"] locations: Dict[str, List[List[GridLocation]]] = {} for word in words: locations[word] = generate_domain(word, grid) csp: CSP[str, List[GridLocation]] = CSP(words, locations) csp.add_constraint(WordSearchConstraint(words)) solution: Optional[Dict[str, List[GridLocation]]] = csp.backtracking_search() if solution is None: print("No solution found!") else: for word, grid_locations in solution.items(): # random reverse half the time if choice([True, False]): grid_locations.reverse() for index, letter in enumerate(word): (row, col) = (grid_locations[index].row, grid_locations[index].column) grid[row][col] = letter display_grid(grid)
def solve_schedules(schedule_problem, algo, allsolns, variableHeuristic='mrv', silent=False, trace=False): #Your implementation for Question 6 goes here. # #Do not but do not change the functions signature #(the autograder will twig out if you do). #If the silent parameter is set to True #you must ensure that you do not execute any print statements #in this function. #(else the output of the autograder will become confusing). #So if you have any debugging print statements make sure you #only execute them "if not silent". (The autograder will call #this function with silent=True, class_scheduling.py will call #this function with silent=False) #You can optionally ignore the trace parameter #If you implemented tracing in your FC and GAC implementations #you can set this argument to True for debugging. # #Once you have implemented this function you should be able to #run class_scheduling.py to solve the test problems (or the autograder). # # '''This function takes a schedule_problem (an instance of ScheduleProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solution(s) it constructs a list (of lists) specifying possible schedule(s) for the student and returns that list (of lists) The required format of the list is: L[0], ..., L[N] is the sequence of class (or NOCLASS) assigned to the student. In the case of all solutions, we will have a list of lists, where the inner element (a possible schedule) follows the format above. ''' #BUILD your CSP here and store it in the varable csp slot_num = schedule_problem.num_time_slots course_num = len(schedule_problem.courses) min_rest_frequency = schedule_problem.min_rest_frequency connected_buildings = schedule_problem._connected_buildings # domain of each slot dom = [NOCLASS] for class_ in schedule_problem.classes: found = False for course in schedule_problem.courses: if course in class_: found = True break if found: dom.append(class_) # variables in csp vars = [] for i in range(slot_num): vars.append(Variable('Slot{}'.format(i), dom)) cons = [] cons.append(NValuesConstraint("name", vars, [NOCLASS], max(0, slot_num-course_num*2), max(0, slot_num-course_num*2))) # for each course, one can only take one lec and one tut lec_candidates = {} tut_candidates = {} for i in range(1, len(dom)): c_info = dom[i].split("-") if c_info[3] == "LEC": if c_info[0] not in lec_candidates: lec_candidates[c_info[0]] = [] lec_candidates[c_info[0]].append(dom[i]) else: if c_info[0] not in tut_candidates: tut_candidates[c_info[0]] = [] tut_candidates[c_info[0]].append(dom[i]) for l in lec_candidates.values(): cons.append(NValuesConstraint("name", vars, l, 1, 1)) for l in tut_candidates.values(): cons.append(NValuesConstraint("name", vars, l, 1, 1)) # CSC108-SF-1-LEC-01 # 0 -> courses, 1 -> location, 2 -> timeslot, 3 -> LEC/TUT, 4 -> section num for i in range(slot_num): for j in range(i+1, slot_num): # for each pair of time slots, create all possible combinations of candidates # store them in a table constaint satisfying_assignments = [] for c1 in dom: c1_info = c1.split("-") for c2 in dom: c2_info = c2.split("-") if c1 == NOCLASS or c2 == NOCLASS: if c1 == NOCLASS and c2 != NOCLASS and (j+1) == int(c2_info[2]) or \ c1 != NOCLASS and c2 == NOCLASS and (i+1) == int(c1_info[2]) or \ c1 == NOCLASS and c2 == NOCLASS: satisfying_assignments.append([c1, c2]) continue # 1. candidate needs to be at the right time slot # 2. for same course, lec must comes before tut # 3. for consective time slot, two buildings need to be connected if c1 == c2 or \ (i+1) != int(c1_info[2]) or (j+1) != int(c2_info[2]) or \ c1_info[0] == c2_info[0] and c1_info[3] == "TUT" and c2_info[3] == "LEC" or \ j-i == 1 and c2_info[1] not in connected_buildings[c1_info[1]]: continue # same course and same type, take either one of them and make the other as NOCLASS if c1_info[0] == c2_info[0] and c1_info[3] == c2_info[3]: satisfying_assignments.append([NOCLASS, c2]) satisfying_assignments.append([c1, NOCLASS]) continue satisfying_assignments.append([c1, c2]) # new table constraint cons.append(TableConstraint("name", [vars[i], vars[j]], satisfying_assignments)) scope = [] for i in range(min_rest_frequency-1): scope.append(vars[i]) for i in range(min_rest_frequency, len(vars)): scope.append(vars[i]) cons.append(NValuesConstraint("name", scope, [NOCLASS], 1, float('inf'))) scope.pop(0) csp = CSP("solve_schedules", vars, cons) #invoke search with the passed parameters solutions, num_nodes = bt_search(algo, csp, variableHeuristic, allsolns, trace) #Convert each solution into a list of lists specifying a schedule #for each student in the format described above. #then return a list containing all converted solutions ans = [] for sol in solutions: l = [] for (var, val) in sol: l.append(val) ans.append(l) return ans
def solve_planes(planes_problem, algo, allsolns, variableHeuristic='mrv', silent=False, trace=False): #Your implementation for Question 6 goes here. # #Do not but do not change the functions signature #(the autograder will twig out if you do). #If the silent parameter is set to True #you must ensure that you do not execute any print statements #in this function. #(else the output of the autograder will become confusing). #So if you have any debugging print statements make sure you #only execute them "if not silent". (The autograder will call #this function with silent=True, plane_scheduling.py will call #this function with silent=False) #You can optionally ignore the trace parameter #If you implemented tracing in your FC and GAC implementations #you can set this argument to True for debugging. # #Once you have implemented this function you should be able to #run plane_scheduling.py to solve the test problems (or the autograder). # # '''This function takes a planes_problem (an instance of PlaneProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solutions it constructs a list of lists specifying a schedule for each plane and returns that list of lists The required format is the list of lists is: For each plane P the list of lists contains a list L. L[0] == P (i.e., the first item of the list is the plane) and L[1], ..., L[k] (i.e., L[1:]) is the sequence of flights assigned to P. The returned list of lists should contain a list for every plane. ''' #BUILD your CSP here and store it in the varable csp dic = {} block = [] cons = [] for plane in planes_problem.planes: start_var = Variable( "Plane:{}_1".format(plane), planes_problem.can_start(plane) + ['Empty']) # initialize the start variable with its location dic[plane] = [start_var] # put the variable in the dictionary fly_plane = planes_problem.can_fly(plane) + ['Empty'] for i in range(2, len(fly_plane)): new = Variable( "Plane:{}_{}".format(plane, i), fly_plane) # initialize other variables that they can fly dic[plane].extend([new]) block.extend(dic[plane]) follow_plane = [] for ( f1, f2 ) in planes_problem.can_follow: # store all the flights that cna be followed if f1 in fly_plane and f2 in fly_plane: follow_plane.append([f1, f2]) for flight in fly_plane: follow_plane.append([flight, "Empty"]) cols = dic[plane] for i in range(len(cols) - 1): new_con = TableConstraint( "Plane_{}_({},{})".format(plane, i + 1, i + 2), [cols[i], cols[i + 1]], follow_plane) cons.append(new_con) # add new constraint into our constraint list maintain_plane = [] maintain_freq = planes_problem.min_maintenance_frequency for f in planes_problem.maintenance_flights: # store all the flights that are maintain if f in fly_plane: maintain_plane.append(f) for i in range(len(cols) - maintain_freq + 1): name = "Plane_{}_Range({},{})".format(plane, i + 1, i + maintain_freq) scope = [] required_values = maintain_plane required_values.append("Empty") for x in range(i, i + maintain_freq): scope.append(cols[x]) lb = 1 maintenance_constraint = NValuesConstraint(name, scope, required_values, lb, maintain_freq) cons.append(maintenance_constraint ) # add the constraints for maintain flights for flight in planes_problem.flights: name = "Flight_{}_assigned".format(flight) required_values = [flight] lb = 1 ub = 1 flight_constrain = NValuesConstraint(name, block, required_values, lb, ub) cons.append(flight_constrain) csp = CSP("Plane", block, cons) #invoke search with the passed parameters solutions, num_nodes = bt_search(algo, csp, variableHeuristic, allsolns, trace) #Convert each solution into a list of lists specifying a schedule #for each plane in the format described above. #then return a list containing all converted solutions #(i.e., a list of lists of lists) acc = [] for item in solutions: final_sol = {} for plane in planes_problem.planes: final_sol[plane] = [] for (var, val) in item: var_name = var.name() row_num = int(var_name.split("_")[1]) final_sol[var_name.split(":")[1].split("_")[0]].append( (row_num, val)) ordered_sol = {} for plane in final_sol: final_sol[plane].sort() ordered_sol[plane] = [] for tup in final_sol[plane]: if tup[1] != "Empty": ordered_sol[plane].append(tup[1]) sol = [] for plane in ordered_sol: sol.append([plane] + ordered_sol[plane]) acc.append(sol) return acc
def sudoku_csp_problem(partial_grid=grid): #Ensure board is 9x9. This could easily be extended to n^2 by n^2 if len(partial_grid) <> 9: 'Error: Board must be 9x9' for i in range(len(partial_grid)): if len(partial_grid[i]) <> 9: return 'Error: Board must be 9x9' # Initialize... constraints = [] indices = [(i, j) for i in range(1, 10) for j in range(1, 10)] variables = [] #Initialize variables with one variable for each square. for (i, j) in indices: if partial_grid[i - 1][j - 1] <> 0: theval = [partial_grid[i - 1][j - 1]] else: theval = range(1, 10) variables.append(Variable(str(i) + ',' + str(j), theval)) #returns i coordinate of a variable def i(var): return var.get_name()[0] #returns j coordinate of a variable def j(var): return var.get_name()[2] #gives the 3x3 box a given square is in, they are numbered left to right, top to bottom. def getbox(stri, strj): i = int(stri) j = int(strj) if i <= 3: if j <= 3: return 1 elif 4 <= j <= 6: return 2 elif 7 <= j <= 9: return 3 elif 4 <= i <= 6: if j <= 3: return 4 elif 4 <= j <= 6: return 5 elif 7 <= j <= 9: return 6 elif 7 <= i <= 9: if j <= 3: return 7 elif 4 <= j <= 6: return 8 elif 7 <= j <= 9: return 9 return 'Error: Please enter i,j in the correct range' # make list of all square sharing a row, column or box # no need to duplicate the other way around since this loops through all edges = [] for v1 in variables: for v2 in variables: if v1 <> v2 and (i(v1) == i(v2) or j(v1) == j(v2) or getbox(i(v1), j(v1)) == getbox(i(v2), j(v2))): edges.append((v1.get_name(), v2.get_name())) # not allowed to have same value for square: def nomatch_constraint(val_a, val_b, name_a, name_b): if val_a == val_b: return False return True for e in edges: constraints.append( BinaryConstraint(e[0], e[1], nomatch_constraint, "Cant match squares in same row, column, or box")) return CSP(constraints, variables)
def solve_planes(planes_problem, algo, allsolns, variableHeuristic='mrv', silent=False, trace=False): # Your implementation for Question 6 goes here. # # Do not change the functions signature # (the autograder will twig out if you do). # If the silent parameter is set to True # you must ensure that you do not execute any print statements # in this function. # (else the output of the autograder will become confusing). # So if you have any debugging print statements make sure you # only execute them "if not silent". (The autograder will call # this function with silent=True, plane_scheduling.py will call # this function with silent=False) # You can optionally ignore the trace parameter # If you implemented tracing in your FC and GAC implementations # you can set this argument to True for debugging. # # Once you have implemented this function you should be able to # run plane_scheduling.py to solve the test problems (or the autograder). # # """This function takes a planes_problem (an instance of PlaneProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solutions it constructs a list of lists specifying a schedule for each plane and returns that list of lists The required format is the list of lists is: For each plane P the list of lists contains a list L. L[0] == P (i.e., the first item of the list is the plane) and L[1], ..., L[k] (i.e., L[1:]) is the sequence of flights assigned to P. The returned list of lists should contain a list for every plane. """ # BUILD your CSP here and store it in the variable csp variables = [] constraints = [] all_planes = planes_problem.planes all_flights = planes_problem.flights NO_FLIGHT_VALUE = "__NO_FLIGHT__" # Helper functions, based on my choice of variables' names extract_plane = lambda var_name: var_name[var_name.find('~') + 1:var_name. rfind('~')] extract_slot = lambda var_name: int(var_name[var_name.rfind('~') + 1:]) # Variables # One variable per plane and flight slot for plane in all_planes: dom = planes_problem.can_fly(plane) for i in range(len(dom)): if i == 0: # if first plane, dom must be restricted to the ones that "can start" variables.append( Variable( "Var~{}~{}".format(plane, i + 1), planes_problem.can_start(plane) + [NO_FLIGHT_VALUE])) else: variables.append( Variable("Var~{}~{}".format(plane, i + 1), dom + [NO_FLIGHT_VALUE])) # Sequence of flights must be feasible # Note: every flight can precede NO_FLIGHT_VALUE, including NO_FLIGHT_VALUE itself, but none can follow it idx = 0 # index of variables list while idx < len(variables) - 1: curr_plane = extract_plane(variables[idx].name()) next_plane = extract_plane(variables[idx + 1].name()) if curr_plane == next_plane: constr_name = "CanFollow~{}~{}".format(variables[idx].name(), variables[idx + 1].name()) constr_scope = [variables[idx], variables[idx + 1]] acceptable_pairs = planes_problem.can_follow + [ (fl, NO_FLIGHT_VALUE) for fl in variables[idx].domain() ] constraints.append( TableConstraint(constr_name, constr_scope, acceptable_pairs)) idx += 1 # Mainteinance check min_freq = planes_problem.min_maintenance_frequency mant_flights = planes_problem.maintenance_flights + [NO_FLIGHT_VALUE] idx_first = 0 # index of first plane idx_last = 0 # index of last plane while idx_last < len(variables): curr_plane = extract_plane(variables[idx_first].name()) next_plane = extract_plane(variables[idx_last].name()) if curr_plane != next_plane: num_of_flights = idx_last - idx_first all_subsequences = [ variables[idx_first:idx_last][i:i + min_freq] for i in range(num_of_flights - min_freq + 1) ] for subsequence in all_subsequences: constraints.append( NValuesConstraint( "MainteinanceCheckForPlane~{}".format(curr_plane), subsequence, mant_flights, 1, min_freq)) idx_first = idx_last idx_last += 1 if idx_first == 0: # if there was only one plane for subsequence in [ variables[i:i + min_freq] for i in range(idx_last - min_freq + 1) ]: constraints.append( NValuesConstraint("MaintCheckForOnlyPlane", subsequence, mant_flights, 1, min_freq)) # All flights must be scheduled exactly once for flight in all_flights: constraints.append( NValuesConstraint("Flight~{}~uniqueness".format(flight), variables, [flight], 1, 1)) csp = CSP("Plane scheduling CSP", variables, constraints) # invoke search with the passed parameters solutions, num_nodes = bt_search(algo, csp, variableHeuristic, allsolns, trace) # Convert each solution into a list of lists specifying a schedule # for each plane in the format described above. to_return = [] for solution in solutions: planes_to_routes = { plane: [None] * len(all_flights) for plane in all_planes } for var, val in solution: curr_plane = extract_plane(var.name()) curr_slot = extract_slot(var.name()) - 1 planes_to_routes[curr_plane][ curr_slot] = val if val != NO_FLIGHT_VALUE else None converted_solutions = map( lambda plane: [plane] + planes_to_routes[plane], planes_to_routes.keys()) # get rid of None's in a functional programming way to_return.append( map(lambda schedule: filter(lambda fl: fl is not None, schedule), converted_solutions)) # then return a list containing all converted solutions # (i.e., a list of lists of lists) return to_return
def solve_planes(planes_problem, algo, allsolns, variableHeuristic='fixed', silent=False, trace=False): #Your implementation for Question 6 goes here. # #Do not but do not change the functions signature #(the autograder will twig out if you do). #If the silent parameter is set to True #you must ensure that you do not execute any print statements #in this function. #(else the output of the autograder will become confusing). #So if you have any debugging print statements make sure you #only execute them "if not silent". (The autograder will call #this function with silent=True, plane_scheduling.py will call #this function with silent=False) #You can optionally ignore the trace parameter #If you implemented tracing in your FC and GAC implementations #you can set this argument to True for debugging. # #Once you have implemented this function you should be able to #run plane_scheduling.py to solve the test problems (or the autograder). # # '''This function takes a planes_problem (an instance of PlaneProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solutions it constructs a list of lists specifying a schedule for each plane and returns that list of lists The required format is the list of lists is: For each plane P the list of lists contains a list L. L[0] == P (i.e., the first item of the list is the plane) and L[1], ..., L[k] (i.e., L[1:]) is the sequence of flights assigned to P. The returned list of lists should contain a list for every plane. ''' #BUILD your CSP here and store it in the varable csp allVariables = [] allConstraints = [] increment = 1 answer = [] noneFlights = 1 flights = planes_problem.flights maintenanceFlights = planes_problem.maintenance_flights mFrequency = planes_problem.min_maintenance_frequency ''' ''' constraintNameString = "C" planes = planes_problem.planes for i in range(len(planes)): currPlane = planes[i] canFlyPlanes = planes_problem.can_fly(currPlane) numFlights = len(canFlyPlanes) for j in range(numFlights): name = str(currPlane) + "." + str(noneFlights) if j > 0: currDomain = list(canFlyPlanes) else: currDomain = list(planes_problem.can_start( currPlane)) # domain is only the "can_start" flights valString = "none." + str(noneFlights) currDomain = currDomain + [valString] var = Variable(name, currDomain) allVariables.append(var) noneFlights = noneFlights + 1 diffCounter = 1 allConstraints.extend([ AllDiffConstraint(constraintNameString + str(diffCounter), allVariables) ]) diffCounter = diffCounter + increment allConstraints.extend([ NValuesConstraint(constraintNameString + str(diffCounter), allVariables, flights, len(flights), np.inf) ]) diffCounter = diffCounter + increment noneString = "none" + "." for i in range(len(planes)): foundVariables = [] for var in allVariables: if planes[i] in var.name(): foundVariables.append(var) for variable_index in range(len(foundVariables[:-1])): first = foundVariables[variable_index] second = foundVariables[variable_index + 1] cnstrBatch = [] noneA = noneString + first.name().split('.')[1] noneB = noneString + second.name().split('.')[1] listOfCo = [] if variable_index == 0: firstdomain = planes_problem.can_start(planes[i]) else: firstdomain = first.domain() for flight in firstdomain: for follow in planes_problem.can_follow: if flight == follow[0]: listOfCo.append(follow) for k in range(len(listOfCo)): nextDomain = second.domain() if listOfCo[k][1] in nextDomain: cnstrBatch.append([listOfCo[k][0], listOfCo[k][1]]) for flight in firstdomain: cnstrBatch.append([flight, noneB]) if variable_index == 0: cnstrBatch.append([noneA, noneB]) scope = [first, second] allConstraints.extend([ TableConstraint(constraintNameString + str(diffCounter), scope, cnstrBatch) ]) if len(foundVariables) == 1: cnstrBatch = [] first = foundVariables[0] firstDomain = first.domain() for flight in firstDomain: cnstrBatch.append([flight]) scope = [first] allConstraints.extend([ TableConstraint(constraintNameString + str(diffCounter), scope, cnstrBatch) ]) diffCounter = diffCounter + increment for i in range(len(planes)): foundVariables = [] for var_index in range(len(allVariables)): if planes[i] in allVariables[var_index].name(): foundVariables.append(allVariables[var_index]) subSequences = map( list, zip(*(foundVariables[i:] for i in range(mFrequency)))) if len(foundVariables) < mFrequency: continue for index in subSequences: planesWithNone = [] for var in index: intermediateLst = var.name().split(".") formattedString = "none." + str(intermediateLst[1]) planesWithNone.append(formattedString) currSequence = index allConstraints = allConstraints + [ NValuesConstraint( constraintNameString + str(diffCounter), currSequence, maintenanceFlights + planesWithNone, 1, np.inf) ] diffCounter = diffCounter + increment csp = CSP("Planes", allVariables, allConstraints) solutions, num_nodes = bt_search(algo, csp, variableHeuristic, allsolns, trace) for i in range(len(solutions)): temp = [] final = [] for plane in planes: foundVariables = [] for var in solutions[i]: if var[0].name().split(".")[0] == plane: foundVariables.append(var) nextVal = [x[1] for x in foundVariables] temp += [plane] temp += nextVal temp = [y for y in temp if (not "none" in y)] final += [temp] temp = [] answer += [final] #print("---------------------------") #for lst in answer: #print(lst) return answer
def solve_planes(planes_problem, algo, allsolns, variableHeuristic='mrv', silent=False, trace=False): # Your implementation for Question 6 goes here. # # Do not but do not change the functions signature # (the autograder will twig out if you do). # If the silent parameter is set to True # you must ensure that you do not execute any print statements # in this function. # (else the output of the autograder will become confusing). # So if you have any debugging print statements make sure you # only execute them "if not silent". (The autograder will call # this function with silent=True, plane_scheduling.py will call # this function with silent=False) # You can optionally ignore the trace parameter # If you implemented tracing in your FC and GAC implementations # you can set this argument to True for debugging. # # Once you have implemented this function you should be able to # run plane_scheduling.py to solve the test problems (or the autograder). # # '''This function takes a planes_problem (an instance of PlaneProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solutions it constructs a list of lists specifying a schedule for each plane and returns that list of lists The required format is the list of lists is: For each plane P the list of lists contains a list L. L[0] == P (i.e., the first item of the list is the plane) and L[1], ..., L[k] (i.e., L[1:]) is the sequence of flights assigned to P. The returned list of lists should contain a list for every plane. ''' # BUILD your CSP here and store it in the variable csp # get the data from the planes_problem object planes = planes_problem.planes # list of planes flights = planes_problem.flights # list of flights can_follow = planes_problem.can_follow maintenance_flights = planes_problem.maintenance_flights frequency = planes_problem.min_maintenance_frequency # first define the variables # construct the variable: each can be allocated slot is a variable, domain is can_fly flights + '' var_array = [] # each plane is in order for plane in planes: plane_slots = [] # the first slot can only have can_start and '' first_dom = planes_problem.can_start ( plane ).append ( '' ) first_var = Variable ( "{} slot1".format ( plane, 1 ), first_dom ) plane_slots.append ( first_var ) # remaining slot have can_fly and '' dom = planes_problem.can_fly ( plane ).append ( '' ) for i in range ( 1, len ( planes_problem.can_fly ( plane ) ) ): var = Variable ( "{} slot{}".format ( plane, i + 1 ), dom ) plane_slots.append ( var ) var_array.append ( plane_slots ) # Set up the constraints # row constraints constraint_list = [] # table constraint for can follow for i in range ( len ( var_array ) ): sequence = [[]] # can_follow for current plane: curr_can_follow = [] for f1, f2 in can_follow: if f1 in planes_problem.can_fly ( planes[i] ) and f2 in planes_problem.can_fly ( planes[i] ): curr_can_follow.append ( (f1, f2) ) # construct the dictionary of the current can follow: {f1: [list of f2]} dict_curr_can_follow = {} for f1, f2 in curr_can_follow: if f1 not in curr_can_follow: dict_curr_can_follow[f1] = [f2] else: if f2 not in dict_curr_can_follow[f1]: dict_curr_can_follow[f1].append ( f2 ) # construct the possible can fly sequences for each plane potential = [] # list of 'flight' sequence for first_flight in planes_problem.can_start ( planes[i] ): sequence.append ( [first_flight] ) for f1 in dict_curr_can_follow: # sequence.append ( potential ) for first_flight in planes_problem.can_start ( planes[i] ): potential.append ( first_flight ) # begin the chain curr_can_follow = can_follow # need to guarantee flights in potential is unique for f1, f2 in curr_can_follow: if f1 == first_flight: # also f2 need in this plane's can_fly # NValue constraint for maintenance for plane_slots in var_array: constraint_list.append ( NValuesConstraint('maintenance', plane_slots, maintenance_flights + [''], 1, frequency)) # all different all_var = [] for plane_slots in var_array: all_var.extend ( plane_slots ) constraint_list.append(AllDiffNoneConstraint ( 'different flights', all_var ) ) # need to check all assigned in later print out # NValue constraint for maintenance # construct csp problem vars = [var for row in var_array for var in row] csp = CSP ( "solve_planes", vars, constraint_list ) # invoke search with the passed parameters solutions, num_nodes = bt_search ( algo, csp, variableHeuristic, allsolns, trace ) # Convert each solution into a list of lists specifying a schedule # for each plane in the format described above. allSolution = [] for solution in solutions:
from csp import CSP crossword_puzzle = CSP( var_domains={ # read across: 'a1': set("bus has".split()), 'a3': set("lane year".split()), 'a4': set("ant car ".split()), # read down: 'd1': set("buys hold".split()), 'd2': set("search syntax".split()), }, constraints={ lambda a1, d1: a1[0] == d1[0], lambda d1, a3: d1[2] == a3[0], lambda a1, d2: a1[2] == d2[0], lambda d2, a3: d2[2] == a3[2], lambda d2, a4: d2[4] == a4[0], })
def main(): """ Parse the command line arguments. Make the CSP object. Do preprocessing if requested. Then call the search object. () -> None """ args = parse_cmd_line_args() #Get the appropriate functions to be used by the search variable_selection_function = get_variable_selection_function( args.variable_heuristic) value_ordering_function = get_value_ordering_function(args.value_heuristic) inference_pre_function = get_inference_function(args.preprocessing) inference_search_function = get_inference_function(args.search_inference) print "Parsing CSP file:", args.input_file_name csp = CSP() if not csp.parse_csp_file(args.input_file_name): return print "Success." initial_assignment = dict([ (var, csp.domains[var][0])\ for var in csp.variables if len(csp.domains[var]) == 1 ]) #Apply preprocessing if requested if inference_pre_function is not None: print "Preprocessing..." result = inference_pre_function(None, initial_assignment, csp) if result is None: print "Error: inconsistency detected in preprocessing." return csp.notify_of_inference(None, initial_assignment, result[0], result[1]) print "Preprocessing made", len(result[1]), "assignments." if args.output_file_name is not None: print "Writing grounded CSP to:", args.output_file_name try: with file(args.output_file_name, "w") as output_file: csp.write(output_file) except IOError as e: print "Error: cannot open output file:", args.output_file_name return print "Performing backtracking search..." assignment, explored, search_time = search(csp, initial_assignment, variable_selection_function, value_ordering_function, inference_search_function) if args.solution_file_name is None: solution_file = sys.stdout else: try: solution_file = file(args.solution_file_name, "w") except IOError as e: print "Error: could not open output file:", args.solution_file_name return #Display the result if assignment is None: print "There is no solution!" solution_file.write("UNSAT\n") solution_file.write("Explored: " + str(explored) + "\n") solution_file.write("Time: " + str(search_time) + "\n") else: print "Solution found." if args.sudoku_output: for y in xrange(1, 10): for x in xrange(1, 10): solution_file.write(assignment[str(x) + str(y)] + " ") if x % 3 == 0 and x < 9: solution_file.write("| ") solution_file.write("\n") if y % 3 == 0 and y < 9: solution_file.write("---------------------\n") else: solution_file.write("SAT\n") solution_file.write("Explored: " + str(explored) + "\n") solution_file.write("Time: " + str(search_time) + "\n") solution_file.write("Solution: " + " ".join([var+"="+val\ for var,val in assignment.iteritems() ]) + "\n")
def sudokuCSP(initial_sudoku_board, model='neq'): '''The input board is specified as a list of 9 lists. Each of the 9 lists represents a row of the board. If a 0 is in the list it represents an empty cell. Otherwise if a number between 1--9 is in the list then this represents a pre-set board position. E.g., the board ------------------- | | |2| |9| | |6| | | |4| | | |1| | |8| | |7| |4|2| | | |3| |5| | | | | |3| | | | | |1| |6| |5| | | | | |3| | | | | |6| |1| | | |5|7| |4| | |6| | |9| | | |2| | | |2| | |8| |1| | | ------------------- would be represented by the list of lists [[0,0,2,0,9,0,0,6,0], [0,4,0,0,0,1,0,0,8], [0,7,0,4,2,0,0,0,3], [5,0,0,0,0,0,3,0,0], [0,0,1,0,6,0,5,0,0], [0,0,3,0,0,0,0,0,6], [1,0,0,0,5,7,0,4,0], [6,0,0,9,0,0,0,2,0], [0,2,0,0,8,0,1,0,0]] Construct and return CSP for solving this sudoku board using binary not equals if model='neq' or using allDiff constraints if model='alldiff' The CSP contains a variable for each cell of the board with with domain equal to {1-9} if the board has a 0 at that position, and domain equal {i} if the board has a fixed number i at that cell. The CSP has a neq constraint between every relevant pair of varibles, or an alldiff constraint between every set of variables in a row, column, or sub-square ''' #your implementation for Question 4 changes this function #implement handleing of model == 'alldiff' if not model in ['neq', 'alldiff']: print "Error wrong sudoku model specified {}. Must be one of {}".format( model, ['neq', 'alldiff']) #first define the variables i = 0 var_array = [] for row_list in initial_sudoku_board: var_array.append([]) j = 0 for col in row_list: cell = initial_sudoku_board[i][j] if cell == 0: dom = [1, 2, 3, 4, 5, 6, 7, 8, 9] else: dom = [cell] var = Variable("V{},{}".format(i + 1, j + 1), dom) var_array[i].append(var) j += 1 i += 1 #Set up the constraints #row constraints constraint_list = [] for row in var_array: if model == 'neq': constraint_list.extend(post_all_pairs(row)) elif model == 'alldiff': constraint_list += [SodukuAllDiff(row)] for col in range(len(var_array[0])): scope = map(lambda row: row[col], var_array) if model == 'neq': constraint_list.extend(post_all_pairs(scope)) elif model == 'alldiff': constraint_list += [SodukuAllDiff(scope)] for i in [0, 3, 6]: for j in [0, 3, 6]: #initial upper left hand index of subsquare scope = [] for k in [0, 1, 2]: for l in [0, 1, 2]: scope.append(var_array[i + k][j + l]) if model == 'neq': constraint_list.extend(post_all_pairs(scope)) elif model == 'alldiff': constraint_list += [SodukuAllDiff(scope)] vars = [var for row in var_array for var in row] return CSP("Sudoku", vars, constraint_list)
def solve_planes(planes_problem, algo, allsolns, variableHeuristic='mrv', silent=False, trace=False): #Your implementation for Question 6 goes here. # #Do not but do not change the functions signature #(the autograder will twig out if you do). #If the silent parameter is set to True #you must ensure that you do not execute any print statements #in this function. #(else the output of the autograder will become confusing). #So if you have any debugging print statements make sure you #only execute them "if not silent". (The autograder will call #this function with silent=True, plane_scheduling.py will call #this function with silent=False) #You can optionally ignore the trace parameter #If you implemented tracing in your FC and GAC implementations #you can set this argument to True for debugging. # #Once you have implemented this function you should be able to #run plane_scheduling.py to solve the test problems (or the autograder). # # '''This function takes a planes_problem (an instance of PlaneProblem class) as input. It constructs a CSP, solves the CSP with bt_search (using the options passed to it), and then from the set of CSP solutions it constructs a list of lists specifying a schedule for each plane and returns that list of lists The required format is the list of lists is: For each plane P the list of lists contains a list L. L[0] == P (i.e., the first item of the list is the plane) and L[1], ..., L[k] (i.e., L[1:]) is the sequence of flights assigned to P. The returned list of lists should contain a list for every plane. ''' #BUILD your CSP here and store it in the variable csp # get the data from the planes_problem object planes = planes_problem.planes # list of planes flights = planes_problem.flights # list of flights can_follow = planes_problem.can_follow maintenance_flights = planes_problem.maintenance_flights frequency = planes_problem.min_maintenance_frequency constraint_list = [] # variable1: 'flight' with domain [(can_follow, 1->maintenance)] variables_flights = [] flight_obj_dict = {} # {'flight': flight_obj} obj_flight_dict = {} # {flight_obj: 'flight'} for flight in flights: name = flight domain = [] for f1, f2 in can_follow: if f1 == name: if f2 in maintenance_flights: domain.append((f2, 1)) else: domain.append((f2, 0)) # deal with the flight in the last domain.append(('None', -1)) flight_obj = Variable(name, domain) variables_flights.append(flight_obj) flight_obj_dict[name] = flight_obj obj_flight_dict[flight_obj] = name constraint_flight = AllDiffConstraint('constraintFlight', variables_flights) constraint_list.append(constraint_flight) # variable2: 'plane' with domain [start flight_obj - can be empty] variables_planes = [] for plane in planes: name = plane domain = [] for flight in planes_problem.can_start(name): domain.append(flight_obj_dict[flight]) # deal with situation there is no flight for the plane domain.append(None) plane_obj = Variable(name, domain) variables_planes.append(plane_obj) # start flight all different except None object constraint_plane = AllDiffFilterConstraint('constraintPlane', variables_planes) constraint_list.append(constraint_plane) # construct csp problem csp = CSP("solve_planes", variables_flights + variables_planes, constraint_list) #invoke search with the passed parameters solutions, num_nodes = bt_search(algo, csp, variableHeuristic, allsolns, trace) # Convert each solution into a list of lists specifying a schedule # for each plane in the format described above. allSolution = [] # list of each_solution for solution in solutions: flight_solution = solution[:len( flights)] # [(flight_obj, ('nxt_flight', 1/0))] plane_solution = solution[ -len(planes):] # [(plane_obj, first_flight_obj)] # convert flight_solution to dictionary flight_solution_dic = {} # dict {flight_obj: ('nxt_flight', 1/0)} for var, val in flight_solution: flight_solution_dic[var] = val # construct plane solution, connect the chain plane_sol_dic = {} # {'plane': [sequence (flight, maintenance)]} for plane, first_flight in plane_solution: plane_sol_dic[plane.name()] = [] if first_flight is not None: # this is just the first sequence maintenance = 0 if first_flight.name() in maintenance_flights: maintenance = 1 plane_sol_dic[plane.name()].append( (first_flight.name(), maintenance)) if first_flight in flight_solution_dic: nxt_flight, maintenance = flight_solution_dic.pop( first_flight) while nxt_flight != 'None': plane_sol_dic[plane.name()].append( (nxt_flight, maintenance)) constructed_path = [] for flight, maintenance in plane_sol_dic[plane.name()]: constructed_path.append(flight) if flight_obj_dict[nxt_flight] in flight_solution_dic: check_nxt_flight, check_maintenance = flight_solution_dic.pop( flight_obj_dict[nxt_flight]) if check_nxt_flight not in constructed_path: nxt_flight, maintenance = check_nxt_flight, check_maintenance else: break else: break # check each flight has been allocated allocate_flight = sum( len(plane_sol_dic[plane]) for plane in plane_sol_dic) if allocate_flight != len(flights): continue each_solution = [ ] # list of solution to each plane ['plane', 'flight1', 'flight2', ...] for plane in plane_sol_dic: # case1: plane only assign < frequency # of flights if len(plane_sol_dic[plane]) < frequency: plane_sol = [plane] for flight, maintenance in plane_sol_dic[plane]: plane_sol.append(flight) each_solution.append(plane_sol) else: # case: assigned sequence length >= frequency # prune the case not satisfies maintenance maintenance_list = [] for flight, maintenance in plane_sol_dic[plane]: maintenance_list.append(maintenance) if maintenance_check(maintenance_list, frequency): plane_sol = [plane] for flight, maintenance in plane_sol_dic[plane]: plane_sol.append(flight) each_solution.append(plane_sol) if each_solution != [] and each_solution not in allSolution: allSolution.append(each_solution) #then return a list containing all converted solutions #(i.e., a list of lists of lists) return allSolution
def question_5(): print_title(4) fails = [False] * 2 test1 = " v1 = Variable('V1', [1, 2])\n\ v2 = Variable('V2', [1, 2])\n\ v3 = Variable('V3', [1, 2, 3, 4, 5])\n\ v4 = Variable('V4', [1, 2, 3, 4, 5])\n\ v5 = Variable('V5', [1, 2, 3, 4, 5])\n\ v6 = Variable('V6', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v7 = Variable('V7', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v8 = Variable('V8', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v9 = Variable('V9', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ vars = [v1, v2, v3, v4, v5, v6, v7, v8, v9]\n\ nv9 = NValuesConstraint('9', vars, [9], 4, 5)\n\ testcsp = CSP('test', vars, [nv9])\n\ GacEnforce([nv9], testcsp, None, None)" v1 = Variable('V1', [1, 2]) v2 = Variable('V2', [1, 2]) v3 = Variable('V3', [1, 2, 3, 4, 5]) v4 = Variable('V4', [1, 2, 3, 4, 5]) v5 = Variable('V5', [1, 2, 3, 4, 5]) v6 = Variable('V6', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v7 = Variable('V7', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v8 = Variable('V8', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v9 = Variable('V9', [1, 2, 3, 4, 5, 6, 7, 8, 9]) vars = [v1, v2, v3, v4, v5, v6, v7, v8, v9] nv9 = NValuesConstraint('9', vars, [9], 4, 5) testcsp = CSP('test', vars, [nv9]) GacEnforce([nv9], testcsp, None, None) soln_doms = [ set([1, 2]), set([1, 2]), set([1, 2, 3, 4, 5]), set([1, 2, 3, 4, 5]), set([1, 2, 3, 4, 5]), set([9]), set([9]), set([9]), set([9]) ] for i, v in enumerate(vars): if set(v.curDomain()) != soln_doms[i]: fails[0] = True print "Error: {}.curDomain() == {}".format(v.name(), v.curDomain()) print "Correct curDomin should be == {}".format(list(soln_doms[i])) if fails[0]: print "\nFail Q5 test 1\nErrors were generated on the following code:" print test1 else: print "Pass Q5 test 1" print_sep() test2 = " v1 = Variable('V1', [1, 2])\n\ v2 = Variable('V2', [1, 2])\n\ v3 = Variable('V3', [1, 2, 3, 4, 5])\n\ v4 = Variable('V4', [1, 2, 3, 4, 5])\n\ v5 = Variable('V5', [1, 2, 3, 4, 5])\n\ v6 = Variable('V6', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v7 = Variable('V7', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v8 = Variable('V8', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ v9 = Variable('V9', [1, 2, 3, 4, 5, 6, 7, 8, 9])\n\ vars = [v1, v2, v3, v4, v5, v6, v7, v8, v9]\n\ nv9 = NValuesConstraint('9', vars, [9], 4, 5)\n\ nv1 = NValuesConstraint('1', vars, [1], 5, 5)\n\ testcsp = CSP('test', vars, [nv1, nv9])\n\ GacEnforce([nv1, nv9], testcsp, None, None)" v1 = Variable('V1', [1, 2]) v2 = Variable('V2', [1, 2]) v3 = Variable('V3', [1, 2, 3, 4, 5]) v4 = Variable('V4', [1, 2, 3, 4, 5]) v5 = Variable('V5', [1, 2, 3, 4, 5]) v6 = Variable('V6', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v7 = Variable('V7', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v8 = Variable('V8', [1, 2, 3, 4, 5, 6, 7, 8, 9]) v9 = Variable('V9', [1, 2, 3, 4, 5, 6, 7, 8, 9]) vars = [v1, v2, v3, v4, v5, v6, v7, v8, v9] nv9 = NValuesConstraint('9', vars, [9], 4, 5) nv1 = NValuesConstraint('1', vars, [1], 5, 5) testcsp = CSP('test', vars, [nv1, nv9]) GacEnforce([nv1, nv9], testcsp, None, None) soln_doms = [ set([1]), set([1]), set([1]), set([1]), set([1]), set([9]), set([9]), set([9]), set([9]) ] #vars[0].pruneValue(1, None, None) for i, v in enumerate(vars): if set(v.curDomain()) != soln_doms[i]: fails[1] = True print "Error: {}.curDomain() == {}".format(v.name(), v.curDomain()) print "Correct curDomin should be == {}".format(list(soln_doms[i])) if fails[1]: print "\nFail Q5 test 2\nErrors were generated on the following code:" print test3 else: print "Pass Q5 test 2" print_sep() if not any(fails): grades[4] = outof[4]
def moose_csp_problem(): constraints = [] # We start with the reduced domain. # So the constraint that McCain must sit in seat 1 is already # covered. variables = [] variables.append(Variable("1", ["Mc"])) variables.append(Variable("2", ["Y", "M", "P"])) variables.append(Variable("3", ["Y", "M", "O", "B"])) variables.append(Variable("4", ["Y", "M", "O", "B"])) variables.append(Variable("5", ["Y", "M", "O", "B"])) variables.append(Variable("6", ["Y", "M", "P"])) # these are all variable pairing of adjacent seats adjacent_pairs = [("1", "2"), ("2", "1"), ("2", "3"), ("3", "2"), ("3", "4"), ("4", "3"), ("4", "5"), ("5", "4"), ("5", "6"), ("6", "5"), ("6", "1"), ("1", "6")] # now we construct the set of non-adjacent seat pairs. nonadjacent_pairs = [] variable_names = ["1", "2", "3", "4", "5", "6"] for x in range(len(variable_names)): for y in range(x, len(variable_names)): if x == y: continue tup = (variable_names[x], variable_names[y]) rev = (variable_names[y], variable_names[x]) if tup not in adjacent_pairs: nonadjacent_pairs.append(tup) if rev not in adjacent_pairs: nonadjacent_pairs.append(rev) # all pairs is the set of all distinct seating pairs # this list is useful for checking where # the two seat are assigned to the same person. all_pairs = adjacent_pairs + nonadjacent_pairs # 1. The Moose is afraid of Palin def M_not_next_to_P(val_a, val_b, name_a, name_b): if ((val_a == "M" and val_b == "P") or (val_a == "P" and val_b == "M")): return False return True for pair in adjacent_pairs: constraints.append( BinaryConstraint(pair[0], pair[1], M_not_next_to_P, "Moose can't be " + "next to Palin")) # 2. Obama and Biden must sit next to each other. # This constraint can be directly phrased as: # # for all sets of adjacents seats # there must exist one pair where O & B are assigned # # C(1,2) or C(2,3) or C(3,4) or ... or C(6,1) # # where C is a binary constraint that checks # whether the value of the two variables have values O and B # # However the way our checker works, the constraint needs to be # expressed as a big AND. # So that when any one of the binary constraints # fails the entire assignment fails. # # To turn our original OR formulation to an AND: # We invert the constraint condition as: # # for all sets of nonadjacent seats # there must *not* exist a pair where O & B are assigned. # # not C(1,3) and not C(1,4) and not C(1,5) ... not C(6,4) # # Here C checks whether the values assigned are O and B. # # Finally, this is an AND of all the binary constraints as required. def OB_not_next_to_each_other(val_a, val_b, name_a, name_b): if (val_a == "O" and val_b == "B") or \ (val_a == "B" and val_b == "O"): return False return True for pair in nonadjacent_pairs: constraints.append( BinaryConstraint(pair[0], pair[1], OB_not_next_to_each_other, "Obama, Biden must be next to each-other")) # 3. McCain and Palin must sit next to each other def McP_not_next_to_each_other(val_a, val_b, name_a, name_b): if ((val_a == "P" and val_b == "Mc") or (val_a == "Mc" and val_b == "P")): return False return True for pair in nonadjacent_pairs: constraints.append( BinaryConstraint( pair[0], pair[1], McP_not_next_to_each_other, "McCain and Palin must be " + "next to each other")) # 4. Obama + Biden can't sit next to Palin or McCain def OB_not_next_to_McP(val_a, val_b, name_a, name_b): if ((val_a == "O" or val_a == "B") \ and (val_b == "Mc" or val_b == "P")) or \ ((val_b == "O" or val_b == "B") \ and (val_a == "Mc" or val_a == "P")): return False return True for pair in adjacent_pairs: constraints.append( BinaryConstraint( pair[0], pair[1], OB_not_next_to_McP, "McCain, Palin can't be next " + "to Obama, Biden")) # No two seats can be occupied by the same person def not_same_person(val_a, val_b, name_a, name_b): return val_a != val_b for pair in all_pairs: constraints.append( BinaryConstraint( pair[0], pair[1], not_same_person, "No two seats can be occupied " + "by the same person")) return CSP(constraints, variables)
class QueensConstraint(Constraint[int, int]): def __init__(self, columns: List[int]) -> None: super().__init__(columns) self.columns: List[int] = columns def satisfied(self, assignment: Dict[int, int]): # q1c = queen 1 column, q1r = queen 1 row for q1c, q1r in assignment.items(): # q2c = queen 2 column for q2c in range(q1c + 1, len(self.columns) + 1): if q2c in assignment: q2r: int = assignment[q2c] if q1r == q2r: # same row return False if abs(q1r - q2r) == abs(q1c - q2c): # same diagonal return False return True if __name__ == "__main__": columns: List[int] = [1, 2, 3, 4, 5, 6, 7, 8] rows: Dict[int, List[int]] = {i: columns for i in range(1, 9)} csp: CSP[int, int] = CSP(columns, rows) csp.add_constraint(QueensConstraint(columns)) solution: Optional[Dict[int, int]] = csp.backtracking_search() if solution is None: print("No solution found") else: print(solution)
from csp import CSP canterbury_colouring = CSP( var_domains={ 'christchurch': {'red', 'green'}, 'selwyn': {'red', 'green'}, 'waimakariri': {'red', 'green'}, }, constraints={ lambda christchurch, waimakariri: christchurch != waimakariri, lambda christchurch, selwyn: christchurch != selwyn, lambda selwyn, waimakariri: selwyn != waimakariri, }) #Unchanged since for every option in every domain there is an option in the #corresponding domain that does not equal it