web-dev-qa-db-fra.com

Algorithme pour la création d'un emploi du temps scolaire

Je me demandais s'il existait des solutions connues pour un algorithme de création d'un emploi du temps scolaire. En gros, il s’agit d’optimiser la "dispersion des heures" (à la fois dans le cas des enseignants et des classes) pour des associations données de professeurs de matières. Nous pouvons supposer que nous avons des ensembles de classes, de matières de cours et d'enseignants associés en entrée et que l'horaire doit être compris entre 8h00 et 16h00. 

Je suppose qu'il n'y a probablement pas d'algorithme précis pour cela, mais peut-être que quelqu'un connaît une bonne approximation ou des astuces pour le développer. 

84
cand

Ce problème est NP-Complete !
En résumé, il faut explorer toutes les combinaisons possibles pour trouver la liste des solutions acceptables. En raison des différences dans les circonstances dans lesquelles le problème apparaît dans les différentes écoles (par exemple: y a-t-il des contraintes en ce qui concerne les salles de classe?), Certaines classes sont-elles divisées en sous-groupes ?, S'agit-il d'un horaire hebdomadaire? etc.) il n’existe pas de classe de problèmes bien connue qui corresponde à tous les problèmes de planification. Peut-être que le problème de Knapsack présente de nombreux éléments de similitude avec ces problèmes en général.

Une confirmation que c’est à la fois un problème difficile et un problème pour lequel les gens cherchent constamment une solution consiste à vérifier cette liste (longue) ) (principalement commerciale)

En raison du grand nombre de variables impliquées, dont les sources les plus importantes sont généralement les désirs du membre du corps professoral; -) ..., il est généralement impossible d’énumérer toutes les combinaisons possibles . Au lieu de cela, nous devons choisir une approche qui visite un sous-ensemble des espaces de problèmes/solutions.
- Algorithmes génétiques , cité dans une autre réponse est (ou, à mon humble avis, semble ) bien équipé pour effectuer ce type de recherche semi-guidée (le problème étant de trouver une bonne fonction d'évaluation pour les candidats à conserver pour la prochaine génération)
- Réécriture de graphes Les approches == sont également utiles pour ce type de problèmes d'optimisation combinatoire.

Plutôt que de nous concentrer sur des implémentations particulières d'un programme de génération automatique de programme, j'aimerais suggérer quelques stratégies pouvant être appliquées, au niveau de la définition de le problème .
L’argument général est que, dans la plupart des problèmes d’ordonnancement dans le monde réel, certains compromis seront nécessaires, pas toutes les contraintes, explicites ou implicites: seront pleinement satisfaites. Nous nous aidons donc par:

  • Définir et classer toutes les contraintes connues
  • Réduire l'espace du problème, manuellement, en fournissant un ensemble de contraintes supplémentaires .
    Cela peut sembler contre-intuitif mais par exemple en fournissant un horaire initial partiellement rempli (environ 30% des créneaux horaires), de manière à satisfaire pleinement toutes les contraintes et en considérant cet horaire partiel comme étant immuable. , nous réduisons considérablement le temps/espace nécessaire pour produire des solutions candidates.
    Une autre manière d’aider les contraintes supplémentaires consiste par exemple à ajouter "artificiellement" une contrainte empêchant d’enseigner certaines matières certains jours de la semaine (s’il s’agit d’un programme hebdomadaire, etc.); Ce type de contraintes conduit à une réduction des espaces problèmes/solutions, sans pour autant exclure un nombre important de bons candidats.
  • S'assurer que certaines des contraintes du problème peuvent être rapidement calculées. Ceci est souvent associé au choix du modèle de données utilisé pour représenter le problème; L'idée est de pouvoir opter rapidement pour certaines options.
  • Redéfinir le problème et permettre de casser quelques fois certaines contraintes (généralement vers les nœuds finaux du graphique). L'idée ici est soit de supprimer quelques contraintes pour remplir les derniers créneaux horaires de la planification, soit de laisser le programme du générateur de planification automatique arrêter de remplir la totalité du programme, au lieu de nous fournir une liste d'une douzaine de candidats plausibles. Comme indiqué, un humain est souvent le mieux placé pour résoudre le casse-tête, en surmontant éventuellement certaines des contraintes, en utilisant des informations qui ne sont généralement pas partagées avec la logique automatisée (par exemple, la règle "Aucune mathématique l'après-midi" peut être rompue à l'occasion. pour le cours "mathématiques et physique avancées" ou "Il est préférable de casser l'une des exigences de M. Jones plutôt que celle de Mme Smith ... ;-))

