学生とプロジェクトの特定の割り当てを最適化するために、シミュレーテッド アニーリング アルゴリズムを実行しています。
これは、Wikipedia の言語に依存しない疑似コードです。
s ← s0; e ← E(s) // Initial state, energy.
sbest ← s; ebest ← e // Initial "best" solution
k ← 0 // Energy evaluation count.
while k < kmax and e > emax // While time left & not good enough:
snew ← neighbour(s) // Pick some neighbour.
enew ← E(snew) // Compute its energy.
if enew < ebest then // Is this a new best?
sbest ← snew; ebest ← enew // Save 'new neighbour' to 'best found'.
if P(e, enew, temp(k/kmax)) > random() then // Should we move to it?
s ← snew; e ← enew // Yes, change state.
k ← k + 1 // One more evaluation done
return sbest // Return the best solution found.
以下は、テクニックの適応です。私の上司は、そのアイデアは理論的には問題ないと言いました。
最初に、ランダム化された割り当てのセット全体からいくつかの割り当て (つまり、プロジェクトのランクを含む、学生と割り当てられたプロジェクトの辞書全体) を取得し、それをコピーして関数に渡します。この割り当てを呼び出しましょうaOld
(辞書です)。aOld
と呼ばれるそれに関連する重みがありwOld
ます。重み付けについては後述します。
この関数は次のことを行います。
- この割り当て
aOld
をbest_node
- すべての生徒からランダムな数の生徒を選び、リストに貼り付けます
- それらのプロジェクトを削除 (DEALLOCATE) ++ プロジェクト (
allocated
パラメーターは nowFalse
) と講師の変更を反映 (1 つ以上のプロジェクトが割り当てられなくなった場合はスロットを解放) - そのリストをランダム化する
- そのリスト プロジェクトの全員を再度割り当て (REALLOCATE) してください。
- 重みを計算します (ランクを合計します。ランク 1 = 1、ランク 2 = 2... およびプロジェクトなしのランク = 101)。
- この新しい割り当て
aNew
では、重みが最初に選択しwNew
た割り当ての重みよりも小さい場合、これは (上記のアルゴリズムで定義された) です。アルゴリズムを適用して続行します。wOld
best_node
Simulated Annealing
aNew
- の場合
wOld < wNew
、アルゴリズムをaOld
再度適用して続行します。
割り当て/データポイントは、「ノード」として表現されます。node = (weight, allocation_dict, projects_dict, lecturers_dict)
現時点では、このアルゴリズムは 1 回しか実行できませんが、数値 N (kmax
ウィキペディアのスニペットでは で示されています) を試して、以前node
の とbest_node
.
元の辞書 (リセットしたいかもしれません) を変更しないように、辞書の浅いコピーを作成しました。ドキュメントで読んだことから、参照をコピーするだけのようで、辞書にはオブジェクトが含まれているため、コピーされた辞書を変更するとオブジェクトが変更されます。copy.deepcopy()
これらの辞書は、SQLA でマップされたオブジェクトを参照します。
Questions:
私は直面している問題に対していくつかの解決策を与えられてきましたが、Python を使用することに対する私の環境への配慮のせいで、それらはすべて私にはやや不可解に聞こえます。
Deepcopy は SQLA とうまく連携していません。ORM オブジェクトのディープコピーにはおそらく問題があり、期待どおりに動作しないと言われています。どうやら、「コピー コンストラクター、つまり def copy(self): return FooBar(....) を作成する」ほうがよいようです。誰かがそれが何を意味するのか説明してもらえますか?
deepcopy
SQLAlchemy がオブジェクトに余分な情報を配置するため、問題があることがわかりました。つまり_sa_instance_state
、コピーには入れたくないが、オブジェクトに必要な属性です。「古いものを手動で吹き飛ばして_sa_instance_state
新しいものをオブジェクトに付ける方法はありますが、最も簡単なのは、新しいオブジェクトを作成して、__init__()
重要な属性を設定することです。ディープコピー。」それは正確にはどういう意味ですか?古いマップされたクラスに似た、マップされていない新しいクラスを作成する必要がありますか?別の解決策は、「オブジェクトに実装
__deepcopy__()
し、新しい _sa_instance_state が設定されていることを確認する必要があります。それを支援できる関数が sqlalchemy.orm.attributes にあります。」繰り返しますが、これは私を超えているので、誰かが親切にそれが何を意味するのか説明できますか?より一般的な質問:上記の情報が与えられた場合、
best_node
(whileループを通じて常に持続する必要がある)およびprevious_node
実際のオブジェクト(辞書によって参照されるため、ノードの場合)の情報/状態を維持する方法に関する提案はありますか) が行われているため、割り当て解除/再割り当てが変更されていますか? つまり、コピーを使用せずに?