From f4c2cd95326a15f65efdf8cd56dc8218a19a5724 Mon Sep 17 00:00:00 2001 From: Yofuria <20377277@buaa.edu.cn> Date: Wed, 2 Aug 2023 23:12:36 +0800 Subject: [PATCH] update --- Environment.py | 51 ++---------------------------------------- ga_new.py | 15 +++++++++++-- initial_material.xlsx | Bin 11285 -> 12252 bytes 3 files changed, 15 insertions(+), 51 deletions(-) diff --git a/Environment.py b/Environment.py index 143c379..bd60219 100644 --- a/Environment.py +++ b/Environment.py @@ -84,6 +84,7 @@ class FMSEnv(ap.Model): if self.t >= self.int_stop_time: self.running = False self.stop() + # else: # # # print(f"running the {self.t} step") @@ -121,22 +122,9 @@ def GA_run(inventory_bound=None): S = tuple(tuple([i, j]) for i, j in zip(material, inventory_bound[ len(pd.read_excel("initial_material.xlsx").to_numpy()): len( pd.read_excel("initial_material.xlsx").to_numpy()) * 2])) - # print(s) - # print(S) + dct_para = { 'time': 300, # 进行总时间数 - # 'xv_int_max_order': random.randint(30, 50), - # 'xv_dlv_product_para': tuple([(30, 100), (30, 50)]), - # 'xv_dlv_product_para': tuple([30,40,30,20]), # 读取生产率 np.read. - # 'xv_int_dlv_period_lam': 8.5, - # 'xv_int_create_order_lam': 2, - # 'xv_ary_price_product': tuple([0.3,0.2,0.5,1]), - # 'xv_ary_cost_material_per': tuple([0.1,0.1,0.2,0.4]), - # 'xv_ary_volume_material': tuple([1.0, 1.5]), - # 'xv_ary_volume_product': tuple([3.0, 5.0]), - # 'xv_array_lead_time': 2, # 读取原材料表格 np.read, 暂时不读 变量代表的含义 - # 'xv_int_lead_time_c': 3, - # 'xv_int_lead_time_d': 1, 'xv_ary_product_id': tuple(pd.read_excel("initial_product.xlsx").iloc[:, 0]), # 产成品id顺序 'xv_ary_material_id': tuple(pd.read_excel("initial_material.xlsx").iloc[:, 0]), # 原材料id顺序 'xv_product_num': len(pd.read_excel("initial_product.xlsx").to_numpy()), # 产成品个数 @@ -150,43 +138,8 @@ def GA_run(inventory_bound=None): 'xv_ary_s': s, # s 'xv_ary_S': S, # S # 应读取遗传算法中随机生成的s,暂写为'1' 创建两个excel分别存储产品和原材料的库存 每个excel中存系统代码和库存 - # 'xv_flt_initial_cash': 50000.0, - # 'dct_status_info': json.dumps({ #需要引入生产状态表 - # "0": {"xv_flt_produce_rate": tuple([0.0, 0.0]), - # "xv_ary_mat_material": tuple([0.0, 0.0]), - # "xv_flt_broken_rate": 0, - # "xv_flt_run_cost": 0.0, - # "name": "wait" - # }, - # "1": {"xv_flt_produce_rate": tuple([90.0, 0.0]), - # "xv_ary_mat_material": tuple([4.0, 1.0]), - # "xv_flt_broken_rate": 0.03, - # "xv_flt_run_cost": 40.0, - # "name": "produceA" - # }, - # "2": {"xv_flt_produce_rate": tuple([0.0, 60.0]), - # "xv_ary_mat_material": tuple([1.5, 5.0]), - # "xv_flt_broken_rate": 0.05, - # "xv_flt_run_cost": 50.0, - # "name": "produceB" - # }, - # "3": {"xv_flt_produce_rate": tuple([55.0, 30.0]), - # "xv_ary_mat_material": tuple([2.0, 1.5]), - # "xv_flt_broken_rate": 0.07, - # "xv_flt_run_cost": 60.0, - # "name": "produceAB" - # }, - # "-1": {"xv_flt_produce_rate": 0.0, - # "xv_ary_mat_material": tuple([0.0, 0.0]), - # "xv_flt_broken_rate": 0.1, - # "xv_flt_run_cost": 100.0, - # "name": "failed" - # } - # }) - } sample = ap.Sample(dct_para) - exp = ap.Experiment(FMSEnv, sample, iterations=1, record=True) results = exp.run() return results['variables']['FMSEnv']['op_os_all_delay_time'][dct_para['time']] / 2 diff --git a/ga_new.py b/ga_new.py index 330e61e..07d821f 100644 --- a/ga_new.py +++ b/ga_new.py @@ -42,7 +42,7 @@ class GeneticAlgorithm: :ivar function: Object that can be used to evaluate the objective function """ - def __init__(self, function, dim, lb, ub, int_var=None, pop_size=20, num_gen=300, start="Random"): + def __init__(self, function, dim, lb, ub, int_var=None, pop_size=6, num_gen=300, start="Random"): self.nvariables = dim # column self.nindividuals = pop_size + (pop_size % 2) # Make sure this is even row @@ -102,6 +102,11 @@ class GeneticAlgorithm: ind = np.where(population[:, i] > self.upper_boundary[i]) population[ind, i] -= 1 + for pop in population: + for i in range(len(pop) // 2): + if pop[i] >= pop[i + len(pop) // 2]: + pop[i], pop[i + len(pop) // 2] = pop[i + len(pop) // 2], pop[i] + # Evaluate all individuals # function_values = self.function(population) we cannot compute in this way to ensure x is one-dim in policy n_row, n_dim = population.shape @@ -125,7 +130,8 @@ class GeneticAlgorithm: for _ in range(self.ngenerations): print('------------------------------') print("当前为第{}代".format(_)) - print("最优个体为:{}".format(best_individual)) + print("最优s为:{}".format(best_individual[0:115])) + print("最优S为:{}".format(best_individual[115:230])) print("最优值为:{}".format(best_value)) print("------------------------------") # Do tournament selection to select the parents @@ -174,6 +180,11 @@ class GeneticAlgorithm: # Keep the best individual population[0, :] = best_individual + for pop in population: + for i in range(len(pop) // 2): + if pop[i] >= pop[i + len(pop) // 2]: + pop[i], pop[i + len(pop) // 2] = pop[i + len(pop) // 2], pop[i] + # Evaluate all individuals # function_values = self.function(population) we cannot compute in this way to ensure x is one-dim in policy n_row, n_dim = population.shape diff --git a/initial_material.xlsx b/initial_material.xlsx index 3ff30df46da3d0fed36a8c2932e44e2aeb74310e..30fd9af86574463f0b83f86d4940ee7efdbc8fb9 100644 GIT binary patch delta 6653 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