En corrigeant cette réponse, je me rends compte qu’elle est assez timide pour donner une réponse définitive, mais elle n'en est pas moins pleine de suggestions pratiques. J'espère que cette aide, avec ce qui est, après tout, un "problème difficile".

78
mjv

C'est le bordel. un désordre royal. Pour ajouter aux réponses, déjà très complètes, je tiens à souligner mon expérience familiale. Ma mère était enseignante et avait l'habitude de participer au processus.

Il s'avère qu’avoir un ordinateur pour le faire est non seulement difficile à coder en tant que tel, mais aussi parce qu’il existe des conditions difficiles à spécifier pour un programme informatique déjà cuit. Exemples:

  • un enseignant enseigne à la fois dans votre école et dans un autre institut. Il est clair que s’il termine la leçon à 10h30, il ne peut pas commencer chez vous à 10h30, car il lui faut du temps pour se déplacer entre les instituts.
  • deux professeurs sont mariés. En règle générale, il est considéré comme une bonne pratique de ne pas avoir deux enseignants mariés dans la même classe. Ces deux professeurs doivent donc avoir deux classes différentes
  • deux enseignants sont mariés et leur enfant fréquente la même école. Encore une fois, vous devez empêcher les deux enseignants d’enseigner dans la classe spécifique où se trouve leur enfant.
  • l'école dispose d'installations séparées, comme un jour où la classe est dans un institut et un autre jour où la classe est dans un autre.
  • l'école dispose de laboratoires partagés, mais ces laboratoires ne sont disponibles que certains jours de la semaine (pour des raisons de sécurité, par exemple, lorsqu'un personnel supplémentaire est requis).
  • certains enseignants ont des préférences pour la journée libre: certains préfèrent le lundi, d'autres le vendredi et d'autres le mercredi. Certains préfèrent venir tôt le matin, d'autres préfèrent venir plus tard.
  • vous ne devriez pas avoir de situations où vous avez une leçon d'histoire, l'histoire à la première heure, puis trois heures de maths, puis une autre heure d'histoire. Cela n'a pas de sens pour les étudiants, ni pour l'enseignant.
  • vous devriez répartir les arguments de manière égale. Cela n'a pas de sens de ne faire que les mathématiques les premiers jours de la semaine, puis la littérature le reste de la semaine.
  • vous devriez donner à certains enseignants deux heures consécutives pour faire des tests d’évaluation.

Comme vous pouvez le constater, le problème n’est pas NP-complet, c’est NP-fou.

Donc, ce qu’ils font, c’est qu’ils ont une grande table avec de petits encarts en plastique et qu’ils les déplacent jusqu’à obtention d’un résultat satisfaisant. Ils ne partent jamais de zéro: ils partent normalement du calendrier de l'année précédente et font des ajustements.

44
Stefano Borini

Le International Timetabling Competition 2007 proposait une piste de planification de cours et de suivi d’examen. De nombreux chercheurs ont participé à ce concours. Beaucoup d'heuristiques et de métaheuristiques ont été essayés, mais à la fin, les métaheuristiques de recherche locales (telles que Tabu Search et Simulated Annealing) surpassent nettement d'autres algorithmes (tels que les algorithmes génétiques).

Jetez un coup d’œil aux 2 frameworks open source utilisés par certains des finalistes:

23
Geoffrey De Smet

Une de mes missions à mi-parcours était une génération de tables d’école à algorithme génétique.

