LPP-图解法

import re
import os
import time
import pickle
import datetime as dt
from pathlib import Path
from datetime import datetime, timedelta

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter
from openpyxl import Workbook, load_workbook
from openpyxl.utils import get_column_letter
from openpyxl.styles import PatternFill, Border, Side, Alignment, Protection, Font, colors, Color
sns.set()

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

def fig_ax_set(ax):
    """
    Purpose
    -------
    图表美化.
    
    Author
    ------
    Doris (YA-4742)@2022/5/25
    
    Parameters
    ----------
    axes: matplotlib.axes._subplots.AxesSubplot, 
        指代fig, axes = plt.subplots()中的axes.
    
    Returns
    -------
    None.
    """
    ## type_1
#     ax.patch.set_facecolor('lightsteelblue')
#     ax.patch.set_alpha(0.2)
    ## type_2
    ax.patch.set_facecolor('White')
    ax.patch.set_alpha(0.9)
    #
    ax.spines['top'].set_visible(False)
    ax.spines['bottom'].set_visible(False)
    ax.spines['left'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.grid(color='white', alpha=0.9, zorder=-1)
    return None

 

#################################################################################################################################
# 有界解-唯一最优解
# -----------------
# V00: 联立方程无解(平行):报错
# V01: V00问题已解决
### V00问题解决方法:联立方程无解要先判断是否可逆(det=0),可逆则该方程组无解.
#################################################################################################################################
def simultaneous_equation_solving(constraints):
    """
    2个变量-联立方程求解,以及判断上下限.
    """
    # 所有方程式
    equations = [
        [constraint['coefficient'][0], constraint['coefficient'][1], constraint['constant']] for constraint in constraints
    ]
    # 方程式两两联立
    simultaneous_equations_A = [ # 系数矩阵
        [[equation_1[0], equation_1[1]], [equation_2[0], equation_2[1]]] 
        for i, equation_1 in enumerate(equations) for equation_2 in equations[i+1:]
    ]
    simultaneous_equations_Y = [ # 常数项矩阵
        [equation_1[2], equation_2[2]] 
        for i, equation_1 in enumerate(equations) for equation_2 in equations[i+1:]
    ]
    # 求解联立方程
    ## 去除平行直线
    set_drop = []
    for i, A in enumerate(simultaneous_equations_A):
        if np.linalg.det(A) == 0:
            set_drop += [i]
        else:
            continue
        #
    #
    set_drop = set(set_drop)
    res = [
        list(np.linalg.inv(A).dot(simultaneous_equations_Y[i])) 
        for i, A in enumerate(simultaneous_equations_A) 
        if i not in set_drop
    ]
    # 分离x1/x2,并去最小最大值作为上下限
    x1 = [i for i, j in res]
    x1_lim = (min(x1), max(x1))
    x2 = [j for i, j in res]
    x2_lim = (min(x2), max(x2))
    
#     return res
    return res, x1_lim, x2_lim

# res, x1_lim, x2_lim = simultaneous_equation_solving(constraints)
# simultaneous_equation_solving(constraints)

 

#################################################################################################################################
# 有界解-唯一最优解
# -----------------
# V00: 填充方向不对(不报错)—— + 2.??
# V01: V00问题已解决
### V00问题解决方法-1.约束直线在0下方且不等关系为"<="时应向上,但 x - 1.9y >= -3.8 不行(x - 1.9y <= 3.8)
### V00问题解决方法-2. 直接先代入(0, 0), 再去判断不等关系:
#################### (1)约束直线在0上方:0 >= -3.8:(a) 不等关系为 >=,所以向下填充;(b) 不等关系为 <=,所以向上填充;
#################### (2)约束直线在0下方:0 <= 3.8 :(a) 不等关系为 <=,所以向上填充;(b) 不等关系为 >=,所以向下填充;
####################  等等.
def fill_between(constraint, x1_Lst, x2_Lst, x1_lim, x2_lim, color, alpha, flag='<='):
    """
    填充颜色:可行域.
    """
    x1, x2 = constraint['coefficient']
    constant = constraint['constant']
    inequation = constraint['inequation']
    ## 判断原点与约束直线的上下关系
    round_n = len((str(constant).split('.') + [''])[1:][0])
    if (x2==0):
        line = constant / x1
    else:  # 包含 x1==0 的情况
        line = constant / x2
    #
    line_0_judge = round(line, round_n) >= 0  # line_0_judge==True 表示直线在原点上方
    #
    ## 判断 constant 与原点的关系
    constant_0_judge = constant >= 0
    flag_min_judge = (flag=='<=')
    ## 
    con_1_a = line_0_judge & (not constant_0_judge) & (not flag_min_judge) # 向下填充
    con_1_b = line_0_judge & (not constant_0_judge) & flag_min_judge # 向上填充
    con_2_a = (not line_0_judge) & constant_0_judge & flag_min_judge # 向上填充
    con_2_b = (not line_0_judge) & constant_0_judge & (not flag_min_judge) # 向下填充
    con_3 = line_0_judge & constant_0_judge & (not flag_min_judge) # 向上填充
    con_4 = line_0_judge & constant_0_judge & flag_min_judge # 向下填充
    con_5 = (not line_0_judge) & (not constant_0_judge) & (not flag_min_judge) # 向上填充
    con_6 = (not line_0_judge) & (not constant_0_judge) & flag_min_judge # 向下填充
#     print(f"{line = }, {line_0_judge = }, {constant_0_judge = }, {flag_min_judge = }")
#     print(con_1_a, con_1_b, con_2_a, con_2_b)
    ## 颜色填充
    if con_1_a or con_2_b or con_4 or con_6:
        ##########
        # 向下填充
        ##########
        if x1_Lst[0]==x1_Lst[1]: # 垂直
            if x1_Lst[0]==x1_lim[0]:
                x = [x1_lim[0]/2, x1_Lst[0]]
            else:
                x = [x1_lim[0], x1_Lst[0]]
            y1, y2 = [x2_Lst[0], x2_Lst[0]], [x2_Lst[1], x2_Lst[1]]
            plt.fill_between(x, y2, y1, color=color, alpha=alpha);
        elif x2_Lst[0]==x2_Lst[1]: # 水平
            x = [x1_Lst[0], x1_Lst[1]]
            if x2_Lst[0]==x2_lim[0]:
                y1, y2 = [x2_lim[0]/2, x2_lim[0]/2], [x2_Lst[1], x2_Lst[1]]
            else:
                y1, y2 = [x2_lim[0], x2_lim[0]], [x2_Lst[1], x2_Lst[1]]
            plt.fill_between(x, y2, y1, color=color, alpha=alpha);
        else: # 倾斜
            y1 = [min(x2_Lst)] * 2
            y2 = [q if y1[i] < q else y1[i] for i, q in enumerate(x2_Lst)]
            plt.fill_between(x1_Lst, y2, y1, color=color, alpha=alpha);
    elif con_1_b or con_2_a or con_3 or con_5:
        ##########
        # 向上填充
        ##########
        if x1_Lst[0]==x1_Lst[1]: # 垂直
            if x1_Lst[1]==x1_lim[1]:
                x = [x1_Lst[0], x1_lim[1]*3/2]
            else:
                x = [x1_Lst[0], x1_lim[1]]
            y1, y2 = [x2_Lst[0], x2_Lst[0]], [x2_Lst[1], x2_Lst[1]]
            plt.fill_between(x, y2, y1, color=color, alpha=alpha);
        elif x2_Lst[0]==x2_Lst[1]: # 水平
            x = [x1_Lst[0], x1_Lst[1]]
            if x2_Lst[1]==x2_lim[1]:
                y1, y2 = [x2_Lst[0], x2_Lst[0]], [x2_lim[1]*3/2, x2_lim[1]*3/2]
            else:
                y1, y2 = [x2_Lst[0], x2_Lst[0]], [x2_lim[1], x2_lim[1]]
            plt.fill_between(x, y2, y1, color=color, alpha=alpha);
        else: # 倾斜
            y2 = [max(x2_Lst)] * 2
            y1 = [q if y2[i] > q else y2[i] for i, q in enumerate(x2_Lst)]
            plt.fill_between(x1_Lst, y2, y1, color=color, alpha=alpha);
        #
    #
    return None

 

#################################################################################################################################
# 有界解-唯一最优解
# -----------------
# V00: 判断约束条件是因为小数位数导致比较出错(不报错,但最优解错误)
# V01: V00问题已解决
### V00问题解决方法:先判断约束条件的常数项的小数位数n,再对可行解做round(y_new, n).

#################################################################################################################################
# 无界解-无最优解
# ---------------
# V00: 由于无边界,故最优解求解错误(不报错,但最优解错误)
# V01: V00问题已解决
### V00问题解决方法:添加判断是否为无界解

#################################################################################################################################
# 无可行解-无最优解
# -----------------
# V00: 由于没有符合约束条件的交点导致后续程式计算异常:报错
# V01: V00问题已解决
### V00问题解决方法:添加判断是否为无可行解——即判断是否有符合约束条件的交点存在

def optimal_solution(res, z, constraints, ByMin=True):
    """
    求解最优解,以及判断可行域的点.
    ===============================
    
    Parameters
    ----------
    res: list, 
        所有直线(约束条件)两两相交的交点list.
    z: dict, 
        目标函数设定.
    constraints: dict, 
        约束条件设定.
    ByMin: bool, 
        是否求最小化目标函数, Min=True表示最小化, Min=False表示最大化.
    
    Returns
    -------
    res_judges: list,
         所有解(满足所有约束条件的交点)的list.
    z_val: list, 
        最优解.
    
    """
    # z的系数
    z_x1, z_x2 = z['coefficient'][0], z['coefficient'][1]
    # 所有方程式
    equations = [
        [constraint['coefficient'][0], constraint['coefficient'][1], constraint['constant'], constraint['inequation']] 
        for constraint in constraints
    ]
    equations_new = [ ## [方程系数x1, 方程系数x2, 常数y, y的小数位数]
        [x1, x2, y, len((str(y).split('.') + [''])[1:][0])] 
        if ine=='<=' else [-x1, -x2, -y, len((str(y).split('.') + [''])[1:][0])]
        for x1, x2, y, ine in equations
    ]
    # 约束判断--找符合条件的点
    constraints_judge = [
        [[0 if (round(x1_res * x1 + x2_res * x2, round_n)) <= y else 1 for x1, x2, y, round_n in equations_new], [x1_res, x2_res]]
        for x1_res, x2_res in res
    ]
    res_judges = [
        res_judge for judge, res_judge in constraints_judge if sum(judge)==0
    ]
    ## 无可行解——判断是否有符合约束条件的交点存在
    if not res_judges:  ## res_judges==[],表示 无可行解
        z_val = None
        MinMax_judges = None
        return res_judges, z_val, MinMax_judges
    #
    # 找最优解
    z_value = [
        [x1, x2, z_x1 * x1 + z_x2 * x2]
        for x1, x2 in res_judges
    ]
    if ByMin:
        z_value.sort(key=lambda a: list(a)[-1], reverse=False)
        MinMax_val = 'Minimize'
    else:
        z_value.sort(key=lambda a: list(a)[-1], reverse=True)
        MinMax_val = 'Maximize'
    #
    z_val = z_value[0] + [MinMax_val]
    #
    ## 无界解——判断是否为无界解
    if ByMin: 
        MinMax_judges_point = [z_val[0], z_val[1]-1]
    else:
        MinMax_judges_point = [z_val[0], z_val[1]+1]
    #
    # 条件1:Z值是否小于(或大于)最小值
    MinMax_judges_z_val = MinMax_judges_point[0]*z_x1 + MinMax_judges_point[1]*z_x2
    #
    # 条件2:Z值是否符合约束条件
    round_n1 = 8
    x1_res, x2_res = MinMax_judges_point
    constraints_judge_MinMax = [
        0 if (round(x1_res * x1 + x2_res * x2, round_n)) <= y else 1 for x1, x2, y, round_n in equations_new
    ]
    constraints_judge_MinMax = sum(constraints_judge_MinMax) == 0
    #
    MinMax_judges = 0
    if ByMin:
        if (MinMax_judges_z_val < z_val[2]) & constraints_judge_MinMax:
            MinMax_judges = 1
    else:
        if (MinMax_judges_z_val > z_val[2]) & constraints_judge_MinMax:
            MinMax_judges = 1
    #
#     return res_judges, z_value
    return res_judges, z_val, MinMax_judges


# res, x1_lim, x2_lim = simultaneous_equation_solving(constraints)
# optimal_solution(res, z, constraints, ByMin=False)
# optimal_solution(res, z, constraints, ByMin=True)
# result, ResJudges = graphical_method(z, constraints, ByMin=ByMin, Obj_Func=Obj_Func, figsize=figsize, xy_lim=xy_lim)

 

def number_text(ax, color, x1_Lst, x2_Lst, ci_xy, ci):
    """
    备注约束条件序号
    """
    xy = [x1_Lst[0], x2_Lst[0]]
    if xy in ci_xy:
        xy = [x1_Lst[1], x2_Lst[1]]
        if xy in ci_xy:
            xy = [(x1_Lst[0]+x1_Lst[1])/5, (x2_Lst[0]+x2_Lst[1])/5]
    #
    ax.text(xy[0], xy[1], f'C{ci+1}', fontsize=12,
            family='Times New Roman', ha='right', va='top', color=color, weight='bold');
    return xy

 

def lines_select(constraints, res_judges):
    """
    筛选可行域边界直线
    """
    # res_judges: 去除重复项
    ## 做round(n)
    n = 9
    res_judges_round = [
        [i, [round(res_xy[0], n), round(res_xy[1], n)]]
        for i, res_xy in enumerate(res_judges)
    ]
    ## 去除重复项
    res_judges_new, temp = [], []
    for i, point in res_judges_round:
        if point not in temp:
            res_judges_new += [res_judges[i]]
            temp += [point]
        #
    #
    # 约束方程
    equations = [
        [constraint['coefficient'][0], constraint['coefficient'][1], constraint['constant']] 
        for constraint in constraints
    ]
    equations = [
        [a1, a2, b, len((str(b).split('.') + [''])[1:][0])] 
        for a1, a2, b in equations
    ]
    #
    # 线段筛选
    ## 罗列所有线段:两两相交
    lines_all = [
        [point_1, point_2, [(point_1[0]+point_2[0])/2, (point_1[1]+point_2[1])/2]]
        for i, point_1 in enumerate(res_judges_new) for point_2 in res_judges_new[i+1:]
    ]
    lines_judges = [
        [point_1, point_2, [1 if round(a1*midpoint[0]+a2*midpoint[1], round_n)==b else 0 for a1, a2, b, round_n in equations]]
        for point_1, point_2, midpoint in lines_all
    ]
    lines = [
        [[point_1[0], point_2[0]], [point_1[1], point_2[1]]]
        for point_1, point_2, judges in lines_judges
        if sum(judges)>0
    ]
    return lines, res_judges_new
# lines_select(constraints, res_judges)

def re_str_round(str_):
    """
    将末尾 '.0' 删除, 针对 round(float, 1).
    """
    res = (str_[:-1]+str_[-1].replace('0', '')).rstrip('.')
    return res

 

# V00: 可行域交叉绘制直线(因为两两绘制直线)
# V01: V00问题已解决 ==> V00问题尚未完全解决,依旧有交叉现象
### V00问题解决方法:对点做sort.
### ============================================================================================================================
# V02: V00问题已解决,并增加判断:目标函数曲线绘制(1)Y轴上下限(左斜or右斜);(2)X轴上下限(左斜+右斜) ==> 约束条件画图程式更改
### V00问题解决方法:判断两两直线的中点是否在约束直线上.
### ============================================================================================================================
# V03: 可行域颜色填充,以及可行交点与最优点是否重合显示判断优化
### V03问题解决方法.
### ============================================================================================================================
# V04: rstrip('.0')原希望将 '1.0' 改为 '1',但是会导致 '1.05' 变成 '15'
# V04: rstrip('.0')原希望将 '1.05' 变成 '1.05',但是会导致 '0.0' 变成 ''
### V04问题解决方法:re_str_round(str_).
### ============================================================================================================================
def graphical_method(z, constraints, ByMin=True, Obj_Func=False, figsize=(6, 6), xy_lim=None):
    """
    绘图.
    ===============================
    
    Parameters
    ----------
    z: dict, 
        目标函数设定.
    constraints: dict, 
        约束条件设定.
    xy_lim: list, 
        X/Y轴上下限设定
    ByMin: bool, 
        是否求最小化目标函数, =True表示最小化, =False表示最大化.
    Obj_Func: bool, 
        是否绘制目标函数曲线, =True表示绘制, =False表示不绘制.
    figsize: tuple, 
        图片大小设定.
    
    
    Returns
    -------
    res_judges: list,
         所有解(满足所有约束条件的交点)的list.
    z_val: list, 
        最优解.
    
    """
    # 设定
    alpha_fill, alpha_lines_constraint, alpha_lines_point_k, alpha_lines_point_b = 0.1, 0.7, 1, 1
    alpha_fill_feasible_region = 0.4
    # 画图
    fig, ax = plt.subplots(1, 1, figsize=figsize, facecolor='whitesmoke')  # whitesmoke, lightsteelblue
    fig_ax_set(ax)
    #
    ## 交点值
    res, x1_lim, x2_lim = simultaneous_equation_solving(constraints)
    ## 约束条件画图
    ci_xy = []
    for cnum, constraint in enumerate(constraints):
        x1, x2 = constraint['coefficient']
        constant = constraint['constant']
        inequation = constraint['inequation']
        ## ------------------------------------
        ## 画图--可行域
        if (x1==0):
            x1_Lst, x2_Lst = [x1_lim[0], x1_lim[1]], [constant/x2, constant/x2]
            p = ax.plot(x1_Lst, x2_Lst, alpha=alpha_lines_constraint)
            color = p[0].get_color()
            fill_between(constraint, x1_Lst, x2_Lst, x1_lim, x2_lim, color, alpha=alpha_fill, flag=inequation)
            ## 备注约束条件序号
            xy = number_text(ax, color, x1_Lst, x2_Lst, ci_xy, ci=cnum)
            ci_xy += [xy]
        elif (x2==0):
            x1_Lst, x2_Lst = [constant/x1, constant/x1], [x2_lim[0], x2_lim[1]]
            p = ax.plot(x1_Lst, x2_Lst, alpha=alpha_lines_constraint)
            color = p[0].get_color()
            fill_between(constraint, x1_Lst, x2_Lst, x1_lim, x2_lim, color, alpha=alpha_fill, flag=inequation)
            ## 备注约束条件序号
            xy = number_text(ax, color, x1_Lst, x2_Lst, ci_xy, ci=cnum)
            ci_xy += [xy]
        else:
            x1_new_1, x1_new_2 = x1_lim[0], x1_lim[1]
            x2_new_1, x2_new_2 = (constant - x1 * x1_new_1) / x2, (constant - x1 * x1_new_2) / x2
            x1_Lst, x2_Lst = [x1_new_1, x1_new_2], [x2_new_1, x2_new_2]
            p = ax.plot(x1_Lst, x2_Lst, alpha=alpha_lines_constraint)
            color = p[0].get_color()
            fill_between(constraint, x1_Lst, x2_Lst, x1_lim, x2_lim, color, alpha=alpha_fill, flag=inequation)
            ## 备注约束条件序号
            xy = number_text(ax, color, x1_Lst, x2_Lst, ci_xy, ci=cnum)
            ci_xy += [xy]
        #
    #
    ax_title = '可行域以及最优解'
    ax.set_title(ax_title, fontsize=20);
    if xy_lim:
        plt.xlim(xy_lim[0][0], xy_lim[0][1])
        plt.ylim(xy_lim[1][0], xy_lim[1][1])
    #
    plt.tight_layout();
    ## 无可行解——判断是否有符合约束条件的交点存在
    res_judges, z_val, MinMax_judges = optimal_solution(res, z, constraints, ByMin=ByMin)
    if not res_judges:
        print('无可行解')
        ax.text(0, 0, f'无可行解: 无最优解', fontsize=16, ha='left', va='bottom', 
                color='red', weight='bold');
        return None, None
    #
    f_val_round = lambda float_: re_str_round(str(round(float_, 2)))
    z_val_round = [[f_val_round(i), f_val_round(j), f_val_round(k), ByMins] 
                 for i, j, k, ByMins in [z_val]]
    print(f"最优解:{z_val_round}")
    #
    ## 绘制可行域边框 + 防止可行域(黑色虚线交叉)
    lines, res_judges_select = lines_select(constraints, res_judges)
    res_judges_select_round = [[f_val_round(i), f_val_round(j)] for i, j in res_judges_select]
    print(f"可行域:{res_judges_select_round}")
    for x1_Lst, x2_Lst in lines:
        ax.plot(x1_Lst, x2_Lst, color='k', marker='o', linestyle='dashed', 
                linewidth=3, markersize=7, alpha=alpha_lines_point_k) # dotted, dashed
    #
    ## 无解界+有界解判断
    constant = z_val[2]
    x1, x2 = z['coefficient']
    lines_z_val = []
    if MinMax_judges: ## ==1, 表示 无解界,无最优解
        # -------------------------------------------
        ax.text(z_val[0], z_val[1], f'无界解\n无最优解-{z_val[3]}', fontsize=16, 
                ha='left', va='bottom', color='darkblue', weight='bold');
    else: ## ==0,表示 有界解(1 or N)
        # ------------------------------
        ## 可行域填充绘制
        point_x = [i for i, j in res_judges_select]
        point_y = [j for i, j in res_judges_select]
        plt.fill(point_x, point_y, color='k', alpha=alpha_fill_feasible_region)
        #
        round_n1 = 8
        lines_z_val_list = [
            [round(pointX[0]*x1+pointY[0]*x2, round_n1), round(pointX[1]*x1+pointY[1]*x2, round_n1)]
            for pointX, pointY in lines
        ]
        lines_z_val = [
            point1_z_val
            for point1_z_val, point2_z_val in lines_z_val_list
            if (point1_z_val==point2_z_val) and (point1_z_val==round(constant, round_n1))
        ]
        if lines_z_val:  ## !=[],表示 有界解,无穷多最优解
            ax.text(z_val[0], z_val[1], f'有界解\n无穷多最优解', fontsize=16, 
                    ha='left', va='bottom', color='darkblue', weight='bold');
        #
    ## 绘制目标函数曲线
    if Obj_Func or lines_z_val or MinMax_judges:
        x1_new_1, x1_new_2 = x1_lim[0], x1_lim[1]
        x2_new_1, x2_new_2 = (constant - x1 * x1_new_1) / x2, (constant - x1 * x1_new_2) / x2
        ## Y轴上下限
        ## =========
        if (x2_new_1 > x2_new_2) & (x2_new_1 > x2_lim[0]) & (x2_new_2 < x2_lim[1]):
            ## 增加判断:目标函数曲线绘制Y轴上下限(左高右低)
            x2_new_1, x2_new_2 = x2_lim[1], x2_lim[0]
            x1_new_1, x1_new_2 = (constant - x2 * x2_new_1) / x1, (constant - x2 * x2_new_2) / x1
        #
        if (x2_new_1 < x2_new_2) & (x2_new_1 < x2_lim[0]) & (x2_new_2 > x2_lim[1]):
            ## 增加判断:目标函数曲线绘制Y轴上下限(左低右高)
            x2_new_1, x2_new_2 = x2_lim[0], x2_lim[1]
            x1_new_1, x1_new_2 = (constant - x2 * x2_new_1) / x1, (constant - x2 * x2_new_2) / x1
        #
        ## ---------
        #
        ## X轴上下限
        ## =========
        ## 增加判断:目标函数曲线绘制X轴上下限(左斜+右斜)
        if (x1_new_1 < x1_lim[0]) & (x1_new_2 <= x1_lim[1]):
            #
            x1_new_1, x1_new_2 = x1_lim[0], x1_new_2
            x2_new_1, x2_new_2 = (constant - x1 * x1_new_1) / x2, (constant - x1 * x1_new_2) / x2
        elif (x1_new_2 > x1_lim[1]) & (x1_new_1 >= x1_lim[0]):
            #
            x1_new_1, x1_new_2 = x1_new_1, x1_lim[1]
            x2_new_1, x2_new_2 = (constant - x1 * x1_new_1) / x2, (constant - x1 * x1_new_2) / x2
        elif (x1_new_1 < x1_lim[0]) & (x1_new_2 > x1_lim[1]):
            #
            x1_new_1, x1_new_2 = x1_lim[0], x1_lim[1]
            x2_new_1, x2_new_2 = (constant - x1 * x1_new_1) / x2, (constant - x1 * x1_new_2) / x2
        #
        ## ---------
        x1_Lst, x2_Lst = [x1_new_1, x1_new_2], [x2_new_1, x2_new_2]
        ax.plot(x1_Lst, x2_Lst, color='darkblue', linewidth=3, zorder=10, alpha=alpha_lines_point_b)  # , linestyle='dotted'
    #
    ## 绘制最优解点
    if (not lines_z_val) and (not MinMax_judges): ## 判断是否为无穷多最优解
        ax.scatter(z_val[0], z_val[1], color='darkblue', marker='*', s=250, zorder=100)
        z_val_str = [
            [re_str_round(str(round(x1, 1))), re_str_round(str(round(x2, 1))), re_str_round(str(round(z, 1))), minmax] 
            for x1, x2, z, minmax in [z_val]
        ][0]
        ax.text(z_val[0], z_val[1], f'{z_val_str[3]}: {z_val_str[2]}\n({z_val_str[0]}, {z_val_str[1]})', fontsize=16, 
                family='Times New Roman', ha='left', va='bottom', color='darkblue', weight='bold');
        #
        for point_x1, point_x2 in res_judges:
            point_x1_str = re_str_round(str(round(point_x1, 1)))
            point_x2_str = re_str_round(str(round(point_x2, 1)))
            z_val_1_str = re_str_round(str(round(z_val[0], 1)))
            z_val_2_str = re_str_round(str(round(z_val[1], 1)))
            if ([point_x1_str, point_x2_str] != [z_val_1_str, z_val_2_str]):
                ax.text(point_x1, point_x2, f'({point_x1_str}, {point_x2_str})', fontsize=15, 
                        family='Times New Roman', ha='left', va='bottom', color='k', weight='bold', zorder=50);
        #
    #
    plt.show();
    plt.close();
    #
    return res, res_judges

# result, ResJudges = graphical_method(z, constraints, ByMin=ByMin, Obj_Func=Obj_Func, figsize=figsize, xy_lim=xy_lim)

 测试

1.

# 针对2个决策变量
# ===================================================================================================================================
## 目标函数
z = {'coefficient': (80, 40)}
ByMin = False  ## 最优化:ByMin=True 表示最小化, ByMin = False 表示最大化
Obj_Func = True  ## 是否绘制目标函数曲线:Obj_Func=True 表示绘制, Obj_Func=False 表示不绘制
## 约束条件/constraint, 条件全部设定为"<="
constraints = [
    {'coefficient': (1, 0), 'constant': 0, 'inequation':'>='},  # 2个决策变量大于0
    {'coefficient': (0, 1), 'constant': 0, 'inequation':'>='},  # 2个决策变量大于0
    # -----------------------------------------------------------------------------
    {'coefficient': (9, 4), 'constant': 14, 'inequation':'<='},  # 约束-1
    {'coefficient': (2, 7), 'constant': 10, 'inequation':'<='},  # 约束-2
    {'coefficient': (5, 10), 'constant': 20, 'inequation':'<='},  # 约束-3
#     {'coefficient': (1, -1.9), 'constant': -3.8, 'inequation':'>='},  # 约束-4
]
figsize = (5, 5)
xy_lim = None  ## xy_lim = [[-1, 1], [-1, 1]]
xy_lim = [[-0.2, 3], [-0.2, 4]]
# constraints, z, Min
# ===================================================================================================================================

result, ResJudges = graphical_method(z, constraints, ByMin=ByMin, Obj_Func=Obj_Func, figsize=figsize, xy_lim=xy_lim)

# 针对2个决策变量
# ===================================================================================================================================
## 目标函数
z = {'coefficient': (80, 40)}
ByMin = False  ## 最优化:ByMin=True 表示最小化, ByMin=False 表示最大化
Obj_Func = True  ## 是否绘制目标函数曲线:Obj_Func=True 表示绘制, Obj_Func=False 表示不绘制
## 约束条件/constraint, 条件全部设定为"<="
constraints = [
    {'coefficient': (1, 0), 'constant': 0, 'inequation':'>='},  # 2个决策变量大于0
    {'coefficient': (0, 1), 'constant': 0, 'inequation':'>='},  # 2个决策变量大于0
    {'coefficient': (9, 4), 'constant': 14, 'inequation':'<='},  # 约束-1
    {'coefficient': (2, 7), 'constant': 10, 'inequation':'<='},  # 约束-2
    {'coefficient': (5, 10), 'constant': 20, 'inequation':'<='},  # 约束-3
#     {'coefficient': (1, 1), 'constant': 40, 'inequation':'<='},  # 约束-4
]
figsize = (5, 5)
xy_lim = None  ## xy_lim = [[-1, 1], [-1, 1]]
xy_lim = [[-0.01, 2], [-0.01, 2]]
# constraints, z, Min
# ===================================================================================================================================

res = graphical_method(z, constraints, ByMin=ByMin, Obj_Func=Obj_Func, figsize=figsize, xy_lim=xy_lim)

 

# 针对2个决策变量
# ===================================================================================================================================
## 目标函数
z = {'coefficient': (1, 2)}
ByMin = True  ## 最优化:ByMin=True 表示最小化, ByMin = False 表示最大化
Obj_Func = True  ## 是否绘制目标函数曲线:Obj_Func=True 表示绘制, Obj_Func=False 表示不绘制
## 约束条件/constraint, 条件全部设定为"<="
constraints = [
    {'coefficient': (1, 0), 'constant': 0, 'inequation':'<='},  # 2个决策变量大于0
    {'coefficient': (0, 1), 'constant': 0, 'inequation':'<='},  # 2个决策变量大于0
    # -----------------------------------------------------------------------------
    {'coefficient': (1, 3), 'constant': 6, 'inequation':'<='},  # 约束-1
    {'coefficient': (1, 1), 'constant': 4, 'inequation':'<='},  # 约束-2
    {'coefficient': (3, 1), 'constant': 6, 'inequation':'<='},  # 约束-3
#     {'coefficient': (1, -1.9), 'constant': -3.8, 'inequation':'>='},  # 约束-4
]
figsize = (5, 5)
xy_lim = None  ## xy_lim = [[-1, 1], [-1, 1]]
# xy_lim = [[-0.01, 2], [-0.01, 2]]
# constraints, z, Min
# ===================================================================================================================================

result, ResJudges = graphical_method(z, constraints, ByMin=ByMin, Obj_Func=Obj_Func, figsize=figsize, xy_lim=xy_lim)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值