2023年12月29日金曜日

ペア制約再考

 ずっとこの問題を考えてきて、一つの方策がリニア化だったのですが、十分でないどころか、殆ど寄与できないことが明らかになり、どうしても再考せざるを得ません。(リニアペア制約が失敗という訳ではなく、前回の会議の日は日勤増みたい制約で威力を発揮しています。)
幸いにしてこの時期は、サポート関係の仕事が入ってこないので、深く思索する時間が持てます。加えて、単にペア制約というだけでなく、ペア制約の一般化を考える必要があるということがあります。ライフワークとして取り組んでいるナーススケジューリング問題ですが、実際的によく起きる問題でありながら、誰もこの問題について指摘・改善に取り組んでいません。孤峰に独り挑む気分です。

一般化ペア制約の定義

スタッフ間でリニア制約以外の関係があるときの制約とします。リニア制約とは、

ΣCoffA[i]*A[i]=[max,min]

という制約で表現できるときは、 リニア制約です。そのスタッフ内でクローズした制約、例えば、公休回数や、夜勤回数は、そのスタッフ内でクローズしているので、ペア制約にはなりません。スタッフ間で、上記制約で表現できない関係があるときに一般化ペア制約と定義します。

これによれば、ペア禁止は、一般化ペア制約ではありません。ペア禁止は、リニア制約で表現できるので、一般化ペア制約ではありません。また列制約の全ては、上記リニア制約で表現出来ます。

プリセプタプリセプティの関係は、リニアです。会議の制約で、シフトを専用に割り振れば、リニアになります。CCと新人の関係もそうです。

専用シフトを設けない会議、CCと新人、助産師と看護師がいて看護師のみペアの夜勤連続不可、といった制約も、一般化ペア制約の範疇ということになります。これらは、AL3/4では、苦手もしくは扱いきれない問題、ということが出来ます。

逆に言えば、専用シフト・タスクを設ければ、大半の問題をリニアに出来るということではないかと思います。





2023年12月28日木曜日

会議の日は、日勤者数を増やす ダイナミック版

というご要望があったので、とりあえずダイナミック版を作成してみました。

ポイントは二つあります。

会議は、ダイナミックにアサインしますが、その際に、日勤者を増員するというものです。

(1)インタラクティブに増員数を決める

増員する度合いが分からないので、そこは、インタラクティブに聞くダイアログを作成しました。pywin32でそのものズバリのダイアログがあったのでそれを使います。列制約で、日勤者数という制約があり、最小2以上を制約しています。それをソース全体から拾ってきて、増員数をインタラクティブに決めています。



(2)看護師長が会議ならば、日勤者数を増やす

これは、SoftLinerCompで実装できます。看護師長が会議という状態をブール変数vとして

Σv*CoffA <= ΣListB[i]*CoffB

とすれば、自由に増員できます。ここで、CoffAは、会議の日における増員後の日勤者数です。

看護師長に会議がアサインされないときは、0<=Σ

となり常に成立しますから、悪さはしません。

実装してみたら、そもそも会議で、日勤者が増えているので、制約することの程でもないような...というオチでした。



import sc3
import pywin.dialogs.list




def 会議の日は日勤者数を増やす(会議シフト名):
    min_day_workers=日勤数[8]#min
    print(min_day_workers)
    title=会議シフト名+'日は日勤者を何人にしますか?'
    s0='通常日勤者数'+str(min_day_workers)+'人に同じ'
    s1='増員1人 '+str(min_day_workers+1)+'人以上'
    s2='増員2人 '+str(min_day_workers+2)+'人以上'
    s3='増員3人 '+str(min_day_workers+3)+'人以上'
    s4='増員4人 '+str(min_day_workers+4)+'人以上'
    s5='増員5人 '+str(min_day_workers+5)+'人以上'
    s6='増員6人 '+str(min_day_workers+6)+'人以上'
    result=pywin.dialogs.list.SelectFromList(title, [s0, s1,s2,s3,s4,s5,s6])
    print(result)
    if result==None or result==0:#同じなら制約しなくてよい
        return
 
    for day in 今月:
        v=sc3.GetShiftVar(0,day,会議シフト名)#看護師長
        listA=[]
        listA.append(v)
        s=会議シフト名+'SLC '+daydef[day]
        mode=-1#mode=1 >=  mode=0 ==  mode=-1 <=
        CoffA=result+min_day_workers
        CoffB=1
        offset=0
        allowable_errors=3
        listB=[]
        for person in 日勤要員:
            v=sc3.GetShiftVar(person,day,'日勤')
            listB.append(v)
        print(daydef[day],CoffA,len(日勤要員))
        sc3.AddSoft(sc3.SoftLinearComp(mode,CoffA,CoffB,offset,allowable_errors,listA,listB),s,5)#level 5
    

会議の日は日勤者数を増やす('リーダ会議')
会議の日は日勤者数を増やす('副看護師長会議')

    

2023年12月27日水曜日

手動Updateの仕方

本ブログ等で、リリースしたとの情報があるにも拘わらず、アップデートされないときは、

以下の手順で更新します。 この手順がもっとも安定しているようです。

(1)ストアにマイクロソフトアカウントを開く







 (2) ストアにサインインする

(3)更新をクリックする


注意:

ストアをサインアウトすると使えません。使用時は、購入時のマイクロソフトアカウントでサインインしてください。

2023年12月25日月曜日

DEC252023BUILD内容

 買い切り版(DEC202023BUILD)内容に同じです。

現在審査中なのでリリースは年末だと思います。

   1)StaffPropertySheet frozen

スケジュールナースのブログ: 細かな改善 (schedule-nurse.blogspot.com)

2)add_fm_solution実装

スケジュールナースのブログ: 選択部を予定に送る (schedule-nurse.blogspot.com)

スケジュールナースのブログ: 「予定に送る」と「選択部を予定に送る」の違い (schedule-nurse.blogspot.com)

3)Python レベル7エラーの色が黄色ー>赤に修正

4)Excelからのインポートでロックが残ってしまう問題の修正

5)入力へ送るで、ロックが解除されるように修正

6)フィルタフォント修正

スケジュールナースのブログ: 細かな改善 (schedule-nurse.blogspot.com)

     7)予定シフト・タスクのみExcelに出力

スケジュールナースのブログ: 予定シフト・タスクのみをExcelに出力 (schedule-nurse.blogspot.com)

2023年12月24日日曜日

スタッフに忖度した勤務表作成の仕方

手動だと、どうしても、こういう作り方になると思います。

人生初の勤務表作成 勤務表作成に、これもありか、という考え方 (nurse-scheduling-software.com)

自動にしてから、それは無くなったとおっしゃっていましたので、自動の常識とあてはまらない世界にいたのだな、と思います。公平・公正・公明が当たり前で、そうあるべきと思っていたのですが、現場の管理者の実際は、もっとドロドロとした世界なのかな?と思います。少し反省し寄り添ってみました。


大学病院での講義ノートとセットでご覧ください

 スケジュールナース講義ノート

2023年12月23日土曜日

細かな改善

1)フィルタの文字が小さすぎる⇒小さくならないようにしました


2)コメント列までFrozen
コメント行が常に見えるようにしました

 いずれも年末のリリースから適用です

2023年12月22日金曜日

「予定に送る」と「選択部を予定に送る」の違い

 予定に送る時は、ロックを全て外します(DEC2023以降のビルド)

これは、次月への移行時のみ使う機能です。予定にロックが残っていると、スタッフ毎の予定でConlfictした予定をSoft化して回避している機構が働かないため、そのように変更しました。

一方、「選択部を予定に送る」は、未だ予定のEdit中を想定しています。そのためUndo/Redoスタックも動作しますし、ロックされたところには書き込めないのは、通常のコピペ動作と同じです。



2023年12月21日木曜日

5連勤の後2連休に制約追加

 制約終了日付近では、5連勤務になり易いです。結果、来月の最初、2連休の人が続出することがあります。そこで、制約終了日では、5連勤務を禁止を追加しました。





2023年12月20日水曜日

予定シフト・タスクのみをExcelに出力

予定関係だけをExcelにExportする機能を実装しました。
 Excelには、予定シフト・予定タスク・基数制約のみがExportされます。

