def golomb(n): # On peut majorer la taille de la règle par 2 ** n. En effet, si # ticks[i] vaut 2**i alors tous les ticks[i] - ticks[j] = 2**i - 2**j # = 2**j * (2**(i-j) - 1) qui sont tous différents. # On a donc au moins cette solution. n2 = 2 ** n ticks = [facile.variable(0, n2) for i in range(n)] # First tick at the start of the ruler facile.constraint(ticks[0] == 0) # Ticks are ordered for i in range(n-1): facile.constraint(ticks[i] < ticks[i+1]) # All distances distances = [] for i in range(n-1): for j in range(i + 1, n): distances.append(ticks[j] - ticks[i]) facile.constraint(facile.alldifferent(distances)) for d in distances: facile.constraint(d > 0) # Breaking the symmetry size = len(distances) facile.constraint(distances[size - 1] > distances[0]) return (facile.minimize(ticks, ticks[n-1])[1])
def golomb(n: int) -> facile.Solution: ticks = [facile.variable(range(2**n)) for i in range(n)] # First tick at the start of the ruler facile.constraint(ticks[0] == 0) # Ticks are ordered for i in range(n - 1): facile.constraint(ticks[i] < ticks[i + 1]) # All distances distances = [] for i in range(n - 1): for j in range(i + 1, n): distances.append(facile.variable(ticks[j] - ticks[i])) facile.constraint(facile.alldifferent(distances)) for d in distances: facile.constraint(d > 0) # Breaking the symmetry size = len(distances) facile.constraint(distances[size - 1] > distances[0]) return facile.minimize(ticks, ticks[n - 1], backtrack=True, on_solution=print)
def test_broadcast() -> None: c = np.array([ [13, 21, 20, 12, 8, 26, 22, 11], [12, 36, 25, 41, 40, 11, 4, 8], [35, 32, 13, 36, 26, 21, 13, 37], [34, 54, 7, 8, 12, 22, 11, 40], [21, 6, 45, 18, 24, 34, 12, 48], [42, 19, 39, 15, 14, 16, 28, 46], [16, 34, 38, 3, 34, 40, 22, 24], [26, 20, 5, 17, 45, 31, 37, 43], ]) var = facile.Array.binary(c.shape) for i in range(c.shape[0]): facile.constraint(var[:, i].sum() == 1) facile.constraint(var[i, :].sum() == 1) # TODO (var * c).sum() sol = facile.minimize(list(var), (var * c.ravel()).sum()) assert sol.solved assert sol.evaluation == 76 assert (np.array(sol.solution).reshape(c.shape) == np.array( # noqa: W503 [ [1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], ])).all()
def solver(cost, OWA): assert OWA in ['utilitarism', 'egalitarism', 'gini'] n_task = cost.shape[1] n_agent = cost.shape[0] boolean_variable = np.array([ facile.array([facile.variable([0, 1]) for i in range(n_task)]) for j in range(n_agent) ]) # Every task must be complete, by only one agent ! for j in range(n_task): facile.constraint(sum(boolean_variable[:, j]) == 1) how_does_it_cost = facile.array([ np.matmul(cost[i, :], facile.array(boolean_variable[i, :])) for i in range(n_agent) ]) if OWA == 'utilitarism': weights = np.array([1 for i in range(n_agent)]) elif OWA == 'egalitarism': # as we only have the .sort() method for desutilities, weights must be in reverse order because the 'desutilities' should be sorted in descending order weights = np.array([0 for i in range(n_agent)]) weights[-1] = 1 else: # as we only have the .sort() method for desutilities, weights must be in reverse order because the 'desutilities' should be sorted in descending order weights = np.flip( np.array([2 * (n_agent - i) + 1 for i in range(1, n_agent + 1)])) print(weights) to_minimize = np.matmul(weights, how_does_it_cost.sort()) vars = [] for i in range(n_agent): for j in range(n_task): vars.append(boolean_variable[i, j]) res = np.array(facile.minimize(vars, to_minimize).solution) boolean_res = res > 0 tasks = np.array([list(string.ascii_lowercase)[0:n_task]]) for i in range(n_agent): boolean_res[i:i + n_task] print(i + 1, ' does : ', tasks[:, boolean_res[n_task * i:n_task * (i + 1)]][0])
def coins(values, maxval): """ Which coins do you need to give back change for any amount between 0 and maxval, using coins from values? """ # How many coin types nb_vals = len(values) nb_min_coins = [variable(0, maxval/values[i]) for i in range(nb_vals)] for val in range(maxval): # How many coins per type nb_coins = [variable(0, maxval/values[i]) for i in range(nb_vals)] 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]) return minimize(nb_min_coins, sum(nb_min_coins))
def coins(values, maxval): """ Which coins do you need to give back change for any amount between 0 and maxval, using coins from values? """ # How many coin types nb_vals = len(values) nb_min_coins = [variable(0, maxval / values[i]) for i in range(nb_vals)] for val in range(maxval): # How many coins per type nb_coins = [variable(0, maxval / values[i]) for i in range(nb_vals)] 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]) return minimize(nb_min_coins, sum(nb_min_coins))
# detail here! def cumulative(s, d, r, b): tasks = [i for i in range(len(s)) if r[i] > 0 and d[i] > 0] times_min = min([s[i].domain()[0] for i in tasks]) times_max = max([s[i].domain()[-1] + max(d) for i in tasks]) for t in range(times_min, times_max + 1): bb = [] for i in tasks: c1 = s[i] <= t c2 = t < s[i] + d[i] bb.append(c1 * c2 * r[i]) facile.constraint(sum(bb) <= b) cumulative(start_times, duration, demand, n_resources) print("---- Minimize resources ----") print( facile.minimize( start_times + end_times + [n_resources], n_resources, on_solution=print ) ) print("---- Minimize end_time ----") print( facile.minimize( start_times + end_times + [end_time], end_time, on_solution=print ) )