Pythonによるポスト処理  
   -制約記述の検証

めでたく、解が出たとしても、それを目視でチェックするのは、時としてつらいものがあります。
また、様式9 等のExcelファイルに、独自の集計結果を直接書き込みたい場合もあるでしょう。

そのような目的に有効な手段としてPythonによるポスト処理があります。

Pythonは、軽量スクリプトといった類の言語です。Pythonは、フリーで使える処理系です。入門やサンプルコードを解説しているサイトが沢山ありますので、文法や、インストールの仕方については、そちらを参照してください。

1. GUI と Pythonの関係


制約を満たす解を見つけるのは、制約ソルバ(求解エンジン)の仕事です。制約ソルバの出力は、制約を満たす解です。 
外部制約ファイルがある場合、同時にプロジェクトファイル名.pyというPythonのソースを、ソルバは、プロジェクトフォルダに出力します。

<制限事項>
この機能は、PC版のみの機能です。(外部サーバ/匠シフタでは出力されません。)
また、GUIは、外部制約ファイルの中身に関して関知しません。(GUI上で制約の行または列の項目としては出力することが出来ません。)
 



2. Pythonの検証ソースコードを出力する

Pythonのソースコードを出力するには、制約ステートメントにラベルを付けます。前章の例でやってみましょう。

制約ステートメントの前に、適当な名前 ここでは、”ハード制約”を追加します。

for (スキル in スキルclass){//職能毎に
	for (人 in スキル){//そのスキルに属する人について
		vector V週;
		for (週 in 週class){//週ごとに
			vector V;
			for(day in 週){
				if (day in 休診日){
					V.push_back(X[人][day][S]);//■■<---こちらから追加	
				}
			}
			V週.push_back($Or(V));//一つでも休日深夜勤務がある
		
			if (V週.size()>=3){//3週溜ったら
				V週.pop_front();// こちらから<---■■■
			}
			if (V週.size()==2){//2週溜れば今月なので
			
				ハード制約:$Inv($And(V週));//制約してよい。2週連続の休日深夜勤務禁止
			}
		}
	}
}

その上で求解すると、プロジェクトフォルダ上に以下のようなpythonの検証ソースコードが出力されます。(解の記述は長くなるので割愛しています。)

#staffdef
staffdef=['夜勤なし型スタッフ0','夜勤なし型スタッフ1','3交代深準型スタッフ2','3交代深準型スタッフ3','3交代深準型スタッフ4','3交代深準型スタッフ5','3交代深準型スタッフ6','3交代深準型スタッフ7','3交代深準型スタッフ8','3交代深準型スタッフ9','3交代深準型スタッフ10','3交代深準型スタッフ11','3交代深準型スタッフ12','3交代深準型スタッフ13','3交代深準型スタッフ14','3交代深準型スタッフ15','3交代深準型スタッフ16','3交代深準型スタッフ17','3交代深準型スタッフ18','3交代深準型スタッフ19','3交代深準型スタッフ20','3交代深準型スタッフ21','3交代深準型スタッフ22','3交代深準型スタッフ23','3交代深準型スタッフ24','3交代深準型スタッフ25']
#daydef
スケジュール開始日=7
スケジュール終了日=37
表示スタート日=0
daydef=['2014年7月25日','2014年7月26日','2014年7月27日','2014年7月28日','2014年7月29日','2014年7月30日','2014年7月31日','2014年8月1日','2014年8月2日','2014年8月3日','2014年8月4日','2014年8月5日','2014年8月6日','2014年8月7日','2014年8月8日','2014年8月9日','2014年8月10日','2014年8月11日','2014年8月12日','2014年8月13日','2014年8月14日','2014年8月15日','2014年8月16日','2014年8月17日','2014年8月18日','2014年8月19日','2014年8月20日','2014年8月21日','2014年8月22日','2014年8月23日','2014年8月24日','2014年8月25日','2014年8月26日','2014年8月27日','2014年8月28日','2014年8月29日','2014年8月30日','2014年8月31日']
#shiftdef
N=0
J=1
S=2
Y=3
H=4

#staffcollection
ベテラン=[3,6,9,12,15,18,21,24]
中堅=[4,7,10,13,16,19,22,25]
若手=[2,5,8,11,14,17,20,23]
中ベ=[4,7,10,13,16,19,22,25,2,5,8,11,14,17,20,23]

#daycollection
月=[3,10,17,24,31]
火=[4,11,18,25,32]
水=[5,12,19,26,33]
木=[6,13,20,27,34]
金=[0,7,14,21,28,35]
土=[1,8,15,22,29,36]
日=[2,9,16,23,30,37]
先月週=[0,1,2,3,4,5,6]
第1週=[7,8,9,10,11,12,13]
第2週=[14,15,16,17,18,19,20]
第3週=[21,22,23,24,25,26,27]
第4週=[28,29,30,31,32,33,34]
第5週=[35,36,37]
平日=[0,3,4,5,6,7,10,11,12,13,14,17,18,19,20,21,24,25,26,27,28,31,32,33,34,35]
週末=[1,2,8,9,15,16,22,23,29,30,36,37]
休診日=[1,2,8,9,15,16,22,23,29,30,36,37]
全日=[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,36,37]
診療日=[0,3,4,5,6,7,10,11,12,13,14,17,18,19,20,21,24,25,26,27,28,31,32,33,34,35]
祝日でない=[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,36,37]
祝日でない土曜日=[1,8,15,22,29,36]
それ以外の休診日=[2,9,16,23,30,37]
スケジュール日=[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]
土曜以外=[0,2,3,4,5,6,7,9,10,11,12,13,14,16,17,18,19,20,21,23,24,25,26,27,28,30,31,32,33,34,35,37]
土曜以外の休診日=[2,9,16,23,30,37]
金土日以外=[3,4,5,6,10,11,12,13,17,18,19,20,24,25,26,27,31,32,33,34]

#shiftcollection
a=[2,1]
x=[3,4]
z=[3,4]
m=[0]
o=[0]

#classcollection
週class=[先月週,第1週,第2週,第3週,第4週,第5週]
スキルclass=[ベテラン,中堅,若手]

def And(*a):
	b=True;
	for x in a:
		b = b and x
	return b
	
def Or(*a):
	b=False;
	for x in a:
		b = b or x
	return b

def Inv(a):
	return not a

def TrueCount(*a):
	b=0;
	for x in a:
		if (x) :
			b=b+1
	return b	
def Assert(a):
	if (a):
		print('Pass.')
	else:
		print('NG.')
		sys.exit()

def AssertLE(min,max,a):
	if (a>=min and a<=max):
		print('Pass.')
	else:
		print('NG.')
		sys.exit()

def VectorOr(V):
	b=False
	for v in V:
		b=b or v
	return b

def VectorAnd(V):
	b=True
	for v in V:
		b=b and v
	return b
	return str;

def check_hard_constraint_ハード制約(X):
	print('Checking ハード制約')
#ハード制約_0
	Assert(Inv(And(Or(X[3][1][2],X[3][2][2]),Or(X[3][8][2],X[3][9][2]))))
#ハード制約_1
	Assert(Inv(And(Or(X[3][8][2],X[3][9][2]),Or(X[3][15][2],X[3][16][2]))))
#ハード制約_2
	Assert(Inv(And(Or(X[3][15][2],X[3][16][2]),Or(X[3][22][2],X[3][23][2]))))
#ハード制約_3
	Assert(Inv(And(Or(X[3][22][2],X[3][23][2]),Or(X[3][29][2],X[3][30][2]))))
#ハード制約_4
	Assert(Inv(And(Or(X[3][29][2],X[3][30][2]),Or(X[3][36][2],X[3][37][2]))))
#ハード制約_5
	Assert(Inv(And(Or(X[6][1][2],X[6][2][2]),Or(X[6][8][2],X[6][9][2]))))
