Untitled
unknown
python
a year ago
9.0 kB
6
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