scikit-opt 遗传算法进阶实战:整数规划、TSP 固定端点与初始种群设定
科学计算【免费下载链接】scikit-opt主流群体智能算法差分进化算法、遗传算法、粒子群算法、模拟退火算法、蚁群算法、免疫优化算法、鱼群算法解决常规最优化问题以及旅行商问题项目地址https://gitcode.com/guofei9987/scikit-opt点击查看免费下载遗传算法GA在实际落地时往往会遇到三个经典痛点如何让某些变量严格取整数、如何在旅行商问题TSP中固定起点与终点、以及如何注入自定义的初始解。本指南以 scikit-opt 仓库中的 more_ga.md 为骨架结合 GA.py 的源码实现与 demo_ga_tsp.py 等示例逐条给出可直接运行的代码与底层原理读完即可在自己的优化任务中复现这三种进阶玩法。用遗传算法做整数规划核心用法让precision为整数在多维优化中想让哪个变量被限制为整数就把对应位置的precision设为整数。例如自定义目标函数demo_func希望第一个变量按步长 2 取值即整数且间隔为 2、第二个变量按步长 1 取值普通整数、第三个变量保持浮点数精度只需写precision[2, 1, 1e-7]from sko.GA import GA demo_func lambda x: (x[0] - 1) ** 2 (x[1] - 0.05) ** 2 x[2] ** 2 ga GA(funcdemo_func, n_dim3, max_iter500, lb[-1, -1, -1], ub[5, 1, 1], precision[2, 1, 1e-7]) best_x, best_y ga.run() print(best_x:, best_x, \n, best_y:, best_y)注意precision的语义是该变量的取值粒度整数模式下第 0 维变量的实际取值是lb[0] k * 2k 为非负整数第 1 维是lb[1] k * 1第 2 维仍按 1e-7 的浮点精度连续取值。precision支持标量自动广播到每个维度也支持列表或数组这一点在 GA.py 中通过np.array(precision) * np.ones(self.n_dim)完成。整数规划模式背后的编码机制从 GA.py 的源码可以看到GA用二进制染色体Gray Code分段编码每个变量段长由精度决定Lind_raw np.log2((self.ub - self.lb) / self.precision 1) self.Lind np.ceil(Lind_raw).astype(int) self.int_mode_ (self.precision % 1 0) (Lind_raw % 1 ! 0) self.int_mode np.any(self.int_mode_) if self.int_mode: self.ub_extend np.where(self.int_mode_ , self.lb (np.exp2(self.Lind) - 1) * self.precision , self.ub)这里有几个可以直接用于调参的结论precision为整数时该维度进入整数规划模式int_modeprecision为浮点如默认的 1e-7时变量按连续区间映射。取值个数最好是 $2^n$。此时染色体段长 $Lind\log_2(取值个数)$ 恰好是整数每个取值与一组二进制编码一一对应收敛速度与效果最佳。取值个数不是 $2^n$ 时依然能正常工作代价是部分编码会冗余。从源码看当取值个数不是 $2^n$ 时GA会自动把上界扩展到ub_extend lb (2**Lind - 1) * precision见 GA.py使可编码取值总数恰好等于 $2^{Lind}$解码时再用np.where(X self.ub, self.ub, X)把超出原ub的值裁剪回去见 GA.py。对取值个数不是 $2^n$的场景文档还提示了另一层约束如果你的等式约束constraint_eq与不等式约束constraint_ueq本身已经很多罚函数带来的影响会被放大更推荐先手动调整变量规避取值个数不是 $2^n$ 的情况。这一提示与 base.py 中x2y()的罚函数实现相互印证——约束违背会以1e5量级的惩罚项叠加到目标值上见 GA.py约束越多搜索空间越崎岖。非整数precision想用整数模式怎么办如果precision不是整数例如原本是 0.5它不会进入整数规划模式。想沿用整数模式文档给出的标准手法是把对应自变量乘以 2使precision变成整数。例如原变量x ∈ [0, 1]、precision0.5可令新变量y 2x ∈ [0, 2]、precision1参与优化最后再把best_x除以 2 还原。本质是先缩放再做整数编码最后反变换。GA 求解 TSP如何固定起点与终点原理起点终点不参与优化TSP 有两种形态闭合回路环与开环路径。若路径是闭合的起点与终点本就在环上固定与否结果等价无需特殊处理只有要求非闭合路径从指定起点出发、在指定终点停下时才需要固定端点。固定起止点的核心思路非常简洁设总共有n 2个点含起点和终点优化的只是中间n个点的访问顺序起点、终点不进入决策变量目标函数按真实路径书写把起点、终点拼接到routine首尾累加相邻点之间的欧氏距离。例如起点为(0, 0)、终点为(1, 1)则目标函数构造如下import numpy as np from scipy import spatial import matplotlib.pyplot as plt num_points 20 points_coordinate np.random.rand(num_points, 2) # generate coordinate of points start_point[[0,0]] end_point[[1,1]] points_coordinatenp.concatenate([points_coordinate,start_point,end_point]) distance_matrix spatial.distance.cdist(points_coordinate, points_coordinate, metriceuclidean) def cal_total_distance(routine): The objective function. input routine, return total distance. cal_total_distance(np.arange(num_points)) num_points, routine.shape # start_point,end_point 本身不参与优化。给一个固定的值参与计算总路径 routine np.concatenate([[num_points], routine, [num_points1]]) return sum([distance_matrix[routine[i], routine[i 1]] for i in range(num_points2-1)])注意这里points_coordinate拼接后num_points号点就是起点(0, 0)num_points1号点就是终点(1, 1)决策变量routine是中间n个点的排列长度恰为num_points。求解与可视化用GA_TSP求解的方式与其他 TSP 场景一致from sko.GA import GA_TSP ga_tsp GA_TSP(funccal_total_distance, n_dimnum_points, size_pop50, max_iter500, prob_mut1) best_points, best_distance ga_tsp.run() fig, ax plt.subplots(1, 2) best_points_ np.concatenate([[num_points],best_points, [num_points1]]) best_points_coordinate points_coordinate[best_points_, :] ax[0].plot(best_points_coordinate[:, 0], best_points_coordinate[:, 1], o-r) ax[1].plot(ga_tsp.generation_best_Y) plt.show()左图把最优排列还原为起点 → 中间 n 点 → 终点的完整坐标序列并连线直观验证路径确实从(0,0)出发、在(1,1)结束右图绘制ga_tsp.generation_best_Y即每一代最优距离的收敛曲线可用于判断max_iter是否足够。与闭合回路 TSP 的实现差异对比仓库中的闭合回路版本 demo_ga_tsp.py其目标函数用取模实现首尾相连return sum([distance_matrix[routine[i % num_points], routine[(i 1) % num_points]] for i in range(num_points)])而固定端点版本则用np.concatenate显式把两个固定端点夹在首尾。两种写法都对应GA_TSP内部的排列编码从 GA.py 可以看到GA_TSP用tmp.argsort(axis1)生成全排列种群交叉算子采用部分匹配交叉PMX见 crossover.py变异算子采用 2-Opt 式的反转变异mutation_reverse见 mutation.py。PMX 与反转变异都能保证子代仍是合法排列这正是排列类优化能正确收敛的结构基础。另外注意GA_TSP.run()与普通GA.run()的差异前者每一代把父代与子代合并后按适应度截取最优的size_pop个个体精英保留策略见 GA.py因此在同样代数下搜索强度更高max_iter可适当调小。如何设定初始点或初始种群四种核心算法都支持注入初始解做法各不相同算法注入方式说明遗传算法GAga.Chrom ...直接覆盖初始二进制染色体种群差分进化DEde.X ...直接覆盖初始实数种群矩阵模拟退火SA构造时传x0初始化起始点粒子群PSOpso.X ...后补算历史最优覆盖粒子位置并同步 pbest / gbestGA覆盖Chrom对于GA实例化ga GA(**params)后直接给Chrom赋值即可设定初始种群例如ga.Chrom np.random.randint(0, 2, size(80, 20))这里的Chrom是形状为(size_pop, len_chrom)的 0/1 矩阵行数80对应种群个体数应与size_pop一致列数20对应整条染色体的基因总长。从源码看染色体总长为各变量编码段长之和self.len_chrom sum(self.Lind)见 GA.py如果你自定义的列数小于len_chromchrom2x()解码时会直接越界出错因此手动赋值前最好先用默认值跑一次检查ga.len_chrom与ga.size_pop。默认初始种群由crtbp()生成即np.random.randint(low0, high2, size(self.size_pop, self.len_chrom))见 GA.py手动赋值只是把这一随机初始化替换为你的先验知识。DE覆盖X差分进化算法DE中de.X是形状为(size_pop, n_dim)的实数种群矩阵默认由crtbp()在[lb, ub]内均匀随机采样生成见 DE.py。要注入初始解直接赋值即可de.X my_initial_population # shape: (size_pop, n_dim)后续mutation()的变异基向量V[i] X[r1] F * (X[r2] - X[r3])见 DE.py会自动基于你给定的X展开且变异越界时会被重新采样到[lb, ub]内因此不必担心越界问题。SA构造时传x0模拟退火算法SA的初始点通过构造函数参数x0传入。从 SA.py 的源码看__init__(self, func, x0, T_max100, T_min1e-7, L300, max_stay_counter150, **kwargs)会执行self.n_dim len(x0)、self.best_x np.array(x0)即x0同时决定了解空间的维度和搜索的出发点from sko.SA import SA sa SA(funcdemo_func, x0[0.5, 0.5], T_max100, T_min1e-7, L300, max_stay_counter150) best_x, best_y sa.run()PSO覆盖X并同步 pbest / gbest粒子群算法PSO初始化时会在[lb, ub]内随机生成粒子位置self.X np.random.uniform(lowself.lb, highself.ub, size(self.pop, self.n_dim))见 PSO.py。手动注入初始解的正确姿势是赋值pso.X之后立即补算三个状态量pso.X my_initial_particles # shape: (pop, n_dim) pso.cal_y() # 重算每个粒子的适应度 Y func(X) pso.update_gbest() # 更新全局最优 gbest_x / gbest_y pso.update_pbest() # 更新每个粒子的历史最优 pbest_x / pbest_y顺序有讲究cal_y()先刷新self.Y见 PSO.pyupdate_pbest()用Y更小且满足约束的粒子更新个体历史最优见 PSO.pyupdate_gbest()从pbest_y中挑出全局最优见 PSO.py。如果只改X不调用这三个方法后续迭代的速度更新V w*V cp*r1*(pbest_x - X) cg*r2*(gbest_x - X)会基于错误的 pbest/gbest 进行注入的初始解反而可能把种群带偏。为什么不建议直接复用.fit()的旧写法仓库基类 base.py 中保留了fit()作为run()的兼容别名但会抛出DeprecationWarning。文档与示例均推荐统一使用run()例如best_x, best_y ga.run()上文的 TSP 固定端点示例也遵循了这一约定。如果你的历史代码仍在用.fit()建议尽快迁移。小结整数规划把对应维度的precision设为整数即可启用整数模式取值个数尽量取 $2^n$非整数精度可先对变量做缩放变换。底层由 GA.py 的段长计算、ub_extend扩展与裁剪逻辑支撑。固定起止点的 TSP让起点、终点不进入决策变量仅优化中间n个点并在目标函数中把两端拼接回去配合GA_TSP的 PMX 交叉与反转变异求解用左图验证路径、右图观察收敛曲线对比闭合回路版本见 demo_ga_tsp.py。初始解注入GA覆盖ga.Chrom、DE覆盖de.X、SA传参x0、PSO覆盖pso.X后依次执行cal_y()/update_gbest()/update_pbest()。以上三种手法都只涉及求解器的调用方式目标函数与数据准备完全由你自己掌控因此同样适用于后续引入更复杂的组合约束、先验路径或多起点重启策略的工程化场景。赞分享科学计算【免费下载链接】scikit-opt主流群体智能算法差分进化算法、遗传算法、粒子群算法、模拟退火算法、蚁群算法、免疫优化算法、鱼群算法解决常规最优化问题以及旅行商问题项目地址https://gitcode.com/guofei9987/scikit-opt点击查看免费下载相关推荐scikit-opt 遗传算法进阶实战整数规划、TSP 固定端点与初始种群设定scikit opt 遗传算法进阶实战整数规划、TSP 固定端点与初始种群设定 本篇基于 scikit opt 仓库的 docs/zh/more_ga.md科学计算scikit-opt 遗传算法进阶实战整数规划、TSP 固定起终点与初始种群设定scikit opt 遗传算法进阶实战整数规划、TSP 固定起终点与初始种群设定 遗传算法GA除了求解连续变量的最优化问题还经常需要处理整数规划、旅行商科学计算scikit-opt 群体智能算法库实战指南七大算法求解最优化问题与 TSP 路线规划scikit opt 群体智能算法库实战指南七大算法求解最优化问题与 TSP 路线规划 scikit opt 是一个用 Python 实现的群体智能算法库基科学计算上一篇Relay 查询变量完全指南从全局变量到 arguments 与 argumentDefinitions下一篇CogVideoX-2b提示词工程指南10个技巧让你的视频生成效果提升300%创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考