Toute la table est un "organisme". L’approche fondée sur les algorithmes génétiques génériques a été modifiée et mise en garde:

  • Des règles ont été établies pour les "tables illégales": deux classes dans la même classe, un enseignant enseignant deux groupes à la fois, etc. Ces mutations ont été immédiatement jugées mortelles et un nouvel "organisme" a immédiatement germé à la place du "défunt". Le premier a été généré par une série d'essais aléatoires pour en obtenir un légal (si insensé). La mutation létale n'a pas été prise en compte dans le nombre de mutations itératives.

  • Les mutations "Exchange" étaient beaucoup plus courantes que les mutations "Modify". Les changements ne concernaient que des parties du gène qui avaient du sens - pas de substitution d'un enseignant à une salle de classe.

  • De petits bonus ont été attribués pour regrouper certaines 2 heures ensemble, pour affecter la même salle de classe générique dans l'ordre pour le même groupe, pour maintenir les heures de travail de l'enseignant et la charge de la classe en continu. Des bonus modérés ont été attribués pour donner les salles de classe correctes à un sujet donné, maintenir les heures de cours dans les coffres (matin ou après-midi), etc. Les gros bonus servaient à attribuer un nombre correct de sujets donnés, une charge de travail donnée à un enseignant, etc.

  • Les enseignants peuvent créer leurs calendriers de charge de travail "vouloir travailler ensuite", "okay pour travailler ensuite", "n'aime pas travailler ensuite", "ne peut pas travailler ensuite", avec les poids appropriés attribués. Les heures entières étaient légales, sauf que la nuit était très indésirable.

  • La fonction de poids ... oh ouais. La fonction de pondération était un énorme produit monstrueux (comme dans la multiplication) des pondérations attribuées aux caractéristiques et propriétés sélectionnées. C'était extrêmement raide, une propriété pouvant facilement la changer d'un ordre de grandeur à la fois - et il y avait des centaines ou des milliers de propriétés dans un seul organisme. Cela s'est traduit par des nombres absolument ÉNORMES comme poids et, par conséquent, il est nécessaire d'utiliser une bibliothèque bignum (gmp) pour effectuer les calculs. Pour un petit test de quelque 10 groupes, 10 enseignants et 10 salles de classe, l’ensemble initial a commencé avec une note de 10 ^ -200 et quelque chose et a fini avec 10 ^ + 300. C'était totalement inefficace quand c'était plus plat. En outre, les valeurs ont augmenté beaucoup plus loin avec de plus grandes "écoles".

  • En termes de temps de calcul, il y avait peu de différence entre une petite population (100) sur une longue période et une grande population (10 000+) sur un nombre inférieur de générations. Le calcul sur le même temps produit à peu près la même qualité.

  • Le calcul (sur un processeur de 1 GHz environ) prend environ 1 heure pour se stabiliser vers 10 ^ + 300, générant ainsi des programmes qui paraissaient assez sympas, pour ledit scénario de test 10x10x10.

  • Le problème peut facilement être comparé en fournissant un service de réseau permettant d'échanger les meilleurs spécimens entre des ordinateurs exécutant le calcul.

Le programme qui en a résulté n'a jamais vu la lumière du jour dehors me procurer une bonne note pour le semestre. Cela promettait quelque chose, mais je n’ai jamais assez de motivation pour ajouter une interface graphique et la rendre utilisable par le grand public.

16
SF.

Ce problème est plus difficile qu'il n'y parait.

Comme d'autres l'ont mentionné, il s'agit d'un problème NP-complet, mais analysons ce que cela signifie.

En gros, cela signifie que vous devez examiner toutes les combinaisons possibles.

Mais "regarder" ne vous dit pas beaucoup ce que vous devez faire.

Générer toutes les combinaisons possibles est facile. Cela pourrait produire une énorme quantité de données, mais vous ne devriez pas avoir beaucoup de difficultés à comprendre les concepts de cette partie du problème.

Le deuxième problème est celui de juger si une combinaison possible donnée est bonne, mauvaise ou meilleure que la "bonne" solution précédente.

Pour cela, vous avez besoin de plus que simplement "est-ce une solution possible".

Par exemple, le même enseignant travaille-t-il 5 jours par semaine pendant X semaines d'affilée? Même si c'est une solution qui fonctionne, ce ne serait peut-être pas une meilleure solution que d'alterner deux personnes pour que chaque enseignant consacre une semaine chacune. Oh, tu n'y as pas pensé? N'oubliez pas qu'il s'agit de personnes avec lesquelles vous traitez, pas simplement d'un problème d'allocation de ressources.

Même si un enseignant pouvait travailler à plein temps pendant 16 semaines d'affilée, cela pourrait être une solution sous-optimale par rapport à une solution qui consiste à alterner les enseignants. Ce type d'équilibrage est très difficile à intégrer au logiciel.

