2023年7月30日日曜日

年休消化の少ない人に休みをつける

 年休消化の少ない人に休みをつける (nurse-scheduling-software.com)

年休を取らない人がいますが、法律上年間決まった数は取らなくてはいけません。で年休取得数が少ない人には、多くの消化年休を、少ない人には、0または、少ない消化年休を制約したい訳です。

この例では、全員に1回の年休を設定していますが、例えば、次のようにすることも出来ます。

ブランクのところは制約されないのでフリー状態となります。







設定通りとなりました。フリーでも年休が入っているのは、日勤に余裕があるためです。(デモ仕様です。)通常は、入っても1個程度だと思います。いずれにせよ、一度このように記述できるようにしておけば、年休消化したい、あるいは、明けの後の2連休をどうにか付けてあげたい、と思ったときに各スタッフ毎に設定出来ます。

スケジュールナースは、GUIで記述する制約プログラミングプラットフォームです。この例でもPythonは使っていないので、(慣れれば)誰でも制約プログラミングが可能です。



2023年7月29日土曜日

BUILD JUL282023 Updated

1)

 スケジュールナースに関するFAQs (nurse-scheduling-software.com)

で、行制約のEnableボタンオフ時の最大ー最小値を維持して欲しいというご要望を実装しました。

2)Download Linkを廃止しました。

3)Col表示ずれを改善しました。

珍しくその日のうちに配信になったようです。


2023年7月28日金曜日

夜勤明け後できれば2連休 

 夜勤明け後、出来れば2連休 (nurse-scheduling-software.com)

この要求は、かなり多いと思います。これは、公休数に関係し、それ故に、月毎でも難易度が異なるのが普通です。普通にできるのは、1回、頑張れば2回できるかもしれません。しかし、それ以上(例えば3回)となると物理的に無理な場合が殆どでしょう。そうした場合の裏技テクニックの紹介です。2連休の終わりを年休を含むという定義にします。それとは別にスタッフプロパティシートでは、年休数を持ちます。このようにすると、

■2連休を達成する

■年休を消化する

を同時に達成することが出来ます。

年休消化が少ないスタッフには、強制的に割り当てることになるので一石二鳥です。

2023年7月26日水曜日

年間パートナーの勤務を月1回合わせる

 年間パートナーの勤務を月1回合わせる (nurse-scheduling-software.com)

基本的には、Kindle本 会議と同じ類です。ただし、全スタッフが二人または3人のペアとなるので、難易度は、こちらの方が高いでしょう。要求仕様は、日勤と長日勤が一緒でもよいとのことでしたが、それほど解空間を狭めることはなさそうなので、日勤のみの実装としています。



2023年7月25日火曜日

Qiitaに寄稿しました

 塾講師配置問題の最適化 - Qiita

ナーススケジューリング問題の第一人者が、最新のナーススケジューリング問題状況を解説した記事です。EUと日本のシフトの違いに言及しています。

二つの違いがあります。

1)シフトパターンが異なる

欧米では、夜勤が3-4日連続するのが普通です。日本では、夜勤専従ならばあり得ますが、それ以外はありえません。根源的な違いであり、ここ数年で変わるとも思えません。

2)日本では、パーソナル要件がかなり考慮される

欧米では、大病院が主体であり、勤務表を機械でつくることが一般的であり、それが故にスタッフの個別事情は、反映されにくいと思います。それに対して、日本では勤務表作成権限が看護師長に与えられており、自動作成でなくても、いや、自動作成でないが故か、かなり考慮されると思います。





2023年7月20日木曜日

ストアでの売り上げ

 ストアでの売り上げは、約3ヶ月遅れでマイクロソフトから海外送金されます。その際、地方銀行を指定したのですが、マネーロンダリングの恐れがあるとかで、ソースの確認書類を提出を求められました。今月から毎月入金予定ですが、その度にTELによる確認が必要とのことです。


2023年7月19日水曜日

2023年7月13日木曜日

CSV file to competition format(INRC2) conversion

 sugawara-system/Schedule_Nurse3_Gallery: The State of the Art commercial solver, Schedule Nurse galleries sites. Contains samples and project files for benchmark test results such as Classical Scheduling Benchmarks, Scheduling Benchmarks, INRC1, INRC2, etc. (github.com)

The solution file can be output as a CSV file. I have written a script to convert this CSV file to the competition format. Usually, I would have used Python, but that would not have been interesting, so I implemented it here as a project for the Schedule Nurse. This project is a dummy project, and the constraints are meaningless. What is meaningful is post_main(), which is executed as a post-process.

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'
                        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()

2023年7月11日火曜日

Update INRC2 8weeks data and project files

 Second International Nurse Rostering Competition (nurse-scheduling-software.com)

For the INRC2 8weeks data, no optimal values were known for any of the instances, but now only one optimal value has been determined. Surprisingly, it was an instance of 120 staff. The project may be the largest instance in Nurse Scheduling History that ever has been solved optimally. I have not calculated the solution space, but may exceed Instance 22 in new scheduling benchmarks.

The project file at the time of the optimal value determination has also been uploaded. You can download it by GitHub Viewer. 



The followings are the exported  data to Excel.


Shift and Task Solution



Anyone can ensure the data.

2023年7月8日土曜日

GitHub Viewer更新

 7月6日ビルドの配布が始まっており、お使いのスケジュールナースは、勝手に更新されていると思います。(私のPCの半分は、更新されています。殆どは、今日中に更新されると思います。)

Viewerをご覧になると、Nextと、Browseが追加されています。

Nextを押すと、塾講師のサンプルプロジェクトが表示されます。


この後にユーザContributionのプロジェクトが表示される予定です。

2023年7月7日金曜日

2023年7月5日水曜日

A sample project for GitHub

Here is a sample project for GitHub Publication.


 sugawara-system/maternity-clinic: Solves nurse scheduling problem for a maternity clinic in Japan by using Schedule Nurse. (github.com)


I've translated the actual user project into English. Since the project I was involved in was the last year, the calendar is not as of Today. The project is a small clinic for maternity in Japan. 


The first key point of this project is using "Integer Count" instead of "Max-Min hours." Since the "Max-Min" hours are hard constraint only and slow, we recommend using "Integer Count" if possible.


The second key point is the "Staff property sheet." Note the end-user is Head-nurse or chief, so she is not an IT engineer. The possible changes in the future should be options in the sheet so that they do not need to touch constraints directly.