Created
August 17, 2024 19:21
-
-
Save CapacitorSet/c1337c582c9af8704eeaef6ce0822ad2 to your computer and use it in GitHub Desktop.
Logica di scheduling per Markov News
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import itertools | |
from ortools.sat.python import cp_model | |
settimana = ("lun", "mar", "mer", "gio", "ven", "sab", "dom") | |
slots = ("7:00", "9:00", "12:00", "16:00", "19:30") | |
categorie = ( | |
"news", | |
"trucchi", | |
"accadde", | |
"proverbi", | |
"barzellette", | |
"sondaggi", | |
"ricette", | |
"parole", | |
"petizioni", | |
) | |
model = cp_model.CpModel() | |
vars = [] | |
combi: dict[tuple[str, str, str], cp_model.IntVar] = {} | |
for day in settimana: | |
day_vars = [] | |
for time in slots: | |
time_vars = [] | |
for cat in categorie: | |
var = model.new_bool_var(day + "_" + time + "_" + cat) | |
combi[day, time, cat] = var | |
time_vars.append(var) | |
# In ogni slot è postato un solo messaggio | |
model.add_exactly_one(time_vars) | |
# Ogni categoria è postata almeno una volta | |
for cat in categorie: | |
model.add_at_least_one(combi[day, time, cat] for day in settimana for time in slots) | |
for day in settimana: | |
# Ogni giorno ci sono 3 news | |
model.add_abs_equality(3, sum(combi[day, time, "news"] for time in slots)) | |
# Al più uno di ciascuna categoria eccetto le news | |
non_news = categorie[1:] | |
for cat in non_news: | |
model.add_at_most_one(combi[day, time, cat] for time in slots) | |
# Accadde, proverbi e parole sono solo alle 7 | |
model.add_abs_equality( | |
0, | |
sum( | |
combi[day, time, cat] | |
for day in settimana | |
for time in slots | |
for cat in ("accadde", "proverbi", "parole") | |
if time != "7:00" | |
), | |
) | |
# Accadde, proverbi e parole sono bilanciati: | |
# c'è al più una differenza di 1 tra le occorrenze di ciascuno | |
for pair in itertools.combinations(("accadde", "proverbi", "parole"), 2): | |
cat1, cat2 = pair | |
model.add_linear_constraint( | |
sum(combi[day, "7:00", cat1] for day in settimana) | |
- sum(combi[day, "7:00", cat2] for day in settimana), | |
-1, | |
+1, | |
) | |
# Ricette sono solo domenica alle 12 | |
model.add_abs_equality( | |
0, | |
sum( | |
combi[day, time, "ricette"] | |
for day in settimana | |
for time in slots | |
if day != "dom" or time != "12:00" | |
), | |
) | |
# Barzellette sono solo alle 16 | |
model.add_abs_equality( | |
0, | |
sum( | |
combi[day, time, "barzellette"] | |
for day in settimana | |
for time in slots | |
if time != "16:00" | |
), | |
) | |
# Trucchi e sondaggi sono solo alle 19 | |
model.add_abs_equality( | |
0, | |
sum( | |
combi[day, time, cat] | |
for day in settimana | |
for time in slots | |
for cat in ("trucchi", "sondaggi") | |
if time != "19:30" | |
), | |
) | |
# Petizioni sono solo alle 16 o alle 19:30 | |
model.add_abs_equality( | |
0, | |
sum( | |
combi[day, time, "petizioni"] | |
for day in settimana | |
for time in slots | |
if time != "16:00" and time != "19:30" | |
), | |
) | |
# Trucchi, sondaggi e petizioni (rubriche "serali") sono bilanciati: | |
# c'è al più una differenza di 1 tra le occorrenze di ciascuno | |
for pair in itertools.combinations(("trucchi", "sondaggi", "petizioni"), 2): | |
cat1, cat2 = pair | |
model.add_linear_constraint( | |
sum(combi[day, time, cat1] for day in settimana for time in slots) | |
- sum(combi[day, time, cat2] for day in settimana for time in slots), | |
-1, | |
+1, | |
) | |
# Non ci sono mai 3 news di fila la mattina | |
for day in settimana: | |
model.add_linear_constraint( | |
sum(combi[day, time, "news"] for time in slots[0:3]), 0, 2 | |
) | |
# Commented out: se attivato rende la schedule impossibile | |
# model.add_linear_constraint( | |
# sum(combi[day, time, "news"] for time in slots[1:4]), 0, 2 | |
# ) | |
model.add_linear_constraint( | |
sum(combi[day, time, "news"] for time in slots[2:5]), 0, 2 | |
) | |
# Non ci sono mai due categorie alla stessa ora in due giorni adiacenti, | |
# eccetto le news | |
for cat in categorie[1:]: | |
for time in slots: | |
for idx in range(0, 6): | |
model.add_at_most_one( | |
combi[day, time, cat] for day in settimana[idx : idx + 2] | |
) | |
cost_fn = 0 | |
for key, value in combi.items(): | |
day, time, cat = key | |
# Penalizziamo le news per favorire le altre categorie | |
if cat == "news": | |
cost_fn -= 1 * value | |
else: | |
cost_fn -= 2 * value | |
model.minimize(cost_fn) | |
solver = cp_model.CpSolver() | |
status = solver.solve(model) | |
if status == cp_model.OPTIMAL or status == cp_model.FEASIBLE: | |
# print(f"Total cost = {solver.objective_value}\n") | |
# print(solver._solution) | |
# print(f"{len(combi)} variables.") | |
for idx, var in enumerate(combi.keys()): | |
if solver._solution.solution[idx]: | |
day, time, cat = var | |
print(f'"{day} {time}": "{cat}",') | |
# print(f"{day.capitalize()} alle {time}: {cat}") | |
# if time == slots[-1]: | |
# print() | |
elif status == cp_model.INFEASIBLE: | |
print("No solution found") | |
else: | |
print("Something is wrong, check the status and the log of the solve") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment