单纯形法的补充与代码实现

news2024/9/23 1:28:25

线性规划中,我们介绍了三种求解算法——单纯形法、对偶理论和内点法。

传送门:线性规划之单纯形法 线性规划的对偶理论 线性规划之内点法

其中单纯形法要建立在标准型上,并且开始迭代要求有一个基本可行解。如果系数矩阵A规模较大,有时候比较难找到初始可行解。这时候需要用人工手段增加变量,来找到初始可行解。具体方法为:

通过从每个约束行中选取系数在对应列向量中唯一非零,而且系数符号与右边项一致的变量作为基变量,可以构造单纯形法的初始基。如果标准型中没有满足条件的变量,可以引入人工变量。此时目标函数为求人工变量之和最小化的问题,即目标函数除人工变量系数为1外,其余变量系数均为0.

我们举一个例子,对于下面的标准型LP问题,引入人工变量找到初始可行集:

fa89b67d9f40c91bbb8232967fe45997.png

首先看第一个约束,变量x4系数在列向量中唯一非零,但其系数为负,而对应的右边项系数为正,因此需要引入人工变量x6;第二个约束,变量x5系数在列向量中唯一非零,且符号与右边项一致,因此x5可作为初始基。第三第四个约束均没有满足条件的向量,引入人工变量x7和x8。

此时要求解的目标函数变为:

2f696826052c88d0ccf80754dbe97628.png

最后四列即可新LP问题的初始可行解,通过单纯形法可以求解最优解。最后还需要检验该问题最优解是否为原模型的可行解。判断标准为:

如果人工变量之和最小值大于0,则原模型无可行解,计算到此为止,否则人工模型最后的基作为求解原模型的初始可行基

我们用python开发完整的单纯形法代码,包含人工模型的(阶段一)以及求解原模型(阶段二)的过程。考虑到有些场景可以直接找到原模型初始可行解,因此阶段一不一定用得上,因此用python的装饰器实现。

import numpy as np
import pandas as pd
from numpy.linalg import det,inv #求解矩阵的秩和逆矩阵


