web-dev-qa-db-ja.com

学校の時刻表を作成するためのアルゴリズム

学校の時刻表を作成するアルゴリズムの既知の解決策があるかどうか疑問に思っていました。基本的に、それは与えられたクラス-サブジェクト-教師のアソシエーションのために「教師とクラスの両方で」「時間分散」を最適化することです。入力時にクラスのセット、レッスンの科目、教師が相互に関連付けられており、時刻表は午前8時から午後4時の間に収まると想定できます。

おそらくそのための正確なアルゴリズムはないと思いますが、誰かがそれを開発するための良い近似やヒントを知っているかもしれません。

85
cand

この問題はNP-Complete!です。
簡単に言えば、許容可能なソリューションのリストを見つけるために、考えられるすべての組み合わせを調べる必要があります。さまざまな学校で問題が発生する状況はさまざまであるため(例:教室に関して制約はありますか?、一部のクラスはサブグループに時々分割されますか?、これは毎週のスケジュールですか?など)すべてのスケジューリング問題に対応する既知の問題クラスはありません。たぶん、 ナップザック問題 は、これらの問題全般と多くの類似要素を持っています。

これが難しい問題であり、人々が常に解決策を模索していることの確認は、この(長い) (ほとんどの商用)ソフトウェアスケジューリングツールのリスト

多くの変数が関係しているため、その最大の原因は、通常、教職員の要望です;-)...、通常、すべての可能な組み合わせを列挙することを検討することは非現実的です。代わりに、問題/ソリューション空間のサブセットを訪問するアプローチを選択する必要があります。
-Genetic Algorithms、別の回答で引用されている(または、私見、と思われる)この種のセミガイド検索(問題候補者が次世代のために保持されるための良い評価関数を見つけることです)
- Graph Rewriting このアプローチは、このタイプの組み合わせ最適化問題でも使用できます。

自動スケジュール生成プログラムの特定の実装に焦点を当てるのではなく、適用可能ないくつかの戦略を提案したい、問題の定義のレベルで
一般的な理論的根拠は、ほとんどの現実世界のスケジューリング問題では、表現および暗示されたすべての制約ではなく、いくつかの妥協が必要になることです。完全に満たされます。したがって、私たちは次の方法で支援します。

  • すべての既知の制約の定義とランク付け
  • 手動で追加の制約のセットを提供することにより、問題スペースを削減します。
    これは直感に反するように思えるかもしれませんが、たとえば、すべての制約を完全に満たす方法で、最初の部分的に満たされたスケジュール(たとえば、タイムスロットの約30%)を提供し、 、候補ソリューションの作成に必要な時間/スペースを大幅に削減します。
    追加の制約が役立つ別の方法として、たとえば、「人工的に」制約を追加して、特定の曜日に一部の科目を教えることを防ぐことがあります(これが週単位のスケジュールの場合...)。このタイプの制約は、通常、かなりの数の優秀な候補者を除外することなく、問題/ソリューションのスペースを削減します。
  • 問題の制約の一部を迅速に計算できるようにします。これは多くの場合、問題を表すために使用されるデータモデルの選択に関連しています。アイデアは、いくつかのオプションを迅速に選択(またはプルーンアウト)できるようにすることです。
  • 問題を再定義し、いくつかの制約を数回破ることを許可します(通常はグラフのエンドノードに向かって)。ここでのアイデアは、スケジュールの最後のいくつかのスロットを埋めるための制約のsomeを削除するか、自動スケジュールジェネレータープログラムにスケジュール全体を完了するのを恥ずかしがらせ、代わりにリストを提供することです十数個のもっともらしい候補者。示されているように、人間は通常、自動化された論理と共有されない情報を使用して、おそらくいくつかの制約を破り、パズルを完成するのにより良い位置にあります(例えば、「午後に数学がありません」ルールは時々破られる可能性があります「高度な数学と物理学」クラスの場合、または「Ms Jonesの要件の1つを破る方が、Ms Smithの要件の1つよりも優れている... ;-))

