Q.当院は師長及び理事長が勤務表の作成をしておりました。 今後はソフトを導入し、各スタッフの希望に沿いつつも、ある程度公平にした勤務表を作りたいと思っています。
もしよろしければご相談に乗っていただければ幸いです。
Ans.
⇒恐れ入りますが、ZOOM予約は、プロジェクト作成サービスのご利用が前提となっております。無償でのZOOM相談は、基本的には行っておりませんのでご理解の程お願いいたします。
Q.当院は師長及び理事長が勤務表の作成をしておりました。 今後はソフトを導入し、各スタッフの希望に沿いつつも、ある程度公平にした勤務表を作りたいと思っています。
もしよろしければご相談に乗っていただければ幸いです。
Ans.
⇒恐れ入りますが、ZOOM予約は、プロジェクト作成サービスのご利用が前提となっております。無償でのZOOM相談は、基本的には行っておりませんのでご理解の程お願いいたします。
正月に、親戚の高専生がゲームプログラマを目指している、というのを聞いて、老婆心ながら、「プログラマになるなら国語力が大事だよ。」
と言ってしまいました。そう言っているのは、私だけではないようで、
プログラミング教育にはどうして国語が必要と言われるのか? | ティーチャーズメディア
国語力とプログラミング力の関係 解説編:【写真】天才プログラマに聞く10の質問(4)(1/2 ページ) - @IT
「子どもを無理矢理プログラミング教室に通わせる必要はない」…大学教授が解説"小中高での必修化"本当の価値(プレジデントオンライン) - Yahoo!ニュース
スケジュールナースを使う上においても同じことが言えると思っています。スケジュールナースは、プログラムじゃないじゃん、と言われるとその通りです。スケジュールナースは、ノーコードプラットフォーム、という見方はある意味正しいです。
しかし、実は、皆さんは、「制約プログラム」をGUIで書いています。コンピュータに指示するというのは、GUIではありますが、言葉で指示をしていることに同じです。言葉なしでは、一切動きません。言葉という指示があって、スケジュールナースは、動きます。
仕様を人に伝える、にしてもそうです。ユーザさんの中で、お医者さんやら看護師勤務表を作っておられる方がいらっしゃいます。この方は、現役ではないのですが、いわゆる事務屋さん、だと思います。そういう方が、畑違いの仕様をまとめて提示してくれていて、非常に助かっています。で、その力の源泉は国語力であると思う次第です。使いこなすのに、ITエンジニアである必要はない、という証明だと思います。
プログラムでも、最初からコーディングすることはありません。何を実現するかというのは、企画書や仕様という日本語という言葉で形にすることで明示することから始まります。概念や目的等、抽象的な要件は、日本語という言葉から始まります。
このユーザさんのように、事務または事務長さんであるユーザさんは結構多いと思います。(訪問クリニック、産科クリニック、脳神経外科クリニック、数病棟の公立病院等、サポート経験からの推測です。)
人と人とのコミュニケーションに長けているということ、人の話を聞くこと、理解してまとめること、これは、全て国語力です。なので、別に看護師長である必要はない、ということだろうと思います。勿論、看護師長自身が使いこなせれば、それがベストですが、制約をメンテナンスする人が、看護師長である必要はありません。
男性か女性かという点においては、経験上、男性の方が国語力の優位性が高いと思います。何故かは分かりません。男性の方がロジカルである傾向があるからかもしれません。
女性がビジネスで活躍するには「ロジカルシンキング」をもっと学ぶべき?(横山信弘) - エキスパート - Yahoo!ニュース
性別を問わず、どんなにITリテラシーに疎くても、国語力とやる気さえあれば、サポート出来る自信はあります。言葉のコミュニケーションさえできれば、必ず前に進めることが出来るからです。
ちなみに、今までに出会ったなかで、国語の達人と思うのは、弁理士さんです。特許の請求項をクレームと言うのですが、クレームでは、日本語で論理的なことを漏れなく明確に記載する必要があります。私が書いたクレーム原案は、殆ど跡形もなく添削されて別なクレームになるのが普通です。それは、特許クレームという一見複雑怪奇な文章ではありますが、見事に精緻で一分の隙もない文にする日本刀の研師のような作業です。これを成すには国語力、ということをおっしゃっていたのを思い出しました。
その弁理士さんは、推敲の際、句読点を区切りながらクレームをよく音読していました。正しいかどうか常に反芻しながら頭を回転させていたのでしょう。で、
スケジュールナースで制約が思い通りに動かないとき、制約を音読してみる、
というのをお勧めしています。自分が今書いた制約が、確かに意図通りであるか?反芻することで、バグを発見できるかもしれないからです。
まずは、ブランク予定で、UB=0を確認しておきます。
UB=0になっています。さらに、自分が良いと思う勤務を入力していきます。黄色部以外が入力したところです。
同じスタイルではありますが、違いは、解が存在する保証があること、そしてベスト解よりも良い解(目的関数値が低い)が存在しないことが違います。自分が入力した勤務パターンでは、其のあとにどんなに頑張っても相応のエラーとなってしまう将来が示されることです。
この違いは、大きいと思います。安心できるのでは、ないでしょうか?
入力の仕方は、従前のやりかたと全く同じです。しかし、良いと思った勤務パターンを入力していっても、スケジュールナースが示す将来のベスト解がエラーだらけ、ということに早晩気づくことになるでしょう。散々入力した挙句に、結局は、スケジュールナース解を採用、もしくは、部分の修正ということに落ち着く、 と思います。いつも同じ修正が入るならば、それは制約を追加した方が時間の節約になる、ということになろうかと思います。
Ans.
前回設定では、無理やり平準化を行う方法を示しました。この方法は、本来、勤務表作成の最後に行う類のものです。初期設計時、ブランク予定で行うべきものではありません。
原則的に、ブランク予定では、エラー0を基準に制約設計を行います。前回のままでは、その原則から外れているので、正しい制約の仕方をここで述べたいと思います。
まず、予定なしでのコマ数から、人員とプロジェクト月の平日日勤者のコマ数を自動算出してみましょう。
Excelで行ってもよいですし、スケジュールナースのマクロで行ってもよいです。
下記でC(x)は、x集合の要素をカウントする関数です。
最初に、全スタッフの人数や、今月の日数を求めています。
これで、任意のスタッフ数、任意のプロジェクト月に対して自動設定することが出来ました。エラーは0です。
<実際には、週休・祝休以外の休みがある>
実際には、夏休み、有給等の休みがあるでしょう。上記実装の問題は、それを無視した値となっています。その辺を加味して設定する必要があります。
<その他の休みまで含んで自動制約化するには?>
Pythonでの記述になります。一応の実装を示します。(制約設計時にここまで凝ることは、全くお勧めしません。その他要因、増員日やらその他要求があるのが普通でそのたびに、Pythonも影響を受け修正を余儀なくされます。従って、自動化実装は、十分な時間が経過した安定稼働後に、自動化したい要求があるときに検討すればよいと思います。)
予定で入れたその他予定休みを勘案して、下限と上限を自動計算する例です。
次のような、週休・祝休以外の休み予定が入ったとします。
Pyhonでその他休みの総和を求め、マクロでのコマ数計算値を呼び出して、平日残りコマ数最小から引き算、平均の平日日勤者数を求めます。
後は、範囲の整数を求めて、最大最小を制約しています。
import sc3
import math
def is_off(s):
if s=='有休' or s=='夏' or s=='特休' or s=='休日':
return True
return False
#その他休み総和を求める
other_off_days_count=0
for person in 全スタッフ:
for day in 今月:
if is_off(shift_schedules[person][day][0]) :
other_off_days_count+=1
r=平日残りコマ数最小-other_off_days_count
ravg=r/平日数
その他休みを考慮した平日残りコマ数最小=int(math.floor(ravg))
その他休みを考慮した平日残りコマ数最大=int(math.ceil(ravg))
print("\n\nその他休みを考慮した平日残りコマ数",r,"平均日勤者数=",ravg,"最小=",その他休みを考慮した平日残りコマ数最小,"最大=",その他休みを考慮した平日残りコマ数最大)
#GUI制約をDisable
#sc3.ConstraintEnable('列制約全体.平日日勤者リーダ看護師長除く4名から5名',False)
#今月平日の日勤者数を制約する
for day in 今月平日:
vlist=[]
s='言語その他休みを考慮した平日日勤者数'+' '+daydef[day]+'\n'
allowable_errors=3
for person in 全スタッフ:
v=sc3.GetShiftVar(person,day,'日勤')
vlist.append(v)
sc3.AddSoft(sc3.SeqError(その他休みを考慮した平日残りコマ数最小,その他休みを考慮した平日残りコマ数最大,allowable_errors,vlist),s,4) #min max allowable errors list
適当にランダム入力でその他休みを入力してみました。
以下はログです。両方共エラー0です。
コンパイルの準備中 ソルバを呼び出し中です。 制約をコンパイル中です。 Python プロパティファイルの生成が終わりました。 その他休みを考慮した平日残りコマ数 100 平均日勤者数= 5.555555555555555 最小= 5 最大= 6 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. Algorithm 1 Solving Process Started.. o 1493 3.962000(sec) o 1481 4.276000(sec) o 1459 4.401000(sec) o 1435 4.446000(sec) o 1397 4.481000(sec) o 1387 4.497000(sec) o 1293 4.513000(sec) o 1284 4.545000(sec) o 1240 4.576000(sec) o 1215 4.635000(sec) o 1165 4.674000(sec) o 1150 4.690000(sec) o 1120 4.746000(sec) o 1098 5.504000(sec) o 1095 5.692000(sec) o 1076 5.723000(sec) o 1072 6.032000(sec) o 1070 9.859000(sec) o 1064 9.888000(sec) o 1052 9.906000(sec) o 1046 9.924000(sec) o 1037 9.945000(sec) o 1004 9.994000(sec) o 976 10.016000(sec) o 968 10.060000(sec) o 946 10.098000(sec) o 936 10.114000(sec) o 920 10.184000(sec) o 909 10.216000(sec) o 896 10.230000(sec) o 875 10.244000(sec) o 871 10.323000(sec) o 865 10.339000(sec) o 850 10.354000(sec) o 845 10.378000(sec) o 831 10.417000(sec) o 820 10.464000(sec) o 789 10.547000(sec) o 776 10.564000(sec) o 773 10.581000(sec) o 768 10.619000(sec) o 763 10.649000(sec) o 759 10.669000(sec) o 736 10.685000(sec) o 713 10.756000(sec) o 706 10.821000(sec) o 693 10.978000(sec) o 675 10.994000(sec) o 666 11.019000(sec) o 662 11.035000(sec) o 659 11.052000(sec) o 656 11.066000(sec) o 651 11.079000(sec) o 645 11.124000(sec) o 632 11.148000(sec) o 597 11.189000(sec) o 580 11.225000(sec) o 575 11.239000(sec) o 558 11.410000(sec) o 547 11.482000(sec) o 544 11.555000(sec) o 511 11.791000(sec) o 507 11.858000(sec) o 488 11.938000(sec) o 474 12.023000(sec) o 455 15.734000(sec) o 452 15.769000(sec) o 422 15.788000(sec) o 388 15.838000(sec) o 371 15.903000(sec) o 343 15.967000(sec) o 313 16.042000(sec) o 294 16.061000(sec) o 285 16.076000(sec) o 269 16.101000(sec) o 261 16.117000(sec) o 258 16.131000(sec) o 236 16.233000(sec) o 228 16.247000(sec) o 204 16.287000(sec) o 174 16.480000(sec) o 172 16.553000(sec) o 155 16.624000(sec) o 152 16.640000(sec) o 141 16.716000(sec) o 108 16.793000(sec) o 102 16.847000(sec) o 92 16.879000(sec) o 69 17.026000(sec) o 67 17.047000(sec) o 64 17.062000(sec) o 61 17.075000(sec) o 60 17.158000(sec) o 56 21.590000(sec) o 54 21.611000(sec) o 53 21.625000(sec) o 46 21.712000(sec) o 45 21.947000(sec) o 43 21.995000(sec) o 40 22.053000(sec) o 39 22.124000(sec) o 32 22.172000(sec) o 28 22.216000(sec) o 24 22.315000(sec) o 23 22.376000(sec) o 22 22.414000(sec) o 21 22.478000(sec) o 20 22.499000(sec) o 19 22.521000(sec) o 16 22.549000(sec) o 15 22.577000(sec) o 14 22.602000(sec) o 12 22.835000(sec) o 11 22.960000(sec) o 9 22.996000(sec) o 8 23.019000(sec) o 6 23.064000(sec) o 5 23.484000(sec) o 4 23.540000(sec) o 3 23.637000(sec) o 2 23.696000(sec) o 0 23.843000(sec) Python プロパティファイルの生成が終わりました。 _____________________________________ | | | | | Weight | Errors | Cost | |___________|___________|_____________| | | | | | 7 | 0 | 0 | | 5 | 0 | 0 | | 3 | 0 | 0 | | 1 | 0 | 0 | |___________|___________|_____________| | | | | Total | 0 | |_______________________|_____________| *********UB=0(0) 25.283(cpu sec) o 0(0) 解探索が終了しました。 26 (秒) 解が得られました。 コンパイルの準備中 ソルバを呼び出し中です。 制約をコンパイル中です。 Python プロパティファイルの生成が終わりました。 その他休みを考慮した平日残りコマ数 51 平均日勤者数= 2.8333333333333335 最小= 2 最大= 3 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1日勤二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1入り二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. 禁止ペア1明け二人不可:column seq erased. Algorithm 1 Solving Process Started.. o 1543 3.482000(sec) o 1506 3.568000(sec) o 1474 3.592000(sec) o 1436 3.604000(sec) o 1413 3.617000(sec) o 1406 3.629000(sec) o 1385 3.641000(sec) o 1379 3.661000(sec) o 1363 3.672000(sec) o 1320 3.690000(sec) o 1255 3.703000(sec) o 1229 3.717000(sec) o 1216 3.728000(sec) o 1185 3.746000(sec) o 1167 3.759000(sec) o 1141 3.865000(sec) o 1129 3.877000(sec) o 1124 3.888000(sec) o 1079 6.724000(sec) o 1073 6.777000(sec) o 1046 6.789000(sec) o 1028 6.806000(sec) o 1011 6.820000(sec) o 998 6.831000(sec) o 973 6.842000(sec) o 972 6.853000(sec) o 971 6.922000(sec) o 946 6.944000(sec) o 916 6.993000(sec) o 898 7.008000(sec) o 873 7.050000(sec) o 864 7.062000(sec) o 853 7.074000(sec) o 816 7.120000(sec) o 804 7.136000(sec) o 791 7.150000(sec) o 776 7.165000(sec) o 758 7.176000(sec) o 741 7.190000(sec) o 718 7.218000(sec) o 704 7.264000(sec) o 692 7.279000(sec) o 682 7.292000(sec) o 669 7.323000(sec) o 662 7.344000(sec) o 645 7.357000(sec) o 639 7.369000(sec) o 637 7.382000(sec) o 628 7.453000(sec) o 623 7.478000(sec) o 608 7.491000(sec) o 605 7.503000(sec) o 597 7.514000(sec) o 575 7.580000(sec) o 571 7.591000(sec) o 565 7.603000(sec) o 553 7.618000(sec) o 550 7.641000(sec) o 536 7.653000(sec) o 533 7.665000(sec) o 527 7.677000(sec) o 513 7.691000(sec) o 500 7.707000(sec) o 485 10.543000(sec) o 473 10.713000(sec) o 468 10.733000(sec) o 457 10.793000(sec) o 434 10.846000(sec) o 413 10.904000(sec) o 410 10.915000(sec) o 371 10.928000(sec) o 348 10.954000(sec) o 315 10.996000(sec) o 312 11.008000(sec) o 287 11.024000(sec) o 279 11.051000(sec) o 254 11.120000(sec) o 218 11.141000(sec) o 193 11.155000(sec) o 188 11.199000(sec) o 167 11.230000(sec) o 138 11.327000(sec) o 118 11.357000(sec) o 111 11.400000(sec) o 95 11.414000(sec) o 93 11.426000(sec) o 92 11.441000(sec) o 80 11.500000(sec) o 76 15.077000(sec) o 70 15.096000(sec) o 67 15.109000(sec) o 55 15.162000(sec) o 54 15.174000(sec) o 52 15.189000(sec) o 48 15.203000(sec) o 45 15.216000(sec) o 42 15.228000(sec) o 39 15.254000(sec) o 37 15.416000(sec) o 36 15.481000(sec) o 34 15.497000(sec) o 29 15.583000(sec) o 28 15.597000(sec) o 25 15.623000(sec) o 24 15.637000(sec) o 23 15.787000(sec) o 22 15.911000(sec) o 21 15.923000(sec) o 17 16.082000(sec) o 15 16.097000(sec) o 13 16.128000(sec) o 11 16.146000(sec) o 10 16.160000(sec) o 9 16.234000(sec) o 8 16.249000(sec) o 7 16.262000(sec) o 3 16.330000(sec) o 2 16.741000(sec) o 1 17.124000(sec) Python プロパティファイルの生成が終わりました。 o 0 17.421000(sec) _____________________________________ | | | | | Weight | Errors | Cost | |___________|___________|_____________| | | | | | 7 | 0 | 0 | | 5 | 0 | 0 | | 3 | 0 | 0 | | 1 | 0 | 0 | |___________|___________|_____________| | | | | Total | 0 | |_______________________|_____________| *********UB=0(0) 18.54(cpu sec) o 0(0) 解探索が終了しました。 19 (秒) 解が得られました。
<現象>
コンペティションの週毎のシフトオフフォーマットの中で、例えば、次のような記述がある場合があり、
その場合、正しく問題を解釈することが出来ません。
NU_27 Day Sat
NU_27 Late Sat
CT_57 Early Tue
CT_57 Late Tue
同一日に、同一の人が二つ以上のシフトをオフにする、という仕様です。この場合、GUIでは、一つのペナルティしか与えることが出来ないので、正しく解釈することが出来ません。
正しくは、
NU_27の土曜日がDayシフトでないのならばペナルティ10
NU_27の土曜日がLateシフトでないのならばペナルティ10
と独立にペナルティを与えないといけないのですが、GUIだけでは正しく実装出来ません。
仕方ないので、GUIでは、一つのペナルティを与え、Pythonで残りをカバーするという実装にしました。
<改善後の実装>
n080w4
REQUIREMENTS
Early HeadNurse (1,1) (1,1) (0,0) (1,1) (1,1) (1,1) (0,1)
Early Nurse (1,1) (1,1) (1,2) (2,2) (1,2) (1,1) (1,1)
Early Caretaker (5,7) (5,7) (4,9) (4,8) (3,7) (3,4) (1,2)
Early Trainee (1,2) (2,3) (1,2) (2,2) (2,2) (0,1) (1,2)
Day HeadNurse (2,2) (1,1) (0,0) (1,1) (0,0) (1,1) (1,1)
Day Nurse (2,2) (2,2) (1,1) (1,1) (2,2) (1,1) (1,1)
Day Caretaker (5,8) (3,6) (4,7) (4,7) (4,7) (3,4) (3,3)
Day Trainee (2,3) (1,3) (1,4) (2,2) (2,2) (0,0) (0,1)
Late HeadNurse (0,0) (1,1) (1,1) (1,1) (1,1) (0,1) (1,1)
Late Nurse (1,1) (2,2) (2,2) (2,2) (1,2) (1,1) (1,1)
Late Caretaker (6,8) (4,6) (6,8) (3,6) (5,7) (2,3) (2,3)
Late Trainee (2,3) (1,2) (1,3) (2,3) (0,3) (1,1) (0,0)
Night HeadNurse (0,1) (0,0) (1,1) (1,1) (1,1) (1,1) (1,1)
Night Nurse (1,1) (1,1) (1,2) (2,2) (2,2) (1,1) (1,1)
Night Caretaker (4,7) (5,7) (5,10) (5,8) (3,7) (3,3) (3,4)
Night Trainee (2,3) (2,2) (1,3) (2,4) (2,3) (1,2) (1,1)
SHIFT_OFF_REQUESTS = 67
CT_37 Night Mon
CT_42 Night Mon
TR_73 Any Mon
CT_31 Any Tue
CT_35 Late Tue
CT_45 Any Tue
CT_47 Early Tue
CT_50 Any Tue
CT_51 Any Tue
CT_52 Any Tue
CT_54 Any Tue
CT_57 Any Tue
HN_5 Late Tue
HN_6 Any Tue
NU_12 Late Tue
TR_61 Any Tue
CT_44 Any Wed
CT_53 Late Wed
CT_54 Early Wed
HN_3 Early Wed
NU_17 Any Wed
TR_75 Any Wed
TR_78 Late Wed
CT_26 Late Thu
CT_42 Night Thu
CT_44 Any Thu
CT_48 Any Thu
CT_50 Any Thu
CT_56 Any Thu
CT_57 Day Thu
NU_12 Day Thu
TR_65 Any Thu
TR_66 Any Thu
TR_68 Any Thu
TR_69 Day Thu
TR_72 Early Thu
TR_74 Early Thu
TR_75 Any Thu
CT_27 Any Fri
CT_30 Any Fri
CT_39 Night Fri
CT_41 Any Fri
CT_47 Any Fri
HN_4 Any Fri
HN_5 Day Fri
NU_19 Any Fri
TR_64 Day Fri
TR_64 Night Fri
TR_67 Any Fri
CT_21 Any Sat
CT_23 Any Sat
CT_30 Any Sat
CT_32 Any Sat
CT_42 Any Sat
CT_45 Any Sat
CT_48 Any Sat
HN_1 Any Sat
NU_15 Late Sat
TR_68 Any Sat
TR_76 Any Sat
CT_31 Day Sun
CT_59 Late Sun
HN_2 Late Sun
HN_7 Any Sun
HN_9 Any Sun
TR_66 Day Sun
TR_68 Any Sun
これに対して、次のようなGUIとPython記述になります。
INRC2プロジェクトのcsv解をValidator用のフォーマットに変更するプロジェクトcsv.nurse3にバグがありました。
下記が修正後のソースです。
import win32gui, win32con, os
import csv
def get_day_str(day):
if day==0:
return "Mon"
elif day==1:
return "Tue"
elif day==2:
return "Wed"
elif day==3:
return "Thu"
elif day==4:
return "Fri"
elif day==5:
return "Sat"
elif day==6:
return "Sun"
else:
raise ValueError("Unsupported Day!")
def get_shift_name(label):
if label=='D':
return "Day"
elif label=='N':
return "Night"
elif label=='L':
return "Late"
elif label=='E':
return "Early"
else :
raise ValueError("Unsupported Shift!")
def get_task_name(label):
if label=='He':
return "HeadNurse"
elif label=='Nu':
return "Nurse"
elif label=='Ca':
return "Caretaker"
elif label=='Tr':
return "Trainee"
else :
raise ValueError("Unsupported Shift!")
def make_weeks_data(lst,fname):
persons=int((len(lst)-3)/2)
items=len(lst[0])
print('items=',items)
name=""
phases=3
weeks=4
start_row=2
print('persons=',persons)
if items==107:
phases=3
weeks=4
elif items==254:
phases=4
weeks=8
elif items==142:
phases=4
weeks=4
else:
raise ValueError("Unsupported Items!")
start_day=2+phases*7
for week in range(weeks):
w_str=""
file_name = "sol-week" + str(week) + ".txt";
assigned=0
for person in range(persons):
#print(person)
#print(lst[person*2+2][0])
name=lst[person*2+start_row][0]
print(name)
for day in range(7):
shift=lst[person*2+start_row][week*7*phases+day*phases+start_day]
if shift=='O' or shift=='':
continue
for ph in range(phases):
task=lst[person*2+1+start_row][week*7*phases+day*phases+start_day+ph]
if task !='':
w_str+=name +' '+get_day_str(day)+' '+get_shift_name(shift) +' '+get_task_name(task)+'\n'
assigned +=1#DEC252024 Bug Fix
break
#assigned +=1
Wstr="SOLUTION\n";
Wstr+=str(week)+' '+ fname[0:6]+ "\n\n";
Wstr+="ASSIGNMENTS = "+ str(assigned) +"\n";
Wstr+=w_str
f1 = open(file_name, 'w')
f1.write(Wstr)
f1.close()
print(file_name,Wstr)
def post_main_sub():
# try:
filter='csv\0*.csv\0'
customfilter='Other file types\0*.*\0'
fname, customfilter, flags=win32gui.GetOpenFileNameW(
InitialDir=project_file_path, #os.environ['temp'],
Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
File='somefilename', DefExt='csv',
Title='GetOpenFileNameW',
Filter=filter,
CustomFilter=customfilter,
FilterIndex=0)
print ('open file names:', repr(fname))
print(fname)
with open(fname, encoding="utf-8") as f:
lst = list(csv.reader(f))
print("row length=",len(lst))
#basename = os.path.basename(fname)
basename_without_ext = os.path.splitext(os.path.basename(fname))[0]
make_weeks_data(lst,basename_without_ext)
def post_main():
post_main_sub()
Ans.
ナーススケジューリング問題は、精緻な制約の積み重ねで成り立っています。新しくプロジェクトを始める場合は、ステップバイステップ、一つ制約を書いて確認、一つ制約を書いて確認...をしながら構築していきましょう。大事なことなので、もう一度書きます。一つ制約を書いて確認、一つ制約を書いて確認.
次は、頂いたプロジェクトの状態です。赤のメッセージがあるので、「解がない」状態であることが分かります。
●次の組み合わせが充足していません。
● 列制約全体.長日勤は4人 2024-12-29
● 列制約全体.入りは4人 2024-12-14
● 列制約全体.入りは4人 2024-12-21
● 列制約全体.明けは4人 2024-12-15
● 列制約全体.明けは4人 2024-12-22
● 列制約全体.平日日勤者5名以上 2024-12-11
● 列制約全体.平日日勤者5名以上 2024-12-12
● 列制約全体.平日日勤者5名以上 2024-12-17
● 列制約全体.休日日勤者3名以上 2024-12-28
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.休日・夏季・正月休暇回数
● 平準化絶対的制約.入り回数
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
● 行制約同数カウントグループ2.長日勤=入り
次に行うことは、制約グループのチェックをオフにしてみます。
具体的には、列制約グループのチェックをオフにして求解してみます。