class Simplex(object):
    '''
    单纯形法求解最值问题,这里固化为求最小值,要是遇到求最大值,将目标系数向量取负号即可
    '''


    def __init__(self, A, b, c, B_x):


        '''


        :param A: 系数矩阵
        :param b: 常数向量
        :param c: 目标函数系数向量
        :param B_x: 初始基变量索引列表
        '''
        self.A = A
        self.b = b
        self.c = c
        self.B_x = B_x


    def __call__(self, *args, **kwargs):


        print('单纯形法第二阶段...')
        x = self.phaseII(self.A, self.b, self.c, self.B_x)
        return x


    @classmethod
    def phaseI(cls, manual_n, A_, b, c, B_x_):


        '''
        单纯形法第一阶段,确定初始可行基
        这里人工变量排在矩阵后面
        :param manual_n: 人工变量的个数
        :param A_: 添加人工变量后的系数矩阵
        :param b: 常数向量
        :param c: 目标函数系数向量
        :param B_x_: 初始可行基
        :return:
        '''


        print('单纯形法第一阶段......')
        c_ = [0 for i in range(len(c))] + [1 for i in range(manual_n)]  # 添加人工变量后的目标函数系数向量, 人工变量系数为1,其余均为0
        c_ = np.array(c_)
        x_ = cls.phaseII(A_, b, c_, B_x_)
        a = np.dot(c_, np.array(x_))


        if a > 0:
            print('原模型无可行解')
        else:
            B_x = []
            for n, i in enumerate(x_):
                if i != 0:
                    B_x.append(n)


            return cls(A_[:, :-manual_n], b, c, B_x)


    @staticmethod
    def phaseII(A, b, c, B_x):
        '''


        :param n: 列向量个数
        :param B_x: 初始基变量索引列表
        :return:
        '''


        n = A.shape[1]  # 列向量个数
        N_x = list(filter(lambda x: 0 if x in B_x else 1, [i for i in range(n)]))  # 初始非基变量索引
        init_B = A[:, B_x]  # 基矩阵
        x_0 = np.dot(inv(init_B), b)  # t=0的解
        for i in N_x:
            x_0 = np.insert(x_0, i, 0)


        t, dim = 0, n - len(N_x)
        while True:


            if t >= 100:
                break


            # print('t={}时刻**********'.format(t))
            print('t={}时刻目标函数取值{}:'.format(t, np.dot(c, x_0)))
            # print('入基变量索引:', B_x)
            # print('出基变量索引:', N_x)
            # print('基矩阵:', init_B)
            # print('唯一解:', x_0)


            v = np.dot(c[B_x], inv(init_B))  # 定价向量
            # print('定价向量:', v)
            delta_c = dict(zip([c[i] - np.dot(v, A[:, i]) for i in N_x], N_x))
            # print('非基变量目标函数变化值:', delta_c)


            if min(delta_c) < 0:
                p = delta_c[min(delta_c)]
            else:
                p = -1
                print('计算结束,最优解为:', x_0)
                break


            delta_x = np.dot(-inv(init_B), A[:, p])
            # print('入基变量索引p={},此时单纯性方向为:{}'.format(p, delta_x))


            if min(delta_x) < 0:
                di = {}
                for i in range(dim):
                    if delta_x[i] < 0:
                        di[B_x[i]] = -x_0[B_x[i]] / delta_x[i]
                lam = min(di.values())
                r = min(di, key=di.get)
            else:
                r = -1
                print('单纯性方向所有元素非负,模型无界')
                break
            # print('出基变量索引r={},此时lamda取值为{}'.format(r,lam))


            E = np.identity(dim)
            E[:, B_x.index(r)] = [
                -1 / delta_x[B_x.index(r)] if i == B_x.index(r) else -delta_x[i] / delta_x[B_x.index(r)]
                for i in range(dim)]
            init_B = inv(np.dot(E, inv(init_B)))


            d = dict(zip(B_x, delta_x))
            delta_x = np.array(list(dict(sorted(d.items(), key=lambda x: x[0])).values()))
            for i in N_x:
                delta_x = np.insert(delta_x, i, 0)
            delta_x[p] = 1


            B_x[B_x.index(r)] = p  # 更新入基变量索引
            N_x = list(filter(lambda x: 0 if x in B_x else 1, [i for i in range(n)]))  # 更新出基变量索引
            x_0 = [x_0[i] + lam * delta_x[i] for i in range(n)]  # 更新解
            t += 1
        #print('###########################################')


        return x_0

下面是应用单纯形法求灵敏度分析的过程:

import itertools as it
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False


def plot(di):


    li1 = list(di.keys())
    li2 = list(di.values())
    plt.scatter([li1[i] for i in [0,80,84,100,199,291,318,355]],[li2[i] for i in [0,80,84,100,199,291,318,355]],c='r')
    # plt.text(5, 9900, s='斜率8.57', verticalalignment='bottom')
    # plt.text(11, 9970, s='斜率36.73', verticalalignment='bottom')
    # plt.text(10, 10020, s='斜率50.11', verticalalignment='bottom')
    plt.plot(di.keys(),di.values())
    # plt.xlim(-1,13)
    plt.xlabel('目标函数系数')
    plt.ylabel('最优值')
    plt.title('废料4成本对目标最优值影响')
    plt.show()