En résumé, produire une bonne solution à ce problème vaudra beaucoup, pour beaucoup de gens. Ce n'est donc pas un problème facile à résoudre et à résoudre. Préparez-vous à fixer des objectifs qui ne sont pas à 100% et à les qualifier de «suffisamment bons».

UPDATE: à partir de commentaires ... devrait aussi avoir des heuristiques!

J'irais avec Prolog ... puis utilisez Ruby ou Perl ou quelque chose pour nettoyer votre solution sous une forme plus jolie.

teaches(Jill,math).
teaches(Joe,history).

involves(MA101,math).
involves(SS104,history).

myHeuristic(D,A,B) :- [test_case]->D='<';D='>'.
createSchedule :- findall(Class,involves(Class,Subject),Classes),
                  predsort(myHeuristic,Classes,ClassesNew),
                  createSchedule(ClassesNew,[]).
createSchedule(Classes,Scheduled) :- [the actual recursive algorithm].

Je suis (encore) en train de faire quelque chose de similaire à ce problème mais en utilisant le même chemin que je viens de mentionner. Prolog (en tant que langage fonctionnel) facilite vraiment la résolution des problèmes NP-Hard.

5
Reed Debaets

Mon algorithme de chronométrage, implémenté dans FET (Free Timetabling Software, http://lalescu.ro/liviu/fet/ , une application réussie):

L'algorithme est heuristique. Je l'ai nommé "échange récursif".

Entrée: un ensemble d'activités A_1 ... A_n et les contraintes.

Sortie: un ensemble d'heures TA_1 ... TA_n (le créneau horaire de chaque activité. Les salles sont exclues ici, pour des raisons de simplicité). L'algorithme doit placer chaque activité à un créneau horaire en respectant les contraintes. Chaque TA_i est compris entre 0 (T_1) et max_time_slots-1 (T_m).

Contraintes:

C1) Basic: liste de paires d’activités qui ne peuvent pas être simultanées (par exemple, A_1 et A_2, car elles ont le même enseignant ou les mêmes étudiants);

C2) Beaucoup d'autres contraintes (exclues ici, pour des raisons de simplicité).

L'algorithme de chronométrage (que j'ai nommé "échange récursif"):

  1. Trier les activités, les plus difficiles en premier. Pas critique, mais accélère l’algorithme peut-être 10 fois ou plus.
  2. Essayez de placer chaque activité (A_i) dans un créneau horaire autorisé, en respectant l'ordre indiqué ci-dessus, un à la fois. Recherchez un emplacement disponible (T_j) pour A_i, dans lequel cette activité peut être placée en respectant les contraintes. Si plusieurs emplacements sont disponibles, choisissez-en un au hasard. Si aucun n'est disponible, effectuez un échange récursif:

    une. Pour chaque créneau horaire T_j, réfléchissez à ce qui se passe si vous mettez A_i dans T_j. Il y aura une liste d'autres activités qui ne sont pas en accord avec ce mouvement (par exemple, l'activité A_k se trouve sur le même emplacement T_j et a le même enseignant ou les mêmes étudiants que A_i). Conservez une liste des activités en conflit pour chaque créneau horaire T_j.

    b. Choisissez un emplacement (T_j) avec le nombre le plus bas d’activités en conflit. Disons que la liste des activités dans cet emplacement contient 3 activités: A_p, A_q, A_r.

    c. Placez A_i à T_j et rendez A_p, A_q, A_r non alloué.

    . Essayez récursivement de placer A_p, A_q, A_r (si le niveau de récursion n’est pas trop grand, disons 14 et si le nombre total d’appels récursifs comptés depuis l’étape 2) sur A_i commencé n’est pas trop grand, disons 2 * n), comme à l'étape 2).

    e. Si vous avez placé avec succès A_p, A_q, A_r, revenez avec succès, sinon essayez d’autres créneaux horaires (passez à l’étape 2 b) et choisissez le créneau horaire suivant).

    F. Si tous (ou un nombre raisonnable) de créneaux horaires ont été essayés sans succès, revenez sans succès.

    g. Si nous sommes au niveau 0 et que nous n’avons pas réussi à placer A_i, placez-le comme dans les étapes 2 b) et 2 c), mais sans récursion. Nous avons maintenant 3 - 1 = 2 activités supplémentaires à placer. Passez à l'étape 2) (certaines méthodes pour éviter le cyclisme sont utilisées ici).