この答えを校正する際に、明確な応答を提供することは非常に恥ずかしがり屋ですが、実際的な提案に満ちています。結局のところ、「困難な問題」であるこの問題に役立つことを願っています。

78
mjv

それは混乱です。王室の混乱。答えに加えて、すでに非常に完全な、私の家族の経験を指摘したいと思います。私の母は教師であり、以前はこのプロセスに関与していました。

そのようにするコンピューターを持つことは、それ自体をコーディングするのが難しいだけでなく、プリベークされたコンピュータープログラムに指定するのが難しい条件があるため、難しいこともわかります。例:

  • 教師はあなたの学校と別の研究所の両方で教えます。明らかに、彼が10.30でレッスンを終了した場合、彼は施設間で通勤するのに時間が必要なため、10.30であなたの施設から始めることはできません。
  • 2人の教師が結婚しています。一般的に、同じクラスに2人の既婚教師がいないことをお勧めします。したがって、これらの2人の教師には2つの異なるクラスが必要です。
  • 2人の教師が結婚しており、子供は同じ学校に通っています。この場合も、2人の教師が子供のいる特定のクラスで教えることを防ぐ必要があります。
  • 学校には別の施設があります。ある日はクラスが1つの研究所にあり、別の日は別の研究所にあります。
  • 学校には実験室が共有されていますが、これらの実験室は特定の平日のみ利用できます(セキュリティ上の理由から、たとえば追加の人員が必要な場合)。
  • 一部の教師は、休日を好む傾向があります。一部は月曜日に、一部は金曜日に、一部は水曜日に好みます。朝早く来ることを好む人もいれば、後で来ることを好む人もいます。
  • たとえば、最初の1時間に歴史、次に3時間の数学、さらに1時間の歴史のレッスンを受けるような状況はありません。それは生徒にとっても教師にとっても意味がありません。
  • 引数を均等に広げる必要があります。週の最初の日は数学のみで、残りの週は文学のみとすることは意味がありません。
  • 一部の教師に2時間連続して評価テストを行う必要があります。

ご覧のように、問題はNP完全ではなく、NP異常です。

そのため、彼らは小さなプラスチックのインセットを備えた大きなテーブルを持ち、満足のいく結果が得られるまでインセットを移動します。彼らはゼロから始めることはありません。彼らは通常、前年の時刻表から始まり、調整を行います。

44
Stefano Borini

International Timetabling Competition 2007 には、レッスンスケジューリングトラックと試験スケジューリングトラックがありました。多くの研究者がその競争に参加しました。多くのヒューリスティックおよびメタヒューリスティックが試行されましたが、最終的にローカル検索メタヒューリスティック(タブー検索やシミュレーテッドアニーリングなど)が他のアルゴリズム(遺伝的アルゴリズムなど)を明らかに打ち負かしました。

ファイナリストの一部が使用している2つのオープンソースフレームワークをご覧ください。

23

私の半期の課題の1つは、遺伝的アルゴリズムの学校のテーブルの生成でした。