ソフト制約も色でExportされるので、コピペで入力すれば、ソフト制約で入力することも出来ます。
スタッフの希望をExcelで取りまとめる部署もあると思うので、転記の手間が省けると思います。
これも12月Endでのリリース機能になります。

2023年12月19日火曜日

選択部を予定に送る

解のViewで挙動に違いがあります。 

タスク解:

選択されたタスク解が予定タスクに送られます。対応するシフト日のシフト解が予定シフトに送られます。

シフト解:

選択されたシフト外が予定シフトに送られます。対応する全てのタスク解が予定タスクにも送られます。

Hybrid解:

選択されたタスク解と選択されたシフト解のみが、シフト予定とタスク予定に送られます。

送られた予定Viewでは、取り消し・やり直し が出来ます。



適用は、12月Endです。


2023年12月18日月曜日

キャッチを変更

 スケジュールナース (nurse-scheduling-software.com)

を変更しました。人力からの移行は、勤務表作成サービスをご利用頂ければ、難しくはありません。しかし、一気に移行するには、不安もあるかもしれないので、人力でのやり方に近い勤務表作成の仕方を紹介したいと思います。

そのためのデモプロジェクトを用意しました。このデモから、「選択部を予定に送る」を新たに実装しました。




2023年12月17日日曜日

ソフトの手動更新

 自動更新されるので、通常必要ありません。ただし、アップデート時のサーバ間の配信の差によって、最新のプロジェクトファイルが読み取れないことも可能性としてはあります。


その場合は、ストアにサインインすると、更新が表示されますので、更新をクリックすれば最新となります。





スケジュールナースは、サブスクリプション、買い切り版、旧版からの更新のお客さま用

の3種類があります。

買い切り版は、マイクロソフトの審査が、自動で行われるようです。これは、買い切り版をストア上では、価格0にしている為のようです。(買い切り版はストアでは公開していません。)
こちらでリリース後、数時間で上記状態となります。その他の版は、土日祝(米国)休みの人力で審査が行われるようです。そのため、リリースそのものが、買い切り版より遅れるのが常です。当然、複数の審査者がいるので、ほぼ毎回、担当者が変わるためそのときの判断が毎回異なるという弊害があります。旧版からの更新のお客さま用は、リリース後、2週間程、英語でやり取りしても審査が通らなかったこともあります。毎回、一から議論を始めなくてはならず、とても疲れました。そのため、出来れば、旧版からの更新のお客さまは、買い切り版に移行したいと思っております。移行してもよい、と思われる方は、ご連絡頂ければ、ライセンスを発行しますので、ご検討ください。

2023年12月16日土曜日

シフト集合の改善

 次のパターンでは解がありません。

入集は、入りまたは単発入りですが、単発入りは、自動シフトでないために無視されます。

入りは、その前に長日をパターン上要求するために解なしとなります。

そこで、演算子を増やしました。または(非自動シフトを含)を追加しています。

ソフト制約でも同様に動作します。


リリースは、今週末位かと思います。




2023年12月15日金曜日

ユーザ論文

整理していたら、昔のユーザさまの論文が出てきました。

病院学会での発表内容らしいです。スケジュールナースのユーザさまは、病院の事務方も沢山、おられるので、こうしたテーマで発表していただけると、昨今の働き方改革に寄与すると思います。(他のソフトと比較検証していただくと、スケジュールナースの素晴らしさがより広まると思います。)

病棟勤務シフト表の作成自動化における効果と課題

ちなみに欧米では、看護師長が作るというよりは、事務方が機械で作るのが一般的だと思います。予定も、日本のように2週間~1週間前に決まると言う感じではなく、かなり前から決まっているのが普通だと思います。機械(ソフト)がつくるので、ある意味日本のように融通が効かない、ということはあります。そうしたシステムが成り立つのは、大病院化と派遣システムが充実しているからだと思います。



2023年12月13日水曜日

ストアにログイン

 ストアにログインできないと、サブスクも買い切り版も使えません。従い、マイクロソフトアカウントの確認として、ストアにログインできることを確認してください。



2023年12月10日日曜日

公休4連休を抑制したい

 Q.希望以外の連休が4連休、5連休2回ついています。ここはのちに手作業で日勤にすると他を休みに調整できるでしょうか?

Ans.

公休4回連続は禁止制約を追加しました。希望4連休が2回あるのは、ハード入力のため、そのままですが、それ以外の公休4連続以上は、禁止となります。
解の手直しが必要なときは、解を直接に直すのではなく、予定で制約、再求解するのが基本となります。
人手で行うと、どうしても制約無視が出てくる恐れがあるためです。 希望予定をロックし、さらに上記のような手入力をロックで確定していくことをお勧めしています。


2023年12月9日土曜日

主任の夜勤は出来る限り分散したい

 Q.     6日、20日の2回、主任さんが長日勤・夜勤に2名重なっています。苦肉の策でそうする場合はありますが、年に1回程度です(昨年度はゼロ、今年度は1回、人力解では。)。減らすことはできるでしょうか?


解説:主任というのは、副看護師長のことです。この病棟の場合3人いらっしゃいます。看護師長から見ると、「副看護師長は、あらゆる時間帯にいて欲しい。」ということらしいです。全体を見て廻してくれる、貴重な存在であるので、そのリソースは、できるかぎり広く使いたい、ということが背景としてあります。あるレベルのスタッフが何人以上 という制約は既に記述済みですが、それプラスの制約が必要ということです。

実装:列制約を追加しました。





2023年12月8日金曜日

Python制約プロセスとポストプロセスとの情報交換

 Pythonでの制約プロセスと、ポスト処理は、別プロセスです。制約プロセスで、A=1と書き込んでも、ポスト処理では、それを見事に忘れてしまいます。なので、情報交換する手段がありません。

これを回避する手段としては、制約プロセスとポスト処理プロセスで、同じ設定ルーチンを呼べば、同じ値で動作させることができます。

しかし、制約プロセスで、ユーザにインタラクティブに挙動を決定させた場合に、その結果をポスト処理で知ることは出来ません。そうした場合の処理方法についてです。

制約プロセスで取得した情報は、CSVで書きこみ、ポスト処理ではそのCSVを読む方法と取っています。



def set_advisor_method():
    global advisor_count_method
    advisor_count_method=1 #0→0 1→1 2→1 3→2 4→2
    #advisor_count_method=1 #0→0 1→0 2→1 3→1 4→2
    
    MessageBox = ctypes.windll.user32.MessageBoxW
    res=MessageBox(HWND, 'アドバイザカウント方法 3人(1人)で2人(1人)でカウント(推奨)する', 'アドバイザカウント方法', 3)
    if res==6:
        advisor_count_method=0
    write_csv('csv.csv')

def write_csv(file_name1):
    file_name =project_file_path+'/'+file_name1
    with open(file_name, 'w') as f:
        writer = csv.writer(f)
        list=[]
        list.append(advisor_count_method)
        writer.writerow(list)

def read_csv(file_name1):
    file_name =project_file_path+'/'+file_name1
    global advisor_count_method
    with open(file_name,'r') as f:
        reader = csv.reader(f)
        cnt=0
        for row in reader:
            print(row)
            if cnt==0:
                advisor_count_method=row[0]
            cnt +=1
        print('advisor_cnt_method',advisor_count_method)

def post_main():
    global advisor_count_method
    read_csv('csv.csv')
    check_comittee()



allowable_errors=3
global advisor_count_method
set_advisor_method()

2023年12月5日火曜日

師長不在の平日は、副師長1名は日勤にする

 看護師長または副看護師長が少なくとも1名とすればよいです。


AならばB
----------------------
A B   C
0 0 1 
0 1 1
1   0   0
1   1   1

題意からは、AならばBです。これは、Implication ~A|B となります。 A=看護師長不在なので、 a |B (a=~A ) aは在籍、となります。
「または」は、OR オペレータですが、数理的には、「少なくとも1個」 に等しいです。よって少なくとも1人を実装すればよい、ということになります。

aまたはB
----------------------
看護師長 副看護師長
x     1
1      x


2023年12月3日日曜日

組織の要件を満足しない要因

プロジェクトファイルを設計していると、組織の要件を満足しないケースが出てきます。伺っていた仕様に問題ガある場合もあるし休み希望が多すぎる問題もあります。経験した事項をまとめてみました。

 

