def solve(): problem = Problem() problem.addVariables("abcdxefgh", range(1, 10)) problem.addConstraint(lambda a, b, c, d, x: a < b < c < d and a + b + c + d + x == 27, "abcdx") problem.addConstraint(lambda e, f, g, h, x: e < f < g < h and e + f + g + h + x == 27, "efghx") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() return solutions
class SudokuProblem(object): def __init__(self): self._problem = Problem() def _each_once_per_line(self): for line_index in range(9): variable_names = [self._variable_name(line_index, column_index) for column_index in range(9)] self._problem.addConstraint(AllDifferentConstraint(), variable_names) def _each_once_per_column(self): for column_index in range(9): variable_names = [self._variable_name(line_index, column_index) for line_index in range(9)] self._problem.addConstraint(AllDifferentConstraint(), variable_names) def _each_once_per_square(self): for line_square_index in range(3): for column_square_index in range(3): variable_names = [] line_index_start = line_square_index * 3 for line_index in range(line_index_start, line_index_start + 3): column_index_start = column_square_index * 3 for column_index in range(column_index_start, column_index_start + 3): variable_names.append(self._variable_name(line_index, column_index)) self._problem.addConstraint(AllDifferentConstraint(), variable_names) def generate_constraints(self): self._each_once_per_line() self._each_once_per_column() self._each_once_per_square() def _variable_name(self, line_index, column_index): return '(l%d,c%d)' % (line_index, column_index) def feed_puzzle(self, values_of_colum_of_line): for line_index, values_of_column in values_of_colum_of_line.items(): for column_index, values in values_of_column.items(): variable_name = self._variable_name(line_index, column_index) self._problem.addVariable(variable_name, values) def iterate_solutions(self): return self._problem.getSolutionIter() def format_solution(self, solution_dict, indent_text): chunks = [] for line_index in range(9): values = [] for column_index in range(9): value = solution_dict[self._variable_name(line_index, column_index)] values.append(value) chunks.append(indent_text + '%d %d %d | %d %d %d | %d %d %d' % tuple(values)) if line_index % 3 == 2 and line_index < 8: chunks.append(indent_text + '------+-------+------') return '\n'.join(chunks)
def solve_board(overlays, verify_just_one=False): problem = Problem() spot_constraints = defaultdict(list) overlay_constraints = [] for overlay in overlays: # the simplest case is a fully 3x3 grid if len(overlay) == 3 and len(overlay[0]) == 3: for x in range(3): for y in range(3): if overlay[x][y] is None: continue spot_constraints[(x, y)].extend( get_constraints(overlay[x][y])) else: # dealing with a grid that is smaller than 3x3 so we # need to make relative constraints - we add those # after the all different constraint so it only needs # to look at possible boards overlay_constraints.append( (FunctionConstraint(floating_overlay(overlay)), locations)) # the unspecified spots could be any piece for x in range(3): for y in range(3): if (x, y) not in spot_constraints: spot_constraints[(x, y)] = pieces for spot, values in spot_constraints.iteritems(): problem.addVariable(spot, values) problem.addConstraint(AllDifferentConstraint()) for overlay_constraint in overlay_constraints: problem.addConstraint(*overlay_constraint) solution = None if verify_just_one: solutions = problem.getSolutions() assert len(solutions) == 1, ('%d solutions but there should be 1' % len(solutions)) solution = solutions[0] else: solution = problem.getSolution() answer = [[None] * 3 for x in range(3)] for x in range(3): for y in range(3): answer[x][y] = solution[(x, y)] print('\n'.join(' '.join(_) for _ in answer)) print('') return answer
def solve(): problem = Problem() total = 5.00 variables = ("0.01", "0.05", "0.10", "0.50", "1.00") values = [float(x) for x in variables] for variable, value in zip(variables, values): problem.addVariable(variable, range(int(total / value))) problem.addConstraint(ExactSumConstraint(total, values), variables) problem.addConstraint(ExactSumConstraint(100)) solutions = problem.getSolutionIter() return solutions, variables
def gen_disjunct_intervals_CSP(ints): p = Problem() size = len(ints) sizeL = range(size) for intnum, key in enumerate(ints): values = [[]] for i in sizeL: values += [ item for item in it.combinations(ints, i + 1) if key in item ] p.addVariable(intnum, values) for i in sizeL: p.addConstraint(check_continuity, (i,)) for i1, i2 in it.product(sizeL, sizeL): if i1 < i2: p.addConstraint(check_all, (i1, i2)) p.addConstraint(all_interval, sizeL) return p.getSolution()
def determine(state): card_played_this_round = [card is not None and 1 or 0 for card in state.cards_played_by_player] remaining_hand_size = 5 - sum(state.tricks_won_by_team) hand_size_by_player = [remaining_hand_size - played for played in card_played_this_round] cards = list(set(deal()) - set(list(chain(*state.hands))) - set(state.cards_played)) shuffle(cards) problem = Problem() for player in range(4): if state.hands[player]: for card_index, card in enumerate(state.hands[player]): problem.addVariable((player, card_index), [card]) else: voids_by_player = state.voids_by_player[player] for card_index in range(hand_size_by_player[player]): if voids_by_player: potential_cards = potential_cards_given_voids( state.trump, voids_by_player, cards) shuffle(potential_cards) problem.addVariable((player, card_index), potential_cards) else: problem.addVariable((player, card_index), cards) problem.addConstraint(AllDifferentConstraint()) cards = sorted(iteritems(problem.getSolution())) hands = [[], [], [], []] for player in range(4): hands[player] = [c[1] for c in cards[:hand_size_by_player[player]]] del cards[:hand_size_by_player[player]] state = state._replace(hands=hands) return state
def solve(sudoku_data): """ Solves the sudoku using simple constraints programming. Returns a list of solutions. Multiple solutions may be found if the sudoku wasn't parsed correctly. """ problem = Problem() # add known numbers for i in range(0, 81): problem.addVariable(i, [int(sudoku_data[i])] if sudoku_data[i] else range(1, 10)) for i in range(0, 9): # row constraint problem.addConstraint(AllDifferentConstraint(), range(i * 9, i * 9 + 9)) # column constraint problem.addConstraint(AllDifferentConstraint(), [(i + 9 * c) for c in range(0, 9)]) # box constraint problem.addConstraint(AllDifferentConstraint(), [(i * 3) + (i / 3 * 18) + (9 * j) + k for j in range(0, 3) for k in range(0, 3)]) return problem.getSolutions()
def __init__(self,nodeGradesInfos=[]): X86AnalyzerBase.__init__(self,nodeGradesInfos) self.problem = Problem(MinConflictsSolver()) # this is to make it human readable .. # we will generator the solution only when we need it and then cache it # TODO make __ self.sol = None for key in self.rewriteDict.keys(): self.rewriteDict[key]['symbolCache'] = {} self.rewriteDict[key]['curLine'] = 1 self.rewriteDict[key]['curPos'] = 1 self.createRewrite()
def buildproblem(terms, total): problem = Problem() letters = sorted(list(set("".join(terms) + total))) initial = set([word[0] for word in terms + [total]]) for letter in letters: if letter in initial: problem.addVariable(letter, list(range(1,10))) else: problem.addVariable(letter, list(range(10))) problem.addConstraint(AllDifferentConstraint()) digit_checks(problem, terms, total, letters) return problem
def solve(size): problem = Problem() cols = range(size) rows = range(size) problem.addVariables(cols, rows) for col1 in cols: for col2 in cols: if col1 < col2: problem.addConstraint(lambda row1, row2: row1 != row2, (col1, col2)) solutions = problem.getSolutions() return solutions
def solve(): problem = Problem() size = 8 cols = range(size) rows = range(size) problem.addVariables(cols, rows) for col1 in cols: for col2 in cols: if col1 < col2: problem.addConstraint(lambda row1, row2, col1=col1, col2=col2: abs(row1 - row2) != abs(col1 - col2) and row1 != row2, (col1, col2)) solutions = problem.getSolutions() return solutions, size
def solve(): problem = Problem() problem.addVariables("abc", range(1, 10)) problem.getSolutions() minvalue = 999 / (9 * 3) minsolution = {} for solution in problem.getSolutions(): a = solution["a"] b = solution["b"] c = solution["c"] value = (a * 100 + b * 10 + c) / (a + b + c) if value < minvalue: minsolution = solution return minvalue, minsolution
def kakuroCSP(): # Pre: variables and equations have been computed by sanityCheck # Will be run in a background thread global solutions, variables # will be accessed by main thread global solverDone problem = Problem() # Restrict the value of each white square as much as possible domains = defaultdict(set) univ = list(range(1,10)) for n in univ: for c in combinations(univ, n): domains[sum(c), n] |= set(c) candidates = {v: set(univ) for v in variables} for eq in equations: for v in eq.variables: candidates[v] &= domains[eq.clue, len(eq.variables)] # one variable for each white square, with values in range computed above for v in variables: problem.addVariable(v, tuple(candidates[v])) for eq in equations: # All the numbers in a single sum are distinct problem.addConstraint(AllDifferentConstraint(), eq.variables) # The numbers must sum to the clue problem.addConstraint(ExactSumConstraint(eq.clue), eq.variables) solutions = problem.getSolutions() solverDone = True
def compute_using_external_solver(predicate, env, varList): # TODO: import at module level # external software: # install http://labix.org/python-constraint # download and unzip python-constraint-1.1.tar.bz2 # python setup.py build # python setup.py install #from pretty_printer import pretty_print #print "predicate:", pretty_print(predicate) from constraint import Problem assert isinstance(predicate, Predicate) var_and_domain_lst = [] # get domain for idNode in varList: assert isinstance(idNode, AIdentifierExpression) atype = env.get_type_by_node(idNode) #if USE_RPYTHON_CODE: # domain = all_values_by_type_RPYTHON(atype, env, idNode) #else: # domain = all_values_by_type(atype, env, idNode) domain = all_values_by_type(atype, env, idNode) tup = (idNode.idName, domain) var_and_domain_lst.append(tup) problem = Problem() # import from "constraint" for tup in var_and_domain_lst: name = tup[0] lst = tup[1] if isinstance(lst, frozenset): lst = set_to_list(lst) problem.addVariable(name, lst) qme_nodes = [] constraint_string = pretty_print_python_style(env, varList, predicate, qme_nodes) names = [x.idName for x in varList] expr = "lambda " for n in names[0:-1]: expr += n+"," expr += varList[-1].idName+":"+constraint_string #print expr my_globales = {"qme_nodes":qme_nodes, "quick_member_eval":quick_member_eval, "env":env} lambda_func = eval(expr, my_globales) # TODO:(#ISSUE 16) not Rpython problem.addConstraint(lambda_func, names) return problem.getSolutionIter()
def solve(): problem = Problem() problem.addVariables(range(1, 21), ["A", "B", "C", "D", "E"]) problem.addConstraint(SomeInSetConstraint(["A"], 4, True)) problem.addConstraint(SomeInSetConstraint(["B"], 4, True)) problem.addConstraint(SomeInSetConstraint(["C"], 4, True)) problem.addConstraint(SomeInSetConstraint(["D"], 4, True)) problem.addConstraint(SomeInSetConstraint(["E"], 4, True)) for row in range(len(STUDENTDESKS) - 1): for col in range(len(STUDENTDESKS[row]) - 1): lst = [STUDENTDESKS[row][col], STUDENTDESKS[row][col + 1], STUDENTDESKS[row + 1][col], STUDENTDESKS[row + 1][col + 1]] lst = [x for x in lst if x] problem.addConstraint(AllDifferentConstraint(), lst) solutions = problem.getSolution() return solutions
def solve(): problem = Problem() # Define the variables: 9 rows of 9 variables rangin in 1...9 for i in range(1, 10): problem.addVariables(range(i * 10 + 1, i * 10 + 10), range(1, 10)) # Each row has different values for i in range(1, 10): problem.addConstraint(AllDifferentConstraint(), range(i * 10 + 1, i * 10 + 10)) # Each colum has different values for i in range(1, 10): problem.addConstraint(AllDifferentConstraint(), range(10 + i, 100 + i, 10)) # Each 3x3 box has different values problem.addConstraint(AllDifferentConstraint(), [11, 12, 13, 21, 22, 23, 31, 32, 33]) problem.addConstraint(AllDifferentConstraint(), [41, 42, 43, 51, 52, 53, 61, 62, 63]) problem.addConstraint(AllDifferentConstraint(), [71, 72, 73, 81, 82, 83, 91, 92, 93]) problem.addConstraint(AllDifferentConstraint(), [14, 15, 16, 24, 25, 26, 34, 35, 36]) problem.addConstraint(AllDifferentConstraint(), [44, 45, 46, 54, 55, 56, 64, 65, 66]) problem.addConstraint(AllDifferentConstraint(), [74, 75, 76, 84, 85, 86, 94, 95, 96]) problem.addConstraint(AllDifferentConstraint(), [17, 18, 19, 27, 28, 29, 37, 38, 39]) problem.addConstraint(AllDifferentConstraint(), [47, 48, 49, 57, 58, 59, 67, 68, 69]) problem.addConstraint(AllDifferentConstraint(), [77, 78, 79, 87, 88, 89, 97, 98, 99]) # Some value is given. initValue = [[0, 9, 0, 7, 0, 0, 8, 6, 0], [0, 3, 1, 0, 0, 5, 0, 2, 0], [8, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 7, 0, 5, 0, 0, 0, 6], [0, 0, 0, 3, 0, 7, 0, 0, 0], [5, 0, 0, 0, 1, 0, 7, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 9], [0, 2, 0, 6, 0, 0, 0, 5, 0], [0, 5, 4, 0, 0, 8, 0, 7, 0]] for i in range(1, 10): for j in range(1, 10): if initValue[i - 1][j - 1] != 0: problem.addConstraint( lambda var, val=initValue[i - 1][j - 1]: var == val, (i * 10 + j, )) # Get the solutions. solutions = problem.getSolutions() return solutions
return "\n".join([ " ".join(self.formatday(d, wd, width) for (d, wd) in theweek), " ".join(self.formathours(d, wd, width) for (d, wd) in theweek), ]) CALENDAR = MCalendar() days = [d for d in CALENDAR.itermonthdates(YEAR, MONTH) if d.month == MONTH] def all_assigned(assignments, variables): return [assignments.get(v, Unassigned) for v in variables].count(Unassigned) == 0 problem = Problem() problem.addVariables(days, list(range(0, 17))) for d in days: if d.day in special: problem.addConstraint(InSetConstraint([special[d.day]]), [d]) elif d.weekday() in regular: problem.addConstraint(InSetConstraint([regular[d.weekday()]]), [d]) problem.addConstraint(MaxSumConstraint(HOURS)) soln = problem.getSolution() CALENDAR.sched = {k.day: v for k, v in soln.items()} CALENDAR.prmonth(YEAR, MONTH)
def solve_board(board, cages): problem = Problem() height = len(board) width = len(board[0]) assert width == height, 'Grid must be a square' cage_name_to_locations = defaultdict(list) for x in range(height): row_variables = [(x, ry) for ry in range(width)] column_variables = [(cx, x) for cx in range(height)] problem.addConstraint(AllDifferentConstraint(), row_variables) problem.addConstraint(AllDifferentConstraint(), column_variables) for y in range(width): if isinstance(board[x][y], basestring): # we are dealing with a function cage_name_to_locations[board[x][y]].append((x, y)) else: # we are dealing with a pre-assigned number problem.addVariable((x, y), [board[x][y]]) for cage_name, cage_locations in cage_name_to_locations.iteritems(): cage_function = cages[cage_name] all_values = product(range(1, width + 1), repeat=len(cage_locations)) possible_values = set(chain(*[values for values in all_values if cage_function(*values)])) for location in cage_locations: problem.addVariable(location, list(possible_values)) problem.addConstraint(FunctionConstraint(cage_function), cage_locations) solution = problem.getSolution() answer = [row[:] for row in board] for x in range(height): for y in range(width): answer[x][y] = solution[(x, y)] return answer
def solution(dimension, solver=None): """Generate binary puzzle solution.""" problem = Problem() if solver is not None: problem.setSolver(solver) else: problem.setSolver(BacktrackingSolver()) problem.addVariables(range(dimension**2), [0, 1]) for i in range(dimension): row_positions = range(i * dimension, (i + 1) * dimension) column_positions = range(i, dimension**2, dimension) # same number of zeros and ones in each row problem.addConstraint(ExactSumConstraint(dimension / 2), row_positions) problem.addConstraint(ExactSumConstraint(dimension / 2), column_positions) # maximum two of the same next to each other for triplet in _nwise(row_positions, 3): problem.addConstraint(MaxSumConstraint(2), triplet) problem.addConstraint(MinSumConstraint(1), triplet) for triplet in _nwise(column_positions, 3): problem.addConstraint(MaxSumConstraint(2), triplet) problem.addConstraint(MinSumConstraint(1), triplet) # unique rows and columns problem.addConstraint( FunctionConstraint(partial(_test_uniqueness, dimension=dimension)), range(dimension**2)) if isinstance(solver, RecursiveBacktrackingSolver): return problem.getSolutions() if isinstance(solver, MinConflictsSolver): return (problem.getSolution(), ) return problem.getSolutionIter()
#Note: Requires 'pip install python-constraint' from constraint import AllDifferentConstraint, InSetConstraint, Problem # variables jobs = "FA EA PA RO AC".split() deskcolor = "Aqua Maroon Pink Cream Purple".split() travel = "Fiji France Canada Japan Thailand".split() drinks = "Peppermint GreenTea Chamomile EarlGrey EnglishBreakfast".split() suburb = "Brunswick, Werribee, Frankston, Oakleigh, StKilda".split(", ") # There are five houses. minn, maxn = 1, 5 problem = Problem() # value of a variable is the number of a house with corresponding property variables = jobs + deskcolor + travel + drinks + suburb problem.addVariables(variables, range(minn, maxn + 1)) # All jobs, colors, travel, drinks, and suburb are unique to each person for vars_ in (jobs, deskcolor, travel, drinks, suburb): problem.addConstraint(AllDifferentConstraint(), vars_) # RULE 4: The cream desk is to the left of the purple desk. #NOTE: interpret it as 'cream desk number' < 'purple desk number' problem.addConstraint(lambda a, b: a < b, ["Cream", "Purple"]) # RULE 8: In the middle desk the drink is Chamomile #NOTE: interpret "middle" in a numerical sense (not geometrical) problem.addConstraint(InSetConstraint([(minn + maxn) // 2]), ["Chamomile"]) # RULE 9: The leftmost desk's job is Financial analyst.
def solveStrimko(routes, values): res = [["." for i in range(size)] for j in range(size)] for r in res: for c in r: print(c, end=" ") print() S = len(res) problem = Problem() for route in routes: problem.addConstraint(AllDifferentConstraint(), route) print(route) for x in values: res[int(x[0])][int(x[1])] = str(x[2]) cellnames = [(i, j) for j, row in enumerate(res) for i, val in enumerate(row)] lookup = {(i, j): res[i][j] for i, j in cellnames} problem.addVariables(cellnames, [str(j) for j in range(1, size + 1)]) for j in range(size): # Columns in grid problem.addConstraint(AllDifferentConstraint(), [(i, j) for i in range(size)]) # Rows in grid problem.addConstraint(AllDifferentConstraint(), [(j, i) for i in range(size)]) for cell, value in lookup.items(): if value != ".": problem.addConstraint(InSetConstraint([str(value)]), [cell]) print("check") print("\n".join(" ".join(lookup[(i, j)] for j in range(size)) for i in range(size))) for solution in problem.getSolutions(): for i in range(0, size): for j in range(0, size): fields[i][j].value = solution[(i, j)]
from constraint import Problem # Define variables for the CSP problem problem = Problem() problem.addVariable("E1", ["A", "R", "M", "P"]) problem.addVariable("E2", ["A", "R", "M", "P"]) problem.addVariable("E3", ["A", "R", "M", "P"]) problem.addVariable("E4", ["A", "R", "M", "P"]) problem.addVariable("E5", ["A", "R", "M", "P"]) problem.addVariable("E6", ["A", "R", "M", "P"]) problem.addVariable("E7", ["A", "R", "M", "P"]) problem.addVariable("E8", ["A", "R", "M", "P"]) problem.addVariable("E9", ["A", "R", "M", "P"]) problem.addVariable("E10", ["A", "R", "M", "P"]) problem.addVariable("E11", ["A", "R", "M", "P"]) problem.addVariable("E12", ["A", "R", "M", "P"]) problem.addVariable("E13", ["A", "R", "M", "P"]) problem.addVariable("E14", ["A", "R", "M", "P"]) problem.addVariable("E15", ["A", "R", "M", "P"]) def lJunction(x, y): if x == "R" and y == "P": return True elif x == "R" and y == "R": return True elif x == "P" and y == "R": return True elif x == "A" and y == "M": return True elif x == "A" and y == "A": return True
def solve(): problem = Problem() # Define the variables: 9 rows of 9 variables rangin in 1...9 for i in range(1, 10): problem.addVariables(range(i * 10 + 1, i * 10 + 10), range(1, 10)) # Each row has different values for i in range(1, 10): problem.addConstraint(AllDifferentConstraint(), range(i * 10 + 1, i * 10 + 10)) # Each colum has different values for i in range(1, 10): problem.addConstraint(AllDifferentConstraint(), range(10 + i, 100 + i, 10)) # Each 3x3 box has different values problem.addConstraint(AllDifferentConstraint(), [11, 12, 13, 21, 22, 23, 31, 32, 33]) problem.addConstraint(AllDifferentConstraint(), [41, 42, 43, 51, 52, 53, 61, 62, 63]) problem.addConstraint(AllDifferentConstraint(), [71, 72, 73, 81, 82, 83, 91, 92, 93]) problem.addConstraint(AllDifferentConstraint(), [14, 15, 16, 24, 25, 26, 34, 35, 36]) problem.addConstraint(AllDifferentConstraint(), [44, 45, 46, 54, 55, 56, 64, 65, 66]) problem.addConstraint(AllDifferentConstraint(), [74, 75, 76, 84, 85, 86, 94, 95, 96]) problem.addConstraint(AllDifferentConstraint(), [17, 18, 19, 27, 28, 29, 37, 38, 39]) problem.addConstraint(AllDifferentConstraint(), [47, 48, 49, 57, 58, 59, 67, 68, 69]) problem.addConstraint(AllDifferentConstraint(), [77, 78, 79, 87, 88, 89, 97, 98, 99]) # Some value is given. initValue = [ [0, 9, 0, 7, 0, 0, 8, 6, 0], [0, 3, 1, 0, 0, 5, 0, 2, 0], [8, 0, 6, 0, 0, 0, 0, 0, 0], [0, 0, 7, 0, 5, 0, 0, 0, 6], [0, 0, 0, 3, 0, 7, 0, 0, 0], [5, 0, 0, 0, 1, 0, 7, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0, 9], [0, 2, 0, 6, 0, 0, 0, 5, 0], [0, 5, 4, 0, 0, 8, 0, 7, 0], ] for i in range(1, 10): for j in range(1, 10): if initValue[i - 1][j - 1] != 0: problem.addConstraint(lambda var, val=initValue[i - 1][j - 1]: var == val, (i * 10 + j,)) # Get the solutions. solutions = problem.getSolutions() return solutions
def solve(): problem = Problem() problem.addVariables("sendmory", range(10)) problem.addConstraint(lambda d, e, y: (d + e) % 10 == y, "dey") problem.addConstraint( lambda n, d, r, e, y: (n * 10 + d + r * 10 + e) % 100 == e * 10 + y, "ndrey" ) problem.addConstraint( lambda e, n, d, o, r, y: (e * 100 + n * 10 + d + o * 100 + r * 10 + e) % 1000 == n * 100 + e * 10 + y, "endory", ) problem.addConstraint( lambda s, e, n, d, m, o, r, y: 1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * r + e == 10000 * m + 1000 * o + 100 * n + 10 * e + y, "sendmory", ) problem.addConstraint(NotInSetConstraint([0]), "sm") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() return solutions
def solve(): problem = Problem() size = matrixOfStrimko.size + 1 # Define the variables: rows of x variables rangin in 1...x # x = tam of the matrix for i in range(1, size): problem.addVariables(range(i * 10 + 1, i * 10 + size), range(1, size)) #Each row has different values for i in range(1, size): problem.addConstraint(AllDifferentConstraint(), range(i * 10 + 1, i * 10 + size)) # Each colum has different values for i in range(1, size): problem.addConstraint(AllDifferentConstraint(), range(10 + i, 10 * size + i, 10)) #Each route has different values for i in range(0, size - 1): problem.addConstraint(AllDifferentConstraint(), matrixOfStrimko.routes[i].elements) return problem.getSolutions()
class GraphletsConstraints(X86AnalyzerBase): #__registers32Bit = ["eax","ebx","ecx","edx","esi","edi","ebp","esp"] __dictNames = ['ref', 'tar'] __printConds = False def __init__(self, nodeGradesInfos=[]): X86AnalyzerBase.__init__(self, nodeGradesInfos) self.problem = Problem(MinConflictsSolver()) # this is to make it human readable .. # we will generator the solution only when we need it and then cache it # TODO make __ self.sol = None for key in self.rewriteDict.keys(): self.rewriteDict[key]['symbolCache'] = {} self.rewriteDict[key]['curLine'] = 1 self.rewriteDict[key]['curPos'] = 1 self.createRewrite() def getEmptyDict(self): d = X86AnalyzerBase.getEmptyDict(self) for key in d.keys(): d[key]['transitions'] = [] d[key]['valuesTrackDict'] = {} #if key != self.REGISTER: d[key]['domain'] = set() #self.rewriteDict[key]['inCmdCounter'] = 1 return d # this will add recorded value to dict, even if there is a conflict it will be recorded... # def insertToDictWithType(self, tarCmdNum, fromStr, refCmdNum, toStr, typeStr, dict2insert=None): assert (dict2insert != None) dict2insert[typeStr]['transitions'].append((tarCmdNum, fromStr, toStr)) #if typeStr != self.REGISTER: dict2insert[typeStr]['domain'].add(toStr) def commitChanges(self, tmpDict): for key in self.rewriteDict.keys(): self.rewriteDict[key]['transitions'].extend( tmpDict[key]['transitions']) #if key != self.REGISTER: self.rewriteDict[key]['domain'].update(tmpDict[key]['domain']) # black list has no generation:) , we can use the rwdict type as they are the same.. def getRewriteWithType(self, tarCmdNum, fromStr, typeStr, FoundBlacklistElement): if self.sol == None: self.callSol() if self.rewriteDict[typeStr]['curLine'] < tarCmdNum: self.rewriteDict[typeStr]['curLine'] = tarCmdNum self.rewriteDict[typeStr]['curPos'] = 1 varName = self.getVarName(self.getShort(typeStr), tarCmdNum, self.rewriteDict[typeStr]['curPos']) self.rewriteDict[typeStr]['curPos'] += 1 if self.sol != None and varName in self.sol: # we have a value! update cache and return it newVal = self.sol[varName] self.rewriteDict[typeStr]['symbolCache'][fromStr] = newVal return newVal elif fromStr in self.rewriteDict[typeStr]['symbolCache']: return self.rewriteDict[typeStr]['symbolCache'][fromStr] else: #not found in this type's map in this generation, return original return fromStr def getShort(self, name): if name == self.FUNCNAME: return "f" elif name == self.VAR: return "m" elif name == self.REGISTER: return "r" else: raise hell def getVarName(self, preFix, curLine, curPos): return preFix + str(curLine) + "-" + str(curPos) + "_TAR" # TODO - make this __ def callSol(self): # we need to go over each dict that is useable, and feed vars and constraints for typeDict in [ x for x in self.rewriteDict.keys() if self.rewriteDict[x]['useAble'] == True ]: curLine = 1 curPos = 1 preFix = self.getShort(typeDict) #if typeDict != self.REGISTER: domain = list(self.rewriteDict[typeDict]['domain']) #else: # domain =self.__registers32Bit for (line, tarStr, refStr) in self.rewriteDict[typeDict]['transitions']: if curLine < line: curPos = 1 curLine = line tarName = self.getVarName(preFix, curLine, curPos) self.problem.addVariables([tarName], domain) if (self.__printConds): print "CONS(text) -> " + tarName + " == " + refStr self.problem.addConstraint(self.checkInputVsTarget(refStr), [tarName]) if tarStr in self.rewriteDict[typeDict][ 'valuesTrackDict'] != None: if (self.__printConds): print "CONS(bag) -> " + self.rewriteDict[typeDict][ 'valuesTrackDict'][tarStr] + " == " + tarName self.problem.addConstraint(self.varsEqual, [ tarName, self.rewriteDict[typeDict]['valuesTrackDict'][tarStr] ]) self.rewriteDict[typeDict]['valuesTrackDict'][tarStr] = tarName curPos += 1 self.sol = self.problem.getSolution() if traceHack: print "(Number of broken - " + str( self.problem.getSolver().getHack()) + ")", def varsEqual(self, v1, v2): return v1 == v2 def checkInputVsTarget(self, target): def retFunc(inputVal): return inputVal == target return retFunc def getSolution(self): if self.sol == None: self.callSol() return self.sol def printSol(self, sol): #better call sol! if sol == None: print "NO SOL!" return last = 1 for key in sorted(sol.iterkeys()): if int(key[1:2]) != last: last = int(key[1:2]) print "" print key + ": " + sol[key] + " ", def getBrokenNumber(self): return self.problem.getSolver().getHack()
def derive_depths(marker_list, additional_constraints=[]): """Use constraint programming to derive the paragraph depths associated with a list of paragraph markers. Additional constraints (e.g. expected marker types, etc.) can also be added. Such constraints are functions of two parameters, the constraint function (problem.addConstraint) and a list of all variables""" if not marker_list: return [] problem = Problem() # Marker type per marker problem.addVariables(["type" + str(i) for i in range(len(marker_list))], markers.types) # Index within the marker list problem.addVariables(["idx" + str(i) for i in range(len(marker_list))], range(51)) # Depth in the tree, with an arbitrary limit of 10 problem.addVariables(["depth" + str(i) for i in range(len(marker_list))], range(10)) all_vars = [] for i in range(len(marker_list)): all_vars.extend(['type' + str(i), 'idx' + str(i), 'depth' + str(i)]) # Always start at depth 0 problem.addConstraint(rules.must_be(0), ("depth0",)) for idx, marker in enumerate(marker_list): idx_str = str(idx) problem.addConstraint(rules.type_match(marker), ("type" + idx_str, "idx" + idx_str)) prior_params = ['type' + idx_str, 'idx' + idx_str, 'depth' + idx_str] for i in range(idx): prior_params += ['type' + str(i), 'idx' + str(i), 'depth' + str(i)] problem.addConstraint(rules.same_type, prior_params) problem.addConstraint(rules.diff_type, prior_params) # @todo: There's probably efficiency gains to making these rules over # prefixes (see above) rather than over the whole collection at once problem.addConstraint(rules.same_depth_same_type, all_vars) problem.addConstraint(rules.stars_occupy_space, all_vars) for constraint in additional_constraints: constraint(problem.addConstraint, all_vars) return [Solution(solution) for solution in problem.getSolutions()]
class Solver(object): problem = None pilots, missions, pilot_prefs = None, None, None uas_max = None # variables pilot_vars, mission_vars = [], [] max_obj = 0 def __init__(self, pilot_map=None, mission_map=None, uas_max=None, pilot_prefs=None): self.problem = Problem(MinConflictsSolver()) self.pilots = pilot_map self.missions = mission_map self.uas_max = uas_max self.pilot_prefs = pilot_prefs def build_variables(self): # pilot-uas variable for key, val in self.pilots.iteritems(): self.problem.addVariable(key, val) self.pilot_vars.append(key) # mission-uas variable for key, val in self.missions.iteritems(): self.problem.addVariable(key, val) self.mission_vars.append(key) def build_constraints(self): # all pilots assigned to different self.problem.addConstraint(AllDifferentConstraint(), self.pilot_vars) # missions must be assigned uas only if a pilot has been assigned to it for mission in self.mission_vars: mission_and_all_pilots = [mission] + self.pilot_vars self.problem.addConstraint( self.__assign__mission_from_assigned_pilots_only, mission_and_all_pilots) # no uas can be assigned to more than 3 missions self.problem.addConstraint(self.__limit_mission_uas, self.mission_vars) def __assign__mission_from_assigned_pilots_only(self, *mission_and_all_pilots): mission = mission_and_all_pilots[0] i = 1 for i in range(1, len(mission_and_all_pilots)): if mission == mission_and_all_pilots[i]: return True return False def __limit_mission_uas(self, *missions): mission_count = {} for i in range(0, self.uas_max + 1): mission_count[i] = 0 for mission in missions: mission_count[mission] += 1 for val in mission_count.itervalues(): if val > 3: return False return True def get_solution(self): return self.problem.getSolution()
def rank(tree): @extend(node.number) def _rank(self): problem.addVariable(id(self), [0]) @extend(node.let) def _rank(self): if isinstance(self.ret, node.ident): # plain assignment -- not a field, lhs indexing vars = [id(self.ret), id(self.args)] try: problem.addVariables(vars, list(range(4))) problem.addConstraint(operator.__eq__, vars) except ValueError: pass else: # lhs indexing or field pass @extend(node.for_stmt) def _rank(self): vars = [id(self.ident), id(self.expr)] problem.addVariables(vars, list(range(4))) problem.addConstraint((lambda u, v: u + 1 == v), vars) @extend(node.if_stmt) def _rank(self): # could use operator.__not__ instead of lambda expression problem.addVariable(id(self.cond_expr), list(range(4))) problem.addConstraint(lambda t: t == 0, [id(self.cond_expr)]) @extend(node.ident) def _rank(self): try: x = id(self) problem.addVariable(x, list(range(4))) for other in self.defs: y = id(other) try: problem.addVariable(y, list(range(4))) except ValueError: pass problem.addConstraint(operator.__eq__, [x, y]) except: print("Ignored ", self) """ @extend(funcall) def rank(self,problem): if not isinstance(self.func_expr,ident): # In MATLAB, chaining subscripts, such as size(a)(1) # is not allowed, so only fields and dot expressions # go here. In Octave, chaining subscripts is allowed, # and such expressions go here. return try: if defs.degree(self.func_expr): # If a variable is defined, it is not a function, # except function handle usages, such as # foo=@size; foo(17) # which is not handled properly yet. x = id(self.func_expr) n = len(self.args) problem.addVariable(x,range(4)) problem.addConstraint((lambda u: u>=n),[x]) return except TypeError: # func_expr is unhashable # For example [10 20 30](2) return except KeyError: # See tests/clear_margins.m return assert getattr(self.func_expr,"name",None) # So func_expr is an undefined variable, and we understand # it's a function call -- either builtin or user-defined. name = self.func_expr.name # if name not in builtins: # # User-defined function # return # builtins[name](self,problem) # #@extend(expr) #def rank(self,problem): # try: # builtins[self.op](self,problem) # except: # pass """ problem = Problem(RecursiveBacktrackingSolver()) for v in node.postorder(tree): for u in v: try: u._rank() except AttributeError: pass s = problem.getSolution() if not s: print("No solutions") else: d = set() #for k in sorted(G.nodes(), key=lambda t: (t.name,t.lexpos)): for k in node.postorder(tree): if isinstance(k, node.ident): print(k.name, k.lineno, s.get(id(k), -1))
def main(puzzle, lines): puzzle = puzzle.rstrip().splitlines() while puzzle and not puzzle[0]: del puzzle[0] # Extract horizontal words horizontal = [] word = [] predefined = {} for row in range(len(puzzle)): for col in range(len(puzzle[row])): char = puzzle[row][col] if not char.isspace(): word.append((row, col)) if char != "#": predefined[row, col] = char elif word: if len(word) > MINLEN: horizontal.append(word[:]) del word[:] if word: if len(word) > MINLEN: horizontal.append(word[:]) del word[:] # Extract vertical words vertical = [] validcol = True col = 0 while validcol: validcol = False for row in range(len(puzzle)): if col >= len(puzzle[row]): if word: if len(word) > MINLEN: vertical.append(word[:]) del word[:] else: validcol = True char = puzzle[row][col] if not char.isspace(): word.append((row, col)) if char != "#": predefined[row, col] = char elif word: if len(word) > MINLEN: vertical.append(word[:]) del word[:] if word: if len(word) > MINLEN: vertical.append(word[:]) del word[:] col += 1 # hnames = ["h%d" % i for i in range(len(horizontal))] # vnames = ["v%d" % i for i in range(len(vertical))] # problem = Problem(MinConflictsSolver()) problem = Problem() for hi, hword in enumerate(horizontal): for vi, vword in enumerate(vertical): for hchar in hword: if hchar in vword: hci = hword.index(hchar) vci = vword.index(hchar) problem.addConstraint(lambda hw, vw, hci=hci, vci=vci: hw[hci] == vw[vci], ("h%d" % hi, "v%d" % vi)) for char, letter in predefined.items(): for hi, hword in enumerate(horizontal): if char in hword: hci = hword.index(char) problem.addConstraint(lambda hw, hci=hci, letter=letter: hw[hci] == letter, ("h%d" % hi,)) for vi, vword in enumerate(vertical): if char in vword: vci = vword.index(char) problem.addConstraint(lambda vw, vci=vci, letter=letter: vw[vci] == letter, ("v%d" % vi,)) wordsbylen = {} for hword in horizontal: wordsbylen[len(hword)] = [] for vword in vertical: wordsbylen[len(vword)] = [] for line in lines: line = line.strip() l = len(line) if l in wordsbylen: wordsbylen[l].append(line.upper()) for hi, hword in enumerate(horizontal): words = wordsbylen[len(hword)] random.shuffle(words) problem.addVariable("h%d" % hi, words) for vi, vword in enumerate(vertical): words = wordsbylen[len(vword)] random.shuffle(words) problem.addVariable("v%d" % vi, words) problem.addConstraint(AllDifferentConstraint()) solution = problem.getSolution() if not solution: print("No solution found!") maxcol = 0 maxrow = 0 for hword in horizontal: for row, col in hword: if row > maxrow: maxrow = row if col > maxcol: maxcol = col for vword in vertical: for row, col in vword: if row > maxrow: maxrow = row if col > maxcol: maxcol = col matrix = [] for row in range(maxrow + 1): matrix.append([" "] * (maxcol + 1)) for variable in solution: if variable[0] == "v": word = vertical[int(variable[1:])] else: word = horizontal[int(variable[1:])] for (row, col), char in zip(word, solution[variable]): matrix[row][col] = char for row in range(maxrow + 1): for col in range(maxcol + 1): sys.stdout.write(matrix[row][col]) sys.stdout.write("\n")
class GraphletsConstraints(X86AnalyzerBase): #__registers32Bit = ["eax","ebx","ecx","edx","esi","edi","ebp","esp"] __dictNames = ['ref','tar'] __printConds = False def __init__(self,nodeGradesInfos=[]): X86AnalyzerBase.__init__(self,nodeGradesInfos) self.problem = Problem(MinConflictsSolver()) # this is to make it human readable .. # we will generator the solution only when we need it and then cache it # TODO make __ self.sol = None for key in self.rewriteDict.keys(): self.rewriteDict[key]['symbolCache'] = {} self.rewriteDict[key]['curLine'] = 1 self.rewriteDict[key]['curPos'] = 1 self.createRewrite() def getEmptyDict(self): d = X86AnalyzerBase.getEmptyDict(self) for key in d.keys(): d[key]['transitions'] = [] d[key]['valuesTrackDict'] = {} #if key != self.REGISTER: d[key]['domain'] = set() #self.rewriteDict[key]['inCmdCounter'] = 1 return d # this will add recorded value to dict, even if there is a conflict it will be recorded... # def insertToDictWithType(self,tarCmdNum,fromStr,refCmdNum,toStr,typeStr,dict2insert=None): assert(dict2insert != None) dict2insert[typeStr]['transitions'].append((tarCmdNum,fromStr,toStr)) #if typeStr != self.REGISTER: dict2insert[typeStr]['domain'].add(toStr) def commitChanges(self,tmpDict): for key in self.rewriteDict.keys(): self.rewriteDict[key]['transitions'].extend(tmpDict[key]['transitions']) #if key != self.REGISTER: self.rewriteDict[key]['domain'].update(tmpDict[key]['domain']) # black list has no generation:) , we can use the rwdict type as they are the same.. def getRewriteWithType(self,tarCmdNum,fromStr,typeStr,FoundBlacklistElement): if self.sol == None: self.callSol() if self.rewriteDict[typeStr]['curLine'] < tarCmdNum : self.rewriteDict[typeStr]['curLine'] = tarCmdNum self.rewriteDict[typeStr]['curPos'] = 1 varName = self.getVarName(self.getShort(typeStr), tarCmdNum, self.rewriteDict[typeStr]['curPos']) self.rewriteDict[typeStr]['curPos'] += 1 if self.sol != None and varName in self.sol: # we have a value! update cache and return it newVal = self.sol[varName] self.rewriteDict[typeStr]['symbolCache'][fromStr] = newVal return newVal elif fromStr in self.rewriteDict[typeStr]['symbolCache']: return self.rewriteDict[typeStr]['symbolCache'][fromStr] else: #not found in this type's map in this generation, return original return fromStr def getShort(self,name): if name == self.FUNCNAME: return "f" elif name == self.VAR: return "m" elif name == self.REGISTER: return "r" else : raise hell def getVarName(self,preFix,curLine,curPos): return preFix + str(curLine) + "-" + str(curPos) + "_TAR" # TODO - make this __ def callSol(self): # we need to go over each dict that is useable, and feed vars and constraints for typeDict in [x for x in self.rewriteDict.keys() if self.rewriteDict[x]['useAble']==True ]: curLine = 1 curPos = 1 preFix = self.getShort(typeDict) #if typeDict != self.REGISTER: domain = list(self.rewriteDict[typeDict]['domain']) #else: # domain =self.__registers32Bit for (line,tarStr,refStr) in self.rewriteDict[typeDict]['transitions']: if curLine < line: curPos = 1 curLine = line tarName = self.getVarName(preFix, curLine, curPos) self.problem.addVariables([tarName],domain) if (self.__printConds): print "CONS(text) -> " + tarName + " == " + refStr self.problem.addConstraint(self.checkInputVsTarget(refStr),[tarName]) if tarStr in self.rewriteDict[typeDict]['valuesTrackDict'] != None: if (self.__printConds): print "CONS(bag) -> " + self.rewriteDict[typeDict]['valuesTrackDict'][tarStr] + " == " + tarName self.problem.addConstraint(self.varsEqual,[tarName,self.rewriteDict[typeDict]['valuesTrackDict'][tarStr]]) self.rewriteDict[typeDict]['valuesTrackDict'][tarStr] = tarName curPos+=1 self.sol = self.problem.getSolution() if traceHack: print "(Number of broken - " + str(self.problem.getSolver().getHack()) + ")", def varsEqual(self,v1, v2): return v1==v2 def checkInputVsTarget(self,target): def retFunc(inputVal): return inputVal == target return retFunc def getSolution(self): if self.sol == None: self.callSol() return self.sol def printSol(self,sol): #better call sol! if sol == None: print "NO SOL!" return last = 1 for key in sorted(sol.iterkeys()): if int(key[1:2]) != last: last = int(key[1:2]) print "" print key + ": " + sol[key] + " ", def getBrokenNumber(self): return self.problem.getSolver().getHack()
def derive_depths(original_markers, additional_constraints=None): """Use constraint programming to derive the paragraph depths associated with a list of paragraph markers. Additional constraints (e.g. expected marker types, etc.) can also be added. Such constraints are functions of two parameters, the constraint function (problem.addConstraint) and a list of all variables""" if additional_constraints is None: additional_constraints = [] if not original_markers: return [] problem = Problem() marker_list = _compress_markerless(original_markers) logger.warn(marker_list) # Depth in the tree, with an arbitrary limit of 10 problem.addVariables(["depth" + str(i) for i in range(len(marker_list))], range(10)) # Always start at depth 0 problem.addConstraint(rules.must_be(0), ("depth0",)) all_vars = [] for idx, marker in enumerate(marker_list): type_var = "type{0}".format(idx) depth_var = "depth{0}".format(idx) # Index within the marker list. Though this variable is redundant, it # makes the code easier to understand and doesn't have a significant # performance penalty idx_var = "idx{0}".format(idx) typ_opts = [t for t in markers.types if marker in t] idx_opts = [i for t in typ_opts for i in range(len(t)) if t[i] == marker] problem.addVariable(type_var, typ_opts) problem.addVariable(idx_var, idx_opts) problem.addConstraint(rules.type_match(marker), [type_var, idx_var]) all_vars.extend([type_var, idx_var, depth_var]) if idx > 0: pairs = all_vars[3 * (idx - 1):] problem.addConstraint(pair_rules, pairs) if idx > 1: pairs = all_vars[3 * (idx - 2):] problem.addConstraint(rules.triplet_tests, pairs) # separate loop so that the simpler checks run first for idx in range(1, len(marker_list)): # start with the current idx params = all_vars[3 * idx:3 * (idx + 1)] # then add on all previous params += all_vars[:3 * idx] problem.addConstraint(rules.continue_previous_seq, params) # @todo: There's probably efficiency gains to making these rules over # prefixes (see above) rather than over the whole collection at once problem.addConstraint(rules.same_parent_same_type, all_vars) for constraint in additional_constraints: constraint(problem.addConstraint, all_vars) solutions = [] for assignment in problem.getSolutionIter(): assignment = _decompress_markerless(assignment, original_markers) solutions.append(Solution(assignment)) if len(solutions) == 10: break # to prevent infinite solution loops return solutions
def computeChannels(self, n, k=2): from constraint import Problem from constraint import SomeInSetConstraint found = False nodes = tuple(self.nodes()) p = Problem() p.addVariables(list(self.nodes()), range(n,0,-1)) # reverse ordering the domain biases the constraint solver towards smaller numbers p.addConstraint(SomeInSetConstraint([1])) def addConstraint(node1, node2, dist, diff): if(node1 in node2.neighbors(dist)): p.addConstraint(lambda x, y: abs(x - y) >= diff,(node1, node2)) return True return False for i in xrange(len(nodes)-1): n1 = nodes[i] for j in xrange(i+1,len(nodes)): n2 = nodes[j] if(not addConstraint(n1, n2, 2, k)): # each node pair needs no more than 1 constraint addConstraint(n1, n2, 4, 1) for rowIter in self.rows(): row = tuple(rowIter) for i in xrange(len(row)-1): p.addConstraint(lambda x, y: y == (x + k) % n + 1,(row[i], row[i+1])) for colIter in self.columns(): col = tuple(colIter) for i in xrange(len(col)-1): p.addConstraint(lambda x, y: y == (x + k - 1) % n + 1,(col[i], col[i+1])) solution = p.getSolution() if(solution == None): return found found = True for node,channel in p.getSolution().iteritems(): node.channel = channel return True
def solve(): problem = Problem() problem.addVariables(range(1, 21), ["A", "B", "C", "D", "E"]) problem.addConstraint(SomeInSetConstraint(["A"], 4, True)) problem.addConstraint(SomeInSetConstraint(["B"], 4, True)) problem.addConstraint(SomeInSetConstraint(["C"], 4, True)) problem.addConstraint(SomeInSetConstraint(["D"], 4, True)) problem.addConstraint(SomeInSetConstraint(["E"], 4, True)) for row in range(len(STUDENTDESKS) - 1): for col in range(len(STUDENTDESKS[row]) - 1): lst = [ STUDENTDESKS[row][col], STUDENTDESKS[row][col + 1], STUDENTDESKS[row + 1][col], STUDENTDESKS[row + 1][col + 1] ] lst = [x for x in lst if x] problem.addConstraint(AllDifferentConstraint(), lst) solutions = problem.getSolution() return solutions
def rank(tree): @extend(node.number) def _rank(self): problem.addVariable(id(self),[0]) @extend(node.let) def _rank(self): if isinstance(self.ret,node.ident): # plain assignment -- not a field, lhs indexing vars = [id(self.ret), id(self.args)] try: problem.addVariables(vars,list(range(4))) problem.addConstraint(operator.__eq__,vars) except ValueError: pass else: # lhs indexing or field pass @extend(node.for_stmt) def _rank(self): vars = [id(self.ident), id(self.expr)] problem.addVariables(vars,list(range(4))) problem.addConstraint((lambda u,v: u+1==v),vars) @extend(node.if_stmt) def _rank(self): # could use operator.__not__ instead of lambda expression problem.addVariable(id(self.cond_expr),list(range(4))) problem.addConstraint(lambda t: t==0, [id(self.cond_expr)]) @extend(node.ident) def _rank(self): try: x = id(self) problem.addVariable(x,list(range(4))) for other in self.defs: y = id(other) try: problem.addVariable(y,list(range(4))) except ValueError: pass problem.addConstraint(operator.__eq__, [x,y]) except: print("Ignored ",self) """ @extend(funcall) def rank(self,problem): if not isinstance(self.func_expr,ident): # In MATLAB, chaining subscripts, such as size(a)(1) # is not allowed, so only fields and dot expressions # go here. In Octave, chaining subscripts is allowed, # and such expressions go here. return try: if defs.degree(self.func_expr): # If a variable is defined, it is not a function, # except function handle usages, such as # foo=@size; foo(17) # which is not handled properly yet. x = id(self.func_expr) n = len(self.args) problem.addVariable(x,range(4)) problem.addConstraint((lambda u: u>=n),[x]) return except TypeError: # func_expr is unhashable # For example [10 20 30](2) return except KeyError: # See tests/clear_margins.m return assert getattr(self.func_expr,"name",None) # So func_expr is an undefined variable, and we understand # it's a function call -- either builtin or user-defined. name = self.func_expr.name # if name not in builtins: # # User-defined function # return # builtins[name](self,problem) # #@extend(expr) #def rank(self,problem): # try: # builtins[self.op](self,problem) # except: # pass """ problem = Problem(RecursiveBacktrackingSolver()) for v in node.postorder(tree): for u in v: try: u._rank() except AttributeError: pass s = problem.getSolution() if not s: print("No solutions") else: d = set() #for k in sorted(G.nodes(), key=lambda t: (t.name,t.lexpos)): for k in node.postorder(tree): if isinstance(k,node.ident): print(k.name,k.lineno, s.get(id(k),-1))
def solve(): problem = Problem() problem.addVariables("seidoz", range(10)) problem.addConstraint(lambda s, e: (2 * s) % 10 == e, "se") problem.addConstraint(lambda i, s, z, e: ((10 * 2 * i) + (2 * s)) % 100 == z * 10 + e, "isze") problem.addConstraint(lambda s, e, i, d, o, z: 2 * (s * 1000 + e * 100 + i * 10 + s) == d * 1000 + o * 100 + z * 10 + e, "seidoz") problem.addConstraint(lambda s: s != 0, "s") problem.addConstraint(lambda d: d != 0, "d") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() return solutions
def solve(): problem = Problem() for i in range(1, 6): problem.addVariable("color%d" % i, ["red", "white", "green", "yellow", "blue"]) problem.addVariable("nationality%d" % i, ["brit", "swede", "dane", "norwegian", "german"]) problem.addVariable("drink%d" % i, ["tea", "coffee", "milk", "beer", "water"]) problem.addVariable("smoke%d" % i, ["pallmall", "dunhill", "blends", "bluemaster", "prince"]) problem.addVariable("pet%d" % i, ["dogs", "birds", "cats", "horses", "fish"]) problem.addConstraint(AllDifferentConstraint(), ["color%d" % i for i in range(1, 6)]) problem.addConstraint(AllDifferentConstraint(), ["nationality%d" % i for i in range(1, 6)]) problem.addConstraint(AllDifferentConstraint(), ["drink%d" % i for i in range(1, 6)]) problem.addConstraint(AllDifferentConstraint(), ["smoke%d" % i for i in range(1, 6)]) problem.addConstraint(AllDifferentConstraint(), ["pet%d" % i for i in range(1, 6)]) for i in range(1, 6): # Hint 1 problem.addConstraint(lambda nationality, color: nationality != "brit" or color == "red", ("nationality%d" % i, "color%d" % i)) # Hint 2 problem.addConstraint(lambda nationality, pet: nationality != "swede" or pet == "dogs", ("nationality%d" % i, "pet%d" % i)) # Hint 3 problem.addConstraint(lambda nationality, drink: nationality != "dane" or drink == "tea", ("nationality%d" % i, "drink%d" % i)) # Hint 4 if i < 5: problem.addConstraint(lambda colora, colorb: colora != "green" or colorb == "white", ("color%d" % i, "color%d" % (i + 1))) else: problem.addConstraint(lambda color: color != "green", ("color%d" % i,)) # Hint 5 problem.addConstraint(lambda color, drink: color != "green" or drink == "coffee", ("color%d" % i, "drink%d" % i)) # Hint 6 problem.addConstraint(lambda smoke, pet: smoke != "pallmall" or pet == "birds", ("smoke%d" % i, "pet%d" % i)) # Hint 7 problem.addConstraint(lambda color, smoke: color != "yellow" or smoke == "dunhill", ("color%d" % i, "smoke%d" % i)) # Hint 8 if i == 3: problem.addConstraint(lambda drink: drink == "milk", ("drink%d" % i,)) # Hint 9 if i == 1: problem.addConstraint(lambda nationality: nationality == "norwegian", ("nationality%d" % i,)) # Hint 10 if 1 < i < 5: problem.addConstraint(lambda smoke, peta, petb: smoke != "blends" or peta == "cats" or petb == "cats", ("smoke%d" % i, "pet%d" % (i - 1), "pet%d" % (i + 1))) else: problem.addConstraint(lambda smoke, pet: smoke != "blends" or pet == "cats", ("smoke%d" % i, "pet%d" % (i == 1 and 2 or 4))) # Hint 11 if 1 < i < 5: problem.addConstraint(lambda pet, smokea, smokeb: pet != "horses" or smokea == "dunhill" or smokeb == "dunhill", ("pet%d" % i, "smoke%d" % (i - 1), "smoke%d" % (i + 1))) else: problem.addConstraint(lambda pet, smoke: pet != "horses" or smoke == "dunhill", ("pet%d" % i, "smoke%d" % (i == 1 and 2 or 4))) # Hint 12 problem.addConstraint(lambda smoke, drink: smoke != "bluemaster" or drink == "beer", ("smoke%d" % i, "drink%d" % i)) # Hint 13 problem.addConstraint(lambda nationality, smoke: nationality != "german" or smoke == "prince", ("nationality%d" % i, "smoke%d" % i)) # Hint 14 if 1 < i < 5: problem.addConstraint(lambda nationality, colora, colorb: nationality != "norwegian" or colora == "blue" or colorb == "blue", ("nationality%d" % i, "color%d" % (i - 1), "color%d" % (i + 1))) else: problem.addConstraint(lambda nationality, color: nationality != "norwegian" or color == "blue", ("nationality%d" % i, "color%d" % (i == 1 and 2 or 4))) # Hint 15 if 1 < i < 5: problem.addConstraint(lambda smoke, drinka, drinkb: smoke != "blends" or drinka == "water" or drinkb == "water", ("smoke%d" % i, "drink%d" % (i - 1), "drink%d" % (i + 1))) else: problem.addConstraint(lambda smoke, drink: smoke != "blends" or drink == "water", ("smoke%d" % i, "drink%d" % (i == 1 and 2 or 4))) solutions = problem.getSolutions() return solutions
def find_mapping(signal_patterns: Set[FrozenSet[str]]) -> Dict[str, str]: # Let’s express this as a constraint satisfaction problem problem = Problem() for signal in "abcdefg": problem.addVariable(signal, "abcdefg") # Each signal wire goes to a different segment problem.addConstraint(AllDifferentConstraint()) # Unambiguous digits based on count of lit segments for digit in {1, 4, 7, 8}: for wire in find_possible_signals_for(signal_patterns, digit): segments = DIGIT_TO_SEGMENTS[digit] problem.addConstraint(InSetConstraint(segments), wire) # Unambiguous segments based on how many times they appear in patterns for signal_wire in {"a", "b", "c", "d", "e", "f", "g"}: count = sum(1 for pattern in signal_patterns if signal_wire in pattern) if count == 4: problem.addConstraint(InSetConstraint(["e"]), signal_wire) elif count == 6: problem.addConstraint(InSetConstraint(["b"]), signal_wire) elif count == 7: problem.addConstraint(InSetConstraint(["d", "g"]), signal_wire) elif count == 8: problem.addConstraint(InSetConstraint(["a", "c"]), signal_wire) elif count == 9: problem.addConstraint(InSetConstraint(["f"]), signal_wire) else: raise ValueError return problem.getSolution()
def __init__(self): self._problem = Problem()
def solve(): problem = Problem() problem.addVariables("sendmory", range(10)) problem.addConstraint(lambda d, e, y: (d + e) % 10 == y, "dey") problem.addConstraint(lambda n, d, r, e, y: (n * 10 + d + r * 10 + e) % 100 == e * 10 + y, "ndrey") problem.addConstraint( lambda e, n, d, o, r, y: (e * 100 + n * 10 + d + o * 100 + r * 10 + e) % 1000 == n * 100 + e * 10 + y, "endory" ) problem.addConstraint( lambda s, e, n, d, m, o, r, y: 1000 * s + 100 * e + 10 * n + d + 1000 * m + 100 * o + 10 * r + e == 10000 * m + 1000 * o + 100 * n + 10 * e + y, "sendmory", ) problem.addConstraint(NotInSetConstraint([0]), "sm") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() return solutions
from constraint import Problem, AllEqualConstraint problem = Problem() problem.addVariables(["a", "b"], [[1,3], [2,4], [5,6]]) problem.addConstraint(AllEqualConstraint(), ["a", "b"]) solutions = problem.getSolutions() print (solutions)
from constraint import AllDifferentConstraint, InSetConstraint, Problem # variables colors = "blue red green white yellow".split() nationalities = "Norwegian Ukranian Japanese Spaniard English".split() pets = "fox dog horse snails zebra".split() drinks = "tea coffee milk orange water".split() fruits = "grapes kiwi bananas peach grapefruit".split() # There are five houses. minn, maxn = 1, 5 problem = Problem() # value of a variable is the number of a house with corresponding property variables = colors + nationalities + pets + drinks + fruits problem.addVariables(variables, range(minn, maxn+1)) # Each house has its own unique color. # All house owners are of different nationalities. # They all have different pets. # They all drink different drinks. # They all smoke different fruits. for vars_ in (colors, nationalities, pets, drinks, fruits): problem.addConstraint(AllDifferentConstraint(), vars_) # In the middle house they drink milk. #NOTE: interpret "middle" in a numerical sense (not geometrical) problem.addConstraint(InSetConstraint([(minn + maxn) // 2]), ["milk"]) # The Norwegian lives in the first house. #NOTE: interpret "the first" as a house number problem.addConstraint(InSetConstraint([minn]), ["Norwegian"]) # The green house is on the left side of the white house.
def problem_2(): """Function for performing the work of problem 2.""" # Initialize the problem. problem = Problem() # Add the variables. problem.addVariable('case', CASES) problem.addVariable('motherboard', MOTHERBOARDS) problem.addVariable('memory', MEMORY) problem.addVariable('GPU', GPUS) problem.addVariable('SSD', SSDS) problem.addVariable('CPU', CPUS) # Add constraints. problem.addConstraint(motherboard_case, ['motherboard', 'case']) problem.addConstraint(motherboard_memory, ['motherboard', 'memory']) problem.addConstraint(motherboard_ssd, ['motherboard', 'SSD']) problem.addConstraint(motherboard_cpu, ['motherboard', 'CPU']) problem.addConstraint(case_gpu, ['case', 'GPU']) return problem
def solve(): problem = Problem() problem.addVariables("twofur", range(10)) problem.addConstraint(lambda o, r: (2 * o) % 10 == r, "or") problem.addConstraint(lambda w, o, u, r: ((10 * 2 * w) + (2 * o)) % 100 == u * 10 + r, "wour") problem.addConstraint(lambda t, w, o, f, u, r: 2 * (t * 100 + w * 10 + o) == f * 1000 + o * 100 + u * 10 + r, "twofur") problem.addConstraint(NotInSetConstraint([0]), "ft") problem.addConstraint(AllDifferentConstraint()) solutions = problem.getSolutions() return solutions
def derive_depths(original_markers, additional_constraints=[]): """Use constraint programming to derive the paragraph depths associated with a list of paragraph markers. Additional constraints (e.g. expected marker types, etc.) can also be added. Such constraints are functions of two parameters, the constraint function (problem.addConstraint) and a list of all variables""" if not original_markers: return [] problem = Problem() marker_list = _compress_markerless(original_markers) # Depth in the tree, with an arbitrary limit of 10 problem.addVariables(["depth" + str(i) for i in range(len(marker_list))], range(10)) # Always start at depth 0 problem.addConstraint(rules.must_be(0), ("depth0",)) all_vars = [] for idx, marker in enumerate(marker_list): type_var = "type{}".format(idx) depth_var = "depth{}".format(idx) # Index within the marker list. Though this variable is redundant, it # makes the code easier to understand and doesn't have a significant # performance penalty idx_var = "idx{}".format(idx) typ_opts = [t for t in markers.types if marker in t] idx_opts = [i for t in typ_opts for i in range(len(t)) if t[i] == marker] problem.addVariable(type_var, typ_opts) problem.addVariable(idx_var, idx_opts) problem.addConstraint(rules.type_match(marker), [type_var, idx_var]) all_vars.extend([type_var, idx_var, depth_var]) if idx > 0: pairs = all_vars[3*(idx-1):] problem.addConstraint(rules.depth_check, pairs) if idx > 1: pairs = all_vars[3*(idx-2):] problem.addConstraint(rules.markerless_sandwich, pairs) problem.addConstraint(rules.star_sandwich, pairs) # separate loop so that the simpler checks run first for idx in range(1, len(marker_list)): # start with the current idx params = all_vars[3*idx:3*(idx+1)] # then add on all previous params += all_vars[:3*idx] problem.addConstraint(rules.sequence, params) # @todo: There's probably efficiency gains to making these rules over # prefixes (see above) rather than over the whole collection at once problem.addConstraint(rules.same_parent_same_type, all_vars) problem.addConstraint(rules.stars_occupy_space, all_vars) for constraint in additional_constraints: constraint(problem.addConstraint, all_vars) solutions = [] for assignment in problem.getSolutionIter(): assignment = _decompress_markerless(assignment, original_markers) solutions.append(Solution(assignment)) return solutions
# Magic Triangle Problem from constraint import Problem from constraint import ExactSumConstraint from constraint import AllDifferentConstraint # Magic triangle with 6 circles (3 on each side), so possible sum is 9,10,11 and 12 print('==========MAGIC TRIANGLE WITH 6 CIRCLES==========\n') for S in range(9, 13): problem = Problem() # Variables problem.addVariable('C1', range(1, 7)) # Corner 1 problem.addVariable('C2', range(1, 7)) # Corner 2 problem.addVariable('C3', range(1, 7)) # Corner 3 problem.addVariable('E1', range(1, 7)) # Edge 1 problem.addVariable('E2', range(1, 7)) # Edge 2 problem.addVariable('E3', range(1, 7)) # Edge 3 # Constraints problem.addConstraint(ExactSumConstraint(S, [1, 1, 1]), ['C1', 'E1', 'C3']) # Side 1 problem.addConstraint(ExactSumConstraint(S, [1, 1, 1]), ['C2', 'E2', 'C1']) # Side 2 problem.addConstraint(ExactSumConstraint(S, [1, 1, 1]), ['C3', 'E3', 'C2']) # Side 3 problem.addConstraint(AllDifferentConstraint(), ['C1', 'C2', 'C3', 'E1', 'E2', 'E3' ]) # Values in each circle are unique solutions = problem.getSolutions() print('Total Number of Possible Solutions for Sum', S, ':', len(solutions))
from constraint import Problem, AllDifferentConstraint from itertools import product from functools import partial columns = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'] rows = [1, 2, 3, 4, 5, 6, 7, 8] mapping = dict((x, y) for x, y in zip(columns, rows)) def bishop_func(a, b, x, y): return abs(mapping[x] - mapping[y]) != abs(a - b) or a == b problem = Problem() problem.addVariables(columns, rows) problem.addConstraint(AllDifferentConstraint()) for column1, column2 in product(columns, columns): problem.addConstraint(partial(bishop_func, x = column1, y = column2), (column1, column2)) for solution in problem.getSolutions(): print sorted(solution.iteritems())
cellnames = sorted(cell for group in groupcells.values() for cell in group) S = len(grid) # size of the grid assert all(len(row) == S for row in grid) assert len(groupnames) == S rownames = list(range(S)) columnnames = list(range(S)) def isadjacent(cell0, cell1): (i0, j0), (i1, j1) = cell0, cell1 return abs(i0 - i1) <= 1 and abs(j0 - j1) <= 1 problem = Problem() problem.addVariables(cellnames, [0, 1]) # 1 = has a star # Each row, column, and group must have exactly N stars for row in rownames: problem.addConstraint(ExactSumConstraint(N), [(x, y) for x, y in cellnames if y == row]) for col in columnnames: problem.addConstraint(ExactSumConstraint(N), [(x, y) for x, y in cellnames if x == col]) for cells in groupcells.values(): problem.addConstraint(ExactSumConstraint(N), cells) # Adjacent cells may not both have a star for cell0 in cellnames: for cell1 in cellnames:
class Scheduler(object): """ This class provides the constraint-based Scheduler. """ def __init__(self, plant, orderList): """ plant is a Plant instance to run the Scheduler on. orderList is the OrderList instance of incoming orders to the Plant. problem is a python-constraint Problem instance where solver is used as the constraint solver. """ assert plant != None assert orderList != None self.plant = plant self.orderList = orderList self.problem = Problem() self.endMargin = 1 self.machineMargin = 1 def createMachineQuantityVarName(self, machine): """ Creates and returns a python-constraint Variable name from a Machine instance. """ assert type(machine) != str or type(machine) != unicode return str(machine.name) + "-quantity" def createEnterTimeVarName(self, order, machine): """ Creates and returns a python-constraint Variable name from an Order instance and a Machine instance. """ if type(machine) == str or type(machine) == unicode: machineName = machine else: machineName = machine.name return str(str(order.id) + "-enter-" + machineName) def createTimeAtMachineVarName(self, order, machine): """ Creates and returns a python-constraint Variable name from an Order instance and a Machine instance. """ if type(machine) == str or type(machine) == unicode: machineName = machine else: machineName = machine.name return str(str(order.id) + "-spend-" + machineName) def addPrecedenceConstraint(self, enterVar, order, machineIndex): """ Adds a python-constraint Variable and Constraint to an order for the precedence of Machine instances. Meaning that an order cannot get into Machine 2 before getting into Machine 1. The sequence is determined by the Plant instance. """ prevMachine = self.plant.machines[machineIndex - 1] enterVar2 = self.createEnterTimeVarName(order, prevMachine) spendVar2 = self.createTimeAtMachineVarName(order, prevMachine) if order.recipe[prevMachine.name] != 0: if prevMachine.quantity <= \ self.plant.machines[machineIndex].quantity \ and prevMachine.canUnhook == False: self.problem.addConstraint(lambda x, y, yt: x == y + yt + \ CraneMoveTime, [enterVar, enterVar2, spendVar2]) else: self.problem.addConstraint(lambda x, y, yt: x >= y + yt + \ CraneMoveTime, [enterVar, enterVar2, spendVar2]) def addFinishTimeVar(self, order): """ Adds a python-constraint Variable and Constraint to an order for the finish time on the Plant. """ var = str(order.id) + "-finish" lastMachine = self.plant.machines[-1] self.problem.addVariable( var, range(order.deadline - self.endMargin, order.deadline + self.endMargin)) self.problem.addConstraint(lambda x, y, yt: x == y + yt, [ var, self.createEnterTimeVarName(order, lastMachine), self.createTimeAtMachineVarName(order, lastMachine) ]) def addOrderEnterTimeAtMachineVar(self, order, machineName, machineIndex): """ Adds a python-constraint Variable and Constraint to an order for the entrance time at a Machine instance. """ var = self.createEnterTimeVarName(order, machineName) if order.recipe[machineName] != 0: machineStart = (order.deadline + self.endMargin) - \ order.recipe.calcMinProcTime(machineName) - self.machineMargin machineEnd = machineStart + self.machineMargin + \ min(self.endMargin, self.machineMargin) variableRange = range(max(machineStart, 0), machineEnd) else: variableRange = range(0, 1) self.problem.addVariable(var, variableRange) if machineIndex != 0: self.addPrecedenceConstraint(var, order, machineIndex) def machineQuantityConstraintFunc(self, *args): quantity = args[0] argsMiddle = (len(args) - 1) / 2 enterTimes = args[1:argsMiddle + 1] spendTimes = args[argsMiddle + 1:] assert len(enterTimes) == len(spendTimes) numberOfCommons = 0 for i, et in enumerate(enterTimes): range1 = range(et, et + spendTimes[i]) numberOfCommons = 0 for j, et2 in enumerate(enterTimes): if i != j: range2 = range(et2, et2 + spendTimes[j]) for v1 in range1: if v1 in range2: numberOfCommons += 1 break return not (numberOfCommons >= quantity) def addMachineQuantityConstraint(self, machine): enterVars = [] spendVars = [] for order in self.orderList.orders: enterVars.append(self.createEnterTimeVarName(order, machine)) spendVars.append(self.createTimeAtMachineVarName(order, machine)) vars = [self.createMachineQuantityVarName(machine)] + \ enterVars + spendVars self.problem.addConstraint(self.machineQuantityConstraintFunc, vars) def machineCapacityConstraintFunc(self, *args): argsMiddle = len(args) / 2 enterTimes = args[0:argsMiddle] nextEnterTimes = args[argsMiddle:] for i, et in enumerate(enterTimes): for j, et2 in enumerate(enterTimes): if i != j: if et > et2 and nextEnterTimes[i] < nextEnterTimes[j]: return False return True def addCapacityConstraint(self, machine, machineIndex): enterVars = [] nextEnterVars = [] nextMachine = self.plant.machines[machineIndex + 1] for order in self.orderList.orders: enterVars.append(self.createEnterTimeVarName(order, machine)) nextEnterVars.append( self.createEnterTimeVarName(order, nextMachine)) self.problem.addConstraint(self.machineCapacityConstraintFunc, enterVars + nextEnterVars) def run(self): """ Runs the main Scheduler logic. """ for order in self.orderList.orders: if order.currentMachine != "": for machineIndex, machine in enumerate(self.plant.machines): if machine.name != order.currentMachine: order.recipe[machine.name] = 0 else: order.recipe[machine.name] = -int( order.currentOvertime) break for machine in self.plant.machines: var = self.createMachineQuantityVarName(machine) self.problem.addVariable(var, [machine.quantity]) for machine in self.plant.machines: for order in self.orderList.orders: var = self.createTimeAtMachineVarName(order, machine) self.problem.addVariable(var, [order.recipe[machine.name]]) for machineIndex, machine in enumerate(self.plant.machines): for order in self.orderList.orders: self.addOrderEnterTimeAtMachineVar(order, machine.name, machineIndex) for machineIndex, machine in enumerate(self.plant.machines): if machine.precedence == True and \ machineIndex != len(self.plant.machines) - 1: self.addCapacityConstraint(machine, machineIndex) self.addMachineQuantityConstraint(machine) for machineIndex, machine in enumerate(self.plant.machines): if len(machine.setOfBreaks()) != 0: for order in self.orderList.orders: enterVar = self.createEnterTimeVarName(order, machine) self.problem.addConstraint( MachineBreaksConstraint(order, machine), [enterVar]) for order in self.orderList.orders: self.addFinishTimeVar(order) return self.printSolutions() def printSolutions(self): """ Properly prints the solutions coming from python-constraint. """ print "Computing solutions..." solutions = self.problem.getSolutions() numberOfSolutions = len(solutions) for i, solution in enumerate(solutions): items = solution.items() # sort by time items.sort(lambda a, b: cmp(a[1], b[1])) # sort by order items.sort(lambda a, b: cmp(a[0][0], b[0][0])) print "Solution number", i + 1 i = 1 for j in items: if j[0][0:1] != str(i): if "enter" in j[0] or "finish" in j[0]: print j, else: print "\n", print "Order no:", i if "enter" in j[0] or "finish" in j[0]: print j, i += 1 print "\n==============================================\n", print "Number of solutions:", numberOfSolutions return solutions, numberOfSolutions def start(self, endMarginLimit=10, machineMarginLimit=2): self.endMargin = 1 while self.endMargin <= endMarginLimit: self.machineMargin = 1 while self.machineMargin <= machineMarginLimit: try: print "End Margin: %d, Machine Margin: %d" % \ (self.endMargin, self.machineMargin) self.problem.reset() solutions, numberOfSolutions = self.run() if numberOfSolutions > 0: return solutions except Exception as e: print e self.machineMargin += 1 self.endMargin += 1 print "No solutions found." return None
def main(puzzle, lines): puzzle = puzzle.rstrip().splitlines() while puzzle and not puzzle[0]: del puzzle[0] # Extract horizontal words horizontal = [] word = [] predefined = {} for row in range(len(puzzle)): for col in range(len(puzzle[row])): char = puzzle[row][col] if not char.isspace(): word.append((row, col)) if char != "#": predefined[row, col] = char elif word: if len(word) > MINLEN: horizontal.append(word[:]) del word[:] if word: if len(word) > MINLEN: horizontal.append(word[:]) del word[:] # Extract vertical words vertical = [] validcol = True col = 0 while validcol: validcol = False for row in range(len(puzzle)): if col >= len(puzzle[row]): if word: if len(word) > MINLEN: vertical.append(word[:]) del word[:] else: validcol = True char = puzzle[row][col] if not char.isspace(): word.append((row, col)) if char != "#": predefined[row, col] = char elif word: if len(word) > MINLEN: vertical.append(word[:]) del word[:] if word: if len(word) > MINLEN: vertical.append(word[:]) del word[:] col += 1 # hnames = ["h%d" % i for i in range(len(horizontal))] # vnames = ["v%d" % i for i in range(len(vertical))] # problem = Problem(MinConflictsSolver()) problem = Problem() for hi, hword in enumerate(horizontal): for vi, vword in enumerate(vertical): for hchar in hword: if hchar in vword: hci = hword.index(hchar) vci = vword.index(hchar) problem.addConstraint(lambda hw, vw, hci=hci, vci=vci: hw[hci] == vw[vci], ("h%d" % hi, "v%d" % vi)) for char, letter in predefined.items(): for hi, hword in enumerate(horizontal): if char in hword: hci = hword.index(char) problem.addConstraint(lambda hw, hci=hci, letter=letter: hw[hci] == letter, ("h%d" % hi,)) for vi, vword in enumerate(vertical): if char in vword: vci = vword.index(char) problem.addConstraint(lambda vw, vci=vci, letter=letter: vw[vci] == letter, ("v%d" % vi,)) wordsbylen = {} for hword in horizontal: wordsbylen[len(hword)] = [] for vword in vertical: wordsbylen[len(vword)] = [] for line in lines: line = line.strip() ll = len(line) if ll in wordsbylen: wordsbylen[ll].append(line.upper()) for hi, hword in enumerate(horizontal): words = wordsbylen[len(hword)] random.shuffle(words) problem.addVariable("h%d" % hi, words) for vi, vword in enumerate(vertical): words = wordsbylen[len(vword)] random.shuffle(words) problem.addVariable("v%d" % vi, words) problem.addConstraint(AllDifferentConstraint()) solution = problem.getSolution() if not solution: print("No solution found!") maxcol = 0 maxrow = 0 for hword in horizontal: for row, col in hword: if row > maxrow: maxrow = row if col > maxcol: maxcol = col for vword in vertical: for row, col in vword: if row > maxrow: maxrow = row if col > maxcol: maxcol = col matrix = [] for row in range(maxrow + 1): matrix.append([" "] * (maxcol + 1)) for variable in solution: if variable[0] == "v": word = vertical[int(variable[1:])] else: word = horizontal[int(variable[1:])] for (row, col), char in zip(word, solution[variable]): matrix[row][col] = char for row in range(maxrow + 1): for col in range(maxcol + 1): sys.stdout.write(matrix[row][col]) sys.stdout.write("\n")