def _generate_solutions(cls, period, doms): """ Each child gets as domain a set of ShiftAssignables, which is generated by their shift preferences; each solution selects for each child a ShiftAssignable so that all assignments are compatible. Here we configure a problem from the constraint library, then call the solver. The problem takes a mapping, doms, from child_pk to a set of assignables for that child, plus a specification, across children, of which assignables are pairwise consistent The solver yields all compatible sets of assignables """ problem = Problem() prefs = (ShiftPreference.objects.filter( period=period).select_related('shift').select_related('child')) for pref in prefs: for assignable in pref.assignables(): if assignable.is_active: doms[assignable.child.pk].append(assignable) for k, dom in doms.items(): try: problem.addVariable(k, dom) except ValueError: return {} cached_compatibility = functools.lru_cache()( lambda a1, a2: a1.is_compatible_with(a2)) for k1, k2 in itertools.combinations(doms.keys(), 2): problem.addConstraint(cached_compatibility, (k1, k2)) # call the solver return problem.getSolutionIter()
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()
def generateSchedule(self, assignments, scoring_function): """ Generate schedule for a user based on scoring_function and user's existing schedule """ problem = Problem() solution = {} print("Name: {self.name}") print("Existing schedule: {self.schedule}") print( f"Possible Rotations: {self.possibleRotations}\nOrder: {self.order}" ) print() if len(self.possibleRotations) > 0: problem.addVariables(self.possibleRotations, self.order) # HARD CONSTRAINT 1 - All rotations must be unique in the period of the program problem.addConstraint(AllDifferentConstraint(), self.possibleRotations) solutions = problem.getSolutions() # Score the options print(f"Scoring {len(solutions)} found") scores = np.zeros(len(solutions)) for sidx, solution in enumerate(solutions): scores[sidx] = scoring_function( assignments, sorted(solution.items(), key=lambda x: x[1]), self.earliestAvailableDate()) chosen = np.argsort(scores) solution = solutions[chosen[0]] print(f"Best solution: {solution}") return solution
def _cp_step(self, state, prob): """ The constraint programming step. This is one of the more complicated steps; it divides the boundary into components that don't influence each other first, then divides each of those into areas that are equally constrained and must therefore have the same probabilities. The combinations of the number of mines in those components is computed with constraint programming. Those solutions are then combined to count the number of models in which each area has the given number of mines, from which we can calculate the average expected number of mines per square in a component if it has M mines, i.e. per component we have a mapping of {num_mines: (num_models, avg_prob)}. This information is then passed on to the combining step to form the final probabilities. :param state: The reduced state. :param prob: The already computed probabilities. :returns: The exact probability for every unknown square. """ components, num_components = self._components(state) c_counts = [] # List of model_count_by_m instances from inside the 'for c' loop. c_probs = [] # List of model_count_by_m instances from inside the 'for c' loop. m_known = self.known_mine_count() # Solve each component individually for c in range(1, num_components+1): areas, constraints = self._get_areas(state, components == c) # Create a CP problem to determine which combination of mines per area is possible. problem = Problem() # Add all variables, each one having a domain [0, num_squares]. for v in areas.values(): problem.addVariable(v, range(len(v)+1)) # Now constrain how many mines areas can have combined. for constraint in constraints: problem.addConstraint(constraint, [v for k, v in areas.items() if constraint in k]) # Add a constraint so that the maximum number of mines never exceeds the number of mines left. problem.addConstraint(MaxSumConstraint(self._total_mines - m_known), list(areas.values())) solutions = problem.getSolutions() model_count_by_m = {} # {m: #models} model_prob_by_m = {} # {m: prob of the average component model} # Now count the number of models that exist for each number of mines in that component. for solution in solutions: m = sum(solution.values()) # Number of models that match this solution. model_count = self._count_models(solution) # Increase counter for the number of models that have m mines. model_count_by_m[m] = model_count_by_m.get(m, 0) + model_count # Calculate the probability of each square in the component having a mines. model_prob = np.zeros(prob.shape) for area, m_area in solution.items(): # The area has `m_area` mines in it, evenly distributed. model_prob[tuple(zip(*area))] = m_area/len(area) # Sum up all the models, giving the expected number of mines of all models combined model_prob_by_m[m] = model_prob_by_m.get(m, np.zeros(prob.shape)) + model_count*model_prob # We've summed the probabilities of each solution, weighted by the number of models with those # probabilities, now divide out the total number of models to obtain the probability of each square of a # model with m mines having a mine. model_prob_by_m = {m: model_prob/model_count_by_m[m] for m, model_prob in model_prob_by_m.items()} c_probs.append(model_prob_by_m) c_counts.append(model_count_by_m) prob = self._combine_components(state, prob, c_probs, c_counts) return prob
def run(self, dag): """run the layout method""" qubits = dag.qubits cxs = set() from constraint import Problem, AllDifferentConstraint, RecursiveBacktrackingSolver from qiskit.transpiler.passes.layout._csp_custom_solver import CustomSolver for gate in dag.two_qubit_ops(): cxs.add((qubits.index(gate.qargs[0]), qubits.index(gate.qargs[1]))) edges = set(self.coupling_map.get_edges()) if self.time_limit is None and self.call_limit is None: solver = RecursiveBacktrackingSolver() else: solver = CustomSolver(call_limit=self.call_limit, time_limit=self.time_limit) variables = list(range(len(qubits))) variable_domains = list(self.coupling_map.physical_qubits) random.Random(self.seed).shuffle(variable_domains) problem = Problem(solver) problem.addVariables(variables, variable_domains) problem.addConstraint( AllDifferentConstraint()) # each wire is map to a single qubit if self.strict_direction: def constraint(control, target): return (control, target) in edges else: def constraint(control, target): return (control, target) in edges or (target, control) in edges for pair in cxs: problem.addConstraint(constraint, [pair[0], pair[1]]) solution = problem.getSolution() if solution is None: stop_reason = "nonexistent solution" if isinstance(solver, CustomSolver): if solver.time_current is not None and solver.time_current >= self.time_limit: stop_reason = "time limit reached" elif solver.call_current is not None and solver.call_current >= self.call_limit: stop_reason = "call limit reached" else: stop_reason = "solution found" self.property_set["layout"] = Layout( {v: qubits[k] for k, v in solution.items()}) for reg in dag.qregs.values(): self.property_set["layout"].add_register(reg) self.property_set["CSPLayout_stop_reason"] = stop_reason
def solver(domain, appointments): problem = Problem() ConstraintGraphCost = nx.Graph() variablesName = [] # for each appointment (iterate on the numerical key of the appointments) for x in appointments: dom = [] # check which elements of the generic domain are necessary for this appointment for y in domain: hour, minutes = y[1].split(".") hour = int(hour) #print(appointments[x]) #print(appointments[x]["Day"]) for a in appointments[x]["Day"]: if "Morning" == a[1] and hour < 12 and y[0] in a[0] and y[ 2] in appointments[x]["House"]: dom.append(y) if "Afternoon" == a[1] and hour > 12 and y[0] in a[0] and y[ 2] in appointments[x]["House"]: dom.append(y) #Aggiungo la variabile corrente con il domain aggiustato # print(dom) variablesName.append(x) ConstraintGraphCost.add_node(x, domain=dom) problem.addVariable(x, dom) a = itertools.combinations(variablesName, 2) for i in a: #print("Considero ", i) stop = False for domItem1 in ConstraintGraphCost.nodes[i[0]]['domain']: if (stop): break else: for domItem2 in ConstraintGraphCost.nodes[i[1]]['domain']: if domItem1[0] == domItem2[0] and domItem1[1] == domItem2[ 1] and domItem1 != "notScheduled": #print("creo edge") ConstraintGraphCost.add_edge(i[0], i[1]) problem.addConstraint(constraintFunction(), (i[0], i[1])) stop = True break start = current_milli_time() solution = problem.getSolution() end = current_milli_time() print("\n\n###########Time spent to find the first solution = ", end - start, " ms.\n\n") # pp.pprint(solution) return solution
def test_toy_python_constraint(): def func1(a): return a < 0 p = Problem() p.addVariable("a", [-1, -2, 0, 1, 2]) p.addConstraint(func1, ["a"]) result = p.getSolutions() print(result)
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 = 3.00 variables = ("0.02", "0.09", "0.13", "1.50", "2.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 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 test_constraint(): c = Problem() c.addVariable("i", range(-100, 10)) c.addVariable("j", range(-10, 10)) c.addVariable("k", range(-10, 10)) c.addConstraint(lambda i, j, k: i <= 0 or j <= 0 or k <= 0, ("i", "j", "k")) C = CustomConstraint(c) values1 = [-1, -1, -1] values2 = [9, 8, 2] assert C.to_fitness(values1) == 9963.0 assert C.to_fitness(values2) == 12349.0
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() 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 color(map, colors=['red', 'green', 'blue']): (vars, adjoins) = parse_map(map) p = Problem() p.addVariables(vars, colors) for (v1, v2) in adjoins: p.addConstraint(NEQ, [v1, v2]) solution = p.getSolution() if solution: for v in sorted(vars): print("{}:{} ".format(v, solution[v]), end='') print() else: print('No solution found :-(')
def processResults(all_data): prob = Problem() for i, d in enumerate(all_data): prob.addVariable(i, d["logic"]) prob.addConstraint(MaxSumConstraint(234720)) solutions = prob.getSolutionIter() for i, s in enumerate(solutions): if i % 1000 == 0: print(i)
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 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(): 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("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 run(self, dag): qubits = dag.qubits cxs = set() for gate in dag.two_qubit_ops(): cxs.add((qubits.index(gate.qargs[0]), qubits.index(gate.qargs[1]))) edges = set(self.coupling_map.get_edges()) if self.time_limit is None and self.call_limit is None: solver = RecursiveBacktrackingSolver() else: solver = CustomSolver(call_limit=self.call_limit, time_limit=self.time_limit) problem = Problem(solver) problem.addVariables(list(range(len(qubits))), self.coupling_map.physical_qubits) problem.addConstraint( AllDifferentConstraint()) # each wire is map to a single qubit if self.strict_direction: def constraint(control, target): return (control, target) in edges else: def constraint(control, target): return (control, target) in edges or (target, control) in edges for pair in cxs: problem.addConstraint(constraint, [pair[0], pair[1]]) random.seed(self.seed) solution = problem.getSolution() if solution is None: stop_reason = 'nonexistent solution' if isinstance(solver, CustomSolver): if solver.time_current is not None and solver.time_current >= self.time_limit: stop_reason = 'time limit reached' elif solver.call_current is not None and solver.call_current >= self.call_limit: stop_reason = 'call limit reached' else: stop_reason = 'solution found' self.property_set['layout'] = Layout( {v: qubits[k] for k, v in solution.items()}) self.property_set['CSPLayout_stop_reason'] = stop_reason
def team_solver(all_players, max_overall): problem = Problem() for position in all_players: problem.addVariable(position, all_players[position]) def constraint(pg, sg, sf, pf, c): team_overall = pg['player']['overall'] + sg['player']['overall'] + \ sf['player']['overall'] + pf['player']['overall'] + \ c['player']['overall'] return team_overall <= max_overall problem.addConstraint(constraint) return problem.getSolutions()
def test_least_conflicts_solver(): # another test for LeastConflictsSolver problem = Problem(LeastConflictsSolver()) result = [[('a', 1), ('b', 2), ('c', 1)], [('a', 2), ('b', 1), ('c', 1)], [('a', 2), ('b', 2), ('c', 1)]] problem.addVariables(["a", "b"], [1, 2]) problem.addVariable("c", [1]) problem.addConstraint(lambda a, b: b != a, ["a", "b"]) problem.addConstraint(lambda a, b: b != a, ["a", "c"]) problem.addConstraint(lambda a, b: b != a, ["b", "c"]) solution = problem.getSolution() assert sorted(solution.items()) in result
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 get_solution(genome_index: pd.Index, genome_constraints: pd.DataFrame, i: int) -> dict: solutions = {} final_solution = {} while solutions is not None: problem = Problem(MinConflictsSolver()) problem.addVariables(list(genome_index), range(1, i)) unmatched_regions = genome_constraints[ genome_constraints.constraint == 0] # todo extract to method unmatched_regions.apply(lambda row: problem.addConstraint( lambda row1, row2: row1 != row2, (row['index_x'], row['index_y'])), axis=1) print("generating a solution for", i - 1, "groups") solutions = problem.getSolution() if solutions is not None: print("solution found for", i - 1, "groups") i -= 1 final_solution = solutions else: print("no solution for", i - 1, "groups, therefore optimal solution is", i, "groups") return final_solution
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()]
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()]
def solver(domain, appointments): problem = Problem() # for each appointment (iterate on the numerical key of the appointments) for x in appointments: dom = [] # check which elements of the generic domain are necessary for this appointment for y in domain: hour, minutes = y[1].split(".") hour = int(hour) if "Morning" in appointments[x]["Pref"] and hour < 12 and y[ 0] in appointments[x]["Day"] and y[2] in appointments[x][ "House"]: dom.append(y) if "Afternoon" in appointments[x]["Pref"] and hour > 12 and y[ 0] in appointments[x]["Day"] and y[2] in appointments[x][ "House"]: dom.append(y) # print("FOR APPOINTMENT:\n") # pp.pprint(x) # print("The domain is:\n") # pp.pprint(dom) # add a variable to the CSP problem with the appointment *x* and the just computed domain *dom* problem.addVariable(x, dom) # add constraints for x in appointments: for y in appointments: if (x != y): problem.addConstraint(constraintFunction(), (x, y)) start = current_milli_time() solution = problem.getSolution() end = current_milli_time() print("\n\n###########Time spent to find the first solution = ", end - start, " ms.\n\n") # pp.pprint(solution) return solution
def solve_puzzles(puzzles, solver): """ Solves an array of sudoku puzzles, recording runtime. :param puzzles: an array of 2D array boards :param solver: the CSP solver to be used :return: none """ fail_count = 0 start_time = datetime.now() # start timer (for runtime) for puzzle in puzzles: # initialize Board b = Board(puzzle) sudoku = Problem(solver) # initialize CSP with custom solver # add variables for each square, indexed 1...size^2 for index in range(b.board_size ** 2): value = b.get_value(index) if value == 0: sudoku.addVariable(index, range(1, b.board_size + 1)) else: sudoku.addVariable(index, [value]) # add uniqueness constraints to each row, column, and subsquare for i in range(b.board_size): sudoku.addConstraint(AllDifferentConstraint(), [el[0] for el in b.row(i)]) sudoku.addConstraint(AllDifferentConstraint(), [el[0] for el in b.col(i)]) sudoku.addConstraint(AllDifferentConstraint(), [el[0] for el in b.subsquare(i)]) sln = sudoku.getSolution() # solve CSP if sln: # assign solved values for index, value in sln.items(): b.set_value(index, value) else: fail_count += 1 # perform/display runtime calculation runtime = datetime.now() - start_time print("Runtime: {} seconds ({} failed)".format(runtime.total_seconds(), fail_count))
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 try_assignment(): problem = Problem() for variable in self.variables: candidates = [assignment[variable.name]] if variable.name in assignment else groups domain = list([g for g in candidates if any(st in variable.types for st in (Typing.as_legacy_type(gt) for gt in g.vector_types))]) if len(domain) == 0: return variable.name in assignment, [] problem.addVariable(variable.name, domain) for f in filters: variables = list([v.name for v in f.variables]) def c_j(ff, vv): return lambda *args: ff.test_relaxed({vv[i]: args[i] for i in range(len(args))}, solutions) problem.addConstraint(c_j(f, variables), variables) return True, list(problem.getSolutions())
def solve(ac=False, pc=False): problem = Problem() # Countries countries = ['A', 'B', 'C'] # Number of colors num_colors = 2 # Neighbours on the map neighbours = ['AB', 'BC', 'CA'] neighbours = [''.join(sorted(n)) for n in neighbours] problem.addVariables(countries, range(num_colors)) for country1 in countries: for country2 in countries: if country1 != country2: constraint = lambda color1, color2, country1=country1, country2=country2: not any( ''.join(sorted(country1 + country2)) in s for s in neighbours) or color1 != color2 problem.addConstraint(constraint, [country1, country2]) solutions = problem.getSolutions(ac, pc) print('Solutions:\n', solutions) return solutions
def player_solver(players, attribute_bounds): def create_constraint(attribute, bounds): min_value, max_value = bounds def constraint(player): return min_value <= player[attribute] return constraint # def constraint(player): # return min_value <= player[attribute] <= max_value # return constraint problem = Problem() problem.addVariable("player", players) for attribute, bounds in attribute_bounds.items(): constraint = create_constraint(attribute, bounds) problem.addConstraint(constraint, ["player"]) return problem.getSolutions()
def test_addVariable_support_domain_subclasses(): class MyCustomDomain(Domain): pass class MyConstraint(Constraint): def __call__(self, variables, domains, assignments, forwardcheck=False): assert isinstance(domains['x'], Domain) assert isinstance(domains['y'], MyCustomDomain) return True problem = Problem() problem.addVariable("x", [0, 1]) problem.addVariable("y", MyCustomDomain([0, 1])) problem.addConstraint(MyConstraint()) solution = problem.getSolution() possible_solutions = [ { "x": 0, "y": 0 }, { "x": 0, "y": 1 }, { "x": 1, "y": 0 }, { "x": 1, "y": 1 }, ] assert solution in possible_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()
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 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 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 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(): 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 run(self, dag): try: from constraint import Problem, RecursiveBacktrackingSolver, AllDifferentConstraint except ImportError: raise TranspilerError('CSPLayout requires python-constraint to run. ' 'Run pip install python-constraint') qubits = dag.qubits() cxs = set() for gate in dag.twoQ_gates(): cxs.add((qubits.index(gate.qargs[0]), qubits.index(gate.qargs[1]))) edges = self.coupling_map.get_edges() problem = Problem(RecursiveBacktrackingSolver()) problem.addVariables(list(range(len(qubits))), self.coupling_map.physical_qubits) problem.addConstraint(AllDifferentConstraint()) # each wire is map to a single qbit if self.strict_direction: def constraint(control, target): return (control, target) in edges else: def constraint(control, target): return (control, target) in edges or (target, control) in edges for pair in cxs: problem.addConstraint(constraint, [pair[0], pair[1]]) random.seed(self.seed) solution = problem.getSolution() if solution is None: return self.property_set['layout'] = Layout({v: qubits[k] for k, v in solution.items()})
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 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 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 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 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
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 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")
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
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. #XXX: what is "the left side"? (linear, circular, two sides, 2D house arrangment) #NOTE: interpret it as 'green house number' + 1 == 'white house number' problem.addConstraint(lambda a,b: a+1 == b, ["green", "white"]) def add_constraints(constraint, statements, variables=variables, problem=problem): for stmt in (line for line in statements if line.strip()): print [v for v in variables if v in stmt]
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
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())
class GraphletsConstraints(RWEngineBase): __printConds = False def __init__(self,nodeGradesInfos): self.nodeGradesInfos = nodeGradesInfos self.sol = None # a field is somthing seperated by " " , an argument is a list of params seperated by "," ; a member is a param seperated by "+" def breakCommand(self,cmd): cmdFields = seperateCmd(cmd) if len(cmdFields) ==0: print "asd" assert (len(cmdFields) >0) if len(cmdFields) == 1 : return {'nemonic':cmdFields[0],'nemonicWithDecoretors':" ".join(cmdFields[0:-1]),'ParamsList':[]} else: return {'nemonic':cmdFields[0],'nemonicWithDecoretors':" ".join(cmdFields[0:-1]),'ParamsList':cmdFields[-1].split(",")} #TODO - add to this.. lvalCmdsStarts = ["mov","sub","add","xor"] def getNemonicType(self,nemonic): if any(map(lambda startString: nemonic.startswith(startString),self.lvalCmdsStarts)): return "WriteThenRead" else: return "Read" FuncPrefix = "f" VARPrefix = "s" RegisterPrefix = "r" OffsetPrefix = "o" OtherPrefix = "X" def getPrefix(self,Str): if isVarStr(Str): return self.VARPrefix elif isRegisterStr(Str): return self.RegisterPrefix elif isOffset(Str): return self.OffsetPrefix else: return self.OtherPrefix def varsEqual(self,v1, v2): return v1==v2 def checkInputVsTarget(self,target): def retFunc(inputVal): return inputVal == target return retFunc def getVarName(self,prefix,lineNumber,varsInThisLine): return prefix + str(lineNumber) + "-" + str(varsInThisLine) + "_TAR" def getMembers(self,param): refMembers = param.split("+") refMembers[0] = refMembers[0][1:] #remove [ from first refMembers[-1] = refMembers[-1][0:-1] # remove ] from last (they can be the same one!) return refMembers def getDomains(self): domains = {self.FuncPrefix:set(),self.VARPrefix:set(),self.RegisterPrefix:set(),self.OffsetPrefix:set()} def getCmdSymbols(cmd): cmdBasicInfo = self.breakCommand(cmd) for param in cmdBasicInfo['ParamsList']: if param.startswith("["): for member in self.getMembers(param): yield member else: yield param def getCmds(cmdsDelimited): return filter(None,cmdsDelimited.split(";")) for cmdList in itertools.imap(lambda nodeGradesInfo:getCmds(nodeGradesInfo['refCode']),self.nodeGradesInfos): for cmd in cmdList: if isCall(cmd): prefix = self.FuncPrefix domains[prefix].add(list(getCmdSymbols(cmd))[0]) else: for symbol in getCmdSymbols(cmd): prefix = self.getPrefix(symbol) if prefix != self.OtherPrefix: domains[prefix].add(symbol) for domainName in domains.keys(): domains[domainName] = list(domains[domainName]) return domains def callSol(self): domains = self.getDomains() #domains[refPrefix].add(refVal) self.problem = Problem(MinConflictsSolver()) tarSymbolsCache = {} self.varsInThisLine = 0 def addInTraceletCons(tarVal,newVarName): if (self.__printConds): print "CONS(IN) -> " + tarSymbolsCache[tarVal] + " == " + newVarName self.problem.addConstraint(self.varsEqual,[newVarName,tarSymbolsCache[tarVal]]) def addCrossTraceletCons(refVal,newVarName,refPrefix): if (self.__printConds): print "CONS(CROSS) -> " + newVarName + " == " + refVal self.problem.addConstraint(self.checkInputVsTarget(refVal),[newVarName]) def addVarWithPrefix(prefix,lineNumber): newVarName = self.getVarName(prefix,lineNumber,self.varsInThisLine) if len(domains[prefix]) == 0: print "EMP" self.problem.addVariables([newVarName],domains[prefix]) self.varsInThisLine+=1 return newVarName # mode can be - WRITE or NORMAL def doDF(refSymbol,tarSymbol,lineNumber,refPrefix,tarPrefix,nemonicType): if refPrefix == self.OtherPrefix or tarPrefix == self.OtherPrefix: return newVarName = addVarWithPrefix(tarPrefix,lineNumber) if (refPrefix == tarPrefix): addCrossTraceletCons(refSymbol,newVarName,refPrefix) if tarSymbol in tarSymbolsCache: addInTraceletCons(tarSymbol,newVarName) if tarPrefix != self.RegisterPrefix or nemonicType=="WriteThenRead": tarSymbolsCache[tarSymbol] = newVarName #for matchedCmd in itertools.chain(map(lambda nodeInfo:nodeInfo['matchedCmds'],self.nodeGradesInfos)): tarBase = 0 refBase = 0 for nodeInfo in self.nodeGradesInfos: for matchedCmd in nodeInfo['matchedCmds']: self.varsInThisLine = 1 # if these cmds are not an operational match, we cannot cross tracelet match them. if matchedCmd['operationMatch'] == True: currentLineNumber = tarBase + matchedCmd['tarCmdNum'] # matchedCmd['tarCmdNum'] is 1 based so we are ok if matchedCmd['tar'] =="" or matchedCmd['ref'] =="": continue tarCmdBasicInfo = self.breakCommand(matchedCmd['tar']) refCmdBasicInfo = self.breakCommand(matchedCmd['ref']) if len(tarCmdBasicInfo['ParamsList'])>0 and len(refCmdBasicInfo['ParamsList'])>0: if tarCmdBasicInfo['nemonic'] == 'call': assert(len(refCmdBasicInfo['ParamsList'])==1) assert(len(tarCmdBasicInfo['ParamsList'])==1) doDF(refCmdBasicInfo['ParamsList'][0], tarCmdBasicInfo['ParamsList'][0], currentLineNumber, self.FuncPrefix,self.FuncPrefix, "Read") else: nemonicType = self.getNemonicType(tarCmdBasicInfo['nemonic']) for (refParam,tarParam) in zip(refCmdBasicInfo['ParamsList'],tarCmdBasicInfo['ParamsList']): tarIsMem = "[" in tarParam if tarIsMem != ("[" in refParam): continue print matchedCmd print "BOY" assert tarIsMem == ("[" in refParam) if not tarIsMem: tarPreFix = self.getPrefix(tarParam) refPreFix = self.getPrefix(refParam) doDF(refParam, tarParam, currentLineNumber, tarPreFix,refPreFix, nemonicType) # TODO - return this to find more classes when we have time... """ if nemonicType == "WriteThenRead": if tarPreFix != self.RegisterPrefix: print matchedCmd assert (tarPreFix == self.RegisterPrefix) # the write is only to the left most param, rest are normal """ else: # this is memory! , first remove '[',']' for (refMember,tarMember) in zip(self.getMembers(refParam),self.getMembers(tarParam)): tarPreFix = self.getPrefix(tarMember) refPreFix = self.getPrefix(refMember) doDF(refMember, tarMember, currentLineNumber, tarPreFix,refPreFix, nemonicType) nemonicType = "Read" #TODO handle the False clause ? tarBase += nodeInfo['tarCode'].count(";") refBase += nodeInfo['refCode'].count(";") self.sol = self.problem.getSolution() #print self.sol def getBrokenNumber(self): return self.problem.getSolver().getHack() # TODO - make this __ def getRW(self): sol = self.getSolution() tarBase = 0 symbolsCache = {} self.varsInThisLine = 0 TotalLineNumber = 0 def getRewrittenSymbolUpdateCache(prefix,symbol): varName = self.getVarName(prefix, TotalLineNumber, self.varsInThisLine) if sol != None and varName in sol: symbolsCache[symbol] = sol[varName] return sol[varName] else: return symbol def rewrittenParam(param): if param.startswith("["): rewrittenMembers = [] for member in self.getMembers(param): rewrittenMembers.append(getRewrittenSymbolUpdateCache(self.getPrefix(member), member)) self.varsInThisLine+=1 return "[" + "+".join(rewrittenMembers) + "]" else: newParam = getRewrittenSymbolUpdateCache(self.getPrefix(param), param) self.varsInThisLine+=1 return newParam for nodeInfo in self.nodeGradesInfos: cmdsStr = nodeInfo['tarCode'] rewrittenCmds = [] lastLineNumber = 0 #filter(None,) for (lineNumber,cmd) in enumerate(cmdsStr.split(";")): TotalLineNumber = tarBase + lineNumber + 1 # we are one based lastLineNumber = lineNumber +1 # we are one based self.varsInThisLine = 1 if cmd != "": tarCmdBasicInfo = self.breakCommand(cmd) if len(tarCmdBasicInfo['ParamsList'])>0: if tarCmdBasicInfo['nemonic'] == 'call': rewrittenCmds.append("call " + getRewrittenSymbolUpdateCache(self.FuncPrefix,tarCmdBasicInfo['ParamsList'][0])) else: rewrittenCmds.append(tarCmdBasicInfo['nemonicWithDecoretors'] + " " + ",".join(map(rewrittenParam,tarCmdBasicInfo['ParamsList']))) else: rewrittenCmds.append(cmd) else: # this mostly cuz of bugs, but if i wont accumidate them it will cause a bad grade for nothing..(everything else wont be aligned) rewrittenCmds.append(cmd) tarBase += lastLineNumber-1 yield ";".join(rewrittenCmds) 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] + " ",
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()