1)物理的限界を超えている

入学式や、年末年始等、大量に発生する休み希望が、物理限界を超えると配置できません。これは、普段の日曜日でもあり得る話です。で、物理限界がどこにあるかは、ある程度計算で求めることはできます。具体的には、予定書き込み痔に、何人以上休みは入れられない、超えたらじゃんけん、というのが最も効率的かつ公平です。この辺の割り切りは、管理者として必要だと思います。


人生初の勤務表作成 算数ができない?師長 (nurse-scheduling-software.com)

変則2交代の場合

長日 10

入り 10

明け 10

明け休み 10

明けの後2連休 (10)

必要日勤数  10

日勤要員数   68

明けの後の2連休まで考えると、純粋な休みとして取得可能なのは、68-60=8人、

明けの後の2連休を考えないと18人 となります。明け休みが休みと被る場合も想定されますが、それは、マージンと考えればよく、目安になると思います。


2)若手の割合

「若手何人以上を同時に配置しない」 という制約は、よくある制約ですが、問題は若手の割合です。例えば、夜勤3人のうち、若手は、1人までという制約があるとすると、若手割合は、1/3以下である必要があります。夜勤要員24人として、若手の定義が8人を超えていたとすると、若手以外のベテランの夜勤回数が必然的に多くなります。こうした状況は、求解時間の増加を招くし、何よりも組織の要件を満足できなくなる可能性が高くなるので好ましくありません。配置制限割合以下に若手の定義を見直す必要があります。以上の議論は、夜勤6人、10人の職場でも同様です。

3)不規則シーケンス

変則2交代は、長入明が一定のパターンとなりますが、不規則シーケンスがあると決してフラットに出来ません。

長遅入明パターンが入ると人数をフラットに出来ない

一般化した変則2交代 (nurse-scheduling-software.com)

https://schedule-nurse.blogspot.com/2023/10/2.html

2)3)は制約設計時の問題で、制約が適切であれば、問題は生じません。1)は、毎月起こりえる問題なので、アラートシステムを備えておくとよいでしょう。次は、限界近くまで休み希望があった場合に警告を発します。


def 休み数警告(threshold):
    for day in 今月:
        off_cnt=0
        for person in 全スタッフ:
            if person in 看護師長:
                continue
            v=shift_schedules[person][day][0]
            if is_off(v):
                off_cnt +=1
        if off_cnt>=threshold:
            print('警告: ',daydef[day],'休み数が',off_cnt,'になっています')

4)過渡なスタッフ間の公平化(フラット化)

スタッフ間の公平、例えば夜勤数は、最大・最小に少し余裕がないと、求解に時間がかかったり、最悪、組織の要件を満足できなかったりします。

5)遊びがあること
組織要件に、遊びがあることが必要です。一般に、休日日勤者の数は、固定でよいのですが、日勤者の数は、最小のみ、最大があったとしても、余裕があるようにします。

2023年12月2日土曜日

翌月の予定を取り込んだ制約

Q. 現在、添付の様なデータになっているのですが、

作成する際に翌月数日間の予定入力を考慮して作成することは可能でしょうか?

但し、勤務日数は今月内だけとして数えます。


例えば、作成したデータでは今月末で4連勤となっており、

5連勤は禁止しているが、翌月の1日は他の方の希望休が多いことが分かっており、

どうしても5連勤になってしまうような場合、初めから月末を4連勤にならないようにしたい。


また、夜間の拘束が連続しないようにしたいが、

翌月1日はAさん以外の3名が拘束できないことが分かっている場合は、

当月末日の拘束はAさんにつかないようにしたい場合などです。


何か解決する方法はありますでしょうか?

Ans.

確かに、月末は、連続勤務になりやすいと思うので、

添付のように、月末4連禁不可を定常的に組み込むのもアリだと思います。

>作成する際に翌月数日間の予定入力を考慮して作成することは可能でしょうか?
難しいです。理屈的には、翌月数日を含んだプロジェクトを作成するこも可能ですが、今度は、またその範囲を超えたところの対応が必要になるので、変更する労力に見合った効果は得にくいと思います。

現実的な対応としては、予め月末予定に制限を加える、もしくは、翌月の予定書き込み時に物理制限を設け、じゃんけんで決める、等になろうかと思います。(物理制約を越えて配置することは所詮無理なので。)

2023年12月1日金曜日

Python Soft LinearComp

 Python SoftLinearComp (nurse-scheduling-software.com)

SoftLinearCompは、GUIペア制約のリニアペア制約の内部実装関数です。比較関数は他にもありますが、これ一つで全てを包含します。

2023年11月30日木曜日

Zoom Meetingについて

ご希望のあるお客さまには、Zoomで操作方法等をお教えしています。(プロジェクト作成サービスのお客さまは無料です。)お客さまのビデオをオフとすることも可能です。

Q.その日までこちらで整えておく設備は何かありますでしょうか?

サブスクはそれまでに入っておきます。zoomは使用したことがありません。

Ans.



■事前準備について、

当日時刻になりましたら、上のURLをクリックすればよいのですが、参考までに、ZOOM Meetingの参考になるサイトをご案内します。ZOOMは、無料版でOKです。


https://yogashare.info/blog/zoom-macbook-2/


サイトで言っているとおり、事前にインストールして、カメラとマイクのテストを行っておくとよいでしょう。


■設備について

マイクは、必須です。カメラは、必須ではないと思いますが、なしで行ったことがないので、WEBカメラを購入されることをお勧めします。

ZOOMミーティング用途だけでしたら、高いのは必要ありません。


https://kakakumag.com/camera/?id=16484


また、NotePCでしたら、購入しなくとも備わっていると思います。



■サブスクのインストール


ダウンロードに時間がかかる場合がございます。当日までに、ZOOMミーミーティング用のPCにインストールをお願いします。

稼働PCとは違っても構わないのですが、説明する画面を共有する関係で同じPCで説明した方が都合がよいです。(同じマイクロソフトアカウントで10台まで使用できますが各々インストールが必要となります。)

以上です。


2023年11月29日水曜日

Pythonの必要性

Q.スケジュールナースはノーコードで論理式を組んで、演算させるソフトなので

それなりに複雑な条件式を仕様書から落とし込まないと実用的なシフト自動作成にはならず、

ノーコードで対応できない部分はPythonのプログラム記述で対応となっていると思います。

なので、買取や月額だけで動くソフトではなく論理式を組む必要があるのですが、その実績もありますか?

A.

恐れ入りますが同意致しかねます。

スケジュールナースは、「集合」を用いたハード制約・ソフト制約という制約で記述するスタイルが、他のソフトと明確に異なります。

雛形はありません。汎用的であり、微細な制約も記述可能な反面、プログラミングスキルに似た一定のバリアが存在し、それさえも面倒で難しいと感じる方が少なくありません。

また、過去にPythonでしか記述出来なかったコードもバージョンアップによりGUI化での記述を促進しており、看護師・介護士勤務表に関しては、GUIのみプロジェクトが大半となっております。


参考:以下のお客さまもPythonなしですが、前述の理由から、菅原システムズのプロジェクト作成サービスを利用されています。


https://www.nurse-scheduling-software.com/japanese/nurse_scheduling_problem/chapter30/

Pythonは、組み込み版(3.10)を採用しています。他の環境は使用しません(出来ません)。


以下は、制約の記述例です。ご利用されている実際のお客さまのプロジェクトの断片を切り取ったものが殆どですが、どのようなときにPythonを使わざるを得ないか?の参考にはなるかと思います。



実績という意味において、看護師・介護士勤務表については、前述の通りです。
その他のプロジェクト作成サービスでPythonを使う頻度は、2-3割程度と思います。
独自言語からPythonに移行して数年経ちますが過去のPythonコードは全て継承するというポリシーは貫いておりますので、ご安心ください。

2023年11月26日日曜日

Nov252023 Release

 1)予定縮小時の不具合改善

https://schedule-nurse.blogspot.com/2023/11/blog-post_15.html

2)UnaryCounterの実装

https://schedule-nurse.blogspot.com/2023/11/blog-post_21.html

https://schedule-nurse.blogspot.com/2023/11/blog-post_17.html