if __name__ == '__main__':
    # 系数矩阵
    A = np.array(
        [[1.000, 1.000, 1.0000, 1.000, 1, 1, 1,  0, 0,  0, 0,  0, 0,  0, 0, 0, 0],
         [0.008, 0.007, 0.0085, 0.004, 0, 0, 0, -1, 0,  0, 0,  0, 0,  0, 0, 0, 0],
         [0.008, 0.007, 0.0085, 0.004, 0, 0, 0,  0, 1,  0, 0,  0, 0,  0, 0, 0, 0],
         [0.180, 0.032, 0.0000, 0.000, 1, 0, 0,  0, 0, -1, 0,  0, 0,  0, 0, 0, 0],
         [0.180, 0.032, 0.0000, 0.000, 1, 0, 0,  0, 0,  0, 1,  0, 0,  0, 0, 0, 0],
         [0.120, 0.011, 0.0000, 0.000, 0, 1, 0,  0, 0,  0, 0, -1, 0,  0, 0, 0, 0],
         [0.120, 0.011, 0.0000, 0.000, 0, 1, 0,  0, 0,  0, 0,  0, 1,  0, 0, 0, 0],
         [0.000, 0.001, 0.0000, 0.000, 0, 0, 1,  0, 0,  0, 0,  0, 0, -1, 0, 0, 0],
         [0.000, 0.001, 0.0000, 0.000, 0, 0, 1,  0, 0,  0, 0,  0, 0,  0, 1, 0, 0],
         [1.000, 0.000, 0.0000, 0.000, 0, 0, 0,  0, 0,  0, 0,  0, 0,  0, 0, 1, 0],
         [0.000, 1.000, 0.0000, 0.000, 0, 0, 0,  0, 0,  0, 0,  0, 0,  0, 0, 0, 1],
         ])


    di = dict()
    for coef in np.linspace(0, 50, 501):
        b = np.array([1000, 6.5, 7.5, 30, 35, 10, 12, 11, 13, 75, 250])  # 常数项
        c = np.array([16, 10, 8, coef, 48, 60, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])  # 目标函数系数
        B_x = [2, 3, 4, 5, 6, 7, 10, 12, 14, 15, 16]
        # B_x = [1,7,8,9,10,11,12,13,14,15,16]
        # print(det(A[:,B_x]))
        # print(A.shape,b.shape,c.shape)
        model = Simplex(A,b,c,B_x)
        x_0 = model()
        di[coef] = np.dot(c,np.array(x_0))


    pd.DataFrame([di.keys(),di.values()]).to_csv(r'RHS.csv',index=False)
    plot(di)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/59736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里云OSS依赖无法导入的问题

版本背景&#xff1a;springboot:2.4.12&#xff0c;spring-cloud:2020.0.1 在使用阿里云对象存储OSS服务时候&#xff0c;根据官方参考文档&#xff1a;aliyun-spring-boot/aliyun-spring-boot-samples/aliyun-oss-spring-boot-sample at master alibaba/aliyun-spring-boot…

第十五章 图的BFS与拓扑序列

图的BFS与拓扑序列一、图的BFS1、思路2、模板&#xff08;1&#xff09;问题&#xff08;2&#xff09;代码模板&#xff08;3&#xff09;代码解析二、拓扑序列引入&#xff1a;1、什么是拓扑序列&#xff1f;2、模板&#xff1a;&#xff08;1&#xff09;问题&#xff1a;&a…

一张图搞懂微服务架构设计

前言 当前&#xff0c;微服务架构在很多公司都已经落地实施了&#xff0c;下面用一张图简要概述下微服务架构设计中常用组件。不能说已经使用微服务好几年了&#xff0c;结果对微服务架构没有一个整体的认知&#xff0c;一个只懂搬砖的程序员不是一个好码农! 流量入口Nginx 在…

Awesome Uplift Modeling【如何学习因果推断、因果机器学习和Uplift建模?All in here】

Awesome-Uplift-Model How to Apply Causal ML to Real Scene Modeling&#xff1f;How to learn Causal ML&#xff1f; Github项目地址&#xff1a;&#x1f449;https://github.com/JackHCC/Awesome-Uplift-Model&#x1f448; &#x1f449;https://github.com/JackHCC/…

汇编原理理论知识复习

书上重点内容 本篇博客整理老师课上强调的重点理论知识&#xff0c;以便复习备考&#xff0c;如有错误欢迎指正。 这门课主要讲CPU芯片与其他芯片&#xff08;内存芯片和I/O接口芯片&#xff09;之间交互。 一条指令的执行过程&#xff1a;取指&#xff08;从主存取到CPU寄…

(五)Vue之data与el的两种写法

文章目录el的两种写法data的两种写法Vue学习目录 上一篇&#xff1a;&#xff08;四&#xff09;Vue之数据绑定 容器&#xff1a; <div id"root"><h1>hello,{{name}}</h1></div>el的两种写法 (1).new Vue时候配置el属性。 new Vue({el:#r…

【C语言航路】第六站:指针初阶