#ハード制約_6
	Assert(Inv(And(Or(X[6][8][2],X[6][9][2]),Or(X[6][15][2],X[6][16][2]))))
#ハード制約_7
	Assert(Inv(And(Or(X[6][15][2],X[6][16][2]),Or(X[6][22][2],X[6][23][2]))))
#ハード制約_8
	Assert(Inv(And(Or(X[6][22][2],X[6][23][2]),Or(X[6][29][2],X[6][30][2]))))
#ハード制約_9
	Assert(Inv(And(Or(X[6][29][2],X[6][30][2]),Or(X[6][36][2],X[6][37][2]))))
#ハード制約_10
	Assert(Inv(And(Or(X[9][1][2],X[9][2][2]),Or(X[9][8][2],X[9][9][2]))))
#ハード制約_11
	Assert(Inv(And(Or(X[9][8][2],X[9][9][2]),Or(X[9][15][2],X[9][16][2]))))
#ハード制約_12
	Assert(Inv(And(Or(X[9][15][2],X[9][16][2]),Or(X[9][22][2],X[9][23][2]))))
#ハード制約_13
	Assert(Inv(And(Or(X[9][22][2],X[9][23][2]),Or(X[9][29][2],X[9][30][2]))))
#ハード制約_14
	Assert(Inv(And(Or(X[9][29][2],X[9][30][2]),Or(X[9][36][2],X[9][37][2]))))
#ハード制約_15
	Assert(Inv(And(Or(X[12][1][2],X[12][2][2]),Or(X[12][8][2],X[12][9][2]))))
#ハード制約_16
	Assert(Inv(And(Or(X[12][8][2],X[12][9][2]),Or(X[12][15][2],X[12][16][2]))))
#ハード制約_17
	Assert(Inv(And(Or(X[12][15][2],X[12][16][2]),Or(X[12][22][2],X[12][23][2]))))
#ハード制約_18
	Assert(Inv(And(Or(X[12][22][2],X[12][23][2]),Or(X[12][29][2],X[12][30][2]))))
#ハード制約_19
	Assert(Inv(And(Or(X[12][29][2],X[12][30][2]),Or(X[12][36][2],X[12][37][2]))))
#ハード制約_20
	Assert(Inv(And(Or(X[15][1][2],X[15][2][2]),Or(X[15][8][2],X[15][9][2]))))
#ハード制約_21
	Assert(Inv(And(Or(X[15][8][2],X[15][9][2]),Or(X[15][15][2],X[15][16][2]))))
#ハード制約_22
	Assert(Inv(And(Or(X[15][15][2],X[15][16][2]),Or(X[15][22][2],X[15][23][2]))))
#ハード制約_23
	Assert(Inv(And(Or(X[15][22][2],X[15][23][2]),Or(X[15][29][2],X[15][30][2]))))
#ハード制約_24
	Assert(Inv(And(Or(X[15][29][2],X[15][30][2]),Or(X[15][36][2],X[15][37][2]))))
#ハード制約_25
	Assert(Inv(And(Or(X[18][1][2],X[18][2][2]),Or(X[18][8][2],X[18][9][2]))))
#ハード制約_26
	Assert(Inv(And(Or(X[18][8][2],X[18][9][2]),Or(X[18][15][2],X[18][16][2]))))
#ハード制約_27
	Assert(Inv(And(Or(X[18][15][2],X[18][16][2]),Or(X[18][22][2],X[18][23][2]))))
#ハード制約_28
	Assert(Inv(And(Or(X[18][22][2],X[18][23][2]),Or(X[18][29][2],X[18][30][2]))))
#ハード制約_29
	Assert(Inv(And(Or(X[18][29][2],X[18][30][2]),Or(X[18][36][2],X[18][37][2]))))
#ハード制約_30
	Assert(Inv(And(Or(X[21][1][2],X[21][2][2]),Or(X[21][8][2],X[21][9][2]))))