3)Python許容エラーオーバライド

https://schedule-nurse.blogspot.com/2023/11/python.html

UnaryCounter

 「半人前」を実現するために導入した制約関数であり、通常の制約関数とは異なります。

この関数は、2種類のリストの一部としか機能しません。2種類のリストとは、


■sc3.SeqError(min,max,allowable_errors,list)

■sc3.SoftLinearComp(eq_mode, CoffA, CoffB,  offset,  allowable_errors,listA,listB); 


です。この2種類しかサポートしません。

パラメータは、二つしかなく、

■sc3.UnaryCounter(bitstart,bit_interval)

です。

UnaryCounterとは、1進加算器のことであり、ビットの桁数は、入力の個数だけあります。

つまり桁上がりがないカウンタになります。


ビットスタート0、ビットインターバル1だと、そのままの出力になります。

 ビットインターバル2だと、一つ飛びに出力されます。/2されるイメージです。

ビットスタートは、mod演算に対応します。下図は、bit interval=2のときの様子ですが、

同じbit interval=2でも、bitstartによって、エンコードの様子が異なります。


余りがないときは、どちらも同じですが、一人のときを1人と数えるか0人と数えるかの違いがあります。どちらのエンコードを指定するかは、bit_startを指定すれば決まります。

この論理構造は、次で実現できます。

これは、アルゴリズム3/4でのグラフ構造になります。アルゴリズム1は、同じ1進加算を使いますが、また別の構造により実現します。

アルゴリズム2と3/4の数理表現では、次のような記述になっています。
上のような回路構造の記述と異なり、数理的な表現になります。

ip.add_constraint(num_working <= (bit_interval) * x+bit_start, x);
ip.add_constraint(num_working >= (bit_interval) * x-(bit_interval-1-bit_start), x);

つまり、同じUnaryCouter機能を実現するのに、アルゴリズム毎に記述を変える必要があります。どれも、同じ機能には違いないのですが、テクノロジーが違うと全く違う表現になる様子を紹介しました。
組み合わせ最適化は、一つのテクノロジだけでは、網羅できません。広範囲のテクノロジーを組み合わせて、スケジュールナース最適化は成っているのです。




2023年11月25日土曜日

python許容エラーオーバライド

 Nov.End.2023リリースの新機能です。

次のPython制約関数において、allowable errorsは、言語で固定されていて変更することは出来ませんでした。

■sc3.SeqError(min,max,allowable_errors,list)

■sc3.SoftSeqComp(offset,allowable_errors,listA,listB)

■sc3.SoftLinearComp(eq_mode, CoffA, CoffB,  offset,  allowable_errors,listA,listB); 

しかし、Python許容エラーオーバライドをオンすると、求解パラメータの許容エラーの値が

オーバライドされます。これにより、Pythonソースをいじらなくても、許容エラーを可変することのが可能になります。


例えば、次の例では、解がないエラーが生じています。
このとき、許容エラーは、言語により3となっています。

しかし、Python許容エラーオーバライドをオンすると、求解パラメータの方が優先され、許容値を5することができます。(0としてハード制約にすることも出来ます。)
その結果として、解が存在できるようになりました。




2023年11月24日金曜日

旧版のストア版への移行について

 Q.2020年にスケジュールナースを購入し、利用させていただいております。

当時、買い切り版で購入しました。

今回、他のPCにソフトのインストールを試みたのですが、サブスク版に導かれます。

ホームページ上では「紐づいたマイクロソフトアカウント上でPC10台まで同時使用可能です。」となっておりますが、インストール方法がわかりませんでした。


サブスク版ではないインストール方法を、教えていただきたいです。

A.

ストア版に移行の際、不通か何かでご案内できませんでした。恐れ入ります。下記の買い切り版対応とさせて頂きます。

https://www.nurse-scheduling-software.com/japanese/service2/onetime_purchase/

勿論、無料にて発行しますが、唯一、手続きとして、マイクロソフトアカウント名を、スケジュールナースストア版と紐づける必要がございます。

アカウント名をお送り頂くと、マイクロソフトのサーバに登録します。登録には、1週間程度見ていただきます。登録完了後は、永続的に使えるようになります。

2023年11月21日火曜日

数を数えるということ

 各テクノロジーのバックグランドが異なるので、実は、数え方は一つではありません。

正確には、アルゴリズム1,2,3毎に違う数え方をしています。数を数えるということは、組み合わせ最適化において、本質的なことではありますが、数理的な数え方と、論理的な数え方の違いということがあります。本質的には、数理的な数え方と論理的な数え方は、同じはずですが、算法的には、違います。汎用問題を考えたとき、有利なのは、数理的解法になります。一方、数が少ないときの組み合わせ最適化を考えたときは、論理的解法の方が有利なような気がします。従い、数が少ない場合の組み合わせ最適化問題、ナーススケジューリング問題では、論理的解法であるアルゴリズム1が一般的には優勢になるのだ、という理解をしています。しかし、問題規模が大きくなってくると、論理的に扱うには、複雑になりすぎ、その場合は、数理解法が有利になってくる、ということではないでしょうか?

それでは、一体、数理解法と論理解法では何が違うか?ということについて考えてみましょう。一番の違いは、論理解法の場合は、何進法を使うか?ということが効いてきます。ところが、数理解法の場合は、それが明示されずに意識されることはほぼありません。論理解法の場合、コンピュータ上のハードウェア資源である乗算器を使うことはほぼないのですが、数理解法の場合は、無しでは考えられません。つまり、ハードウェア資源である乗算器の使用の有無が、大いに関係しています。

乗算器をブール代数でグラフ化したものを見たことがあるでしょうか?16x16bitでさえ、トンでもない規模のグラフとなります。乗算器というのは、組わせ回路の塊であり、AND/OR/INVの回路からのみ成りますが、大きな数を表すといることは、それだけ多くの組み合わせがある、ということの裏返しということでしょう。そういう場合には、直接にPC資源を利用した方がよい、ということではないかと思います。(昨今の人口知能における機械学習において、この乗算器の存在は必須です。)

論理的解法と数理解法について言及しましたが、もう少し正確に言うと、論理解法は、アルゴリズム1、数理解法は、アルゴリズム2、両者のハイブリッド解法が、アルゴリズム3/4ということになります。最初に説明した通り、各々、数の数え方が違うので、「半人前」の実装において違いを見ていきたいと思います。

https://schedule-nurse.blogspot.com/2023/11/unarycounter.html



2023年11月19日日曜日

委員会のチェック

 9つある委員会は、全て日勤です。解から、開催日を人手が割り出すのは手間です。また、ソフトエラーがあった場合、必ずしも、目的の人数が確保できている訳ではありませんので、最大確保できた日を報告することとします。また、確保できなかった場合、長日勤を含めてカウントするとどうなるかも報告しています。

このプロジェクトは、多人数かつタイトなプロジェクトで時間がかなりかかっています。


import sc3
import itertools
import ctypes

def 委員会制約():
    MessageBox = ctypes.windll.user32.MessageBoxW
    res=MessageBox(HWND, '委員会に長日を含めますか?(推奨)', '長日を含める選択', 3)
    include_long=False
    if res==6:
        include_long=True
    use_hard_constraint=False
    res=MessageBox(HWND, '委員会制約をハード制約にしますか?(推奨)', '委員会制約をハード制約にする選択', 3)
    if res==6:
        use_hard_constraint=True
    global_vars = globals()
    print("グローバル変数一覧:")
    for var_name, var_value in global_vars.items():
        if '委員会' in var_name and isinstance(var_value,list):#委員会という名前を持つリストオブジェクトのみリストアップ
            assign_comittee(var_name,var_value[0],include_long,use_hard_constraint)# ":", var_value)

def assign_comittee(name,vars_list,include_long,use_hard_constraint):
    print(name,vars_list,include_long)
    day_end=100
    if name=='現任教育委員会' or name=='新任教育委員会':#10日までに開催委員会
        day_end=制約開始日+10
    day_list=[]
    for day in 今月稼働日:
        and_list=[]
        for person in vars_list:
            v=sc3.GetShiftVar(person,day,'日勤')
            if include_long:
                v2=sc3.GetShiftVar(person,day,'ロング日勤')
                and_list.append(v2|v)
            else:
                and_list.append(v)
        vx=sc3.And(and_list)
        day_list.append(vx)
        if day>day_end:
            break
    if use_hard_constraint:
        sc3.AddHard(sc3.Or(day_list),name)
    else :
        sc3.AddSoft(sc3.Or(day_list),name,5)
    
