def main(): # BookingFile = "book/exp.csv" BookingFile = args[1] HoldFile = "data/hold.csv" MainLampFile = "data/mainlamp.csv" BackMainLampFile = "data/back_mainlamp.csv" AfrMainLampFile = "data/afr_mainlamp.csv" # AfrMainLampFile = "data/new_road_restriction.csv" StressFile = "data/stress_mainlamp.csv" Gang2File = "data/gangnum_2.csv" Gang3File = "data/gangnum_3.csv" print("File:" + BookingFile) booking_name = BookingFile.split("/")[1].split(".")[0] # 注文情報の読み込み T, L, D, J, U, A, G, J_small, J_medium, J_large, Port, Check_port, Booking, divide_dic\ = read_booking.Read_booking(BookingFile) # 船体情報の読み込み1 I, B, I_pair, I_next, I_same, I_lamp, I_deck, RT_benefit, delta_s, min_s, max_s, delta_h, max_h, Hold_encode, Hold\ = read_hold.Read_hold(HoldFile) # 船体情報の読み込み2 Ml_Load, Ml_Back, Ml_Afr, Stress, GANG2, GANG3\ = read_other.Read_other(MainLampFile, BackMainLampFile, AfrMainLampFile, StressFile, Gang2File, Gang3File, Hold_encode) J_t_load = [] # J_t_load:港tで積む注文の集合 J_t_keep = [] # J_t_keep:港tを通過する注文の集合 J_t_dis = [] # J_t_dis:港tで降ろす注文の集合 J_lk = [] # J_lk:J_t_load + J_t_keep J_ld = [] # J_ld:J_t_load + J_t_dis for t in T: J_load = [] J_keep = [] J_dis = [] lk = [] ld = [] tmp_load = list(Port.iloc[:, 0]) tmp_dis = list(Port.iloc[:, 1]) N = len(J) k = 0 for i in L: if k < i: k = i count = 0 for t_l in tmp_load: if t == t_l: J_load.append(count) lk.append(count) ld.append(count) count = count + 1 count = 0 for t_d in tmp_dis: if t == t_d: J_dis.append(count) ld.append(count) count = count + 1 for t_k in range(N): if t > tmp_load[t_k] and t < tmp_dis[t_k]: J_keep.append(J[t_k]) lk.append(t_k) J_t_load.append(J_load) J_t_keep.append(J_keep) J_t_dis.append(J_dis) J_lk.append(lk) J_ld.append(ld) # モデリング1(定数・変数の設定) # ============================================================================================== # Gurobiパラメータ設定 GAP_SP = gp.Model() GAP_SP.setParam("TimeLimit", 3600) GAP_SP.setParam("MIPFocus", 1) GAP_SP.setParam("LPMethod", 1) GAP_SP.printStats() # ハイパーパラメータ設定 # 各目的関数の重み w1 = 1 w2 = 1 w3 = 1 w4 = 1 w5 = 1 # 目的関数1のペナルティ penal1_z = 10 # 目的関数2のペナルティ penal2_load = 1 penal2_dis = 10 # 目的関数4のチェックポイント check_point = Check_port # 目的関数5のペナルティ penal5_k = 1000 # 最適化変数 # V_ij:注文jをホールドiにk(kはUnit数)台割り当てる # V_ij = {} # for i in I: # for j in J: # V_ij[i, j] = GAP_SP.addVar( # lb=0, ub=U[j], vtype=gp.GRB.INTEGER, name=f"V_ij({i},{j})") V_ij = np.zeros((len(I), len(J)), dtype=np.int) # 目的関数1 # X_ij:注文jをホールドiに割り当てるなら1、そうでなければ0 # X_ij = GAP_SP.addVars(I, J, vtype=gp.GRB.BINARY) X_ij = np.zeros((len(I), len(J)), dtype=np.int) # Y_keep_it:港tにおいてホールドiを通過する注文があるなら1、そうでなければ0 # Y_keep_it = GAP_SP.addVars(I, T, vtype=gp.GRB.BINARY) Y_keep_it = np.zeros((len(I), len(T))) # Y_it1t2:ホールドiにおいてt1で積んでt2で降ろす注文があるなら1、そうでなければ0 # Y_it1t2 = GAP_SP.addVars(I, T, T, vtype=gp.GRB.BINARY) Y_it1t2 = np.zeros((len(I), len(T), len(T)), dtype=np.int) # Z_it1t2:ホールドiにおいてt2を通過する注文があるとき異なる乗せ港t1の数分のペナルティ # Z_it1t2 = GAP_SP.addVars(I, L, D, vtype=gp.GRB.BINARY) Z_it1t2 = np.zeros((len(I), len(L), len(D)), dtype=np.int) # OBJ1 = gp.quicksum( # w1 * penal1_z * Z_it1t2[i, t1, t2] for i in I for t1 in L for t2 in D) OBJ1 = np.sum(Z_it1t2) * w1 * penal1_z # 目的関数2 # Y_load_i1i2t:港tにおいてホールドペア(i1,i2)で積む注文があるなら1 # Y_load_i1i2t = GAP_SP.addVars(I, I, L, vtype=gp.GRB.BINARY) Y_load_i1i2t = np.zeros((len(I), len(I), len(L)), dtype=np.int) # Y_keep_i1i2t:港tにおいてホールドペア(i1,i2)を通過する注文があるなら1 # Y_keep_i1i2t = GAP_SP.addVars(I, I, T, vtype=gp.GRB.BINARY) Y_keep_i1i2t = np.zeros((len(I), len(I), len(T)), dtype=np.int) # Y_dis_i1i2t:港tにおいてホールドペア(i1,i2)で揚げる注文があるなら1 # Y_dis_i1i2t = GAP_SP.addVars(I, I, D, vtype=gp.GRB.BINARY) Y_dis_i1i2t = np.zeros((len(I), len(I), len(D)), dtype=np.int) # ホールドペア(i1,i2)においてtで注文を積む際に既にtで積んだ注文があるときのペナルティ # Z1_i1i2t = GAP_SP.addVars(I, I, L, vtype=gp.GRB.BINARY) Z1_i1i2t = np.zeros((len(I), len(I), len(L)), dtype=np.int) # ホールドペア(i1,i2)においてtで注文を揚げる際にtを通過する注文があるときのペナルティ # Z2_i1i2t = GAP_SP.addVars(I, I, D, vtype=gp.GRB.BINARY) Z2_i1i2t = np.zeros((len(I), len(I), len(D)), dtype=np.int) # OBJ2_1 = gp.quicksum( # penal2_load * Z1_i1i2t[i1, i2, t] for i1 in I for i2 in I for t in L) # OBJ2_2 = gp.quicksum( # penal2_dis * Z2_i1i2t[i1, i2, t] for i1 in I for i2 in I for t in D) OBJ2_1 = np.sum(Z1_i1i2t) * penal2_load OBJ2_2 = np.sum(Z2_i1i2t) * penal2_dis OBJ2 = w2 * (OBJ2_1 + OBJ2_2) # 目的関数3 # M_it:港tにおいてホールドiが作業効率充填率を超えたら1 # M_it = GAP_SP.addVars(I, T, vtype=gp.GRB.BINARY) M_it = np.zeros((len(I), len(T)), dtype=np.int) # M_ijt:港tにおいてホールドiに自動車を積むまでに作業効率充填率を上回ったホールドに自動車を通すペナルティ # M_ijt = GAP_SP.addVars(I, J, T, lb=0, vtype=gp.GRB.CONTINUOUS) M_ijt = np.zeros((len(I), len(J), len(T)), dtype=np.int) # OBJ3 = gp.quicksum(w3 * M_ijt[i, j, t] for i in I for j in J for t in T) OBJ3 = np.sum(M_ijt) * w3 # 目的関数4 残容量のやつ # N_jt:チェックポイントにおけるホールドiの残容量 # N_it = GAP_SP.addVars(I, check_point, lb=0, vtype=gp.GRB.CONTINUOUS) N_it = np.zeros((len(I)), dtype=np.int) # OBJ4 = gp.quicksum(w4 * N_it[i, t] * RT_benefit[i] # for i in I for t in check_point) OBJ4 = np.sum(N_it) * w4 # 目的関数5 デッドスペース,たぶん # K1_it:lampで繋がっている次ホールドが充填率75%を上回ったら1、そうでなければ0 # K1_it = GAP_SP.addVars(I_lamp, L, vtype=gp.GRB.BINARY) K1_it = np.zeros((len(I_lamp)), dtype=np.int) # K2_it:ホールドiが1RT以上のスペースがあったら1、そうでなければ0 # K2_it = GAP_SP.addVars(I, L, lb=0, vtype=gp.GRB.BINARY) K2_it = np.zeros((len(I), len(L)), dtype=np.int) # K3_it:目的関数5のペナルティ # K3_it = GAP_SP.addVars(I_lamp, L, lb=0, vtype=gp.GRB.CONTINUOUS) K3_it = np.zeros((len(I_lamp), len(L)), dtype=np.int) # OBJ5 = gp.quicksum(w5 * penal5_k * K3_it[i, t] for i in I_lamp for t in L) OBJ5 = np.sum(K3_it) * w5 * penal5_k # 目的関数の設計 OBJ = OBJ1 + OBJ2 + OBJ3 - OBJ4 + OBJ5 # GAP_SP.setObjective(OBJ, gp.GRB.MINIMIZE) # モデリング2(制約) # ============================================================================================== # 基本制約 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 割当てた注文がコンパートメント毎にリソースを超えない GAP_SP.addConstrs( gp.quicksum(V_ij[i, j] * A[j] for j in J) <= B[i] for i in I) # 全注文内の自動車の台数を全て割り当てる GAP_SP.addConstrs( gp.quicksum(V_ij[i, j] * X_ij[i, j] for i in I) == U[j] for j in J) # VとXの制約 GAP_SP.addConstrs(V_ij[i, j] / U[j] <= X_ij[i, j] for i in I for j in J) # 目的関数の制約 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 目的関数1の制約 for t in T: GAP_SP.addConstrs(X_ij[i, j] <= Y_keep_it[i, t] for i in I for j in J_t_keep[t]) for t in D: t2 = t for t1 in L: J_sub = [] # J_sub:t1で積んでt2で揚げる注文の集合 for j in J_t_dis[t2]: if j in J_t_load[t1]: J_sub.append(j) GAP_SP.addConstrs(X_ij[i, j] <= Y_it1t2[i, t1, t2] for i in I for j in J_sub) GAP_SP.addConstrs(Z_it1t2[i, t1, t2] <= Y_it1t2[i, t1, t2] for i in I) GAP_SP.addConstrs(Z_it1t2[i, t1, t2] <= Y_keep_it[i, t2] for i in I) GAP_SP.addConstrs( Z_it1t2[i, t1, t2] >= Y_it1t2[i, t1, t2] + Y_keep_it[i, t2] - 1 for i in I) # 目的関数2の制約 for t in T: for i1, i2 in I_pair: GAP_SP.addConstrs( X_ij[i1, j] + X_ij[i2, j] <= 2 * Y_keep_i1i2t[i1, i2, t] for j in J_t_keep[t]) if t in L: GAP_SP.addConstrs( X_ij[i1, j] + X_ij[i2, j] <= 2 * Y_load_i1i2t[i1, i2, t] for j in J_t_load[t]) GAP_SP.addConstr( Z1_i1i2t[i1, i2, t] <= Y_load_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z1_i1i2t[i1, i2, t] <= Y_keep_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z1_i1i2t[i1, i2, t] >= Y_load_i1i2t[i1, i2, t] + Y_keep_i1i2t[i1, i2, t] - 1) if t in D: GAP_SP.addConstrs( X_ij[i1, j] + X_ij[i2, j] <= 2 * Y_dis_i1i2t[i1, i2, t] for j in J_t_dis[t]) GAP_SP.addConstr(Z2_i1i2t[i1, i2, t] <= Y_dis_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z2_i1i2t[i1, i2, t] <= Y_keep_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z2_i1i2t[i1, i2, t] >= Y_dis_i1i2t[i1, i2, t] + Y_keep_i1i2t[i1, i2, t] - 1) # # 目的関数3の制約 for t in T: GAP_SP.addConstrs(M_it[i, t] >= -Stress[i] + (gp.quicksum(V_ij[i, j] * A[j] for j in J_t_keep[t]) / B[i]) for i in I) for i1 in I: I_primetmp = [] for k in Ml_Load.iloc[i1, :]: I_primetmp.append(k) I_prime = [x for x in I_primetmp if str(x) != 'nan'] I_prime.pop(0) GAP_SP.addConstrs( M_ijt[i1, j, t] >= V_ij[i1, j] * gp.quicksum(M_it[i2, t] for i2 in I_prime) for j in J_ld[t]) # 目的関数4の制約 残容量 for t in check_point: GAP_SP.addConstrs(N_it[i, t] <= B[i] - gp.quicksum(V_ij[i, j] * A[j] for j in J_lk[t]) for i in I) # 目的関数5の制約 デッドスペース GAP_SP.addConstrs( K1_it[i, t] >= -0.75 + gp.quicksum(V_ij[i, j] * A[j] for j in J_lk[t]) / B[i] for i in I_lamp for t in L) GAP_SP.addConstrs(K2_it[i, t] >= 1 - (gp.quicksum(V_ij[i, j] * A[j] for j in J_lk[t]) + 1) / B[i] for i in I for t in L) for i in range(len(Ml_Back)): i1 = Ml_Back.iloc[i, 0] I_backtmp = [] for k in Ml_Back.iloc[i, :]: I_backtmp.append(k) I_back_i1 = [x for x in I_backtmp if str(x) != 'nan'] I_back_i1.pop(0) GAP_SP.addConstrs(K3_it[i1, t] >= len(I) * (K1_it[i1, t] - 1) + gp.quicksum(K2_it[i2, t] for i2 in I_back_i1) for t in L) # 特殊制約1(注文の分割制約) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # J_small # 分割しない GAP_SP.addConstrs(gp.quicksum(X_ij[i, j] for i in I) == 1 for j in J_small) # J_medium GAP_SP.addConstrs( gp.quicksum(X_ij[i, j] for i in I) == 1 for j in J_medium) # J_large for k1 in range(len(I_deck)): for k2 in range(k1): GAP_SP.addConstrs( gp.quicksum(X_ij[i1, j] for i1 in I_deck[k1]) * gp.quicksum(X_ij[i2, j] for i2 in I_deck[k2]) <= 0 for j in J_large) # 特殊制約2(移動経路制約) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 港を通過する荷物が移動の邪魔をしない for t in T: # 港 for i1 in I: # ホールド I_primetmp = [] Frtmp = [] for k in Ml_Load.iloc[i1, :]: I_primetmp.append(k) for k in Ml_Afr.iloc[i1, :]: Frtmp.append(k) I_prime = [int(x) for x in I_primetmp if str(x) != 'nan'] Fr = [x for x in Frtmp if str(x) != 'nan'] I_prime.pop(0) Fr.pop(0) N_prime = len(I_prime) for k in range(N_prime): i2 = int(I_prime[k]) GAP_SP.addConstrs( gp.quicksum(V_ij[i2, j1] * A[j1] for j1 in J_t_keep[t]) / B[i2] <= 1 + Fr[k] - X_ij[i1, j2] for j2 in J_ld[t]) # 特殊制約3(船体重心の制約) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 船の上下前後の配置バランスが閾値を超えない for t in T: # 荷物を全て降ろしたとき GAP_SP.addConstr( gp.quicksum(delta_h[i] * G[j] * V_ij[i, j] for j in J_t_keep[t] for i in I) <= max_h) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_t_keep[t] for i in I) <= max_s) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_t_keep[t] for i in I) >= min_s) # 荷物を全て載せたとき GAP_SP.addConstr( gp.quicksum(delta_h[i] * G[j] * V_ij[i, j] for j in J_lk[t] for i in I) <= max_h) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_lk[t] for i in I) <= max_s) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_lk[t] for i in I) >= min_s) # 最適化計算 # ============================================================================================== print( "\n========================= Solve Assignment Problem =========================" ) GAP_SP.optimize() # 解の保存 # ============================================================================================== # 目的関数の値 val_opt = GAP_SP.ObjVal # ペナルティ計算 print("-" * 65) print("penalty count => ") # OBJ1のペナルティ penal1 = 0 for i in I: for t1 in L: for t2 in D: if Z_it1t2[i, t1, t2].X > 0: penal1 = penal1 + Z_it1t2[i, t1, t2].X # OBJ2のペナルティ penal2_1 = penal2_2 = 0 for i1 in I: for i2 in I: for t in L: if Z1_i1i2t[i1, i2, t].X > 0: penal2_1 = penal2_1 + 1 # print(f"ホールド{i1},{i2}で積み地ペナルティ") for t in D: if Z2_i1i2t[i1, i2, t].X > 0: penal2_2 = penal2_2 + 1 # print(f"ホールド{i1},{i2}で揚げ地ペナルティ") # OBJ3のペナルティ penal3 = 0 for i in I: for j in J: for t in T: if M_ijt[i, j, t].X > 0: penal3 = penal3 + M_ijt[i, j, t].X # OBJ4のペナルティ benefit4 = 0 for t in check_point: for i in I: if N_it[i, t].X > 0: benefit4 = benefit4 + N_it[i, t].X # OBJ5のペナルティ penal5 = 0 for t in L: for i in I_lamp: if K3_it[i, t].X > 0: penal5 = penal5 + K3_it[i, t].X # 解の書き込み answer = [] assign = [] for i in I: for j in J: if V_ij[i, j].X > 0: # assign_data[GAPホールド番号、GAP注文番号、積む台数,ホールド番号、注文番号、ユニット数、RT、積み港、降ろし港、資源要求量] answer.append([i, j]) assign.append([0, 0, V_ij[i, j].X, 0, 0, "L", "D", 0]) print("") print("[weight]") print(f"Object1's weight : {w1}") print(f"Object2's weight : {w2}") print(f"Object3's weight : {w3}") print(f"Object4's weight : {w4}") print(f"Object5's weight : {w5}") print("") print("[penalty & benefit]") print( f"Different discharge port in one hold : {penal1_z} × {penal1}" ) print( f"Different loading port in pair hold : {penal2_load} × {penal2_1}" ) print( f"Different discharge port in pair hold : {penal2_dis} × {penal2_2}" ) print(f"The number of cars passed holds that exceed threshold : {penal3}") print( f"The benefit remaining RT of hold near the entrance : {benefit4}") print( f"The penalty of total dead space : {penal5_k} × {penal5}" ) print("") print(f" => Total penalty is {val_opt}") print("-" * 65) # 残リソース I_left_data = Hold.iloc[:, 0:2] for k in range(len(assign)): key = Booking.columns.get_loc('Index') i_t = answer[k][0] j_t = int(Booking.iloc[answer[k][1], key]) # hold_ID assign[k][0] = Hold.iloc[i_t, 0] # order_ID assign[k][1] = Booking.iloc[j_t, Booking.columns.get_loc('Order_num')] # Units(original booking) assign[k][3] = Booking.iloc[j_t, Booking.columns.get_loc('Units')] for j in range(len(divide_dic)): if assign[k][1] - 1 == divide_dic[j][0]: assign[k][3] = divide_dic[j][1] # RT assign[k][4] = Booking.iloc[j_t, Booking.columns.get_loc('RT')] # L_port assign[k][5] = Booking.iloc[j_t, Booking.columns.get_loc('LPORT')] # D_port assign[k][6] = Booking.iloc[j_t, Booking.columns.get_loc('DPORT')] # Cost assign[k][7] = assign[k][2] * assign[k][4] # 残リソース計算 I_left_data.iloc[answer[k][0], 1] = I_left_data.iloc[answer[k][0], 1] - assign[k][7] if I_left_data.iloc[answer[k][0], 1] < 0.1: I_left_data.iloc[answer[k][0], 1] = 0 c_list = [] c_list.append("Hold_ID") c_list.append("Order_ID") c_list.append("Load_Units") c_list.append("Units") c_list.append("RT") c_list.append("LPORT") c_list.append("DPORT") c_list.append("Cost") booking_name = BookingFile.split("/")[1].split(".")[0] assignment_result_name = "result/" + booking_name + "_assignment.xlsx" leftRT_result_name = "result/" + booking_name + "_leftRT.xlsx" assign_data = pd.DataFrame(assign, columns=c_list) assign_data.to_excel(assignment_result_name, index=False, columns=c_list) I_left_data.to_excel(leftRT_result_name, index=False)
def lp_relaxation(FileName): # 前処理 # ============================================================================================== # ファイルロード # BookingFile = "book/exp_height.csv" BookingFile = FileName HoldFile = "data/hold.csv" MainLampFile = "data/mainlamp.csv" BackMainLampFile = "data/back_mainlamp.csv" AfrMainLampFile = "data/afr_mainlamp.csv" StressFile = "data/stress_mainlamp.csv" Gang2File = "data/gangnum_2.csv" Gang3File = "data/gangnum_3.csv" print("File:" + BookingFile) booking_name = BookingFile.split("/")[1].split(".")[0] # 注文情報の読み込み T, L, D, J, U, A, G, J_small, J_medium, J_large, Port, Check_port, Booking, divide_dic\ = read_booking.Read_booking(BookingFile) # 船体情報の読み込み1 I, B, I_pair, I_next, I_same, I_lamp, I_deck, RT_benefit, delta_s, min_s, max_s, delta_h, max_h, Hold_encode, Hold\ = read_hold.Read_hold(HoldFile) # 船体情報の読み込み2 Ml_Load, Ml_Back, Ml_Afr, Stress, GANG2, GANG3\ = read_other.Read_other(MainLampFile, BackMainLampFile, AfrMainLampFile, StressFile, Gang2File, Gang3File, Hold_encode) J_t_load = [] # J_t_load:港tで積む注文の集合 J_t_keep = [] # J_t_keep:港tを通過する注文の集合 J_t_dis = [] # J_t_dis:港tで降ろす注文の集合 J_lk = [] # J_lk:J_t_load + J_t_keep J_ld = [] # J_ld:J_t_load + J_t_dis for t in T: J_load = [] J_keep = [] J_dis = [] lk = [] ld = [] tmp_load = list(Port.iloc[:, 0]) tmp_dis = list(Port.iloc[:, 1]) N = len(J) k = 0 for i in L: if k < i: k = i count = 0 for t_l in tmp_load: if t == t_l: J_load.append(count) lk.append(count) ld.append(count) count = count + 1 count = 0 for t_d in tmp_dis: if t == t_d: J_dis.append(count) ld.append(count) count = count + 1 for t_k in range(N): if t > tmp_load[t_k] and t < tmp_dis[t_k]: J_keep.append(J[t_k]) lk.append(t_k) J_t_load.append(J_load) J_t_keep.append(J_keep) J_t_dis.append(J_dis) J_lk.append(lk) J_ld.append(ld) print(len(J)) #注文数 print(len(I)) #ホールドの数 # モデリング1(定数・変数の設定) # ============================================================================================== # ここから緩和問題 # """ # Gurobiパラメータ設定 GAP_SP = gp.Model() # GAP_SP.setParam("TimeLimit", 3600) GAP_SP.setParam("SolutionLimit", 1) GAP_SP.setParam("MIPFocus", 1) GAP_SP.setParam("LPMethod", 1) # GAP_SP.setParam("MIPGap",0.3) GAP_SP.printStats() # ハイパーパラメータ設定 # 各目的関数の重み w1 = 1 w2 = 1 w3 = 1 w4 = 1 w5 = 1 # 目的関数1のペナルティ penal1_z = 10 # 目的関数2のペナルティ penal2_load = 1 penal2_dis = 10 # 目的関数4のチェックポイント check_point = Check_port # 目的関数5のペナルティ penal5_k = 1000 # 最適化変数 # V_ij:注文jをホールドiにk(kはUnit数)台割り当てる V_ij = {} for i in I: for j in J: V_ij[i, j] = GAP_SP.addVar(lb=0.0, ub=float(U[j]), vtype=gp.GRB.CONTINUOUS, name=f"V_ij({i},{j})") # 目的関数1 # X_ij:注文jをホールドiに割り当てるなら1、そうでなければ0 X_ij = GAP_SP.addVars(I, J, vtype=gp.GRB.BINARY) # Y_keep_it:港tにおいてホールドiを通過する注文があるなら1、そうでなければ0 Y_keep_it = GAP_SP.addVars(I, T, vtype=gp.GRB.BINARY) # Y_it1t2:ホールドiにおいてt1で積んでt2で降ろす注文があるなら1、そうでなければ0 Y_it1t2 = GAP_SP.addVars(I, T, T, vtype=gp.GRB.BINARY) # Z_it1t2:ホールドiにおいてt2を通過する注文があるとき異なる乗せ港t1の数分のペナルティ Z_it1t2 = GAP_SP.addVars(I, L, D, vtype=gp.GRB.BINARY) OBJ1 = gp.quicksum(w1 * penal1_z * Z_it1t2[i, t1, t2] for i in I for t1 in L for t2 in D) # 目的関数2 # Y_load_i1i2t:港tにおいてホールドペア(i1,i2)で積む注文があるなら1 Y_load_i1i2t = GAP_SP.addVars(I, I, L, vtype=gp.GRB.BINARY) # Y_keep_i1i2t:港tにおいてホールドペア(i1,i2)を通過する注文があるなら1 Y_keep_i1i2t = GAP_SP.addVars(I, I, T, vtype=gp.GRB.BINARY) # Y_dis_i1i2t:港tにおいてホールドペア(i1,i2)で揚げる注文があるなら1 Y_dis_i1i2t = GAP_SP.addVars(I, I, D, vtype=gp.GRB.BINARY) # ホールドペア(i1,i2)においてtで注文を積む際に既にtで積んだ注文があるときのペナルティ Z1_i1i2t = GAP_SP.addVars(I, I, L, vtype=gp.GRB.BINARY) # ホールドペア(i1,i2)においてtで注文を揚げる際にtを通過する注文があるときのペナルティ Z2_i1i2t = GAP_SP.addVars(I, I, D, vtype=gp.GRB.BINARY) OBJ2_1 = gp.quicksum(penal2_load * Z1_i1i2t[i1, i2, t] for i1 in I for i2 in I for t in L) OBJ2_2 = gp.quicksum(penal2_dis * Z2_i1i2t[i1, i2, t] for i1 in I for i2 in I for t in D) OBJ2 = w2 * (OBJ2_1 + OBJ2_2) # 目的関数3 # M_it:港tにおいてホールドiが作業効率充填率を超えたら1 M_it = GAP_SP.addVars(I, T, vtype=gp.GRB.BINARY) # M_ijt:港tにおいてホールドiに自動車を積むまでに作業効率充填率を上回ったホールドに自動車を通すペナルティ M_ijt = GAP_SP.addVars(I, J, T, lb=0, vtype=gp.GRB.CONTINUOUS) OBJ3 = gp.quicksum(w3 * M_ijt[i, j, t] for i in I for j in J for t in T) # 目的関数4 # N_jt:チェックポイントにおけるホールドiの残容量 N_it = GAP_SP.addVars(I, check_point, lb=0, vtype=gp.GRB.CONTINUOUS) OBJ4 = gp.quicksum(w4 * N_it[i, t] * RT_benefit[i] for i in I for t in check_point) # 目的関数5 # K1_it:lampで繋がっている次ホールドが充填率75%を上回ったら1、そうでなければ0 K1_it = GAP_SP.addVars(I_lamp, L, vtype=gp.GRB.BINARY) # K2_it:ホールドiが1RT以上のスペースがあったら1、そうでなければ0 K2_it = GAP_SP.addVars(I, L, lb=0, vtype=gp.GRB.BINARY) # K3_it:目的関数5のペナルティ K3_it = GAP_SP.addVars(I_lamp, L, lb=0, vtype=gp.GRB.CONTINUOUS) OBJ5 = gp.quicksum(w5 * penal5_k * K3_it[i, t] for i in I_lamp for t in L) # 目的関数の設計 OBJ = OBJ1 + OBJ2 + OBJ3 - OBJ4 + OBJ5 GAP_SP.setObjective(OBJ, gp.GRB.MINIMIZE) # モデリング2(制約) # ============================================================================================== # 基本制約 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 割当てた注文がコンパートメント毎にリソースを超えない GAP_SP.addConstrs( gp.quicksum(V_ij[i, j] * A[j] for j in J) <= B[i] for i in I) # 全注文内の自動車の台数を全て割り当てる GAP_SP.addConstrs( gp.quicksum(V_ij[i, j] * X_ij[i, j] for i in I) == U[j] for j in J) # VとXの制約 GAP_SP.addConstrs(V_ij[i, j] / U[j] <= X_ij[i, j] for i in I for j in J) # 目的関数の制約 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 目的関数1の制約 for t in T: GAP_SP.addConstrs(X_ij[i, j] <= Y_keep_it[i, t] for i in I for j in J_t_keep[t]) for t in D: t2 = t for t1 in L: J_sub = [] # J_sub:t1で積んでt2で揚げる注文の集合 for j in J_t_dis[t2]: if j in J_t_load[t1]: J_sub.append(j) GAP_SP.addConstrs(X_ij[i, j] <= Y_it1t2[i, t1, t2] for i in I for j in J_sub) GAP_SP.addConstrs(Z_it1t2[i, t1, t2] <= Y_it1t2[i, t1, t2] for i in I) GAP_SP.addConstrs(Z_it1t2[i, t1, t2] <= Y_keep_it[i, t2] for i in I) GAP_SP.addConstrs( Z_it1t2[i, t1, t2] >= Y_it1t2[i, t1, t2] + Y_keep_it[i, t2] - 1 for i in I) # 目的関数2の制約 for t in T: for i1, i2 in I_pair: GAP_SP.addConstrs( X_ij[i1, j] + X_ij[i2, j] <= 2 * Y_keep_i1i2t[i1, i2, t] for j in J_t_keep[t]) if t in L: GAP_SP.addConstrs( X_ij[i1, j] + X_ij[i2, j] <= 2 * Y_load_i1i2t[i1, i2, t] for j in J_t_load[t]) GAP_SP.addConstr( Z1_i1i2t[i1, i2, t] <= Y_load_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z1_i1i2t[i1, i2, t] <= Y_keep_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z1_i1i2t[i1, i2, t] >= Y_load_i1i2t[i1, i2, t] + Y_keep_i1i2t[i1, i2, t] - 1) if t in D: GAP_SP.addConstrs( X_ij[i1, j] + X_ij[i2, j] <= 2 * Y_dis_i1i2t[i1, i2, t] for j in J_t_dis[t]) GAP_SP.addConstr(Z2_i1i2t[i1, i2, t] <= Y_dis_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z2_i1i2t[i1, i2, t] <= Y_keep_i1i2t[i1, i2, t]) GAP_SP.addConstr( Z2_i1i2t[i1, i2, t] >= Y_dis_i1i2t[i1, i2, t] + Y_keep_i1i2t[i1, i2, t] - 1) # 目的関数3の制約 for t in T: GAP_SP.addConstrs(M_it[i, t] >= -Stress[i] + (gp.quicksum(V_ij[i, j] * A[j] for j in J_t_keep[t]) / B[i]) for i in I) for i1 in I: I_primetmp = [] for k in Ml_Load.iloc[i1, :]: I_primetmp.append(k) I_prime = [x for x in I_primetmp if str(x) != 'nan'] I_prime.pop(0) GAP_SP.addConstrs( M_ijt[i1, j, t] >= V_ij[i1, j] * gp.quicksum(M_it[i2, t] for i2 in I_prime) for j in J_ld[t]) # 目的関数4の制約 for t in check_point: GAP_SP.addConstrs(N_it[i, t] <= B[i] - gp.quicksum(V_ij[i, j] * A[j] for j in J_lk[t]) for i in I) # 目的関数5の制約 GAP_SP.addConstrs( K1_it[i, t] >= -0.75 + gp.quicksum(V_ij[i, j] * A[j] for j in J_lk[t]) / B[i] for i in I_lamp for t in L) GAP_SP.addConstrs(K2_it[i, t] >= 1 - (gp.quicksum(V_ij[i, j] * A[j] for j in J_lk[t]) + 1) / B[i] for i in I for t in L) for i in range(len(Ml_Back)): i1 = Ml_Back.iloc[i, 0] I_backtmp = [] for k in Ml_Back.iloc[i, :]: I_backtmp.append(k) I_back_i1 = [x for x in I_backtmp if str(x) != 'nan'] I_back_i1.pop(0) GAP_SP.addConstrs(K3_it[i1, t] >= len(I) * (K1_it[i1, t] - 1) + gp.quicksum(K2_it[i2, t] for i2 in I_back_i1) for t in L) # 特殊制約2(移動経路制約) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 港を通過する荷物が移動の邪魔をしない for t in T: for i1 in I: I_primetmp = [] Frtmp = [] for k in Ml_Load.iloc[i1, :]: I_primetmp.append(k) for k in Ml_Afr.iloc[i1, :]: Frtmp.append(k) I_prime = [int(x) for x in I_primetmp if str(x) != 'nan'] Fr = [x for x in Frtmp if str(x) != 'nan'] I_prime.pop(0) Fr.pop(0) N_prime = len(I_prime) for k in range(N_prime): i2 = int(I_prime[k]) GAP_SP.addConstrs( gp.quicksum(V_ij[i2, j1] * A[j1] for j1 in J_t_keep[t]) / B[i2] <= 1 + Fr[k] - X_ij[i1, j2] for j2 in J_ld[t]) # 特殊制約3(船体重心の制約) # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # 船の上下前後の配置バランスが閾値を超えない for t in T: # 荷物を全て降ろしたとき GAP_SP.addConstr( gp.quicksum(delta_h[i] * G[j] * V_ij[i, j] for j in J_t_keep[t] for i in I) <= max_h) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_t_keep[t] for i in I) <= max_s) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_t_keep[t] for i in I) >= min_s) # 荷物を全て載せたとき GAP_SP.addConstr( gp.quicksum(delta_h[i] * G[j] * V_ij[i, j] for j in J_lk[t] for i in I) <= max_h) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_lk[t] for i in I) <= max_s) GAP_SP.addConstr( gp.quicksum(delta_s[i] * G[j] * V_ij[i, j] for j in J_lk[t] for i in I) >= min_s) # 最適化計算 # ============================================================================================== print( "\n========================= Solve Assignment Problem =========================" ) GAP_SP.optimize() # 解の保存 # ============================================================================================== # 目的関数の値 val_opt = GAP_SP.ObjVal # ペナルティ計算 print("-" * 65) print("penalty count => ") # 解を全て格納する配列 relaxed_all_assignment = [] # 解の書き込み answer = [] assign = [] for i in I: tmp_assignment = [] for j in J: tmp_assignment.append(V_ij[i, j].X) relaxed_all_assignment.append(tmp_assignment) initial_assingment_T = np.array(relaxed_all_assignment).T return initial_assingment_T
def main(): # BookingFile = "book/exp.csv" BookingFile = args[1] HoldFile = "data/hold.csv" MainLampFile = "data/mainlamp.csv" BackMainLampFile = "data/back_mainlamp.csv" AfrMainLampFile = "data/afr_mainlamp.csv" AfrFile = "data/accepted_filling_rate.csv" StressFile = "data/stress_mainlamp.csv" Gang2File = "data/gangnum_2.csv" Gang3File = "data/gangnum_3.csv" # print("File:" + BookingFile) booking_name = BookingFile.split("/")[1].split(".")[0] # 注文情報の読み込み T, L, D, J, U, A, G, J_small, J_medium, J_large, Port, Check_port, Booking, divide_dic\ = read_booking.Read_booking(BookingFile) # 船体情報の読み込み1 I, B, I_pair, I_next, I_same, I_lamp, I_deck, RT_benefit, delta_s, min_s, max_s, delta_h, max_h, Hold_encode, Hold\ = read_hold.Read_hold(HoldFile) # 船体情報の読み込み2 Ml_Load, Ml_Back, Ml_Afr, Stress, GANG2, GANG3\ = read_other.Read_other(MainLampFile, BackMainLampFile, AfrMainLampFile, StressFile, Gang2File, Gang3File, Hold_encode) filling_rate = read_hold.Read_other(AfrFile) deeper_holds = {} for index, row in Ml_Back.iterrows(): first_hold = int(row["Hold0"]) tmp = [] tmp_idx = 1 deeper = [] while tmp_idx <= 42 and str(row["Hold" + str(tmp_idx)]) != 'nan': deeper.append(int(row["Hold" + str(tmp_idx)])) tmp_idx += 1 deeper_holds[first_hold] = deeper # ハイパーパラメータ設定 # 各目的関数の重み w1 = 1 w2 = 1 w3 = 1 w4 = 1 w5 = 1 # 目的関数1のペナルティ penal1_z = 10 # 目的関数2のペナルティ penal2_load = 1 penal2_dis = 10 # デッドスペースのペナルティ penal5_k = 1000 J_t_load = [] # J_t_load:港tで積む注文の集合 J_t_keep = [] # J_t_keep:港tを通過する注文の集合 J_t_dis = [] # J_t_dis:港tで降ろす注文の集合 J_lk = [] # J_lk:J_t_load + J_t_keep J_ld = [] # J_ld:J_t_load + J_t_dis for t in T: J_load = [] J_keep = [] J_dis = [] lk = [] ld = [] tmp_load = list(Port.iloc[:, 0]) tmp_dis = list(Port.iloc[:, 1]) N = len(J) k = 0 for i in L: if k < i: k = i count = 0 for t_l in tmp_load: if t == t_l: J_load.append(count) lk.append(count) ld.append(count) count = count + 1 count = 0 for t_d in tmp_dis: if t == t_d: J_dis.append(count) ld.append(count) count = count + 1 for t_k in range(N): if t > tmp_load[t_k] and t < tmp_dis[t_k]: J_keep.append(J[t_k]) lk.append(t_k) J_t_load.append(J_load) J_t_keep.append(J_keep) J_t_dis.append(J_dis) J_lk.append(lk) J_ld.append(ld) def assign_to_hold(assignment_list): hold_assignment = [] for i in range(HOLD_COUNT): hold_assignment.append([]) unloaded_orders = [] half_way_loaded_rt = [] #最終港以外で,積みを終えたときのRTの配列 half_way_assignments = [] #1港目を積み終えたときのバランスを計算するための配列 for loading_port_num in range(len(L) - 1): tmp = {} tmp2 = [] for hold_num in range(HOLD_COUNT): tmp[hold_num] = [] tmp2.append(0) half_way_assignments.append(tmp) half_way_loaded_rt.append(tmp2) balance_penalty = 0 for segment_num in range(SEGMENT_COUNT): segment = segments[segment_num] assignment = assignment_list[segment_num] assignment_RT = [] assignment_unit = [] assignment_total_space = [] for loading_port_num in range(len(assignment)): tmp_assignment_RT = [] tmp_assignment_unit = [] tmp_assignment_total_space = [] for order in assignment[loading_port_num]: tmp_assignment_RT.append(A[order]) tmp_assignment_unit.append(int(U[order])) tmp_assignment_total_space.append(A[order] * int(U[order])) assignment_RT.append(tmp_assignment_RT) assignment_unit.append(tmp_assignment_unit) assignment_total_space.append(tmp_assignment_total_space) left_spaces = {} for hold in segment: left_spaces[hold] = B[hold] for loading_port_num in range(len(assignment)): orders = assignment[loading_port_num] order_cnt = 0 #どの注文まで積んだか orders_size = len(orders) #注文の個数 if loading_port_num == len(assignment) - 1: #最後に積む港 for hold in segment: # 全部詰め切るか,そのホールドに注文をまるごと詰め込めなくなったらwhileを抜ける while (order_cnt < orders_size and assignment_total_space[loading_port_num] [order_cnt] < left_spaces[hold]): left_spaces[hold] -= assignment_total_space[ loading_port_num][order_cnt] hold_assignment[hold].append([ assignment[loading_port_num][order_cnt], assignment_unit[loading_port_num][order_cnt] ]) assignment_total_space[loading_port_num][ order_cnt] = 0 assignment_unit[loading_port_num][order_cnt] = 0 order_cnt += 1 # まるごとは注文を詰め込めなくても,一部なら可能なら一部を詰め込む if order_cnt < orders_size: possible_unit_cnt = int( left_spaces[hold] // assignment_RT[loading_port_num][order_cnt]) if (possible_unit_cnt > 0): left_spaces[ hold] -= assignment_RT[loading_port_num][ order_cnt] * possible_unit_cnt hold_assignment[hold].append([ assignment[loading_port_num][order_cnt], possible_unit_cnt ]) assignment_total_space[loading_port_num][ order_cnt] -= assignment_RT[ loading_port_num][ order_cnt] * possible_unit_cnt assignment_unit[loading_port_num][ order_cnt] -= possible_unit_cnt else: #最後に積む港ではない場合 for hold in segment: ALLOWANCE_SPACE = B[hold] * (1 - filling_rate[hold]) ALLOWANCE_STRESS_SPACE = B[hold] * (1 - Stress[hold]) # 全部詰め切るか,そのホールドに作業効率充填率を満たしつつ注文をまるごと詰め込めなくなったらwhileを抜ける while (order_cnt < orders_size and assignment_total_space[loading_port_num] [order_cnt] < (left_spaces[hold]) - ALLOWANCE_STRESS_SPACE): left_spaces[hold] -= assignment_total_space[ loading_port_num][order_cnt] hold_assignment[hold].append([ assignment[loading_port_num][order_cnt], assignment_unit[loading_port_num][order_cnt] ]) half_way_assignments[loading_port_num][ hold].append([ assignment[loading_port_num][order_cnt], assignment_unit[loading_port_num] [order_cnt] ]) assignment_total_space[loading_port_num][ order_cnt] = 0 assignment_unit[loading_port_num][order_cnt] = 0 order_cnt += 1 # まるごとは注文を詰め込めなくても,作業効率充填率を満たしつつ一部なら可能なら一部を詰め込む if order_cnt < orders_size: possible_unit_cnt = int( (left_spaces[hold] - ALLOWANCE_STRESS_SPACE) // assignment_RT[loading_port_num][order_cnt]) if (possible_unit_cnt > 0): left_spaces[ hold] -= assignment_RT[loading_port_num][ order_cnt] * possible_unit_cnt hold_assignment[hold].append([ assignment[loading_port_num][order_cnt], possible_unit_cnt ]) half_way_assignments[loading_port_num][ hold].append([ assignment[loading_port_num] [order_cnt], possible_unit_cnt ]) assignment_total_space[loading_port_num][ order_cnt] -= assignment_RT[ loading_port_num][ order_cnt] * possible_unit_cnt assignment_unit[loading_port_num][ order_cnt] -= possible_unit_cnt # 全部詰め切るか,そのホールドに注文をまるごと詰め込めなくなったらwhileを抜ける while (order_cnt < orders_size and assignment_total_space[loading_port_num] [order_cnt] < (left_spaces[hold]) - ALLOWANCE_SPACE): left_spaces[hold] -= assignment_total_space[ loading_port_num][order_cnt] hold_assignment[hold].append([ assignment[loading_port_num][order_cnt], assignment_unit[loading_port_num][order_cnt] ]) half_way_assignments[loading_port_num][ hold].append([ assignment[loading_port_num][order_cnt], assignment_unit[loading_port_num] [order_cnt] ]) assignment_total_space[loading_port_num][ order_cnt] = 0 assignment_unit[loading_port_num][order_cnt] = 0 order_cnt += 1 # まるごとは注文を詰め込めなくても,一部なら可能なら一部を詰め込む if order_cnt < orders_size: possible_unit_cnt = int( (left_spaces[hold] - ALLOWANCE_SPACE) // assignment_RT[loading_port_num][order_cnt]) if (possible_unit_cnt > 0): left_spaces[ hold] -= assignment_RT[loading_port_num][ order_cnt] * possible_unit_cnt hold_assignment[hold].append([ assignment[loading_port_num][order_cnt], possible_unit_cnt ]) half_way_assignments[loading_port_num][ hold].append([ assignment[loading_port_num] [order_cnt], possible_unit_cnt ]) assignment_total_space[loading_port_num][ order_cnt] -= assignment_RT[ loading_port_num][ order_cnt] * possible_unit_cnt assignment_unit[loading_port_num][ order_cnt] -= possible_unit_cnt half_way_loaded_rt[loading_port_num][ hold] = B[hold] - left_spaces[hold] for index in range(len(assignment_unit[loading_port_num])): if assignment_unit[loading_port_num][index] > 0: unloaded_orders.append([ orders[index], assignment_unit[loading_port_num][index] ]) # バランス制約を計算 # 最後に積む港以外 balance1 = 0 balance2 = 0 for loading_port_num in range(len(L) - 1): half_way_assignment = half_way_assignments[loading_port_num] for hold_num, orders in half_way_assignment.items(): if len(orders) > 0: for order in orders: #横方向 balance1 += delta_h[hold_num] * G[order[0]] * order[1] # balance_penalty += max(0,(delta_h[hold_num] * G[order[0]] * order[1]) - max_h) #縦方向 balance2 += delta_s[hold_num] * G[order[0]] * order[1] # balance_penalty += max(0,(delta_s[hold_num] * G[order[0]] * order[1]) - max_s) # balance_penalty += max(0,min_s-(delta_s[hold_num] * G[order[0]] * order[1])) balance_penalty += max(0, balance1 - max_h) balance_penalty += max(0, balance2 - max_s) balance_penalty += max(0, min_s - balance2) balance1 = 0 balance2 = 0 # 最後に積む港 for hold_num in range(len(hold_assignment)): tmp_assignment = hold_assignment[hold_num] if len(tmp_assignment) > 0: for order in tmp_assignment: #横方向 balance1 += delta_h[hold_num] * G[order[0]] * order[1] # balance_penalty += max(0,(delta_h[hold_num] * G[order[0]] * order[1]) - max_h) #縦方向 balance2 += delta_s[hold_num] * G[order[0]] * order[1] # balance_penalty += max(0,(delta_s[hold_num] * G[order[0]] * order[1]) - max_s) # balance_penalty += max(0,min_s-(delta_s[hold_num] * G[order[0]] * order[1])) balance_penalty += max(0, balance1 - max_h) balance_penalty += max(0, balance2 - max_s) balance_penalty += max(0, min_s - balance2) """ 返り値は,2次元の配列 hold_assignment[i]で,ホールドiに割り当てられる注文の情報の配列を取得できる hold_assignment[i][j]で,ホールドiにj番目に割り当てられる注文を取得できる 配列の0番目が,注文の番号 配列の1番目が,割り当てる台数 """ return hold_assignment, unloaded_orders, balance_penalty, half_way_loaded_rt def evaluate(assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt): # 全注文内の自動車の台数を全て割り当てる n_it = [] total_left_RT = 0 for hold_num in range(HOLD_COUNT): assignment = assignment_hold[hold_num] left_RT = B[hold_num] for order in assignment: left_RT -= A[order[0]] * order[1] n_it.append(left_RT) total_left_RT += left_RT unloaded_units = 0 for order in unloaded_orders: unloaded_units += order[1] # ここまで constraint1 = 0 #移動経路制約 objective3 = 0 #作業効率充填率 # 縦横方向のバランス制約 balance_constraint1 = [0 for i in range(len(D))] balance_constraint2 = [0 for i in range(len(D))] # 経路確保とバランス制約の計算に使う配列を作成 for hold_num in range(len(assignment_hold)): assignment_in_hold = assignment_hold[hold_num] destination_assignments = [[] for i in range(len(D))] for assign in assignment_in_hold: destination_port = int(Booking.at[assign[0], "DPORT"]) if (destination_port - len(L) != 0): for i in range(1, destination_port - len(L) + 1): destination_assignments[i].append(assign) #降ろし地での経路確保 降ろし地での作業効率充填率 hold_space = B[hold_num] for i in range(1, len(destination_assignments)): total_loaded_space = 0 for assign in destination_assignments[i]: total_loaded_space += A[assign[0]] * assign[1] if total_loaded_space > hold_space * filling_rate[hold_num]: constraint1 += (total_loaded_space - (hold_space * filling_rate[hold_num])) # if total_loaded_space > hold_space*Stress[hold_num]: # objective3 += (total_loaded_space-(hold_space*Stress[hold_num])) #ここまで #降ろし地でのバランス制約 for destination_load_num in range(1, len(destination_assignments)): for assign in destination_assignments[destination_load_num]: balance_constraint1[destination_load_num] += delta_h[ hold_num] * G[assign[0]] * assign[1] balance_constraint2[destination_load_num] += delta_s[ hold_num] * G[assign[0]] * assign[1] #ここまで # 降ろし地での作業効率充填率 order_array = [] accpeted_rate = Stress[hold_num] for port_num in range(len(T)): order_array.append([]) for item in assignment_in_hold: lport = Booking.at[item[0], "LPORT"] for i in range(int(lport), int(L[-1]) + 1): order_array[i].append(item) dport = Booking.at[item[0], "DPORT"] for i in range(int(D[0]), int(dport)): order_array[i].append(item) for port in check_port: order = order_array[port] total_RT = 0 for item in order: single_rt = Booking.at[item[0], "RT"] total_RT += item[1] * single_rt if total_RT > B[hold_num] * accpeted_rate: objective3 += total_RT - (B[hold_num] * accpeted_rate) #全ての降ろし地での全てのバランス制約を計算したので,制約違反していたらペナルティ for destination_load_num in range(1, len(destination_assignments)): balance_penalty += max( 0, balance_constraint1[destination_load_num] - max_h) balance_penalty += max( 0, balance_constraint2[destination_load_num] - max_s) balance_penalty += max( 0, min_s - balance_constraint2[destination_load_num]) #ここまで objective1 = 0 # 目的関数1 ひとつのホールドで,異なる降ろし地の注文を少なくする for each_assignment in assignment_hold: different_destination_area_orders = [] for order in each_assignment: different_destination_area_orders.append(Booking.at[order[0], "DPORT"]) unique_destination_ports = set(different_destination_area_orders) if (len(unique_destination_ports) > 1): objective1 += penal1_z * (len(unique_destination_ports) - 1) # ここまで objective2 = 0 # 目的関数2 注文の積み降ろし地を揃える for p in I_pair: hold1 = p[0] hold2 = p[1] orders1 = assignment_hold[hold1] orders2 = assignment_hold[hold2] lport1 = [] lport2 = [] dport1 = [] dport2 = [] for order in orders1: dport1.append(Booking.at[order[0], "DPORT"]) lport1.append(Booking.at[order[0], "LPORT"]) for order in orders2: dport2.append(Booking.at[order[0], "DPORT"]) lport2.append(Booking.at[order[0], "LPORT"]) dport1 = set(dport1) dport2 = set(dport2) dport = set() if len(dport.union(dport1, dport2)) > 1: objective2 += penal2_dis * len(dport.union(dport1, dport2)) - 1 lport1 = set(lport1) lport2 = set(lport2) lport = set() if len(lport.union(lport1, lport2)) > 1: objective2 += penal2_load * len(lport.union(lport1, lport2)) - 1 #ここまで # 目的関数4 デッドスペースを作らない objective4 = 0 check_port_dead_space = L[:-1] for port in check_port_dead_space: total_RT = half_way_loaded_rt[port] for hold_with_lamp in I_lamp: if total_RT[hold_with_lamp] > B[hold_with_lamp] * filling_rate[ hold_with_lamp]: for hold in deeper: if B[hold] - total_RT[hold] >= 1: objective4 += penal5_k # ここまで # 目的関数5 残容量を入り口に寄せる objective5 = 0 for i in range(len(n_it)): objective5 += n_it[i] * RT_benefit[i] # ここまで return unloaded_units + balance_penalty + constraint1, objective1 + objective2 + objective3 + objective4 - objective5 def is_feasible(assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt): # 全注文内の自動車の台数を全て割り当てる n_it = [] total_left_RT = 0 for hold_num in range(HOLD_COUNT): assignment = assignment_hold[hold_num] left_RT = B[hold_num] for order in assignment: left_RT -= A[order[0]] * order[1] n_it.append(left_RT) total_left_RT += left_RT unloaded_units = 0 for order in unloaded_orders: unloaded_units += order[1] # ここまで constraint1 = 0 #移動経路制約 objective3 = 0 #作業効率充填率 # 縦横方向のバランス制約 balance_constraint1 = [0 for i in range(len(D))] balance_constraint2 = [0 for i in range(len(D))] # 経路確保とバランス制約の計算に使う配列を作成 for hold_num in range(len(assignment_hold)): assignment_in_hold = assignment_hold[hold_num] destination_assignments = [[] for i in range(len(D))] for assign in assignment_in_hold: destination_port = int(Booking.at[assign[0], "DPORT"]) if (destination_port - len(L) != 0): for i in range(1, destination_port - len(L) + 1): destination_assignments[i].append(assign) #降ろし地での経路確保 降ろし地での作業効率充填率 hold_space = B[hold_num] for i in range(1, len(destination_assignments)): total_loaded_space = 0 for assign in destination_assignments[i]: total_loaded_space += A[assign[0]] * assign[1] if total_loaded_space > hold_space * filling_rate[hold_num]: constraint1 += (total_loaded_space - (hold_space * filling_rate[hold_num])) # if total_loaded_space > hold_space*Stress[hold_num]: # objective3 += (total_loaded_space-(hold_space*Stress[hold_num])) #ここまで #降ろし地でのバランス制約 for destination_load_num in range(1, len(destination_assignments)): for assign in destination_assignments[destination_load_num]: balance_constraint1[destination_load_num] += delta_h[ hold_num] * G[assign[0]] * assign[1] balance_constraint2[destination_load_num] += delta_s[ hold_num] * G[assign[0]] * assign[1] #ここまで # 降ろし地での作業効率充填率 order_array = [] accpeted_rate = Stress[hold_num] for port_num in range(len(T)): order_array.append([]) for item in assignment_in_hold: lport = Booking.at[item[0], "LPORT"] for i in range(int(lport), int(L[-1]) + 1): order_array[i].append(item) dport = Booking.at[item[0], "DPORT"] for i in range(int(D[0]), int(dport)): order_array[i].append(item) for port in check_port: order = order_array[port] total_RT = 0 for item in order: single_rt = Booking.at[item[0], "RT"] # print(item[0]) # print(Booking.at[item[0]-1,"RT"]) total_RT += item[1] * single_rt # print(single_rt,item[1]) if total_RT > B[hold_num] * accpeted_rate: objective3 += total_RT - (B[hold_num] * accpeted_rate) #全ての降ろし地での全てのバランス制約を計算したので,制約違反していたらペナルティ for destination_load_num in range(1, len(destination_assignments)): balance_penalty += max( 0, balance_constraint1[destination_load_num] - max_h) balance_penalty += max( 0, balance_constraint2[destination_load_num] - max_s) balance_penalty += max( 0, min_s - balance_constraint2[destination_load_num]) #ここまで objective1 = 0 # 目的関数1 ひとつのホールドで,異なる降ろし地の注文を少なくする for each_assignment in assignment_hold: different_destination_area_orders = [] for order in each_assignment: different_destination_area_orders.append(Booking.at[order[0], "DPORT"]) unique_destination_ports = set(different_destination_area_orders) if (len(unique_destination_ports) > 1): objective1 += penal1_z * (len(unique_destination_ports) - 1) # ここまで objective2 = 0 # 目的関数2 注文の積み降ろし地を揃える for p in I_pair: hold1 = p[0] hold2 = p[1] orders1 = assignment_hold[hold1] orders2 = assignment_hold[hold2] lport1 = [] lport2 = [] dport1 = [] dport2 = [] for order in orders1: dport1.append(Booking.at[order[0], "DPORT"]) lport1.append(Booking.at[order[0], "LPORT"]) for order in orders2: dport2.append(Booking.at[order[0], "DPORT"]) lport2.append(Booking.at[order[0], "LPORT"]) dport1 = set(dport1) dport2 = set(dport2) dport = set() if len(dport.union(dport1, dport2)) > 1: objective2 += penal2_dis * len(dport.union(dport1, dport2)) - 1 lport1 = set(lport1) lport2 = set(lport2) lport = set() if len(lport.union(lport1, lport2)) > 1: objective2 += penal2_load * len(lport.union(lport1, lport2)) - 1 #ここまで # 目的関数4 デッドスペースを作らない objective4 = 0 check_port_dead_space = L[:-1] for port in check_port_dead_space: total_RT = half_way_loaded_rt[port] for hold_with_lamp in I_lamp: if total_RT[hold_with_lamp] > B[hold_with_lamp] * filling_rate[ hold_with_lamp]: for hold in deeper: if B[hold] - total_RT[hold] >= 1: objective4 += penal5_k # ここまで # 目的関数5 残容量を入り口に寄せる objective5 = 0 for i in range(len(n_it)): objective5 += n_it[i] * RT_benefit[i] print(unloaded_units, balance_penalty, constraint1) print(objective1, objective2, objective3, objective2, objective5) # ここまで return penalty_coefficient * ( unloaded_units + balance_penalty + constraint1 ) + objective1 + objective2 + objective3 + objective4 - objective5 random.seed(1) SEGMENT_COUNT = 18 HOLD_COUNT = 43 ORDER_COUNT = len(J) UNIQUE_ORDER_COUNT = len(set(Booking["Order_num"])) check_port = L[:-1] + D[:-1] # 分割したホールドで,奥から詰める順番で配列を作成 segments = np.array([[1, 0], [2, 3], [4], [5, 6, 7], [8, 9, 10], [11, 12, 13, 14], [18, 17, 16, 15], [22, 21, 20, 19], [23, 24], [26, 25], [27, 28], [30, 29], [31, 32], [34, 33], [35, 36], [38, 37], [39, 40], [42, 41]]) each_segments_size = [] for i in range(SEGMENT_COUNT): total_size = 0 for j in range(len(segments[i])): total_size += B[segments[i][j]] each_segments_size.append(total_size) ''' 解の持ち方 3次元配列で持つ assignment[i]で,セグメントiに割り振られた注文を見れる assignment[i][j]で,セグメントiに割り振られた注文の,なかで,j個目の積み地のものを見れる assignment[i][j][k]で,j個目の港でk個目に積み込む注文を見れる ''' dt1 = datetime.datetime.now() # 解の初期化 assignment = [] # とりあえず空で初期化 for i in range(SEGMENT_COUNT): tmp = [] for j in range(len(L)): #積み地の数だけ空配列を追加 tmp.append([]) assignment.append(tmp) for i in range(len(L)): randomed_J = random.sample(J_t_load[i], len(J_t_load[i])) for j in range(len(randomed_J)): assignment[j % SEGMENT_COUNT][i].append(randomed_J[j]) penalty_coefficient = 10000 #初期解を,ホールドに割当 assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt = assign_to_hold( assignment) #初期解のペナルティ penalty, objective = evaluate(assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt) evaluated_value = penalty_coefficient * penalty + objective shift_neighbor_list = operation.create_shift_neighbor( ORDER_COUNT, SEGMENT_COUNT) shift_count = 0 swap_neighbor_list = operation.create_swap_neighbor(J_t_load) swap_count = 0 total_improve = 1 while total_improve != 0: while (shift_count < len(shift_neighbor_list)): shift_order = shift_neighbor_list[shift_count][0] shift_seg = shift_neighbor_list[shift_count][1] copied_assignment = copy.deepcopy(assignment) tmp_assignment, is_changed = operation.shift( copied_assignment, shift_order, shift_seg, operation.find_loading_port(shift_order, J_t_load)) if is_changed: assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt = assign_to_hold( tmp_assignment) tmp_penalty, tmp_objective = evaluate(assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt) tmp_evaluated_value = penalty_coefficient * tmp_penalty + tmp_objective if tmp_evaluated_value < evaluated_value: print("改善 " + str(tmp_evaluated_value)) evaluated_value = tmp_evaluated_value assignment = copy.deepcopy(tmp_assignment) # 探索リストを最初からやり直し shift_count = 0 random.shuffle(shift_neighbor_list) else: shift_count += 1 else: shift_count += 1 total_improve = 0 """ while(swap_count < len(swap_neighbor_list)): swap_order1 = swap_neighbor_list[swap_count][0] swap_order2 = swap_neighbor_list[swap_count][1] copied_assignment = copy.deepcopy(assignment) tmp_assignment,is_changed = operation.swap(copied_assignment,swap_order1,swap_order2,operation.find_loading_port(swap_order1,J_t_load)) if is_changed: assignment_hold,unloaded_orders,balance_penalty,half_way_loaded_rt = assign_to_hold(tmp_assignment) tmp_penalty,tmp_objective = evaluate(assignment_hold,unloaded_orders,balance_penalty,half_way_loaded_rt) tmp_evaluated_value = penalty_coefficient*tmp_penalty+tmp_objective if tmp_evaluated_value < evaluated_value: print("改善 "+str(tmp_evaluated_value)) evaluated_value= tmp_evaluated_value assignment = copy.deepcopy(tmp_assignment) # 探索リストを最初からやり直し swap_count = 0 random.shuffle(swap_neighbor_list) total_improve += 1 else: swap_count += 1 else: swap_count += 1 """ assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt = assign_to_hold( assignment) penalty, objective = evaluate(assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt) print(penalty * penalty_coefficient + objective) print("----") output = is_feasible(assignment_hold, unloaded_orders, balance_penalty, half_way_loaded_rt) print(output) dt2 = datetime.datetime.now() print("計算時間: " + str((dt2 - dt1).total_seconds()) + "秒") result = [[ "Hold_ID", "Order_ID", "Load_Units", "Units", "RT", "LPORT", "DPORT" ]] for index in range(len(assignment_hold)): assignment_dict = {} other_info_dict = {} each_assignment = assignment_hold[index] for item in each_assignment: original_order_num = int(Booking.at[item[0], "Order_num"]) other_info_dict[original_order_num] = [] original_units = int(Booking.at[item[0], "Units"]) original_RT = Booking.at[item[0], "RT"] lport = int(Booking.at[item[0], "LPORT"]) dport = int(Booking.at[item[0], "DPORT"]) other_info_dict[original_order_num].append(original_units) other_info_dict[original_order_num].append(original_RT) other_info_dict[original_order_num].append(lport) other_info_dict[original_order_num].append(dport) if original_order_num in assignment_dict: assignment_dict[original_order_num] += item[1] else: assignment_dict[original_order_num] = item[1] hold_id = int(Hold_encode[Hold_encode["Index"] == index]["Hold"]) for order_id, load_unit in assignment_dict.items(): info = [hold_id, order_id, load_unit] info.extend(other_info_dict[order_id]) result.append(info) out_df = pd.DataFrame(result) booking_name = BookingFile.split("/")[1].split(".")[0]
BookingFile = "book/exp.csv" AssignmentsFile = args[1] # AssignmentsFile = "/Users/takedakiyoshi/lab/kline/KLINE/out/exp_assignment.xlsx" # AssignmentsFile = '/Users/takedakiyoshi/lab/kline/KLINE/ヒューリスティック/exp_2_5_assignment_86400.xlsx' HoldFile = "data/hold.csv" MainLampFile = "data/mainlamp.csv" BackMainLampFile = "data/back_mainlamp.csv" AfrMainLampFile = "data/afr_mainlamp.csv" StressFile = "data/stress_mainlamp.csv" Gang2File = "data/gangnum_2.csv" Gang3File = "data/gangnum_3.csv" T, L, D, J, U, A, G, J_small, J_medium, J_large, Port, Check_port, Booking, divide_dic\ = read_booking.Read_booking(BookingFile) # 船体情報の読み込み1 I, B, I_pair, I_next, I_same, I_lamp, I_deck, RT_benefit, delta_s, min_s, max_s, delta_h, max_h, Hold_encode, Hold\ = read_hold.Read_hold(HoldFile) # 船体情報の読み込み2 Ml_Load, Ml_Back, Ml_Afr, Stress, GANG2, GANG3\ = read_other.Read_other(MainLampFile, BackMainLampFile, AfrMainLampFile, StressFile, Gang2File, Gang3File, Hold_encode) df = pd.read_excel(AssignmentsFile) print(df) # ハイパーパラメータ設定 # 各目的関数の重み w1 = 1