目录 一、指针是什么 二、指针和指针类型 1.指针类型的意义 2.指针-整数 3.指针解引用 三、野指针 1.野指针的成因 &#xff08;1&#xff09;指针未初始化 &#xff08;2&#xff09;指针越界访问 &#xff08;3&#xff09;指针指向的空间释放 2.如何规避野指针 &a…

伸手运动想象训练与伸手抓取想象的关系

本研究旨在确定为期4周的目标导向性伸手&#xff08;抓取任务&#xff09;的运动想象训练&#xff08;MIT&#xff09;是否会以相同的方式影响伸手&#xff08;MIR&#xff09;和抓取&#xff08;MIG&#xff09;运动想象的皮质活动。试验过程中&#xff0c;我们在健康的年轻参…

基于未知环境下四旋飞行器运动规划应用研究(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

QT QDoubleSpinBox 浮点计数器控件(使用详解)

本文详细的介绍了QDoubleSpinBox控件的各种操作&#xff0c;例如&#xff1a;新建界面、获取数值、设置前后缀、设置最大/小值、设置显示精度、关联信号槽、优化信号、关联控件、文件源码、样式表等等操作。 本文是QT控件使用详解的第十五篇 QT QDoubleSpinBox 浮点计数器控件(…

【ArcGIS风暴】ArcGIS栅格影像去除黑边(背景值)方法汇总

文章目录 1. 数据加载时属性中设置去除黑边2. 应用setnull工具去除黑边3. 应用栅格计算器去除黑边4. 应用复制栅格工具去除黑边5. 应用影像分析去除黑边6. 应用镶嵌数据集去除黑边影像产生黑边的原因无外乎在设置无效值时,将无效值设成了0,而影像在导入软件进行渲染时,并没有…

制作一个简单HTML静态网页(HTML+CSS)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

TensorRT安装

本文是为了记录安装TensorRT过程中遇到的一些问题。 首先进入TensorRT下载页面&#xff0c;选择你要下载的TensorRT版本。 因为TensorRT不同的版本依赖于不同的cuda版本和cudnn版本。所以很多时候我们都是根据我们自己电脑的cuda版本和cudnn版本来决定要下载哪个TensorRT版本。…

[附源码]计算机毕业设计校园招聘系统设计Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

如何收到消息第一时间将网站置灰,难道让程序员上个线?

注意&#xff1a;文本不是讲如何将网站置灰的那个技术点&#xff0c;那个技术点之前汶川地震的时候说过。 本文不讲如何实现技术&#xff0c;而是讲如何在第一时间知道消息后&#xff0c;更快速的实现这个置灰需求的上线。 实现需求不是乐趣&#xff0c;指挥别人去实现需求才…

安全研究 # 二进制代码相似性检测综述

本文参考&#xff1a; [1]方磊,武泽慧,魏强.二进制代码相似性检测技术综述[J].计算机科学,2021,48(05):1-8. (信息工程大学数学工程与先进计算国家重点实验室, 国家重点研发课题,北大核心) 摘要 代码相似性检测常用于代码预测、知识产权保护和漏洞搜索等领域&#xff0c;可分为…

Numpy入门[11]——生成数组的函数

Numpy入门[11]——生成数组的函数 参考&#xff1a; https://ailearning.apachecn.org/ 使用Jupyter进行练习 import numpy as nparange arange 类似于Python中的 range 函数&#xff0c;只不过返回的不是列表&#xff0c;而是数组&#xff1a; arange(start, stop None, st…

Java并发编程—java内存模型2

文章目录重排序数据依赖性as-if-serial重排序对多线程的影响顺序一致性同步程序的顺序一致性效果同步/异步总线事务双重校验锁—————————————————————————————————— 重排序 数据依赖性 数据依赖不能进行重排序 as-if-serial as-if-seri…

[附源码]计算机毕业设计大学生心理健康测评系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Compressed Bloom Filters论文总结

Compressed Bloom Filters论文总结AbstractI. INTRODUCTIONII. COMPRESSED BLOOM FILTERS:THEORYA. Bloom FiltersB. Compressed Bloom FiltersIII. COMPRESSED BLOOM FILTERS:PRACTICEA. ExamplesIV. DELTA COMPRESSIONV. COUNTING BLOOM FILTERSVI. CONCLUSIONAbstract 我们…