def check_comittee_sub(name,vars_list,include_long=False):
    #print(name,vars_list)
    day_end=100
    if name=='現任教育委員会' or name=='新任教育委員会':#10日までに開催委員会
        day_end=制約開始日+10
    day_list=[]
    big_cnt_day=0
    big_cnt=0
    for day in 今月稼働日:
        and_cnt=0
        for person in vars_list:
            if include_long:
                v=shift_solution[person][day]=='日勤' or shift_solution[person][day]=='ロング日勤' or shift_solution[person][day]=='ロング日勤単発'
            else:
                v=shift_solution[person][day]=='日勤' 
            if v:
                and_cnt+=1
        if and_cnt>big_cnt:
            big_cnt=and_cnt
            big_cnt_day=day
        if big_cnt==len(vars_list):
            day_list.append(day)
        if day>day_end:
            break
    success=True
    if len(day_list)>=1:
        if include_long:
            print("長日を含めると")
        print("successful ",name)
        for day in day_list:
            print(name,"委員会日は、",daydef[day],"参加者全員は",len(vars_list),"人です")
        print("")
    else:
        if include_long:
            print("長日を含めても")
        print("unsuccessful ",name,len(vars_list),"人に対して",big_cnt,"人しかアサインされていません。",daydef[day])
        success=False
        if include_long:
            print("")
    
    return success
def check_comittee():
    
    global_vars = globals()
    print("グローバル変数一覧:")
    for var_name, var_value in global_vars.items():
        if '委員会' in var_name and isinstance(var_value,list):#list list
            success=check_comittee_sub(var_name,var_value[0])# ":", var_value)
            if not success:
                check_comittee_sub(var_name,var_value[0],True)


    

def post_main():
    check_comittee()
    

委員会制約()

ポスト処理後は、以下の表示となりました。
コンパイルの準備中
ソルバを呼び出し中です。
	制約をコンパイル中です。
	Python プロパティファイルの生成が終わりました。