4
Liviu Lalescu

Les algorithmes génétiques sont souvent utilisés pour une telle planification.

Trouvé cet exemple (Créer un programme de cours à l'aide d'un algorithme génétique) qui correspond assez bien à vos besoins.

4
Christian V

Voici quelques liens que j'ai trouvés:

Calendrier scolaire - Répertorie certains problèmes rencontrés

Un algorithme génétique hybride pour la programmation scolaire

Utilitaires et outils de planification

4
Niyaz

Ce document décrit assez bien le problème des horaires scolaires et leur approche de l’algorithme: " Le développement de SYLLABUS - Un ordonnanceur interactif à base de contraintes pour les écoles et les collèges. " [PDF]

L'auteur m'informe que le logiciel SYLLABUS est encore utilisé/développé ici: http://www.scientia.com/uk/

2
Leftium

Je travaille sur un moteur de planification largement utilisé qui fait exactement cela. Oui, c'est NP-Complete; les meilleures approches cherchent à approximer une solution optimale. Et bien sûr, il y a beaucoup de façons différentes de dire laquelle est la "meilleure" solution - est-il plus important que vos professeurs soient satisfaits de leur emploi du temps, ou que les étudiants entrent dans toutes les classes, par exemple?

La question la plus importante à résoudre dès le départ est Qu'est-ce qui rend une méthode de planification de ce système meilleure qu'une autre ? En d’autres termes, si j’ai un horaire avec Mme Jones qui enseigne les mathématiques à 8 heures et M. Smith qui enseigne les mathématiques à 9 ans, est-ce que c’est mieux ou pire qu’un qui enseigne les mathématiques à 10 ans? Est-ce mieux ou pire que Mme Jones enseignant à 8 ans et M. Jones enseignant à 2 ans? Pourquoi?

Le principal conseil que je voudrais donner ici est de diviser le problème autant que possible - peut-être cours par cours, peut-être professeur par enseignant, salle par salle, et de résoudre le problème en premier. Là, vous devriez vous retrouver avec plusieurs solutions parmi lesquelles choisir et choisir l'une des solutions les plus probables. Ensuite, essayez de faire en sorte que les sous-problèmes "antérieurs" tiennent compte des besoins des sous-problèmes ultérieurs lors de l'évaluation de leurs solutions potentielles. Ensuite, essayez peut-être de vous sortir de situations délicates (en supposant que vous ne pouvez pas anticiper ces situations dans les sous-problèmes précédents) lorsque vous arrivez à un état "pas de solutions valables".

Une passe d'optimisation de la recherche locale est souvent utilisée pour "peaufiner" la réponse finale afin d'obtenir de meilleurs résultats.

Notez que nous traitons généralement avec des systèmes fortement limités en ressources dans le calendrier scolaire. Les écoles ne passent pas toute l'année avec beaucoup de salles vides ou d'enseignants assis dans le salon 75% de la journée. Les approches qui fonctionnent le mieux dans des environnements riches en solutions ne sont pas nécessairement applicables dans le calendrier scolaire.

2
Tom Dibble

J'ai conçu des algorithmes commerciaux pour les horaires de cours et d'examen. Pour le premier j'ai utilisé la programmation entière; pour la seconde une heuristique basée sur la maximisation d'une fonction objectif en choisissant des échanges de slots, très similaire au processus manuel original qui avait été développé. Pour que ces solutions soient acceptées, il est essentiel de pouvoir représenter toutes les contraintes du monde réel; et que les calendriers humains ne puissent pas voir les moyens d’améliorer la solution. Au final, la partie algorithmique était relativement simple et facile à mettre en œuvre par rapport à la préparation des bases de données, à l'interface utilisateur, à la possibilité de générer des statistiques telles que l'utilisation des salles, la formation des utilisateurs, etc. 

2
Permaquid

En règle générale, la programmation par contraintes constitue une bonne approche de ce type de problème de planification. Une recherche sur la "programmation par contraintes" et la planification ou "planification par contraintes" à la fois dans le dépassement de capacité de la pile et sur Google génère de bonnes références. Ce n'est pas impossible - il est juste un peu difficile de penser à l'utilisation de méthodes d'optimisation traditionnelles telles que l'optimisation linéaire ou entière. Un résultat serait: existe-t-il un calendrier qui satisfait à toutes les exigences? Cela, en soi, est évidemment utile. 