テーブル全体が1つの「生物」です。一般的な遺伝的アルゴリズムのアプローチには、いくつかの変更と警告がありました。

  • 「違法なテーブル」のルールが作成されました。同じ教室の2つのクラス、2つのグループに同時に教える1人の教師などです。最初のものは、合法的な(無意味な場合)を取得しようとする一連のランダムな試行によって生成されました。致死突然変異は、反復中の突然変異のカウントにはカウントされませんでした。

  • 「交換」突然変異は「修正」突然変異よりもはるかに一般的でした。変更は、意味のある遺伝子の部分間でのみ行われ、教師を教室に置き換えることはありませんでした。

  • 一定の2時間をまとめ、同じグループに同じ一般的な教室を順番に割り当て、教師の労働時間とクラスの負荷を継続させるために、小さなボーナスが割り当てられました。適度なボーナスは、特定の科目に正しい教室を提供するため、授業時間を絆(朝または午後)に保つなどのために割り当てられました。大きなボーナスは、与えられた科目の正しい数、教師の与えられたワークロードなどを割り当てることでした。

  • 教師は、適切な重みを割り当てて、「当時働きたい」、「働きたい」、「働きたくない」、「働けない」のワークロードスケジュールを作成できます。夜間が非常に望ましくないことを除いて、24時間全体が合法的な労働時間でした。

  • 重み関数...そうそう。重み関数は、選択したフィーチャとプロパティに割り当てられた重みの巨大な巨大な積(乗算など)でした。それは非常に急勾配で、1つのプロパティで簡単に1桁上または下に変更できます。1つの生物には数百または数千のプロパティがありました。これにより、重みとして絶対に膨大な数が発生し、直接的な結果として、bignumライブラリ(gmp)を使用して計算を実行する必要がありました。約10グループ、10教師、10教室の小さなテストケースの場合、最初のセットは10 ^ -200somethingのメモで始まり、10 ^ + 300somethingで終わりました。よりフラットな場合、完全に非効率的でした。また、より大きな「学校」により、価値ははるかに広くなりました。

  • 計算時間に関しては、長期間の小さな人口(100)と少ない世代の大きな人口(10k +)の間にはほとんど差がありませんでした。同じ時間の計算では、ほぼ同じ品質が得られました。

  • (1GHz CPUでの)計算は、10 ^ + 300近くで安定するのに1時間かかり、10x10x10のテストケースでは非常に見栄えの良いスケジュールを生成しました。

  • この問題は、計算を実行しているコンピューター間で最適な標本を交換するネットワーク機能を提供することにより、簡単に並列化できます。

結果として得られたプログラムは、学期中に良い成績を得ることができず、外の昼光を見ることはありませんでした。それはいくつかの約束を示しましたが、GUIを追加してそれを一般大衆が使用できるようにするための十分な動機がありませんでした。

16
SF.

この問題は見かけよりも難しいです。

他の人が示唆しているように、これはNP完全な問題ですが、それが何を意味するのか分析してみましょう。

基本的に、すべての可能な組み合わせを調べる必要があります。

しかし、「見る」では、何をする必要があるかはわかりません。

可能なすべての組み合わせを生成するのは簡単です。大量のデータが生成される可能性がありますが、問題のこの部分の概念を理解するのにそれほど問題はないはずです。

2番目の問題は、与えられた可能な組み合わせが以前の「良い」ソリューションよりも良いか、悪いか、良いかを判断することです。

このためには、「可能性のある解決策」以上のものが必要です。

たとえば、同じ教師がX週間連続して週5日働いていますか?それが有効な解決策であっても、各教師がそれぞれ1週間を行うように、2人を交互に使用するよりも良い解決策ではないかもしれません。ああ、あなたはそれについて考えなかったのですか?覚えておいてください、これはあなたが扱っている人々であり、単なるリソース割り当ての問題ではありません。

1人の教師が16週間フルタイムで働くことができたとしても、教師を交代させようとするソリューションと比較すると、最適なソリューションではない可能性があります。この種のバランスをソフトウェアに組み込むのは非常に困難です。

要約すると、この問題に対する適切なソリューションを作成することは、多くの人々にとって大きな価値があります。したがって、分解して解決するのは簡単な問題ではありません。 100%ではないいくつかの目標を賭けて、それらを「十分に良い」と呼ぶ準備をしてください。

更新:コメントから...ヒューリスティックも必要です!

私はPrologに行きます...その後、RubyまたはPerlまたは何かを使用して、ソリューションをきれいな形式にクリーンアップします。

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].

私は(まだ)この問題と似たようなことをしているが、先ほど述べたのと同じ道を使っている。 Prolog(関数型言語として)は、NP-Hardの問題を本当に簡単に解決します。

5
Reed Debaets

