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])
Example #2
0
def test_invalid_array() -> None:

    n = 5
    var_array = [[facile.variable(0, 1) for _ in range(n)] for _ in range(n)]
    np_array = np.array([var_array[0], var_array[1][1:]])
    msg = (
        "Only numpy arrays of variables, expressions, constraints and integers "
        "are accepted")
    with pytest.raises(TypeError, match=msg):
        _ = facile.array(np_array)
Example #3
0
def test_basic_array() -> None:
    var_list = [facile.variable(0, 1) for _ in range(5)]
    array = facile.array(var_list)
    x = facile.variable(range(10))

    msg = "list indices must be integers or slices, not facile.core.Variable"
    with pytest.raises(TypeError, match=msg):
        facile.constraint(var_list[x] == 1)  # type: ignore

    facile.constraint(array[x] == 1)
    facile.constraint(array.sum() == 1)
    facile.constraint(x == 1)

    solution = facile.solve([*array, x])
    assert solution.solved
    assert array.value() == [0, 1, 0, 0, 0]
Example #4
0
def test_2d_array() -> None:
    n = 5
    # array = facile.Array.binary((n, n))
    var_array = [[facile.variable(0, 1) for _ in range(n)] for _ in range(n)]
    array = facile.array(np.array(var_array))

    for i in range(n):
        facile.constraint(array[:, i].sum() == 1)
        facile.constraint(array[i, :].sum() == 1)

    x, y = facile.variable(range(n)), facile.variable(range(n))
    facile.constraint(array[x, y] == 1)
    # TODO redundant but necessary to test one of the arguments as a variable
    # facile.constraint(array[:, x].sum() == 1)

    sol = facile.solve([*array])
    assert sol.solved

    sol = facile.solve([*array, x, y])
    assert sol.solved
    *_, x_, y_ = sol.solution
    assert array[x_, y_].value() == 1
Example #5
0
#
# The formulation is generalized to any number of golfers, groups and weeks.

nb_groups = 5
nb_golfers = 15
size_group = 3

assert (size_group * nb_groups == nb_golfers)

nb_weeks = 5

# An array of nb_weeks * nb_golfers decision variables to choose the group of
# every golfer every week

groups = [ facile.array(
    [facile.variable(0, nb_groups-1) for i in range(nb_golfers)]
    ) for j in range(nb_weeks)]

# For each week, exactly size_group golfers in each group:
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
Example #6
0
n = 4
duration = [30, 10, 15, 15]
demand = [3, 1, 3, 2]
upper_limit = 160

start_times = [facile.variable(range(upper_limit)) for i in range(n)]
end_times = [facile.variable(range(2 * upper_limit)) for i in range(n)]

end_time = facile.variable(range(2 * upper_limit))
n_resources = facile.variable(range(11))

for i in range(n):
    facile.constraint(end_times[i] == start_times[i] + duration[i])

facile.constraint(end_time == facile.array(end_times).max())


# 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)
Example #7
0
n = 4
duration = [30, 10, 15, 15]
demand = [3, 1, 3, 2]
upper_limit = 160

start_times = [fcl.variable(range(upper_limit)) for i in range(n)]
end_times = [fcl.variable(range(2 * upper_limit)) for i in range(n)]

end_time = fcl.variable(range(2 * upper_limit))
n_resources = fcl.variable(range(11))

for i in range(n):
    fcl.constraint(end_times[i] == start_times[i] + duration[i])

fcl.constraint(end_time == fcl.array(end_times).max())


# 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])
        fcl.constraint(sum(bb) <= b)
Example #8
0
#
# The formulation is generalized to any number of golfers, groups and weeks.

nb_groups = 5
nb_golfers = 15
size_group = 3

assert (size_group * nb_groups == nb_golfers)

nb_weeks = 5

# An array of nb_weeks * nb_golfers decision variables to choose the group of
# every golfer every week

groups = [
    facile.array(
        [facile.variable(0, nb_groups - 1) for i in range(nb_golfers)])
    for j in range(nb_weeks)
]

# For each week, exactly size_group golfers in each group:
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)
Example #9
0
    [1, 2, 4, 3, 5],
    [3, 5, 1, 2, 4],
    [5, 4, 2, 1, 3],
    [1, 3, 5, 4, 2],
    [4, 2, 3, 5, 1],
]

rank_men = [
    [5, 1, 2, 4, 3],
    [4, 1, 3, 2, 5],
    [5, 3, 2, 4, 1],
    [1, 5, 4, 3, 2],
    [4, 3, 2, 1, 5],
]

wife = array([variable(range(n)) for i in range(n)])
husband = array([variable(range(n)) for i in range(n)])

# You are your wife's husband, and conversely
for m in range(n):
    constraint(husband[wife[m]] == m)
for w in range(n):
    constraint(wife[husband[w]] == w)

for m in range(n):
    for w in range(n):
        # m prefers this woman to his wife
        c1 = rank_men[m][w] < array(rank_men[m])[wife[m]]
        # w prefers her husband to this man
        c2 = array(rank_women[w])[husband[w]] < rank_women[w][m]
        # alias for c1 => c2