グローバル変数一覧:
現任教育委員会 [5, 22, 28, 33, 46, 51, 56] False
新任教育委員会 [2, 29, 32, 54, 58, 62] False
リスク委員会 [3, 25, 31, 57, 64] False
感染委員会 [4, 24, 37, 55, 59, 66] False
業務委員会 [2, 21, 39, 52, 62, 65] False
倫理委員会 [3, 34, 41, 42, 49, 61] False
ケア委員会 [3, 23, 43, 48, 50, 53] False
教育企画委員会 [5, 6, 19, 30, 35, 45] False
記録委員会 [4, 26, 27, 38, 47, 60] False
Aチームリーダ会議 [6, 8, 9, 10] [12, 13, 14, 15, 16, 17, 18] 2
Bチームリーダ会議 [7, 11, 12, 13] [12, 13, 14, 15, 16, 17, 18] 2
今月休日8人以上 8 [5, 11, 12, 13, 18, 19, 25, 26, 32, 33] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
今月平日副看護師長会議日以外9人以上 9 [6, 7, 8, 9, 10, 14, 15, 16, 17, 20, 21, 22, 23, 27, 28, 29, 30, 31, 34, 35] [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
今月副看護師長会議日9人以上 9 [24] [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]
	Algorithm 1 Solving Process Started..
			o 2887   16.728000(sec) 
			o 2738   16.861000(sec) 
			o 2677   17.144000(sec) 
			o 2593   17.609000(sec) 
			o 2534   17.730000(sec) 
			o 2509   17.818000(sec) 
			o 2440   17.914000(sec) 
			o 2418   18.003000(sec) 
			o 2363   18.090000(sec) 
			o 2318   18.174000(sec) 
			o 2282   18.281000(sec) 
			o 2265   18.373000(sec) 
			o 2219   18.473000(sec) 
			o 2150   18.576000(sec) 
			o 2022   18.726000(sec) 
			o 2003   18.808000(sec) 
			o 1948   18.896000(sec) 
			o 1890   18.983000(sec) 
			o 1883   19.061000(sec) 
			o 1843   19.139000(sec) 
			o 1789   19.299000(sec) 
			o 1733   19.433000(sec) 
			o 1670   19.525000(sec) 
			o 1642   19.630000(sec) 
			o 1587   19.798000(sec) 
			o 1573   19.878000(sec) 
			o 1497   20.035000(sec) 
			o 1432   20.116000(sec) 
			o 1340   20.400000(sec) 
			o 1332   20.482000(sec) 
			o 1315   20.592000(sec) 
			o 1278   20.767000(sec) 
			o 1194   20.913000(sec) 
			o 1172   20.993000(sec) 
			o 1112   21.085000(sec) 
			o 1104   21.164000(sec) 
			o 1094   21.243000(sec) 
			o 1073   21.326000(sec) 
			o 1024   21.616000(sec) 
			o 1006   21.699000(sec) 
			o 999   21.780000(sec) 
			o 972   21.869000(sec) 
			o 939   21.958000(sec) 
			o 927   22.037000(sec) 
			o 911   22.118000(sec) 
			o 897   22.208000(sec) 
			o 864   22.312000(sec) 
			o 857   22.393000(sec) 
			o 832   22.479000(sec) 
			o 825   22.575000(sec) 
			o 807   22.656000(sec) 
			o 784   22.761000(sec) 
			o 770   22.868000(sec) 
			o 764   22.948000(sec) 
			o 749   23.195000(sec) 
			o 708   23.274000(sec) 
			o 692   23.360000(sec) 
			o 684   23.445000(sec) 
			o 669   23.537000(sec) 
			o 646   23.637000(sec) 
			o 632   23.819000(sec) 
			o 611   23.956000(sec) 
			o 586   24.037000(sec) 
			o 571   24.119000(sec) 
			o 548   24.383000(sec) 
			o 521   24.496000(sec) 
			o 504   24.592000(sec) 
			o 497   24.870000(sec) 
			o 490   24.955000(sec) 
			o 468   25.050000(sec) 
			o 442   25.287000(sec) 
			o 438   25.372000(sec) 
			o 416   25.457000(sec) 
			o 407   25.539000(sec) 
			o 392   25.808000(sec) 
			o 376   25.903000(sec) 
			o 368   25.984000(sec) 
			o 353   26.120000(sec) 
			o 350   40.217000(sec) 
			o 338   40.329000(sec) 
			o 333   40.490000(sec) 
			o 329   40.598000(sec) 
			o 323   40.742000(sec) 
			o 308   40.834000(sec) 
			o 295   41.180000(sec) 
			o 291   41.284000(sec) 
			o 287   41.526000(sec) 
			o 280   41.625000(sec) 
			o 272   41.704000(sec) 
			o 267   55.882000(sec) 
			o 262   56.089000(sec) 
			o 257   56.176000(sec) 
			o 252   56.261000(sec) 
			o 247   56.582000(sec) 
			o 239   56.681000(sec) 
			o 231   56.787000(sec) 
			o 226   56.873000(sec) 
			o 221   56.964000(sec) 
			o 213   81.083000(sec) 
			o 212   105.596000(sec) 
			o 210   105.677000(sec) 
			o 206   105.769000(sec) 
			o 202   105.848000(sec) 
			o 198   106.304000(sec) 
			o 196   106.438000(sec) 
			o 194   106.518000(sec) 
			o 191   106.757000(sec) 
			o 190   106.837000(sec) 
			o 188   106.933000(sec) 
			o 186   107.012000(sec) 
			o 184   107.386000(sec) 
			o 183   107.742000(sec) 
			o 181   108.191000(sec) 
			o 178   108.484000(sec) 
			o 176   108.569000(sec) 
			o 174   109.120000(sec) 
			o 170   109.210000(sec) 
			o 168   109.290000(sec) 
			o 166   109.373000(sec) 
			o 164   109.656000(sec) 
			o 162   109.930000(sec) 
			o 160   110.008000(sec) 
			o 158   110.088000(sec) 
			o 156   110.167000(sec) 
			o 154   110.430000(sec) 
			o 149   110.526000(sec) 
			o 147   110.606000(sec) 
			o 145   110.687000(sec) 
			o 143   110.925000(sec) 
			o 141   111.321000(sec) 
			o 135   111.558000(sec) 
			o 134   111.643000(sec) 
			o 132   111.784000(sec) 
			o 130   111.864000(sec) 
			o 128   111.943000(sec) 
			o 126   112.346000(sec) 
			o 125   112.451000(sec) 
			o 123   112.530000(sec) 
			o 121   112.622000(sec) 
			o 120   137.179000(sec) 
			o 118   137.262000(sec) 
			o 115   137.376000(sec) 
			o 113   137.460000(sec) 
			o 112   137.970000(sec) 
			o 109   138.207000(sec) 
			o 108   138.288000(sec) 
			o 107   138.368000(sec) 
			o 106   138.965000(sec) 
			o 105   139.044000(sec) 
			o 104   139.125000(sec) 
			o 103   139.205000(sec) 
			o 101   139.556000(sec) 
			o 98   139.636000(sec) 
			o 97   140.223000(sec) 
			o 92   140.411000(sec) 
			o 91   140.494000(sec) 
			o 89   140.575000(sec) 
			o 88   140.654000(sec) 
			o 86   140.734000(sec) 
			o 85   140.819000(sec) 
			o 84   140.901000(sec) 
			o 82   141.306000(sec) 
			o 81   141.384000(sec) 
			o 80   141.465000(sec) 
			o 78   141.546000(sec) 
			o 77   141.707000(sec) 
			o 76   141.787000(sec) 
			o 74   141.900000(sec) 
			o 72   141.980000(sec) 
			o 70   142.111000(sec) 
			o 68   142.191000(sec) 
			o 67   142.270000(sec) 
			o 66   142.357000(sec) 
			o 65   142.514000(sec) 
			o 64   142.846000(sec) 
			o 62   142.926000(sec) 
			o 59   143.006000(sec) 
			o 58   143.085000(sec) 
			o 55   143.165000(sec) 
			o 54   143.245000(sec) 
			o 52   143.324000(sec) 
			o 50   143.405000(sec) 
			o 49   143.484000(sec) 
			o 48   143.896000(sec) 
			o 46   143.976000(sec) 
			o 43   144.054000(sec) 
			o 41   144.261000(sec) 
			o 40   144.341000(sec) 
			o 39   144.449000(sec) 
			o 37   144.586000(sec) 
			o 36   144.667000(sec) 
			o 35   144.748000(sec) 
			o 34   144.857000(sec) 
			o 33   147.963000(sec) 
			o 32   148.264000(sec) 
			o 31   148.850000(sec) 
			o 30   149.683000(sec) 
			o 29   152.470000(sec) 
			o 28   152.940000(sec) 
			o 27   155.131000(sec) 
			o 26   157.387000(sec) 
			o 25   157.683000(sec) 
			o 23   160.193000(sec) 
			o 22   160.365000(sec) 
			o 21   160.537000(sec) 
			o 20   160.705000(sec) 
			o 19   161.021000(sec) 
			o 18   163.325000(sec) 
			o 17   164.045000(sec) 
			o 16   170.757000(sec) 
			o 15   171.258000(sec) 
			o 14   173.438000(sec) 
			o 12   173.907000(sec) 
			o 10   175.485000(sec) 
			o 9   188.802000(sec) 
			o 8   191.120000(sec) 
			o 7   215.816000(sec) 
			o 6   220.261000(sec) 
			o 5   223.345000(sec) 
	Python プロパティファイルの生成が終わりました。
 _____________________________________
|           |           |             |
|   Weight  |   Errors  |    Cost     |
|___________|___________|_____________|
|           |           |             |
|         7 |         0 |           0 |
|         6 |         0 |           0 |
|         5 |         0 |           0 |
|         3 |         0 |           0 |
|         2 |         2 |           4 |
|         1 |         1 |           1 |
|___________|___________|_____________|
|                       |             |
|         Total         |           5 |
|_______________________|_____________|
	*********UB=5(0)  267.77(cpu sec)
o 5(0)
解探索が終了しました。 270 (秒)
解が得られました。
ポスト処理を実行します。ソルバを呼び出し中です。
グローバル変数一覧:
successful  現任教育委員会
現任教育委員会 委員会日は、 2023-10-11 参加者全員は 7 人です
現任教育委員会 委員会日は、 2023-10-12 参加者全員は 7 人です

successful  新任教育委員会
新任教育委員会 委員会日は、 2023-10-02 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-03 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-04 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-05 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-06 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-10 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-11 参加者全員は 6 人です
新任教育委員会 委員会日は、 2023-10-12 参加者全員は 6 人です

successful  リスク委員会
リスク委員会 委員会日は、 2023-10-30 参加者全員は 5 人です
リスク委員会 委員会日は、 2023-10-31 参加者全員は 5 人です

successful  感染委員会
感染委員会 委員会日は、 2023-10-02 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-03 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-04 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-05 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-06 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-10 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-11 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-12 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-13 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-16 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-17 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-18 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-19 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-20 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-23 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-24 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-25 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-26 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-27 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-30 参加者全員は 6 人です
感染委員会 委員会日は、 2023-10-31 参加者全員は 6 人です

successful  業務委員会
業務委員会 委員会日は、 2023-10-20 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-23 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-24 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-25 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-26 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-27 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-30 参加者全員は 6 人です
業務委員会 委員会日は、 2023-10-31 参加者全員は 6 人です

successful  倫理委員会
倫理委員会 委員会日は、 2023-10-31 参加者全員は 6 人です

successful  ケア委員会
ケア委員会 委員会日は、 2023-10-23 参加者全員は 6 人です
ケア委員会 委員会日は、 2023-10-24 参加者全員は 6 人です
ケア委員会 委員会日は、 2023-10-25 参加者全員は 6 人です
ケア委員会 委員会日は、 2023-10-26 参加者全員は 6 人です
ケア委員会 委員会日は、 2023-10-27 参加者全員は 6 人です
ケア委員会 委員会日は、 2023-10-30 参加者全員は 6 人です
ケア委員会 委員会日は、 2023-10-31 参加者全員は 6 人です

successful  教育企画委員会
教育企画委員会 委員会日は、 2023-10-26 参加者全員は 6 人です
教育企画委員会 委員会日は、 2023-10-27 参加者全員は 6 人です
教育企画委員会 委員会日は、 2023-10-30 参加者全員は 6 人です
教育企画委員会 委員会日は、 2023-10-31 参加者全員は 6 人です

successful  記録委員会
記録委員会 委員会日は、 2023-10-05 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-06 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-10 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-11 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-12 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-13 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-16 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-17 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-18 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-19 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-20 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-23 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-24 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-25 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-26 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-27 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-30 参加者全員は 6 人です
記録委員会 委員会日は、 2023-10-31 参加者全員は 6 人です

Aチームリーダ会議 [6, 8, 9, 10] [12, 13, 14, 15, 16, 17, 18] 2
Aチームリーダ会議は確保できました。必要人数 2 人に対して 2 人確保しました。 2023-10-12
Bチームリーダ会議 [7, 11, 12, 13] [12, 13, 14, 15, 16, 17, 18] 2
Bチームリーダ会議は確保できました。必要人数 2 人に対して 2 人確保しました。 2023-10-10
ポスト処理を終了しました。 1 (秒)

2023年11月18日土曜日

委員会の設計

現任教育委員会(現任者(2年目以降)の人が教育・研修計画を立案・計画・実施する)や新任教育委員会等、 委員会を動的に割り当てるには、シフトを分ける必要があり、これが多数あると面倒です。

シフトの種類としては、日勤なので、委員会用のシフトも日勤集合とする必要があります。

これが面倒な場合には、Pythonで記述します。



委員会と名のつく変数で、なおかつリストオブジェクトである変数が候補となります。それらのANDを取って、少なくとも一つ以上であることが必要となります。
委員会日は、日勤です。このようにすると、委員会の数や参加者が変化してもスタッフプロパティシート群のみを編集すればよいので、メンテナンス上好ましいです。

ただし、解を見ただけは、開催日がいつかは分かりにくくなるので、ポスト処理で、解をチェックし該当日を報告する設計としています。


2023年11月17日金曜日

”半人前”の設計


さて、「新人は、人数にカウントしない」、はよくある実装です。これは、新人グループという集合を作成して、それ以外の集合のみをカウントすれば事足ります。

次に、「あの人は、半人前だ」についての実装を考えてみます。「半人前集合」を定義して、0.5カウントすればよいのですが、制約系は、全て整数が基本なので、二人で一カウントすればよいことになります。問題は、二人で一カウントすることが現機能では出来ないことです。

簡単そうに見えますが、最高難易度の問題です。ソルバーは、AL1、AL2,AL4とテクノロジーバックグランドの異なる系を備えているので、各々のバックグランドに適した実装とする必要があります。

https://schedule-nurse.blogspot.com/2023/11/blog-post_21.html



2023年11月16日木曜日

ダイアログを前面に出すハンドル

 ダイアログが隠れていると気付かずに、ハングしたのでは?と不安になってしまいます。






そんなときに前に出してくれるのがハンドルHWNDです。MessageBoxの第一パラメータとなっています。

HWNDは、GUIのハンドルです。

ソース全体を見ると定義されています。

メッセージダイアログを出しているのは、pythonを解釈実行中のソルバーでありGUIとは別プロセスですが、このおかげで、少なくともGUIよりは前面にダイアログが出力されます。

Pythonの中身を看護師長がEditするのは難しいと思うので、こういうインタラクティブなIFで、パラメータを変更できるようにすると良いと思います。



2023年11月15日水曜日

予定縮小時の不具合いについて

  11月6日の週は、妻のお供で、東京に滞在している時間が多く、ほぼメールのみの対応とさせて頂きました。全ての関連行事は滞りなく終了しました。今週よりまた復帰します。


Q.12月の勤務表作成時から、予定入力しているシフトの文字サイズのみが

少し大きく表示される様になり、枠内におさまらない表示になりました。

設定等、対処方法がありましたら、教えてください。

現状では、枠サイズを大きめにしていますので、大きな支障はありません。

A.

「シフト数が百数十個あり画面からはみ出し表示されなくなる」というお客さま用に、修正したのが仇になってしまいました。

下記ツールストリップサイズで、調整することができます。


ただし、これだと拡大時にも同じサイズになってしまいます。この点について、次回11月ENDのリリースで改善するので、お待ちになっていただければ何もする必要はありません。


2023年11月8日水曜日

シフト勤務表で日勤者数を日毎に変えるには?

 

制約による 曜日や特別な日の設定ではなく、日毎に勤務者数を指定したい、という場合は、タスク予定の基数制約テーブルで指定します。しかし、自分の勤務表スタイルは、シフト勤務表だ、という方もいらっしゃるかと思います。そんな方のための処方箋です。




2023年11月7日火曜日

連続日勤3日まで

 グループ属性で、アイテムを記述します

スタッフプロパティシートで、設定します。
制約します。






連続日勤5日までの記述は、既に、連続勤務6日禁止であるので不要です。


2023年11月6日月曜日

NOV052023BUILD内容

■ soft error 解析改善

■ キーボード入力サポート

https://schedule-nurse.blogspot.com/2023/11/blog-post.html

■ Day集合Error解析改善

■ NoTaskVarのみ Export 改善

■ TaskSchedule基数 数値入力チェック 追加

2023年11月5日日曜日

一般化変則2交代記述スタイル変更

 応援先として救急外来があったとき、タスクを使って表しています。

このとき、

NoTaskVar:自職場

救急外来:応援先

を表現しています。

日勤者の列制約の変更前と変更後です。青部が該当箇所です。

上の記述では、
応援先もしくは、自職場の制約人数が変化したとき、どちらも影響がでてしまいます。
下の記述は、変化があったところだけをメンテすればよいことになります。煩雑な
曜日集合演算も必要ありません。

さらに、曜日により複雑に日勤者数が変化する場合には、


とすることもできます。これだと、ベクトル表現で一行で記述できますが、

毎月メンテする必要があるのが難点です。


制約の方法は、一つではなく

1)制約記述による方法