FETに実装された私の時間割アルゴリズム(無料の時間割ソフトウェア、 http://lalescu.ro/liviu/fet/ 、成功したアプリケーション):

アルゴリズムはヒューリスティックです。私はそれを「再帰スワッピング」と名付けました。

入力:アクティビティA_1 ... A_nと制約のセット。

出力:一連の時間TA_1 ... TA_n(各アクティビティのタイムスロット。簡単にするために、ここでは部屋を除外しています)。アルゴリズムは、制約を尊重して、各アクティビティをタイムスロットに配置する必要があります。各TA_iは0(T_1)からmax_time_slots-1(T_m)の間です。

制約:

C1)基本:同時に実行できないアクティビティのペアのリスト(たとえば、A_1とA_2、同じ教師または同じ生徒がいるため)。

C2)他の多くの制約(簡単にするためにここでは除外)。

時間割アルゴリズム(私は「再帰スワッピング」と名付けました):

  1. アクティビティをソートします。最も難しいものから先に。重要なステップではありませんが、アルゴリズムを10倍以上高速化します。
  2. 上記の順序に従って、許可されたタイムスロットに各アクティビティ(A_i)を1つずつ配置してみてください。 A_iの使用可能なスロット(T_j)を検索します。このアクティビティには、制約を考慮して配置できます。使用可能なスロットがさらにある場合は、ランダムなスロットを選択します。使用可能なものがない場合、再帰的なスワップを実行します。

    a。各タイムスロットT_jについて、A_iをT_jに入れるとどうなるかを検討してください。この動きに同意しない他のアクティビティのリストがあります(たとえば、アクティビティA_kは同じスロットT_jにあり、A_iと同じ教師または同じ生徒がいます)。各タイムスロットT_jの競合するアクティビティのリストを保持します。

    b。競合するアクティビティの数が最も少ないスロット(T_j)を選択します。このスロットのアクティビティのリストには、A_p、A_q、A_rの3つのアクティビティが含まれているとします。

    c。 A_iをT_jに配置し、A_p、A_q、A_rを未割り当てにします。

    d。再帰的にA_p、A_q、A_rを配置しようとします(再帰のレベルが大きすぎない場合、たとえば14、ステップ2以降にカウントされた再帰呼び出しの合計数)がA_iの開始時に大きすぎない場合、たとえば2 * nステップ2)のように。

    e。 A_p、A_q、A_rが正常に配置された場合、成功して戻ります。それ以外の場合は、他のタイムスロットを試し(手順2 bに進み)、次に最適なタイムスロットを選択します。

    f。すべて(または妥当な数)のタイムスロットが失敗した場合、成功せずに戻ります。

    g。レベル0で、A_iの配置に成功しなかった場合、ステップ2 b)および2 c)のように配置しますが、再帰は行いません。これで、3-1 = 2個のアクティビティを配置できます。ステップ2)に進みます(サイクリングを回避するためのいくつかの方法がここで使用されています)。

4
Liviu Lalescu

このようなスケジューリングには、遺伝的アルゴリズムがよく使用されます。

見つかった この例(遺伝的アルゴリズムを使用してクラススケジュールを作成する) これは要件にかなり一致します。

4
Christian V

ここに私が見つけたいくつかのリンクがあります:

School timetable -関係するいくつかの問題をリストします

学校の時間割のためのハイブリッド遺伝的アルゴリズム

スケジューリングユーティリティとツール

4
Niyaz

このホワイトペーパーでは、学校の時刻表の問題とアルゴリズムへのアプローチについて非常によく説明しています。「 SYLLABUSの開発-学校および大学向けのインタラクティブな制約ベースのスケジューラ。 」[ PDF]

著者は、SYLLABUSソフトウェアがここでまだ使用/開発されていることを私に知らせています: http://www.scientia.com/uk/

2
Leftium

私は、これを正確に行う広く使用されているスケジューリングエンジンに取り組んでいます。はい、NP完全です。最適なアプローチは、最適なソリューションを近似しようとします。そして、もちろん、どれが「最良の」解決策であるかを言う多くの異なる方法があります-あなたの教師が彼らのスケジュールに満足している、または学生がすべてのクラスに参加することは、例えば、より重要ですか?