#ハード制約_31
	Assert(Inv(And(Or(X[21][8][2],X[21][9][2]),Or(X[21][15][2],X[21][16][2]))))
#ハード制約_32
	Assert(Inv(And(Or(X[21][15][2],X[21][16][2]),Or(X[21][22][2],X[21][23][2]))))
#ハード制約_33
	Assert(Inv(And(Or(X[21][22][2],X[21][23][2]),Or(X[21][29][2],X[21][30][2]))))
#ハード制約_34
	Assert(Inv(And(Or(X[21][29][2],X[21][30][2]),Or(X[21][36][2],X[21][37][2]))))
#ハード制約_35
	Assert(Inv(And(Or(X[24][1][2],X[24][2][2]),Or(X[24][8][2],X[24][9][2]))))
#ハード制約_36
	Assert(Inv(And(Or(X[24][8][2],X[24][9][2]),Or(X[24][15][2],X[24][16][2]))))
#ハード制約_37
	Assert(Inv(And(Or(X[24][15][2],X[24][16][2]),Or(X[24][22][2],X[24][23][2]))))
#ハード制約_38
	Assert(Inv(And(Or(X[24][22][2],X[24][23][2]),Or(X[24][29][2],X[24][30][2]))))
#ハード制約_39
	Assert(Inv(And(Or(X[24][29][2],X[24][30][2]),Or(X[24][36][2],X[24][37][2]))))
#ハード制約_40
	Assert(Inv(And(Or(X[4][1][2],X[4][2][2]),Or(X[4][8][2],X[4][9][2]))))
#ハード制約_41
	Assert(Inv(And(Or(X[4][8][2],X[4][9][2]),Or(X[4][15][2],X[4][16][2]))))
#ハード制約_42
	Assert(Inv(And(Or(X[4][15][2],X[4][16][2]),Or(X[4][22][2],X[4][23][2]))))
#ハード制約_43
	Assert(Inv(And(Or(X[4][22][2],X[4][23][2]),Or(X[4][29][2],X[4][30][2]))))
#ハード制約_44
	Assert(Inv(And(Or(X[4][29][2],X[4][30][2]),Or(X[4][36][2],X[4][37][2]))))
#ハード制約_45
	Assert(Inv(And(Or(X[7][1][2],X[7][2][2]),Or(X[7][8][2],X[7][9][2]))))
#ハード制約_46
	Assert(Inv(And(Or(X[7][8][2],X[7][9][2]),Or(X[7][15][2],X[7][16][2]))))
#ハード制約_47
	Assert(Inv(And(Or(X[7][15][2],X[7][16][2]),Or(X[7][22][2],X[7][23][2]))))
#ハード制約_48
	Assert(Inv(And(Or(X[7][22][2],X[7][23][2]),Or(X[7][29][2],X[7][30][2]))))
#ハード制約_49
	Assert(Inv(And(Or(X[7][29][2],X[7][30][2]),Or(X[7][36][2],X[7][37][2]))))
#ハード制約_50
	Assert(Inv(And(Or(X[10][1][2],X[10][2][2]),Or(X[10][8][2],X[10][9][2]))))
#ハード制約_51
	Assert(Inv(And(Or(X[10][8][2],X[10][9][2]),Or(X[10][15][2],X[10][16][2]))))
#ハード制約_52
	Assert(Inv(And(Or(X[10][15][2],X[10][16][2]),Or(X[10][22][2],X[10][23][2]))))
#ハード制約_53
	Assert(Inv(And(Or(X[10][22][2],X[10][23][2]),Or(X[10][29][2],X[10][30][2]))))
#ハード制約_54
	Assert(Inv(And(Or(X[10][29][2],X[10][30][2]),Or(X[10][36][2],X[10][37][2]))))
#ハード制約_55
	Assert(Inv(And(Or(X[13][1][2],X[13][2][2]),Or(X[13][8][2],X[13][9][2]))))