Bonne chance !

1
Grembo

Vous pouvez le faire avec des algorithmes génétiques, oui. Mais tu ne devrais pas :). Cela peut être trop lent et le réglage des paramètres peut prendre trop de temps, etc.

Il existe d'autres approches réussies. Tous mis en œuvre dans des projets open source:

  • Approche basée sur les contraintes
    • Implémenté dans UniTime (pas vraiment pour les écoles)
    • Vous pouvez également aller plus loin et utiliser la programmation Integer. Fait avec succès à l'université Udine et également à l'université Bayreuth (j'y ai participé) à l'aide du logiciel commercial (ILOG CPLEX)
    • Approche basée sur des règles avec heuristisc - Voir Drools planner
  • Différentes heuristiques - FET et my own

Voir ici pour une liste de logiciels schedabling

1
Karussell

Je pense que vous devriez utiliser un algorithme génétique parce que:

Regardez aussi: une question similaire et une autre

0
Betamoo

Je ne sais pas si quelqu'un sera d'accord avec ce code, mais j'ai développé ce code à l'aide de mon propre algorithme et travaille pour moi dans Ruby.Espoir que cela aidera ceux qui le recherchent Dans le code suivant, le periodflag, dayflag subjectflag et teacherflag sont le hachage avec l'identifiant correspondant et la valeur de drapeau qui est Boolean . Tout problème contactez-moi ....... (-_-)

periodflag.each do | k2, v2 |

            if(TimetableDefinition.find(k2).period.to_i != 0)
                subjectflag.each do |k3,v3|
                    if (v3 == 0)
                        if(getflag_period(periodflag,k2))
                            @teachers=EmployeesSubject.where(subject_name: @subjects.find(k3).name, division_id: division.id).pluck(:employee_id)
                            @teacherlists=Employee.find(@teachers)
                            teacherflag=Hash[teacher_flag(@teacherlists,teacherflag,flag).to_a.shuffle] 
                            teacherflag.each do |k4,v4|
                                if(v4 == 0)
                                    if(getflag_subject(subjectflag,k3))
                                        subjectperiod=TimetableAssign.where("timetable_definition_id = ? AND subject_id = ?",k2,k3)
                                        if subjectperiod.blank?
                                            issubjectpresent=TimetableAssign.where("section_id = ? AND subject_id = ?",section.id,k3)
                                            if issubjectpresent.blank?
                                                isteacherpresent=TimetableAssign.where("section_id = ? AND employee_id = ?",section.id,k4)
                                                if isteacherpresent.blank?
                                                    @finaltt=TimetableAssign.new
                                                    @finaltt.timetable_struct_id=@timetable_struct.id
                                                    @finaltt.employee_id=k4
                                                    @finaltt.section_id=section.id
                                                    @finaltt.standard_id=standard.id
                                                    @finaltt.division_id=division.id
                                                    @finaltt.subject_id=k3
                                                    @finaltt.timetable_definition_id=k2
                                                    @finaltt.timetable_day_id=k1
                                                    set_school_id(@finaltt,current_user)
                                                    if(@finaltt.save)

                                                        setflag_sub(subjectflag,k3,1)
                                                        setflag_period(periodflag,k2,1)
                                                        setflag_teacher(teacherflag,k4,1)
                                                    end
                                                end
                                            else
                                                @subjectdetail=TimetableAssign.find_by_section_id_and_subject_id(@section.id,k3)
                                                @finaltt=TimetableAssign.new
                                                @[email protected]_struct_id
                                                @[email protected]_id
                                                @finaltt.section_id=section.id
                                                @finaltt.standard_id=standard.id
                                                @finaltt.division_id=division.id
                                                @[email protected]_id
                                                @finaltt.timetable_definition_id=k2
                                                @finaltt.timetable_day_id=k1
                                                set_school_id(@finaltt,current_user)
                                                if(@finaltt.save)

                                                    setflag_sub(subjectflag,k3,1)
                                                    setflag_period(periodflag,k2,1)
                                                    setflag_teacher(teacherflag,k4,1)
                                                end
                                            end
                                        end
                                    end
                                end
                            end
                        end
                    end
                end
            end
        end
0
user3218146