早い段階で解決する必要がある絶対的な最も重要な質問は、このシステムをスケジュールする1つの方法が他の方法よりも優れている理由?です。つまり、ジョーンズ夫人が8で数学を教え、スミスさんが9で数学を教えるスケジュールがある場合、両方が10で数学を教えるスケジュールよりも良いですか、それとも悪いですか?ジョーンズ夫人が8で教え、ジョーンズ氏が2で教えているよりも良いですか、悪いですか?どうして?

私がここで与える主なアドバイスは、問題を可能な限り分割することです-おそらくコースごと、おそらく教師ごと、おそらく部屋ごと-そして最初に副問題を解決することに取り組みます。そこで、複数のソリューションから選択することになり、最も可能性の高い最適なソリューションを選択する必要があります。次に、「以前の」副問題を作成する作業を行い、潜在的な解決策を採点する際に後の副問題のニーズを考慮します。次に、「有効な解決策がない」状態になったときに、角に塗られた状況(以前の副問題でこれらの状況を予測できないと仮定)から抜け出す方法に取り組みます。

ローカル検索最適化パスは、より良い結果を得るために最終回答を「研磨」するためによく使用されます。

通常、学校のスケジューリングでは非常にリソースに制約のあるシステムを扱っていることに注意してください。学校は、1日の75%が空いている部屋やラウンジに座っている教師が多いため、1年は通っていません。ソリューションが豊富な環境で最適に機能するアプローチは、必ずしも学校のスケジュールに適用できるとは限りません。

2
Tom Dibble

クラスの時間割と試験の時間割の両方に対応する商用アルゴリズムを設計しました。最初は整数プログラミングを使用しました。 2つ目は、スロットスワップを選択して目的関数を最大化することに基づいたヒューリスティックで、進化してきた元の手動プロセスに非常に似ています。こうしたソリューションを受け入れてもらうための主なものは、現実世界のすべての制約を表現する能力です。また、人間のタイムテーブル作成者が解決策を改善する方法を見つけられないようにします。最終的に、アルゴリズムの部分は、データベースの準備、ユーザーインターフェイス、部屋の使用状況、ユーザー教育などの統計をレポートする機能と比較して、非常に簡単で実装が簡単でした。

2
Permaquid

一般に、制約プログラミングは、このタイプのスケジューリング問題に対する優れたアプローチです。スタックオーバーフローとGoogleの両方で「制約プログラミング」とスケジューリングまたは「制約ベースのスケジューリング」を検索すると、いくつかの優れたリファレンスが生成されます。不可能ではありません-線形最適化や整数最適化などの従来の最適化手法を使用する場合、考えるのは少し難しいです。 1つの出力は次のようになります-すべての要件を満たすスケジュールは存在しますか?それ自体、明らかに役立ちます。

がんばろう !

1
Grembo

遺伝的アルゴリズムでそれをタグ付けできます、はい。しかし、あなたはすべきではありません:)。遅すぎたり、パラメーターの調整に時間がかかりすぎたりする場合があります。

他にも成功したアプローチがあります。すべてがオープンソースプロジェクトに実装されています:

  • 制約ベースのアプローチ
    • niTime で実装(実際には学校向けではありません)
    • さらに進んで、整数プログラミングを使用することもできます。 ウディネ大学 で成功し、商用ソフトウェア(ILOG CPLEX)を使用してバイロイト大学(私もそこで関与していました)で成功しました
    • Heuristiscを使用したルールベースのアプローチ- Drools planner を参照
  • 異なるヒューリスティック- [〜#〜] fet [〜#〜] および my own

時間割設定ソフトウェアのリスト についてはこちらをご覧ください

1
Karussell

私はあなたが遺伝的アルゴリズムを使用すべきだと思う:

同様の質問 および 別の質問 もご覧ください

0
Betamoo

誰もこのコードに同意するかわかりませんが、私は自分のアルゴリズムの助けを借りてこのコードを開発し、Rubyで働いています。次のコードで期間フラグ、日フラグsubjectflagとteacherflagは、対応するidとブール値であるフラグ値を持つハッシュです。どんな問題でも私に連絡してください.......(-_-)

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