#ハード制約_56
	Assert(Inv(And(Or(X[13][8][2],X[13][9][2]),Or(X[13][15][2],X[13][16][2]))))
#ハード制約_57
	Assert(Inv(And(Or(X[13][15][2],X[13][16][2]),Or(X[13][22][2],X[13][23][2]))))
#ハード制約_58
	Assert(Inv(And(Or(X[13][22][2],X[13][23][2]),Or(X[13][29][2],X[13][30][2]))))
#ハード制約_59
	Assert(Inv(And(Or(X[13][29][2],X[13][30][2]),Or(X[13][36][2],X[13][37][2]))))
#ハード制約_60
	Assert(Inv(And(Or(X[16][1][2],X[16][2][2]),Or(X[16][8][2],X[16][9][2]))))
#ハード制約_61
	Assert(Inv(And(Or(X[16][8][2],X[16][9][2]),Or(X[16][15][2],X[16][16][2]))))
#ハード制約_62
	Assert(Inv(And(Or(X[16][15][2],X[16][16][2]),Or(X[16][22][2],X[16][23][2]))))
#ハード制約_63
	Assert(Inv(And(Or(X[16][22][2],X[16][23][2]),Or(X[16][29][2],X[16][30][2]))))
#ハード制約_64
	Assert(Inv(And(Or(X[16][29][2],X[16][30][2]),Or(X[16][36][2],X[16][37][2]))))
#ハード制約_65
	Assert(Inv(And(Or(X[19][1][2],X[19][2][2]),Or(X[19][8][2],X[19][9][2]))))
#ハード制約_66
	Assert(Inv(And(Or(X[19][8][2],X[19][9][2]),Or(X[19][15][2],X[19][16][2]))))
#ハード制約_67
	Assert(Inv(And(Or(X[19][15][2],X[19][16][2]),Or(X[19][22][2],X[19][23][2]))))
#ハード制約_68
	Assert(Inv(And(Or(X[19][22][2],X[19][23][2]),Or(X[19][29][2],X[19][30][2]))))
#ハード制約_69
	Assert(Inv(And(Or(X[19][29][2],X[19][30][2]),Or(X[19][36][2],X[19][37][2]))))
#ハード制約_70
	Assert(Inv(And(Or(X[22][1][2],X[22][2][2]),Or(X[22][8][2],X[22][9][2]))))
#ハード制約_71
	Assert(Inv(And(Or(X[22][8][2],X[22][9][2]),Or(X[22][15][2],X[22][16][2]))))
#ハード制約_72
	Assert(Inv(And(Or(X[22][15][2],X[22][16][2]),Or(X[22][22][2],X[22][23][2]))))
#ハード制約_73
	Assert(Inv(And(Or(X[22][22][2],X[22][23][2]),Or(X[22][29][2],X[22][30][2]))))
#ハード制約_74
	Assert(Inv(And(Or(X[22][29][2],X[22][30][2]),Or(X[22][36][2],X[22][37][2]))))
#ハード制約_75
	Assert(Inv(And(Or(X[25][1][2],X[25][2][2]),Or(X[25][8][2],X[25][9][2]))))
#ハード制約_76
	Assert(Inv(And(Or(X[25][8][2],X[25][9][2]),Or(X[25][15][2],X[25][16][2]))))
#ハード制約_77
	Assert(Inv(And(Or(X[25][15][2],X[25][16][2]),Or(X[25][22][2],X[25][23][2]))))
#ハード制約_78
	Assert(Inv(And(Or(X[25][22][2],X[25][23][2]),Or(X[25][29][2],X[25][30][2]))))
#ハード制約_79
	Assert(Inv(And(Or(X[25][29][2],X[25][30][2]),Or(X[25][36][2],X[25][37][2]))))
#ハード制約_80
	Assert(Inv(And(Or(X[2][1][2],X[2][2][2]),Or(X[2][8][2],X[2][9][2]))))
#ハード制約_81
	Assert(Inv(And(Or(X[2][8][2],X[2][9][2]),Or(X[2][15][2],X[2][16][2]))))
