Untitled
unknown
python
6 months ago
9.0 kB
3
Indexable
import random from constraints import ensure_bean_crop_in_future_three_years, mushroom_season_constraints, no_continuous_crop_rotation_constraints_1,crop_location_season_constraints_v2,is_valid_for_greenhouse_second_season,is_valid_for_irrigated_land_second_season def selection(particles, num_selected): """ 轮盘赌选择操作,根据粒子的适应度值选择一定数量的粒子参与交叉和变异。 :param particles: 当前粒子群 :param num_selected: 需要选择的粒子数量 :return: 被选中的粒子列表 """ fitness_values = [particle.best_value for particle in particles] # 将适应度标准化为正值 min_fitness = min(fitness_values) if min_fitness < 0: fitness_values = [fitness - min_fitness for fitness in fitness_values] total_fitness = sum(fitness_values) selection_probs = [fitness / total_fitness for fitness in fitness_values] # 使用权重选择粒子 selected_particles = random.choices(particles, weights=selection_probs, k=num_selected) return selected_particles def crossover_with_constraints(parent1, parent2, crossover_point, land_info, crop_type_mapping, generate_random_position_with_constraints, previous_year_crops_mapping): """ 单点交叉操作后,验证约束,若有错误使用传递的生成新粒子函数重新生成。 """ try: child1 = parent1[:crossover_point] + parent2[crossover_point:] child2 = parent2[:crossover_point] + parent1[crossover_point:] if not validate_child_constraints(child1, land_info, 2024, previous_year_crops_mapping, crop_type_mapping): print("子代1不符合约束,生成新粒子替代") child1 = generate_random_position_with_constraints(land_info, crop_type_mapping) if not validate_child_constraints(child2, land_info, 2024, previous_year_crops_mapping, crop_type_mapping): # print("子代2不符合约束,生成新粒子替代") child2 = generate_random_position_with_constraints(land_info, crop_type_mapping) return child1, child2 except IndexError: #print("交叉操作中出现索引错误,生成新粒子替代") return generate_random_position_with_constraints(land_info, crop_type_mapping), generate_random_position_with_constraints(land_info, crop_type_mapping) def validate_child_constraints(child, land_info, current_year, previous_year_crops_mapping, crop_type_mapping): """ 验证子代是否符合所有约束条件。 :param child: 子代粒子 :param land_info: 地块信息 :param current_year: 当前年份 :param previous_year_crops_mapping: 上一年种植情况 :param crop_type_mapping: 作物类型映射 :return: 如果子代符合所有约束,返回 True,否则返回 False """ single_season_lands = [land for land in land_info if land_info[land]['type'] == '旱地'] for land_idx, land_name in enumerate(land_info.keys()): for year_idx in range(len(child[land_idx])): # 遍历年份 num_seasons = 1 if land_name in single_season_lands else 2 land_type = land_info[land_name]['type'] for season_idx in range(num_seasons): # 遍历季节 for crop_idx in range(len(child[land_idx][year_idx][season_idx])): crop_data = child[land_idx][year_idx][season_idx][crop_idx] # 检查是否符合所有约束 if not (ensure_bean_crop_in_future_three_years(land_name, child, current_year, previous_year_crops_mapping) and no_continuous_crop_rotation_constraints_1(land_type, crop_data, child[land_idx][year_idx-1][season_idx] if year_idx > 0 else []) and crop_location_season_constraints_v2(land_type, season_idx, crop_data[0]) and mushroom_season_constraints(land_type, season_idx, crop_data[0]) and is_valid_for_greenhouse_second_season(land_type, season_idx, crop_data[0], ['榆黄菇', '香菇', '白灵菇', '羊肚菌']) and is_valid_for_irrigated_land_second_season(land_type, season_idx, crop_data[0], ['大白菜', '白萝卜', '红萝卜'])): return False # 不符合约束,返回 False return True # 符合所有约束 def mutate_crop_selection_or_area(crop_data, land_info, crop_type_mapping, land_name): """ 变异操作,随机改变作物的选择或种植面积。 :param crop_data: 当前的作物信息 :param land_info: 地块信息 :param crop_type_mapping: 作物类型映射 :param land_name: 当前地块的名称,用于从 land_info 中获取面积信息 :return: 变异后的作物信息 """ # 随机决定变异是改变作物还是改变面积 try: if random.random() < 0.5: # 随机改变作物 crop_data[0] = random.choice(list(crop_type_mapping.keys())) else: # 根据 land_name 获取地块的面积 max_area = land_info[land_name]['area'] # 随机改变种植面积 crop_data[3] = random.uniform(0, max_area) except KeyError: print(f"KeyError: '{land_name}' 地块中缺少 'area' 属性。") return crop_data def validate_structure(particle): """ 验证粒子数据结构的完整性,确保没有空的季节或作物数据。 """ for land_idx in range(len(particle)): for year_idx in range(len(particle[land_idx])): for season_idx in range(len(particle[land_idx][year_idx])): if not isinstance(particle[land_idx][year_idx][season_idx], list) or len(particle[land_idx][year_idx][season_idx]) == 0: return False return True def mutate(particle, land_info, crop_type_mapping, generate_random_position_with_constraints, current_year, previous_year_crops_mapping, single_season_lands, mutation_rate=0.05): """ 变异操作,若变异出错则使用传递的函数生成新粒子替代。 """ try: for land_idx, land_name in enumerate(land_info.keys()): for year_idx in range(len(particle.position[land_idx])): # 遍历年份 num_seasons = 1 if land_name in single_season_lands else 2 land_type = land_info[land_name]['type'] for season_idx in range(num_seasons): # 遍历季节 for crop_idx in range(len(particle.position[land_idx][year_idx][season_idx])): if random.random() < mutation_rate: crop_data = particle.position[land_idx][year_idx][season_idx][crop_idx] original_crop_data = crop_data[:] crop_data = mutate_crop_selection_or_area(crop_data, land_info, crop_type_mapping,land_name) if (ensure_bean_crop_in_future_three_years(land_name, particle.position, current_year, previous_year_crops_mapping) and no_continuous_crop_rotation_constraints_1(land_type, crop_data, particle.position[land_idx][year_idx-1][season_idx] if year_idx > 0 else []) and crop_location_season_constraints_v2(land_type, season_idx, crop_data[0]) and mushroom_season_constraints(land_type, season_idx, crop_data[0]) and is_valid_for_greenhouse_second_season(land_type, season_idx, crop_data[0], ['榆黄菇', '香菇', '白灵菇', '羊肚菌']) and is_valid_for_irrigated_land_second_season(land_type, season_idx, crop_data[0], ['大白菜', '白萝卜', '红萝卜'])): particle.position[land_idx][year_idx][season_idx][crop_idx] = crop_data else: particle.position[land_idx][year_idx][season_idx][crop_idx] = original_crop_data return particle except IndexError: #print("变异操作中出现索引错误,生成新粒子替代") return generate_random_position_with_constraints(land_info, crop_type_mapping) def validate_structure(particle): """ 验证粒子数据结构的完整性,确保没有空的季节或作物数据。 """ for land_idx in range(len(particle)): for year_idx in range(len(particle[land_idx])): for season_idx in range(len(particle[land_idx][year_idx])): if not isinstance(particle[land_idx][year_idx][season_idx], list) or len(particle[land_idx][year_idx][season_idx]) == 0: return False return True
Editor is loading...
Leave a Comment