def arithmetic(puzzle="SEND+MORE=MONEY", base=10) -> None: problem = re.split(r"[\s+=]", puzzle) # remove spaces problem = list(filter(lambda w: len(w) > 0, problem)) letters = { letter: facile.variable(range(base)) for letter in set("".join(problem)) } # expressions expr_pb = [[letters[a] for a in word] for word in problem] def horner(a: Expression, b: Expression): return 10 * a + b words = [reduce(horner, word) for word in expr_pb] # constraints facile.constraint(facile.alldifferent(letters.values())) facile.constraint(facile.sum(words[:-1]) == words[-1]) for word in expr_pb: facile.constraint(word[0] > 0) assert facile.solve(letters.values()) # print solutions for word, numbers in zip(problem, expr_pb): strings = [str(n.value()) for n in numbers] print(f"{word} = {''.join(strings)}")
def print_current(sol): print("Solution after {} backtracks:".format(sol.backtrack)) for i, x in enumerate(sol.solution): if x == 0: continue print(" {} × {:<20} : {:>5}".format(x, products[i], x * price[i])) total = sum(x * price[i] for i, x in enumerate(sol.solution)) print(" Total : {:>5}".format(total))
def test_magical() -> None: array = [facile.variable(range(10)) for i in range(10)] for i in range(10): sum_ = facile.sum(x == i for x in array) facile.constraint(sum_ == array[i]) solution = facile.solve(array) assert solution.solved assert solution.solution == [6, 2, 1, 0, 0, 0, 1, 0, 0, 0]
def coins(values, maxval) -> Optional[Solution]: """ Which coins do you need to give back change for any amount between 0 and maxval, using coins from values? """ # How many coin types n = len(values) nb_min_coins = [variable(range(maxval // values[i])) for i in range(n)] for val in range(maxval): # How many coins per type nb_coins = [variable(range(maxval // values[i])) for i in range(n)] mysum = sum([x[0] * x[1] for x in zip(values, nb_coins)]) constraint(mysum == val) for j in range(len(nb_coins)): constraint(nb_coins[j] <= nb_min_coins[j]) total = variable(sum(nb_min_coins)) return minimize(nb_min_coins, total)
import facile # Magical sequence! # The value inside array[i] is equal to the number of i in array array = [facile.variable(range(10)) for i in range(10)] for i in range(10): facile.constraint(facile.sum(x == i for x in array) == array[i]) if facile.solve(array): print([v.value() for v in array])
# Agatha hates everybody except the butler. constraint(hates[agatha, charles] == 1) constraint(hates[agatha, agatha] == 1) constraint(hates[agatha, butler] == 0) # The butler hates everyone not richer than Aunt Agatha. # (richer[i, agatha] = 0) => (hates[butler, i] = 1), for i in range(n): constraint((richer[i, agatha] == 0) <= (hates[butler, i] == 1)) # The butler hates everyone whom Agatha hates. # (hates[agatha, i] = 1) => (hates[butler, i] = 1), for i in range(n): constraint((hates[agatha, i] == 1) <= (hates[butler, i] == 1)) # No one hates everyone. # (sum j: hates[i, j]) <= 2, for i in range(n): constraint(sum([hates[i, j] for j in range(n)]) <= 2) # Who killed Agatha? constraint(victim == agatha) assert solve(list(hates) + list(richer) + [victim, killer]) killer_value = killer.value() assert killer_value is not None msg = "{} killed Agatha." print(msg.format(["Agatha", "The butler", "Charles"][killer_value]))
buckets = [ [variable(range(capacity[b] + 1)) for b in range(nb)] for i in range(steps) ] constraint(buckets[0][0] == 8) constraint(buckets[0][1] == 0) constraint(buckets[0][2] == 0) constraint(buckets[steps - 1][0] == 4) constraint(buckets[steps - 1][1] == 4) constraint(buckets[steps - 1][2] == 0) for i in range(steps - 1): # we change the contents of two buckets at a time sum_buckets = sum([buckets[i][b] != buckets[i + 1][b] for b in range(nb)]) constraint(sum_buckets == 2) # we play with a constant amount of water sum_water = sum([buckets[i][b] for b in range(nb)]) constraint(sum_water == 8) for b1 in range(nb): for b2 in range(b1): constraint( # either the content of the bucket does not change (buckets[i][b1] == buckets[i + 1][b1]) | (buckets[i][b2] == buckets[i + 1][b2]) | # or the bucket ends up empty or full (buckets[i + 1][b1] == 0) | (buckets[i + 1][b1] == capacity[b1]) | (buckets[i + 1][b2] == 0)
for i in range(nb_weeks): # [1] Use a Sorting Constraint (redundant with [2]) s = groups[i, :].sort() for j in range(nb_golfers): facile.constraint(s[j] == j // size_group) # [2] Use a Global Cardinality Constraint (redundant with [1]) gcc = groups[i, :].gcc([(size_group, i) for i in range(nb_groups)]) facile.constraint(gcc) # Two golfers do not play in the same group more than once for g1 in range(nb_golfers): for g2 in range(g1 + 1, nb_golfers): g1_with_g2 = [groups[w, g1] == groups[w, g2] for w in range(nb_weeks)] facile.constraint(facile.sum(g1_with_g2) <= 1) # Breaking the symmetries # - 0 always in the first group, 1 in a group less than 1, ... # - First week (0) a priori chosen for w in range(nb_weeks): for g in range(nb_groups): facile.constraint(groups[w, g] <= g) for g in range(nb_golfers): facile.constraint(groups[0, g] == g // size_group) if not facile.solve(list(groups)): print("No solution found") else:
price = [215, 275, 335, 355, 420, 580] total = 1505 products = [ "mixed fruit", "french fries", "side salad", "host wings", "mozzarella sticks", "samples place", ] # how many items of each dish quantity = [variable(range(10)) for p in price] constraint(sum(q * p for q, p in zip(quantity, price)) == total) def print_current(sol): print("Solution after {} backtracks:".format(sol.backtrack)) for i, x in enumerate(sol.solution): if x == 0: continue print(" {} × {:<20} : {:>5}".format(x, products[i], x * price[i])) total = sum(x * price[i] for i, x in enumerate(sol.solution)) print(" Total : {:>5}".format(total)) res = solve_all(quantity, backtrack=True, on_solution=print_current) print("Total of {} backtracks".format(res[-1].backtrack))
information. """ from facile import Variable, constraint, sum row_sums = [0, 0, 8, 2, 6, 4, 5, 3, 7, 0, 0] col_sums = [0, 0, 7, 1, 6, 3, 4, 5, 2, 7, 0, 0] rows = len(row_sums) cols = len(col_sums) x = [[Variable.binary() for j in col_sums] for i in row_sums] for i in range(rows): constraint(sum(x[i][j] for j in range(cols)) == row_sums[i]) for j in range(cols): constraint(sum(x[i][j] for i in range(rows)) == col_sums[j]) def print_solution(): print(" ", end=" ") for j in range(cols): print(col_sums[j], end=" ") print() for i in range(rows): print(row_sums[i], end=" ") for j in range(cols): if x[i][j].value() == 1: print("#", end=" ") else: