2019年4月26日金曜日

Pythonの制約ステートメント

import sc3

v1=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-27  ', '  オンコール ')
sc3.AddHard(v1,' 川畑拓也2017-05-27    オンコール')


制約するには、シフト変数v1を取り出します。シフト変数は、3次元で、Person、Day,Shiftの順にGetShiftVar関数で取り出します。 引き数は、GUIで定義した文字列、もしくは、配列Indexです。または、任意の組合せ(文字列/配列Index)になります。どちらもPropertyファイルを参照して、Validな名前、範囲を確認することが出来ます。文字列の場合、空白はあっても構いません。(Trimされます。) で、取り出した変数をアサートするには、AdddHard関数を呼び出します。AddHard関数は、1番目に変数、2番目にコメントになっています。上記は、川畑拓也の2017-5-27の勤務はオンコールであること、というハード制約になります。 下が実行結果です。確かに、オンコールのラベルであるになっています。

同様にして、日付を追加したソースが次です。
import sc3

v1=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-27  ', '  オンコール ')
sc3.AddHard(v1,' 川畑拓也2017-05-27    オンコール')

v2=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-28  ', '  オンコール ')
sc3.AddHard(v2,' 川畑拓也2017-05-28    オンコール')

v3=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-29  ', '  オンコール ')
sc3.AddHard(v3,' 川畑拓也2017-05-29    オンコール')

v4=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-30  ', '  訪問看護 ')
sc3.AddHard(v4,' 川畑拓也2017-05-30    オンコール')
実行結果は次です。
 

次は、Andに関するどれもValidな構文です。And()関数の引き数は、4個までサポートしています。2項演算子&を使えばその制限はありませんが、3個以上の演算については、リストを使うことを推奨します。
import sc3

v1=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-27  ', '  オンコール ')
v2=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-28  ', '  オンコール ')
v3=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-29  ', '  オンコール ')
v4=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-30  ', '  訪問看護 ')
sc3.AddHard(v1&v2&v3&v4,' 川畑拓也2017-05-30パターン    オンコール')

vlist=[v1,v2,v3,v4]#3個以上はリストを推奨
sc3.AddHard(sc3.And(vlist),' 川畑拓也2017-05-30Vlistパターン    オンコール')

v5=sc3.And(v1,v2,v3,v4)#引き数は4個まで
sc3.AddHard(v5,' 川畑拓也2017-05-30Andパターン    オンコール')
ハード制約にはコメントをつける
コメントは、空白でSPLITされる任意の文字列とします。 上の記述は、3つのANDの制約は、お互いが等価な制約です。感心しない記述ですが、お互い矛盾しないのでエラーは出ません。 ここで意図的にエラーを作ってどのような 事象になるかを見てみます。具体的には、v4をInvert(Not)してみます。制約BC間は、矛盾しませんが、制約AB,AC間では矛盾が起こります。
import sc3

v1=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-27  ', '  オンコール ')
v2=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-28  ', '  オンコール ')
v3=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-29  ', '  オンコール ')
v4=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-30  ', '  訪問看護 ')
sc3.AddHard(v1&v2&v3&~v4,' 川畑拓也2017-05-30パターン    オンコール')#制約A)故意にエラーを生成

vlist=[v1,v2,v3,v4]
sc3.AddHard(sc3.And(vlist),' 川畑拓也2017-05-30Vlistパターン    オンコール')#制約B

v5=sc3.And(v1,v2,v3,v4)
sc3.AddHard(v5,' 川畑拓也2017-05-30Andパターン    オンコール')#制約C
コンパイルの準備中ソルバを呼び出し中です。
 python propertyファイル生成を開始します。
 python propertyファイル生成が終了しました。
 満たしていないハード制約の集約化を行います。
 o=11 Time=3.153(CPU秒)
 o=10 Time=3.183(CPU秒)
 o=9 Time=3.245(CPU秒)
 o=8 Time=3.362(CPU秒)
 o=7 Time=3.425(CPU秒)
 o=6 Time=3.516(CPU秒)
 o=5 Time=3.593(CPU秒)
 o=4 Time=3.666(CPU秒)
 o=3 Time=3.773(CPU秒)
 o=2 Time=3.805(CPU秒)
 o=1 Time=3.907(CPU秒)
 f=0 Time=3.969(CPU秒)
 Optimum ConUB found
 b=1 Time=4.039(CPU秒)
 以下に矛盾または満たしていない可能性がある制約を示します。
  ● 川畑拓也2017-05-30パターン
解探索が終了しました。 4 (秒)
解を見つけることが出来ませんでした。
上記は、ソルバーが充足解を見つけられないと判断し、充足しない原因を探すために、どの制約を外せば、充足するようになるかという エラーの最小化アルゴリズムが実施された結果です。結果、一つの制約を外せば、全て満たされることが示されています。 制約の開発・設計過程においては、上記のようなことが割りに頻繁に起きます。そのとき、コメントがブランクだったらどうなるでしょう? 矛盾している制約の数が1個であることは分かりますが、コメントがブランクだと、それがどこなのかは、知ることができません。ナーススケジューリングの場合、制約の数は、数万を越えることは普通にあります。面倒でも、ハード制約には他の制約と区別するコメントをつけておくことを強くお勧めしたい理由がここにあります。SC3は、数理最適化系のソルバーも搭載しますが、こちらの場合は、運がよければ目的関数値が妙にでかくなる、大抵の場合は、線形制約ソルバーが充足しないので手も足も出ません。結果、どこが問題かは、見当をつけることさえ困難です。厳密解を目指す場合、数理最適化系が有利になる場合がありそちらのソルバーを最終的に使う場合でも、制約記述の開発・設計には、こちらのモードで行うのがよいでしょう。
import sc3

v1=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-27  ', '  オンコール ')
v2=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-28  ', '  オンコール ')
v3=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-29  ', '  オンコール ')
v4=sc3.GetShiftVar(' 川畑拓也 ',  ' 2017-05-30  ', '  訪問看護 ')
sc3.AddSoft(v1&v2&v3&~v4,' 川畑拓也2017-05-30パターン    オンコール',  1  )#制約A)故意にエラーを生成レベル1でソフト制約

vlist=[v1,v2,v3,v4]
sc3.AddHard(sc3.And(vlist),' 川畑拓也2017-05-30Vlistパターン    オンコール')#制約B

v5=sc3.And(v1,v2,v3,v4)
sc3.AddHard(v5,' 川畑拓也2017-05-30Andパターン    オンコール')#制約C

制約Aをソフト制約化するには、AddHardをAddSoftに置き換え、最後にレベルを加えます。上では、レベル1に設定しました。 SC2では、エラーをカウントするという意味で、INV化(Not化)する必要がありましたが、SC3では、必要なく、上記変更だけで事足ります。 ソフト制約化することにより下のように充足することになります。

python propertyファイル生成を開始します。
 python propertyファイル生成が終了しました。
 解探索を開始します。2.370(CPU秒)

 User Soft Constraint Level 1
 o=1 Time=2.454(CPU秒)
 f=0 Time=2.484(CPU秒)
 Optimum ConUB found
 o=1 Time=2.563(CPU秒)
 o=1 Time=2.587(CPU秒)
 b=1 Time=2.603(CPU秒)
 充足解を書き込み中です。


SC3、Pythonによる言語制約について概観しました。Python言語制約の公式Tutorialは、6月にリリース予定です。SC3で追加した、Phase/Task機能、さらにPythonによる言語制約により、 およそ勤務表と名のつくスケジューリング問題で出来ない勤務表はないと思います。SC2は、元々他の勤務表ソフトでは記述不能な、複雑で込み入った仕様の勤務表について、トップを独走中でした。今回の機能強化により、工場の工程管理、コールセンター等、大規模な勤務表分野にも参入します。さらに、SC2では、基本1ヶ月単位でしたが、3ヶ月・1年といった単位での管理のご要望がありまして、そちらについても対応予定です。

0 件のコメント:

コメントを投稿