python遗传算法解决分段线性约束问题

问题描述

  • 模型
    python遗传算法解决分段线性约束问题_第1张图片

  • 分析

  • 带有分段约束和max最值,导致使用一般的线性规划pulp问题进行求解会比较麻烦
  • 如果将分段约束转化为0/1整数规划,其余变量 u i u_i ui未必还是整数,就涉及混整问题相对麻烦,所以考虑使用遗传算法进行求解

Python代码

import numpy as np
import matplotlib.pyplot as plt
from pylab import *

mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

####################初始化参数#####################
NP = 50  # 种群数量
L = 2  # 对应x,y
Pc = 0.4  # 交叉率
Pm = 0.1  # 变异率
G = 100  # 最大遗传代数


########################这里定义一些参数,分别是计算适应度函数和计算约束惩罚项函数############

def calc_f(X, ri, qi,k):
    """计算群体粒子的目标函数值, size * N(,size表示种群数,N表示决策变量个数) """
    if k==1:
        return sum((ri - qi) * X)
    elif k==2:
        lamda =0.5
        return lamda * sum(ri * X) - (1 - lamda) * sum(qi * qi * X * X)


def calc_e(X, qi, pi, ki, Mi):
    """计算群体粒子的目惩罚项,X 的维度是 size * N(,size表示种群数,N表示N表示决策变量个数为11) """
    sumcost = []
    C_X = []

    for i in range(X.shape[0]):
        C_X = []
        ee = 0
        """计算第一个约束的惩罚项"""
        e1 = max(qi * X[i]) - 250
        ee += max(0, e1)
        """计算第二个约束的惩罚项"""
        for j in range(X.shape[1]):
            if X[i, j] > Mi[j]:
                CX = ki[j] + pi[j] * X[i, j]
                C_X.append(CX)
            else:
                CX = ki[j] + pi[j] * Mi[j]
                C_X.append(CX)
        e2 = sum(X[i] + C_X) - 50000
        ee += max(0, e2)
        sumcost.append(ee)
    return sumcost


##############遗传操作方法#########

def select(X, fitness):
    """根据轮盘赌法选择优秀个体"""
    fitness = 1 / fitness  # fitness越小表示越优秀,被选中的概率越大,做 1/fitness 处理
    fitness = fitness / fitness.sum()  # 归一化
    idx = np.array(list(range(X.shape[0])))
    X2_idx = np.random.choice(idx, size=X.shape[0], p=fitness)  # 根据概率选择
    X2 = X[X2_idx, :]
    return X2


def crossover(X, c):
    """按顺序选择2个个体以概率c进行交叉操作"""
    for i in range(0, X.shape[0], 2):
        parent1 = X[i].copy()  # 父亲
        parent2 = X[i + 1].copy()  # 母亲
        # 产生0-1区间的均匀分布随机数,判断是否需要进行交叉替换
        if np.random.rand() <= c:
            child1 = (1 - c) * parent1 + c * parent2  # 交叉子代
            child2 = c * parent1 + (1 - c) * parent2  # 交叉子代
            X[i, :] = child1
            X[i + 1, :] = child2
    return X


def mutation(X, m):
    """变异操作"""
    for i in range(X.shape[0]):  # 遍历每一个个体
        # 产生0-1区间的均匀分布随机数,判断是否需要进行变异
        parent = X[i].copy()  # 父辈
        if np.random.rand() <= m:
            child = np.random.uniform(0, 25, (1, 11))  # 用随机赋值的方式进行变异子代
            X[i] = child
    return X