#ハード制約_82
	Assert(Inv(And(Or(X[2][15][2],X[2][16][2]),Or(X[2][22][2],X[2][23][2]))))
#ハード制約_83
	Assert(Inv(And(Or(X[2][22][2],X[2][23][2]),Or(X[2][29][2],X[2][30][2]))))
#ハード制約_84
	Assert(Inv(And(Or(X[2][29][2],X[2][30][2]),Or(X[2][36][2],X[2][37][2]))))
#ハード制約_85
	Assert(Inv(And(Or(X[5][1][2],X[5][2][2]),Or(X[5][8][2],X[5][9][2]))))
#ハード制約_86
	Assert(Inv(And(Or(X[5][8][2],X[5][9][2]),Or(X[5][15][2],X[5][16][2]))))
#ハード制約_87
	Assert(Inv(And(Or(X[5][15][2],X[5][16][2]),Or(X[5][22][2],X[5][23][2]))))
#ハード制約_88
	Assert(Inv(And(Or(X[5][22][2],X[5][23][2]),Or(X[5][29][2],X[5][30][2]))))
#ハード制約_89
	Assert(Inv(And(Or(X[5][29][2],X[5][30][2]),Or(X[5][36][2],X[5][37][2]))))
#ハード制約_90
	Assert(Inv(And(Or(X[8][1][2],X[8][2][2]),Or(X[8][8][2],X[8][9][2]))))
#ハード制約_91
	Assert(Inv(And(Or(X[8][8][2],X[8][9][2]),Or(X[8][15][2],X[8][16][2]))))
#ハード制約_92
	Assert(Inv(And(Or(X[8][15][2],X[8][16][2]),Or(X[8][22][2],X[8][23][2]))))
#ハード制約_93
	Assert(Inv(And(Or(X[8][22][2],X[8][23][2]),Or(X[8][29][2],X[8][30][2]))))
#ハード制約_94
	Assert(Inv(And(Or(X[8][29][2],X[8][30][2]),Or(X[8][36][2],X[8][37][2]))))
#ハード制約_95
	Assert(Inv(And(Or(X[11][1][2],X[11][2][2]),Or(X[11][8][2],X[11][9][2]))))
#ハード制約_96
	Assert(Inv(And(Or(X[11][8][2],X[11][9][2]),Or(X[11][15][2],X[11][16][2]))))
#ハード制約_97
	Assert(Inv(And(Or(X[11][15][2],X[11][16][2]),Or(X[11][22][2],X[11][23][2]))))
#ハード制約_98
	Assert(Inv(And(Or(X[11][22][2],X[11][23][2]),Or(X[11][29][2],X[11][30][2]))))
#ハード制約_99
	Assert(Inv(And(Or(X[11][29][2],X[11][30][2]),Or(X[11][36][2],X[11][37][2]))))
#ハード制約_100
	Assert(Inv(And(Or(X[14][1][2],X[14][2][2]),Or(X[14][8][2],X[14][9][2]))))
#ハード制約_101
	Assert(Inv(And(Or(X[14][8][2],X[14][9][2]),Or(X[14][15][2],X[14][16][2]))))
#ハード制約_102
	Assert(Inv(And(Or(X[14][15][2],X[14][16][2]),Or(X[14][22][2],X[14][23][2]))))
#ハード制約_103
	Assert(Inv(And(Or(X[14][22][2],X[14][23][2]),Or(X[14][29][2],X[14][30][2]))))
#ハード制約_104
	Assert(Inv(And(Or(X[14][29][2],X[14][30][2]),Or(X[14][36][2],X[14][37][2]))))
#ハード制約_105
	Assert(Inv(And(Or(X[17][1][2],X[17][2][2]),Or(X[17][8][2],X[17][9][2]))))
#ハード制約_106
	Assert(Inv(And(Or(X[17][8][2],X[17][9][2]),Or(X[17][15][2],X[17][16][2]))))
