File size: 5,445 Bytes
48d920c
 
 
 
 
 
 
 
 
 
 
 
28d83d0
 
48d920c
28d83d0
48d920c
28d83d0
48d920c
 
 
28d83d0
48d920c
 
 
 
 
 
 
28d83d0
48d920c
 
 
 
 
 
 
 
 
 
 
28d83d0
48d920c
 
 
 
 
 
28d83d0
48d920c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28d83d0
48d920c
28d83d0
48d920c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28d83d0
 
 
48d920c
 
 
28d83d0
48d920c
28d83d0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# -*- coding: utf-8 -*-
"""optimisation_examen_PMNE.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1Uewn7e8zZiGZdAAYHqXJtl-3TA7sj5eL
"""

#!pip install pulp
#!pip install gradio

import gradio as gr
import pandas as pd
from pulp import LpMinimize, LpProblem, LpVariable, lpSum

def planifier_examens(examens_text, salles_text, jours_text, creneaux_text, disponibilite_salle_text, conflits_text):
    # --- 1. Parsing des données ---
    # Examens
    examens = []
    for line in examens_text.strip().splitlines():
        parts = line.split(',')
        if len(parts) == 3:
            exam_id, nb_students, duration = parts
            examens.append((exam_id.strip(), int(nb_students.strip()), int(duration.strip())))

    # Salles et capacités
    salles = {}
    for line in salles_text.strip().splitlines():
        parts = line.split(',')
        if len(parts) == 2:
            room_id, capacity = parts
            salles[room_id.strip()] = int(capacity.strip())

    # Jours et créneaux
    jours = [int(j.strip()) for j in jours_text.split(',')]
    creneaux = [int(c.strip()) for c in creneaux_text.split(',')]

    # Disponibilité des salles
    disponibilite_salle = {}
    for line in disponibilite_salle_text.strip().splitlines():
        parts = line.split(',')
        room_id = parts[0].strip()
        disponibilite_salle[room_id] = [int(s) for s in parts[1:]]

    # Conflits entre examens
    conflits = []
    for line in conflits_text.strip().splitlines():
        parts = line.split(',')
        conflits.append((parts[0].strip(), parts[1].strip()))

    # --- 2. Modélisation avec PuLP (PMNE) ---
    model = LpProblem("Planification_Examens", LpMinimize)

    # Variables de décision
    X = {(e, d, c, s): LpVariable(f"X_{e}_{d}_{c}_{s}", cat="Binary")
         for e, _, _ in examens for d in jours for c in creneaux for s in salles}
    Y = {d: LpVariable(f"Y_{d}", cat="Binary") for d in jours}

    # Contrainte 1 : Chaque examen doit être programmé une seule fois
    for e, _, _ in examens:
        model += lpSum(X[e, d, c, s] for d in jours for c in creneaux for s in salles) == 1

    # Contrainte 2 : Capacité des salles respectée
    for d in jours:
        for c in creneaux:
            for s in salles:
                model += lpSum(nb_students * X[e, d, c, s] for e, nb_students, _ in examens) <= salles[s]

    # Contrainte 3 : Une salle ne peut accueillir qu’un seul examen par créneau
    for d in jours:
        for c in creneaux:
            for s in salles:
                model += lpSum(X[e, d, c, s] for e, _, _ in examens) <= 1

    # Contrainte 4 : Disponibilité des salles
    for e, _, _ in examens:
        for d in jours:
            for c in creneaux:
                for s in salles:
                    if disponibilite_salle[s][c - 1] == 0:
                        model += X[e, d, c, s] == 0

    # Contrainte 5 : Conflits entre examens (ne pas être en même temps)
    for e1, e2 in conflits:
        for d in jours:
            for c in creneaux:
                model += lpSum(X[e1, d, c, s] for s in salles) + lpSum(X[e2, d, c, s] for s in salles) <= 1

    # Contrainte 6 : Activation des jours
    for d in jours:
        for e, _, _ in examens:
            for c in creneaux:
                for s in salles:
                    model += Y[d] >= X[e, d, c, s]

    # Fonction Objectif : Minimiser le nombre de jours utilisés
    model += lpSum(Y[d] for d in jours)

    # --- 3. Résolution ---
    model.solve()

    # --- 4. Extraction des résultats ---
    planning = []
    for e, _, _ in examens:
        for d in jours:
            for c in creneaux:
                for s in salles:
                    if X[e, d, c, s].varValue == 1:
                        planning.append({"Examen": e, "Jour": d, "Créneau": c, "Salle": s})

    df = pd.DataFrame(planning)
    df.to_csv("planning_examens.csv", index=False)

    return df, "planning_examens.csv"

# Interface avec Gradio
with gr.Blocks() as demo:
    gr.Markdown("# 📅 Planification des Examens avec PMNE et Gradio")

    exams_input = gr.Textbox(label="Examens (exam_id, nb_étudiants, durée)", lines=5,
                             value="E1, 30, 2\nE2, 25, 1\nE3, 40, 2\nE4, 20, 1")
    rooms_input = gr.Textbox(label="Salles (room_id, capacité)", lines=3,
                             value="S1, 50\nS2, 30\nS3, 40")
    jours_input = gr.Textbox(label="Jours disponibles (séparés par des virgules)", value="1, 2, 3")
    creneaux_input = gr.Textbox(label="Créneaux disponibles (séparés par des virgules)", value="1, 2, 3, 4")
    disponibilite_input = gr.Textbox(label="Disponibilité des salles (room_id, slot1, slot2, ...)", lines=4,
                                     value="S1, 1, 1, 1, 1\nS2, 1, 1, 0, 1\nS3, 1, 1, 1, 0")
    conflits_input = gr.Textbox(label="Conflits entre examens (exam1, exam2)", lines=3,
                                value="E1, E3")

    output_table = gr.Dataframe(headers=["Examen", "Jour", "Créneau", "Salle"], label="Planning des examens")
    output_file = gr.File(label="Télécharger le planning")

    solve_btn = gr.Button("Planifier les examens")
    solve_btn.click(
        fn=planifier_examens,
        inputs=[exams_input, rooms_input, jours_input, creneaux_input, disponibilite_input, conflits_input],
        outputs=[output_table, output_file]
    )

demo.launch()