2)特別な日のカレンダを使う方法

3)予定基数制約を使う方法

があります。

■制約が、将来的にも、殆ど変化しなければ、1)がよいでしょうし、

■制約しない月もある場合は、2)がよいでしょう

■ランダムに日勤者数が変化する場合は、3)がよいでしょう。(毎月メンテしないと誤制約になってしまいます。)

それでは、シフト勤務表では、3)が使えないのでは? と思われるかもしれませんが、上と同様に使えます。(https://schedule-nurse.blogspot.com/2023/11/blog-post_8.html





2023年11月4日土曜日

キーボードバインディング

 以前からご要望のあったキーボードによる予定入力を実装しました。



深夜のツールバーのところマウスをホバリングさせると、深夜:3というのがツールチップされています。ツールバーは、内部で番号が割り当ててあり、その番号を出力しています。このようにして、任意のラベルの番号を調べることができます。

キーボードとのバインディング

ファンクションキーF1-F9、数値キー1-9、テンキー1-9まで、総計27個までキーボードとのバインディングを指定することができます。F1は、ファンクションキーのF1,D1は、数値キーの1、NumPad1は、テンキーの1を指します。

ウィンドゥズの設定のところで、キーボードとのマッピングを設定します。-2は初期値で

なにもしません。(初期はDisable状態です。)-1は、ブランク、1-199番までラベルを指定可能となります。この表は、レジストリに保存しています。シフトおよびタスクについて動作します。




加えて、キーボードのカーソルキーも動くようにしています。

11月6日の週にリリースするので、審査で落ちなければ、11月10日頃から配信が始まると思います。


2023年11月3日金曜日

6連勤務禁止バグ修正

 バグがありました。

正しくは、下です。制約最終日に、長日、または入りがくると、次の日は、また勤務が強制されるので、それを禁止します。最後のパターンは、それの1日前の長日で始まるパターンの禁止です。




2023年10月31日火曜日

看護師勤務表にタスクを追加

シフト勤務表で、状態が足りないときがあります。

例えば、看護師・介助員のうち、以下のタスクを割り当てる場合です。

介助員ができるのは、介助タスクだけです。しかし、看護師は、そのスキルによって、

以下の全部を出来る人もいれば、スタッフナースタスクだけしかできない、という人も存在します。

□リーダタスク

□介助タスク

□スタッフナースタスク

そうした場合に、看護師が割り当てられたタスクが、上のどれかを判別するには、シフト情報だけでは不足しています。具体的には、夜勤、深夜、準夜用に、各ナースに各タスクが明示的に割り当てられる必要があります。

そうした場合、全部をシフトで行うやり方がありますが、得策ではありません。途端に状態数が爆発してしまうからです。解決策としては、タスク勤務表化があります。本プロジェクト例は、シフト勤務表から、上記のタスクを追加するタスク勤務表にするデモプロジェクトです。

本当にシフト関連には、一切手をつけずに、タスク追加だけで、出来てしまいました。

こうした例は、他に、

■同じようなシフトを持つ複数の棟をタスクにする

■応援先をタスクにする

■医師当直表の 夜勤タスク

等の例があります。

いずれもシフトでは状態特定するので、タスクになっています。タスクとシフトは分離しているので、将来、棟が増えたり、応援先が増えたり、夜勤タスクが増えたとしても、タスク部分だけを追加すればよいことになるので、メンテナンス性が良いのです。

看護師勤務表にタスクを追加 (nurse-scheduling-software.com)




2023年10月29日日曜日

医師当直勤務表に関して寄稿頂きました

勤務表を見るまでは、シフト勤務のブラック度は、

介護>看護師>その他

の順だと思っていたのですが、実は、勤務医がそのトップではないか?と思うようになりました。勿論、診療科によるとは思いますが、その実態を知っていただくべくお願いをして書いて頂きました。忙しいなか、書いて頂きありがとうございました。


医師当直表 スケジュールナースに関する寄稿 (nurse-scheduling-software.com)


2023年10月28日土曜日

OCT242023-OCT26BUILD内容

 タスク勤務表、列制約、シフト付きフェーズ制約で予定に、該当しないシフトがあったときのバグ修正を行いました。(大半の方には影響しないコーナケースです。)

2023年10月27日金曜日

Microsoft Certification Errorによりサブスク1週間の無料お試し期間無くしました

 突然に、

https://learn.microsoft.com/en-us/answers/questions/1390603/help-with-submission-error-10-1-4-6-app-quality-mi?source=docs

と同じで理由で、審査に落ちました。何のことかさっぱり分かりません。

問い合わせてみると、


Thank you for contacting us. The description claims that there is a week free trial. At launch, the product asks, "Do you like to purchase a subscription?". Selecting "No" closes the product. There is no option to choose a week free trial. Please either remove the free trial claim from the description or ensure that there is a free trial within the product and resubmit the product for certification.

Microsoft Store Team

<原因解析>

ソースは何も変えていません。ストア登録のところで、無料期間設定を7日にしていた筈なのに、なぜか、「なし」にされていました。再度 7日に設定し再申請したのですが、同じく、落ちました。原因は不明です。

<対策>
そこで、上で指示されているとおりに、「お試し期間なし」を表明することにしました。下記がその表示です。



英語版では、

<考察>
恐らく、Microsoftの何かが変わったのだと思います。恐らく、私以外にも被害者はいると思いますが、当面はこのスタイルとなります。これで審査はパスしました。(一応7日の設定はしたままなのでが、実際の挙動がどうなっているかは、簡単に確かめることが出来ないので分かりません。)

スケジュールナースは既に、多くの方々に使われており、その性能については疑いがない、という地位を確立しつつあると思いますので、実害はないと思います。

2023年10月26日木曜日

変則2交代一般化パターンの検討と最終実装案

<目的>

長日、ロング日勤を使用するパターンは、近年色々出ていますが、勤怠システムのサポート問題があります。様々な制約実装パターンに対して、最も実装が容易な形態について考察、考案しその普及を促すことを目的とします。

■列制約長入明数が同じならば、長入明パターンとするのが望ましい

例えば、長入明が(3,3,3)ならば、長入明パターンだけを用いて列数を揃えることはできる。

長入明しかないのであれば、前月との貸し借りでみれば、+-0であり、補償項(非番、半休)が必要ない。(今月という枠で見ると、長入り差は+-1発生する。これを勤怠システムの都合で、同じとすることは、解空間を狭めること、実装が重いこと、により推奨しない。勤務シフト上良いことは何もない。勤怠システムのために、看護師が余計に難しいシフトを強制されることは不条理)

より一般的な変則2交代では、このほかにパターン上のシフトを導入する。単長と、単入である。また遅番が必要な病棟もある。単長と単入は、長入明パターンにあてはまらない全ての長日と、入りシフトを表す。

■同じでない(例えば、長入明(4,3,3)あるいは、曜日により異なる)ならば、単長を導入する

列数が全て同じであれば、長入明パターンだけで実現できるが、そうでない場合は、必要な列数を過不足なく実現するには、単長の導入が必須となる。

単長に関しては、1.5Dayが必要となり、就業日数の増加に対する補償が必要とも考えられる。同値制約にこれを月内で自動補償するやり方、単長数=2*非番、も案としてはあるが、全スタッフに適用するにはソルバ負荷が重過ぎるので採用しない

そこで、非番、半休に関しての補償は、月累計にて、希望非番数、希望半休数という制約で、月毎に行うものとする。具体的には、非番数をスタッフプロパティシートに記載し、累計結果を見ながら適宜、補償を行う。

■単入の発生箇所

単入は、就業日数の減少を生むので、勤怠システムでも補償がしにくく発生自体をなるべく避けるべきと考える。

単入が発生するのは、次である

1)長日を行わないスタッフが少なくとも一人いる