# 子代和父辈之间的选择操作
def update_best(parent, parent_fitness, parent_e, child, child_fitness, child_e):
    """
        判
        :param parent: 父辈个体
        :param parent_fitness:父辈适应度值
        :param parent_e    :父辈惩罚项
        :param child:  子代个体
        :param child_fitness 子代适应度值
        :param child_e  :子代惩罚项

        :return: 父辈 和子代中较优者、适应度、惩罚项

        """
    # 规则1,如果 parent 和 child 都没有违反约束,则取适应度小的
    if parent_e <= 0.0000001 and child_e <= 0.0000001:
        if parent_fitness <= child_fitness:
            return parent, parent_fitness, parent_e
        else:
            return child, child_fitness, child_e
    # 规则2,如果child违反约束而parent没有违反约束,则取parent
    if parent_e < 0.0000001 and child_e >= 0.0000001:
        return parent, parent_fitness, parent_e
    # 规则3,如果parent违反约束而child没有违反约束,则取child
    if parent_e >= 0.0000001 and child_e < 0.0000001:
        return child, child_fitness, child_e
    # 规则4,如果两个都违反约束,则取适应度值小的
    if parent_fitness <= child_fitness:
        return parent, parent_fitness, parent_e
    else:
        return child, child_fitness, child_e


def ga_answer1(ri, qi, pi, ki, Mi,k):
    """遗传算法主函数"""
    best_fitness = []  # 记录每次迭代的效果
    best_U = []  # 存放最优U
    f = np.random.uniform(0, 25, (NP, 11))  # 初始化种群
    for i in range(G):  # 遍历每一次迭代
        fitness = np.zeros((NP, 1))  # 存放适应度值
        ee = np.zeros((NP, 1))  # 存放惩罚项值

        parentfit = calc_f(f, ri, qi,k)  # 计算父辈目标函数值
        parentee = calc_e(f, qi, pi, ki, Mi)  # 计算父辈惩罚项
        parentfitness = parentfit + parentee  # 计算父辈适应度值   适应度值=目标函数值+惩罚项
        X2 = select(f, parentfitness)  # 选择
        X3 = crossover(X2, Pc)  # 交叉
        X4 = mutation(X3, Pm)  # 变异

        childfit = calc_f(X4, ri, qi,k)  # 子代目标函数值
        childee = calc_e(X4, qi, pi, ki, Mi)  # 子代惩罚项
        childfitness = childfit + childee  # 子代适应度值

        # 更新群体
        for j in range(NP):  # 遍历每一个个体
            X4[j], fitness[j], ee[j] = update_best(f[j], parentfitness[j], parentee[j], X4[j], childfitness[j],
                                                   childee[j])

        best_fitness.append(fitness.min())
        U = X4[fitness.argmin()]
        best_U.append(U)
        f = X4

        # 多次迭代后的最终效果
    portfolio_optimal_value = -min(best_fitness)
    portfolio_optimal_solution = best_U[best_fitness.index(min(best_fitness))]
    print("最优值是:", -min(best_fitness))  # best_fitness记录最优值
    print("最优解是:", best_U[best_fitness.index(min(best_fitness))])  # best_U记录最优解集
    return portfolio_optimal_solution

# 第一问答案
ri = np.array([3.5, 5.4, 4.5, 6.7, 7.7, 8.8, 8, 6.5, 7.3, 9.1, 2.3]);
qi = np.array([11, 12, 25, 25, 19, 33, 32, 31, 33, 34, 0]);
pi = np.array([0.12, 0.15, 0.15, 0.2, 0.11, 0.13, 0.18, 0.2, 0.25, 0.2, 0]);
ki = np.array([0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.1, 0.2, 0.3, 0.2, 0]);
Mi = np.array([50, 50, 100, 50, 100, 50, 100, 50, 100, 100, 0]);
k=1
ga_answer1(ri, qi, pi, ki, Mi,k)

  • 结果
    在这里插入图片描述

优缺点

  • 优点:可以解决带分段约束的线性规划问题,当然也可以将非线性的分段约束规划转化为0/1规划,然后再利用 u i u_i ui w 1 w_1 w1 w 2 w_2 w2 w 3 w_3 w3关系,将其余 u i u_i ui都用 w 1 w_1 w1 w 2 w_2 w2 w 3 w_3 w3表示,没有试过,不过可以尝试一下
  • 缺点:遗传算法不是唯一解,变异率、变异率等参数可以调整一下,交叉和变异处可以更改交叉和变异规则,会得到不一样的效果

参考文献

遗传算法求解带约束优化问题(源码实现)

你可能感兴趣的:(python,python,开发语言)