Created
August 17, 2024 19:21
-
-
Save CapacitorSet/c1337c582c9af8704eeaef6ce0822ad2 to your computer and use it in GitHub Desktop.
Revisions
-
CapacitorSet created this gist
Aug 17, 2024 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,173 @@ 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")