2)休入を予定に入れてくるスタッフ

3)長遅入明パターンが一人でもいる


<単長が定常的に発生する職場>

単長が定常シフトとして存在する職場では、単長により列を揃えることは障害とならない。

<単長が定常的に発生しない職場>


長入明しかないパターンの職場では、列を揃えるため、他のスタッフに単長が必要となる。つまり、あるスタッフの単入を実現するために、単長が他のスタッフで必須となる。上を認めるか?禁止とするか?、で単入が必要かどうかが決まる。

いずれにせよ、単入に関しては、勤怠システムのサポートが必須となる。

設計例

      )2)可。3)禁止

   全夜勤スタッフが単長サポート。 ただし  単長数<=2

         列制約が長日数==入り数の場合、制約最終日の単長数は0にソフト制約する  

        単入は、自動アサインしない 

        (長日がないスタッフは、予定入力で、シフト集合[でない]を用いて夜勤可能候補日を指定する。)

   半休は、自動アサインしない

        非番数は、スタッフプロパティシート管理(繰越計算による指定)

     遅番3回連続禁止、遅番の後は、遅番または休みとする

このシステムでは、長入明の列数が同じであれば、パターンも基本、長入明だけになる。単長、単入も各スタッフは、アサイン可能であっても自然にそうなる。単入は、自動アサインにしないので、予定入力されたときだけ発生する。単入がなければ、単長があっても列を揃えることは出来ないので、自然に長入明だけになる。但し、制約最終日だけは、自然にそうはならないので、ソフト制約する。

長入明が揃わない例えば、(4,3,3)では、単長が1日一個生成されることによる。また、長入明を乱す上記1)2)3)の入力も可能とすることも可能とする実装にすることも可能ではあるが、単入りは、自動アサインしないので、余計に単入、単長が生成されることを抑制する効果がある。

単長と単入は、勤怠システムでのサポートが必要となるが、シフトとして区別可能で計数は容易である。(単にそのシフト数を計数すればよい。)

以上の実装と各種仕様への変更の仕方を示したプロジェクトの公開を行う予定。




      



3)に関しては、他のスタッフでの補償が必須となり影響度が大きいことから禁止とすべきと考える。





2023年10月25日水曜日

老健施設 日勤者数 風呂日3人それ以外2人

 まずは、風呂日集合を作ります。2F,3F,4Fで風呂日が違います。


後は、列制約で、日勤者数をそれぞれ指定すればよいだけです。


2023年10月23日月曜日

老健施設 夜勤者の階が被らない

 2F,3F,4Fというグループ属性を生成します。




各スタッフに階を設定します。


列制約でMax=1に設定します。


2023年10月22日日曜日

自動割り当てなしの挙動

 シフト自動割り当てなしは、ちょっと曲者で整理してみました。(OCT18/192023 BUILD版以降)

A■予定入力なし

自動割り当てのチェックがされていないシフトは、決して割り当てされることはありません。つまり、割り当てされるのは、自動割り当てチェックがされたシフトのみが可能性としてあります。

B■ハード予定入力 シフトの場合

そのシフトが自動割り当りあてのチェックの如何に関係なくそのシフトが割り当てられます。

C■ハード予定入力 シフト集合「または」の場合

自動割り当てチェックがないシフトが含まれる場合、そのシフトは割り当てられません。割り当てられるのは、シフト集合内の自動割り当てチェックされているシフトのみが可能性として、割り当てられます。

D■ハード予定入力 シフト集合「でない」の場合

そのシフトが自動割り当りあてのチェックの如何に関係なく集合演算結果のみにより、そのシフトが割り当てられます。

E■ソフト予定入力 シフトの場合

そのシフトが、自動割り当てされている場合、そのシフトとその他自動割り当てされたシフトが可能性として、割り当てられます。

F■ソフト予定入力 シフト集合の場合

予定入力なしと同じ挙動になります。自動割り当てされたシフトのみが可能性として、割り当てられます。

要するに、自動割り当てなしにされていて、シフト集合の場合が、要注意ということになります。特に、ハード制約「または」、と 「でない」が違います。


 例えば、下の予定ラベル日入は、日勤または、入りシフトですが、日勤は、自動割り当てなしされません。行制約によって入連続は禁止ですからラベル部日入には、入れるものがなくなるので、ハードエラーとなります。



それに対して、「でない」での予定集合夜1は、集合演算上、日勤または、明けが残ります。各々行制約禁止により、一つだけが残ります。

このどちらも自動割り当てなしではありますが、ルールDにより、各々明け、日が必然の結果として割り当てられます。