#ハード制約_107
	Assert(Inv(And(Or(X[17][15][2],X[17][16][2]),Or(X[17][22][2],X[17][23][2]))))
#ハード制約_108
	Assert(Inv(And(Or(X[17][22][2],X[17][23][2]),Or(X[17][29][2],X[17][30][2]))))
#ハード制約_109
	Assert(Inv(And(Or(X[17][29][2],X[17][30][2]),Or(X[17][36][2],X[17][37][2]))))
#ハード制約_110
	Assert(Inv(And(Or(X[20][1][2],X[20][2][2]),Or(X[20][8][2],X[20][9][2]))))
#ハード制約_111
	Assert(Inv(And(Or(X[20][8][2],X[20][9][2]),Or(X[20][15][2],X[20][16][2]))))
#ハード制約_112
	Assert(Inv(And(Or(X[20][15][2],X[20][16][2]),Or(X[20][22][2],X[20][23][2]))))
#ハード制約_113
	Assert(Inv(And(Or(X[20][22][2],X[20][23][2]),Or(X[20][29][2],X[20][30][2]))))
#ハード制約_114
	Assert(Inv(And(Or(X[20][29][2],X[20][30][2]),Or(X[20][36][2],X[20][37][2]))))
#ハード制約_115
	Assert(Inv(And(Or(X[23][1][2],X[23][2][2]),Or(X[23][8][2],X[23][9][2]))))
#ハード制約_116
	Assert(Inv(And(Or(X[23][8][2],X[23][9][2]),Or(X[23][15][2],X[23][16][2]))))
#ハード制約_117
	Assert(Inv(And(Or(X[23][15][2],X[23][16][2]),Or(X[23][22][2],X[23][23][2]))))
#ハード制約_118
	Assert(Inv(And(Or(X[23][22][2],X[23][23][2]),Or(X[23][29][2],X[23][30][2]))))
#ハード制約_119
	Assert(Inv(And(Or(X[23][29][2],X[23][30][2]),Or(X[23][36][2],X[23][37][2]))))

def check_all_constraints():
	X=Sol0
	check_hard_constraint_ハード制約(X)
#Main routine
check_all_constraints()

このコードは、自動検証コードになっており、走らせると、結果が出力されます。
この例では、交代3X2.nurseというプロジェクトファイルですので、交代3x2.pyというPythonのソースコード名になります。
cygwin64上で走らせてみると、以下のようになります。Pythonは、3.xx以上を使用してください。


$ python3 交代3X2.py
Checking ハード制約
Pass.
Pass.
Pass.
Pass.
Pass.
Pass.
...

求解後に解があれば、NGと言ってくることは決して無いはずです。というのは、このコードは、ソルバが認識したところの制約をPythonに落としただけだからです。要するにソルバ自体の検証コードに過ぎないのです。それでは、役にたたないのでは? と思われるかもしれませんが、決してそうではありません。

第一に検証コード自体を見てください。Assert()の中身が制約文そのものになっています。上の交代3X2.txt では、僅かに1行に過ぎませんでしたが、展開されて全体では、120個の制約になっているということです。Assertという文は、単に解から得た論理値がTrueであることを確認しているだけのコードになっています。その記述は、あなたが書いたところの制約を正確に反映しています。機械が書いたコードは大変読みにくいのですが、頑張って読むと結局自分が書いたコードそのものになっているはずです。ですから、Assertの中身を眺めて、そんな風に記述したつもりはない! という箇所がないか見て下さい というのが第一のポイントです。

第二に、Pythonソースコードを見てください。GUIで定義した集合が全て載っています。これらはPythonで直接に扱えます!Excelやら他のマクロ言語やスクリプトを使うよりもずっど便利であることがすぐにご理解頂けると思います。

3. Pythonで検証コードを書く

Pythonで、上記解の検証を行ってみましょう。

