解生成後に、解を整形したり、解を統計解析したい場合があります。そんな用途に、ポスト処理用Pythonを用意しました。
例えば、フェーズオブジェクトを用いた制約系では、次のような解出力になります。3フェーズ/Day出力となります。
しかし、実際にユーザが管理しているのは、次のようなExcelフォーマットです。このフォーマットはユーザ毎に違います。SC3のExcel出力オプションでなんとかなるレベルではありません。
このGAPを埋めるのに、Excelマクロを使ったり、Openpyxl等を使った処理が必要になります。残念ながら、Openpyxlは、巨大すぎて実装できていないので、次善の策として、Pythonで整形したCSVファイルを出力することにしました。
Pythonソースは、以下です。
#post operation
def get_day_index(day):
return day-今月[0]+1 #名前項目分
def draw_row(person,day,row0,row1):
phases=3
t0=task_solution[person][day*phases+0]
t1=task_solution[person][day*phases+1]
t2=task_solution[person][day*phases+2]
d=get_day_index(day)
#debug sc3.print(str(d)+' '+str(len(row0))+'\n')
#勤務処理
if t0=='日T' and t1=='日T':
if day in 休勤日今月:
row0[d]='休勤'
else :
row0[d]='日勤'
elif t0=='日T' and t1=='有給':
row0[d]='後有'
elif t1=='日T' and t0=='有給':
row0[d]='前有'
elif t0=='有給' and t1=='有給':
row0[d]='有休'
elif t0=='公休' and t1=='公休':
row0[d]='休み'
elif t0=='日T' and t1=='公休':
row0[d]='午前'
elif t1=='日T' and t0=='公休':
row0[d]='午後'
elif t0=='希望休み' and t1=='希望休み':
row0[d]='希休'
else:
row0[d]='M休'
#属性処理
if t2 !='公休':
if day in 土:
row1[d]='土拘'
else :
row1[d]='拘束'
if shift_schedules[person][day]=='希望休み扱い':
if row0[d] !='希休':
row1[d]='希休'
def post_main():
sc3.print('\n\n*********ポスト処理を実行中です。*************\n')
sol_list=[]
for person in 全スタッフ:
row0=[]
row1=[]
row0.append(staffdef[person])
row1.append('')
for day in 今月:
row0.append('') #配列確保
row1.append('') #配列確保
draw_row(person,day,row0,row1)
sol_list.append(row0)
sol_list.append(row1)
#Write csv file
sc3.print('CSVファイルを生成中です。\n')
os.chdir(project_file_path)
file_path=project_file_path+'/this_month_solution.csv'
with open(file_path, 'w', newline='') as file_path:
writer = csv.writer(file_path)
writer.writerows(sol_list)
sc3.print('CSVファイルを生成しました。\n')
sc3.print('********ポスト処理を終了します。*******************\n')
#Main rountine
勤務日数設定OneShift()
有給日数設定OneShift()
週あたりの勤務日数設定OneShift()
このPythonソース中、def post_main(): がポスト処理で使用されるルーチンです。構文チェックは、
制約実行時に行われるので、構文エラーは、制約実行段階でチェックされます。制約実行時、解は未だありませんが、インタプリタの利点で、実行までその存在チェックはされないので、なくても問題ありません。
ポスト処理時は、制約実行のmain routineは、カットされます。このために、次のような記述構造としてください。
解は、shift_solution/task_solutionとして、2次元リストで得られます。これを解析してCSV出力しています。
処理内容としては、作業フォルダをプロジェクトファイルにした後、解をユーザフォーマットに変換して、CSV処理するだけです。ユーザは出力されたCSVをExcelで読み、そのシートを貼り付けるだけで済みます。
ポスト処理時のソースは、以下のソース全体(ポスト)で見ることが出来ます。(ReadOnlyです)
#staffdef
staffdef=['スタッフ1','スタッフ2','スタッフ3','スタッフ4']
#daydef
制約開始日=6
制約終了日=35
表示開始日=0
daydef=['2020-05-26','2020-05-27','2020-05-28','2020-05-29','2020-05-30','2020-05-31','2020-06-01','2020-06-02','2020-06-03','2020-06-04','2020-06-05','2020-06-06','2020-06-07','2020-06-08','2020-06-09','2020-06-10','2020-06-11','2020-06-12','2020-06-13','2020-06-14','2020-06-15','2020-06-16','2020-06-17','2020-06-18','2020-06-19','2020-06-20','2020-06-21','2020-06-22','2020-06-23','2020-06-24','2020-06-25','2020-06-26','2020-06-27','2020-06-28','2020-06-29','2020-06-30']
#staffcollection
全スタッフ=[0,1,2,3]
正社員=[0,1]
パート=[2,3]
Work=[0,1,2,3]
日T=[0,1,2,3]
西拘束=[0,1,2,3]
拘束=[0,1,2,3]
有給=[0,1,2,3]
公休=[0,1,2,3]
希望休み=[0,1,2,3]
NoTaskVar=[0,1,2,3]
#daycollection
今月=[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]
日=[5,12,19,26,33]
月=[6,13,20,27,34]
火=[0,7,14,21,28,35]
水=[1,8,15,22,29]
木=[2,9,16,23,30]
金=[3,10,17,24,31]
土=[4,11,18,25,32]
全日=[0,1,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]
祝=[]
振=[]
Dr1人木金=[9,16,24,31]
特別休業=[]
パート給与計算1週目=[5,6,7,8,9,10,11]
パート給与計算2週目=[12,13,14,15,16,17,18]
パート給与計算3週目=[19,20,21,22,23,24,25]
パート給与計算4週目=[26,27,28,29,30,31,32]
パート給与計算5週目=[33,34,35]
増員火曜日=[7,35]
特別全員出勤日=[]
稼働日=[0,1,2,3,4,6,7,8,9,10,11,13,14,15,16,17,18,20,21,22,23,24,25,27,28,29,30,31,32,34,35]
制約開始日一日前=[5]
制約開始日二日前=[4]
制約開始日三日前=[3]
制約開始日四日前=[2]
制約開始日五日前=[1]
制約開始日六日前=[0]
制約開始日七日前=[]
制約開始日P1=[7]
制約開始日P2=[8]
制約開始日P3=[9]
制約開始日P4=[10]
制約開始日P5=[11]
制約開始日P6=[12]
第一週=[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]
第六週=[]
四週間=[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]
制約開始日1日前から=[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]
制約開始日2日前から=[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]
制約開始日3日前から=[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]
制約開始日4日前から=[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]
制約開始日5日前から=[1,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]
制約開始日6日前から=[0,1,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]
制約開始日7日前から=[0,1,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]
制約終了日六日前=[29]
制約終了日五日前=[30]
制約終了日四日前=[31]
制約終了日三日前=[32]
制約終了日二日前=[33]
制約終了日一日前=[34]
金土日=[3,4,5,10,11,12,17,18,19,24,25,26,31,32,33]
金土日月=[3,4,5,6,10,11,12,13,17,18,19,20,24,25,26,27,31,32,33,34]
休日でない月=[6,13,20,27,34]
休日でない火=[0,14,21,28]
休日でない水=[1,8,15,22,29]
休日でない木=[2,9,16,23,30]
休日でない金=[3,10,17,24,31]
休日でない土=[4,11,25]
実月水=[1,6,8,13,15,20,22,27,29,34]
実月火水=[0,1,6,7,8,13,14,15,20,21,22,27,28,29,34,35]
実火土=[0,4,11,14,21,25,28]
実土ではない=[0,1,2,3,5,6,7,8,9,10,12,13,14,15,16,17,18,19,20,21,22,23,24,26,27,28,29,30,31,32,33,34,35]
実木金=[2,3,9,10,16,17,23,24,30,31]
Dr2人の木=[2,23,30]
Dr2人の金=[3,10,17]
今月月=[6,13,20,27,34]
今月火=[7,14,21,28,35]
今月水=[8,15,22,29]
今月木=[9,16,23,30]
今月金=[10,17,24,31]
今月土=[11,18,25,32]
実土=[4,11,18,25,32]
今月実土=[11,18,25,32]
実土でない=[0,1,2,3,5,6,7,8,9,10,12,13,14,15,16,17,19,20,21,22,23,24,26,27,28,29,30,31,33,34,35]
実土でない今月=[6,7,8,9,10,12,13,14,15,16,17,19,20,21,22,23,24,26,27,28,29,30,31,33,34,35]
土日=[4,11,18,19,25,32,33]
土日今月=[11,18,19,25,32,33]
休勤日=[5,12,19,26,33]
休勤日今月=[12,19,26,33]
#shiftcollection
#classcollection
全スタッフ属性=[全スタッフ]
雇用形態=[正社員,パート]
#shiftdef
shiftdef={'Work':Work}
#taskdef
taskdef={'日T':日T,'西拘束':西拘束,'拘束':拘束,'有給':有給,'公休':公休,'希望休み':希望休み,'NoTaskVar':NoTaskVar}
#non_auto_tasks
non_auto_tasks=['希望休み']
#phase_list
午前=0
午後=1
拘束=2
#task collections
休日集合={'有給':有給,'公休':公休,'希望休み':希望休み}
拘束集合={'拘束':拘束,'西拘束':西拘束}
働きカウント={'有給':有給,'日T':日T}
働きカウントしない={'公休':公休,'希望休み':希望休み}
#phase_objects def
phase_objects_def={'日勤','午前','午後','日勤拘束','日勤PV','公休PV','有休PV','希望PV','午前拘束PV','午前拘束西PV','午後拘束PV','午後拘束西PV','日勤拘束西PV','拘束ダメ','午前カウント','午後カウント','西の','拘束カウント','午前有休PV','午後有休PV','午前働','午後働','前後働'}
#phase_object_aggregates
phase_aggregate_object_def={'お休み','午前希望','午後希望','希望休み扱い','Any勤務','日勤扱い','午後扱い','有休集合','働集合'}
#digited group
勤務日数最大={0:22,1:22,2:14.5,3:14.5}
勤務日数最小={0:22,1:22,2:13,3:13.5}
有給日数最大={0:2,1:2,2:1,3:1}
有給日数最小={0:0,1:2,2:0,3:0}
週あたりの勤務日数最大={2:4,3:4}
週あたりの勤務日数最小={2:3,3:3}
補助制約={'拘束タスクは、午前なし':B_拘束タスクは午前なし,'拘束タスクは、午後なし':C_拘束タスクは午後なし,'日タスクは、拘束フェーズなし':D_日タスクは拘束フェーズなし,'西野先生ではない休日':西野先生ではない休日,'西野先生休日':西野先生休日,'西野先生平日拘束':西野先生平日拘束,'西野先生ではない日(ひ)':E_西野先生ではない日ひ,'西野先生土曜日':西野先生土曜日}
column_constraints={'列制約グループ1':列制約グループ1,'補助制約':補助制約}
#shift schedules
shift_schedules=[[('',0),('日勤',0),('日勤拘束',0),('日勤',0),('お休み',0),('お休み',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('希望休み扱い',0),('',0),('',0),('',0),('',0),('',0)]
,[('',0),('日勤拘束',0),('日勤',0),('お休み',0),('午前',0),('日勤拘束',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('拘束ダメ',0),('希望休み扱い',0),('希望休み扱い',0),('',0),('',0)]
,[('',0),('お休み',0),('有休PV',0),('午前',0),('午前拘束PV',0),('お休み',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('拘束ダメ',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0)]
,[('',0),('日勤',0),('午前',0),('日勤拘束',0),('お休み',0),('お休み',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('午前希望',0),('',0),('希望休み扱い',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('希望休み扱い',0),('希望休み扱い',0),('',0),('',0)]
]
task_schedules=[[('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0)]
,[('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0)]
,[('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0)]
,[('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0),('',0)]
]
project_file_path='C:/Users/sugaw/Documents/FA/sc3'
shift_solution=[['Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work']
,['Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work']
,['Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work']
,['Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work','Work']
]
task_solution=[['公休','日T','公休','日T','日T','公休','日T','日T','拘束','日T','日T','公休','公休','公休','公休','公休','公休','公休','日T','日T','拘束','日T','日T','公休','日T','日T','公休','日T','日T','拘束','公休','公休','公休','日T','公休','公休','日T','日T','拘束','公休','公休','公休','日T','日T','公休','日T','日T','公休','日T','日T','拘束','日T','日T','公休','公休','公休','公休','公休','公休','公休','日T','日T','拘束','日T','日T','公休','日T','日T','公休','有給','有給','公休','日T','日T','拘束','日T','公休','公休','公休','公休','公休','日T','日T','公休','日T','日T','拘束','日T','日T','公休','有給','有給','公休','日T','公休','公休','日T','公休','西拘束','公休','公休','公休','日T','日T','公休','日T','日T','公休']
,['公休','日T','公休','日T','日T','拘束','日T','日T','公休','公休','公休','公休','日T','公休','公休','日T','日T','拘束','公休','公休','公休','有給','有給','公休','日T','日T','公休','日T','日T','公休','日T','日T','公休','日T','公休','拘束','公休','公休','公休','日T','日T','公休','日T','日T','公休','日T','日T','拘束','日T','日T','公休','有給','有給','公休','日T','公休','公休','日T','日T','西拘束','公休','公休','公休','日T','日T','公休','日T','日T','拘束','日T','日T','公休','日T','日T','公休','公休','公休','公休','日T','日T','拘束','公休','公休','公休','日T','日T','公休','日T','日T','公休','日T','日T','拘束','日T','日T','公休','公休','公休','公休','公休','公休','公休','日T','日T','公休','日T','日T','拘束']
,['日T','公休','公休','公休','公休','公休','有給','有給','公休','日T','公休','公休','日T','公休','拘束','公休','公休','公休','日T','日T','公休','日T','日T','公休','日T','日T','拘束','公休','公休','公休','日T','公休','公休','公休','公休','公休','公休','公休','公休','日T','日T','拘束','公休','公休','公休','日T','日T','公休','公休','公休','公休','日T','日T','拘束','公休','公休','公休','公休','公休','公休','日T','日T','公休','公休','日T','拘束','有給','日T','公休','日T','公休','公休','公休','公休','公休','日T','公休','拘束','公休','公休','公休','日T','日T','公休','公休','公休','公休','日T','日T','拘束','日T','公休','公休','公休','公休','公休','日T','公休','公休','日T','日T','西拘束','公休','公休','公休','公休','日T','公休']
,['日T','日T','公休','日T','日T','公休','日T','公休','公休','日T','日T','拘束','公休','公休','公休','公休','公休','公休','日T','日T','公休','日T','日T','拘束','公休','公休','公休','公休','公休','公休','日T','日T','拘束','公休','公休','公休','公休','公休','公休','日T','日T','公休','有給','日T','拘束','公休','公休','公休','公休','公休','公休','日T','公休','公休','日T','公休','西拘束','公休','公休','公休','日T','日T','公休','有給','公休','公休','日T','公休','公休','日T','日T','拘束','公休','公休','公休','公休','公休','公休','公休','公休','公休','日T','日T','拘束','公休','日T','公休','公休','公休','公休','日T','日T','公休','公休','日T','拘束','公休','公休','公休','公休','公休','公休','日T','日T','拘束','日T','公休','公休']
]
import sc3
import sys
import os
import csv
def 勤務カウントOneShift(person,day,vlist):
v=sc3.GetTaskVar(person,day,0,'日T');#AM
vlist.append(v)
v=sc3.GetTaskVar(person,day,1,'日T');#PM
vlist.append(v)
v=sc3.GetTaskVar(person,day,0,'有給');#AM
vlist.append(v)
v=sc3.GetTaskVar(person,day,1,'有給');#PM
vlist.append(v)
def 勤務日数設定OneShift():
for person in 全スタッフ:
max=-1
min=0
st=staffdef[person]+' 勤務日数を制約'
sc3.print(st+'します。\n')
if person in 勤務日数最大:
max=勤務日数最大[person]#float
if person in 勤務日数最小:
min=勤務日数最小[person]#float
max *=2
min *=2
if isinstance(max, float) and not max.is_integer():
sc3.print('勤務日数設定でmaxが整数型ではありません。')
continue
if isinstance(min, float) and not min.is_integer():
sc3.print('勤務日数設定でminが整数型ではありません。')
continue
max =int(max) #float to int
min =int(min) #float to int
sc3.print('最大='+str(max)+' 最小='+str(min)+'\n')
vlist=[]
for day in 今月:#午前・午後の日勤と有給taskと有給シフトをカウントする 有給シフトは、2回分
勤務カウントOneShift(person,day,vlist)
#sc3.AddSoft(sc3.SeqError(min,max,15,vlist),st,7)#許容2 ->8hours
sc3.AddHard(sc3.SeqLE(min,max,vlist),st)#hard constraint
def 有給日数設定OneShift():
min_sum=0;
vlist_sum=[];
for person in 全スタッフ:
max=-1
min=0
st=staffdef[person]+' 有給日数を制約'
sc3.print(st+'します。\n')
if person in 有給日数最大:
max=有給日数最大[person]#float
if person in 有給日数最小:
min=有給日数最小[person]#float
max *=2
min *=2
min_sum+=min;
if isinstance(max, float) and not max.is_integer():
sc3.print('勤務日数設定でmaxが整数型ではありません。')
continue
if isinstance(min, float) and not min.is_integer():
sc3.print('勤務日数設定でminが整数型ではありません。')
continue
max =int(max) #float to int
min =int(min) #float to int
sc3.print('最大='+str(max)+' 最小='+str(min)+'\n')
vlist=[]
for day in 今月:#午前・午後の日勤と有給taskと有給シフトをカウントする 有給シフトは、2回分
v=sc3.GetTaskVar(person,day,0,'有給');#AM
vlist.append(v)
v=sc3.GetTaskVar(person,day,1,'有給');#PM
vlist.append(v)
sc3.AddSoft(sc3.SeqError(min,max,1,vlist),st,7)
vlist_sum+=vlist;
sc3.AddSoft(sc3.SeqError(min_sum,min_sum,10,vlist_sum),'Total有給の極小化',5)#重みは調整ください
def 週あたりの勤務日数設定OneShift():
for person in 全スタッフ:
max=14
min=0
st=staffdef[person]+' 週あたりの勤務日数を制約'
sc3.print(st+'します。\n')
if person in 週あたりの勤務日数最大:
max=週あたりの勤務日数最大[person]#float
if person in 週あたりの勤務日数最小:
min=週あたりの勤務日数最小[person]#float
if max==14 and min==0:
continue
max *=2
min *=2
if isinstance(max, float) and not max.is_integer():
sc3.print('週あたりの勤務日数設定でmaxが整数型ではありません。')
continue
if isinstance(min, float) and not min.is_integer():
sc3.print('週あたりの勤務日数設定でminが整数型ではありません。')
continue
max =int(max) #float to int
min =int(min) #float to int
sc3.print('最大='+str(max)+' 最小='+str(min)+'\n')
week=0
for sun in 日:#日曜日を起点に1週間見る
sc3.print('日曜日='+str(sun)+'\n')
VList=[]
days=0
for d in range(7):
day=sun+d
if day >制約終了日:
break
else:
勤務カウントOneShift(person,day,VList)
days+=1
s="週あたりの勤務回数設定"+str(week)+' '+"person"+str(person) #Keyword+ space +variable word
week+=1
if days==7:
sc3.AddSoft(sc3.SeqError(min,max,2,VList),s,7) #level 3 許容エラー4
else:
nmax=int( days*max/7);#7日に満たない場合は、リニア目標値設定 端数切捨て
nmin=int( days*min/7);#7日に満たない場合は、リニア目標値設定 端数切捨て
sc3.print(str(nmax)+"に目標値最大を設定しました。\n")
sc3.print(str(nmin)+"に目標値最最小を設定しました。\n")
sc3.AddSoft(sc3.SeqError(nmin,nmax,2,VList),s,7)#level 3 許容エラー4
#post operation
def get_day_index(day):
return day-今月[0]+1 #名前項目分
def draw_row(person,day,row0,row1):
phases=3
t0=task_solution[person][day*phases+0]
t1=task_solution[person][day*phases+1]
t2=task_solution[person][day*phases+2]
d=get_day_index(day)
#debug sc3.print(str(d)+' '+str(len(row0))+'\n')
#勤務処理
if t0=='日T' and t1=='日T':
if day in 休勤日今月:
row0[d]='休勤'
else :
row0[d]='日勤'
elif t0=='日T' and t1=='有給':
row0[d]='後有'
elif t1=='日T' and t0=='有給':
row0[d]='前有'
elif t0=='有給' and t1=='有給':
row0[d]='有休'
elif t0=='公休' and t1=='公休':
row0[d]='休み'
elif t0=='日T' and t1=='公休':
row0[d]='午前'
elif t1=='日T' and t0=='公休':
row0[d]='午後'
elif t0=='希望休み' and t1=='希望休み':
row0[d]='希休'
else:
row0[d]='M休'
#属性処理
if t2 !='公休':
if day in 土:
row1[d]='土拘'
else :
row1[d]='拘束'
if shift_schedules[person][day]=='希望休み扱い':
if row0[d] !='希休':
row1[d]='希休'
def post_main():
sc3.print('\n\n*********ポスト処理を実行中です。*************\n')
sol_list=[]
for person in 全スタッフ:
row0=[]
row1=[]
row0.append(staffdef[person])
row1.append('')
for day in 今月:
row0.append('') #配列確保
row1.append('') #配列確保
draw_row(person,day,row0,row1)
sol_list.append(row0)
sol_list.append(row1)
#Write csv file
sc3.print('CSVファイルを生成中です。\n')
os.chdir(project_file_path)
file_path=project_file_path+'/this_month_solution.csv'
with open(file_path, 'w', newline='') as file_path:
writer = csv.writer(file_path)
writer.writerows(sol_list)
sc3.print('CSVファイルを生成しました。\n')
sc3.print('********ポスト処理を終了します。*******************\n')
#Main rountine
post_main()
プリ・ポスト共GUI集合情報を元に記述できるので便利です。大半の情報は、既にGUIで記述済みですので、記述量が少なくて済みます。
実装では、pythonのソース解析が必要かなと一瞬思いましたが、Pythonの単純な文法構造のおかげで、Bisonを用いての真面目な処理は、行っていません。
以上の実装後の、ログは次のようになりました。
コンパイルの準備中ソルバを呼び出し中です。
Python ファイルを生成中です。
Python プロパティファイルの生成が終わりました。
制約をコンパイル中です。
スタッフ1 勤務日数を制約します。
最大=44 最小=44
スタッフ2 勤務日数を制約します。
最大=44 最小=44
スタッフ3 勤務日数を制約します。
最大=29 最小=26
スタッフ4 勤務日数を制約します。
最大=29 最小=27
スタッフ1 有給日数を制約します。
最大=4 最小=0
スタッフ2 有給日数を制約します。
最大=4 最小=4
スタッフ3 有給日数を制約します。
最大=2 最小=0
スタッフ4 有給日数を制約します。
最大=2 最小=0
スタッフ1 週あたりの勤務日数を制約します。
スタッフ2 週あたりの勤務日数を制約します。
スタッフ3 週あたりの勤務日数を制約します。
最大=8 最小=6
日曜日=5
日曜日=12
日曜日=19
日曜日=26
日曜日=33
3に目標値最大を設定しました。
2に目標値最最小を設定しました。
スタッフ4 週あたりの勤務日数を制約します。
最大=8 最小=6
日曜日=5
日曜日=12
日曜日=19
日曜日=26
日曜日=33
3に目標値最大を設定しました。
2に目標値最最小を設定しました。
Algorithm 1 Solving Process Started..
o 9920 0.964000(sec)
o 8930 0.970000(sec)
o 6780 0.987000(sec)
o 5770 0.999000(sec)
o 2780 1.010000(sec)
o 1780 1.018000(sec)
o 630 1.085000(sec)
o 580 3.105000(sec)
o 530 3.157000(sec)
o 520 4.958000(sec)
充足解を書き込みました。
139612[KB] used.
5.729000(sec)
Python ファイルを生成中です。
Python プロパティファイルの生成が終わりました。
_____________________________________
| | | |
| Weight | Errors | Cost |
|___________|___________|_____________|
| | | |
| 1000 | 0 | 0 |
| 100 | 0 | 0 |
| 50 | 9 | 450 |
| 10 | 7 | 70 |
|___________|___________|_____________|
| | |
| Total | 520 |
|_______________________|_____________|
o 520(0)
*********ポスト処理を実行中です。*************
CSVファイルを生成中です。
CSVファイルを生成しました。
********ポスト処理を終了します。*******************
解探索が終了しました。 7 (秒)
解が得られました。
良くあるエラーは、次です、<string>
(434)ダブルクリックして次の表示となります。アクセス拒否されたので、Excelを終了させて再試行してください。