Skip to content

Instantly share code, notes, and snippets.

@CapacitorSet
Created August 17, 2024 19:21
Show Gist options
  • Save CapacitorSet/c1337c582c9af8704eeaef6ce0822ad2 to your computer and use it in GitHub Desktop.
Save CapacitorSet/c1337c582c9af8704eeaef6ce0822ad2 to your computer and use it in GitHub Desktop.
Logica di scheduling per Markov News
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