ソルバが出力したソースコードは、新しく求解すると上書きされてしまうので、検証コードは、別なファイルに書き、上記ソースコードは全てimportしてしまいます。
こうすると、上記コードの関数や、定義は全てそのまま使うことが出来ます。(短所はその裏返しですが、使っている変数名は使えなくなってしまうことです。)


最初は、ソルバが出力したpython ファイルを交代3X2.py をインポートします。チェック関数を定義したあと、解の配列Sol0をXに代入します。
関数は、グローバル配列Xを前提に書かれているためです。(2番目の解を使う場合には、X=Sol1 としてください。)
 
チェック関数を見て、制約ファイルに似ていることに気づかれたでしょうか? appendが push_backだったり、pop(0)がpop_backだったり、あるいは、len() が.size()だったりしますが、基本的には、同じ構成になっています。もともと制約するというのは、ルールを書くことですから、制約式とチェックする関数の構成が同じになるのは不思議ではありません。

Ana3交代X2.pyというファイル名にて次のように記述しました。(インポートするファイル名の最初が数字だとエラーになってしまったのでファイル名を変更しました。)

from 交代3X2 import *

def 週連続休日夜勤不可():
	print ("	週連続休日夜勤不可		をチェック中です。")
	for スキル in スキルclass:#/職能毎に
		for 人 in スキル:#そのスキルに属する人について
	
			V週=[];#週間コンテナ
			for 週 in 週class:
				V=[];#週のコンテナ
				for day in 週:
					if day in 休診日 :
						V.append(X[人][day][S]);	
					
		
				V週.append(VectorOr(V));

				if ( len(V週)>=3):
					V週.pop(0);
		
				if ( len(V週)==2):
					if(VectorAnd(V週)):
						print(staffdef[人],週, "Warning: 2週連続休日夜勤があります。")

	print("	週連続休日夜勤不可		をチェック終了しました。")

X=Sol0 #解1をXに入れる
週連続休日夜勤不可() #Call チェック

週classや、スキルclass,休診日、等は元々GUIで定義したものですが、すべて交代3x2.pyというソルバが出力したコード内に定義されています。その他の関数も同じファイル内で定義しています。


cygwin64上で次のようにRUNすると以下のようにエラーなしで終了しました。


$ python3 Ana3交代X2.py
...
Pass.
Pass.
        週連続休日夜勤不可              をチェック中です。
        週連続休日夜勤不可              をチェック終了しました。

これでチェック完了なのですが、このままでは、本当にチェックしているのか不安です。試しに
制約ファイルの制約部をコメントアウトして走らせます

	//ハード制約:$Inv($And(V週));//制約してよい。2週連続の休日深夜勤務禁止

求解した後、再びcygwin64上で走らせると

$ python3 Ana3交代X2.py
確かに、次のようなエラーが発生しました。
$ python3 Ana交代3X2.py
        週連続休日夜勤不可              をチェック中です。
3交代深準型スタッフ12 [28, 29, 30, 31, 32, 33, 34] Warning: 2週連続休日夜勤があります。
3交代深準型スタッフ13 [14, 15, 16, 17, 18, 19, 20] Warning: 2週連続休日夜勤があります。
3交代深準型スタッフ16 [7, 8, 9, 10, 11, 12, 13] Warning: 2週連続休日夜勤があります。
3交代深準型スタッフ16 [35, 36, 37] Warning: 2週連続休日夜勤があります。
3交代深準型スタッフ2 [35, 36, 37] Warning: 2週連続休日夜勤があります。
3交代深準型スタッフ8 [21, 22, 23, 24, 25, 26, 27] Warning: 2週連続休日夜勤があります。
        週連続休日夜勤不可              をチェック終了しました。
上の指摘の箇所をGUIでチェックすると確かに、指摘通りの2週連続休日夜勤の箇所がありました。

以上の試行から、上記チェック関数は確かに動作していると考えます。

このようにして、python を使うことにより、少ない行数でスマートに制約をチェックすることができます


[Prev] [Next] [Index] [Home]