├── README.md ├── LP.py ├── LP_math_model2.py └── LP_math_model.py /README.md: -------------------------------------------------------------------------------- 1 | 线性规划(带不等式和等式约束)单纯形算法分析技术博客见: https://www.jianshu.com/p/a0fc8a57f452 2 | -------------------------------------------------------------------------------- /LP.py: -------------------------------------------------------------------------------- 1 | # 线性规划-单纯形算法 2 | import numpy as np 3 | np.set_printoptions(precision=4, suppress=True, threshold=np.inf) 4 | # 线性规划转化为松弛形式 5 | def get_loose_matrix(matrix): 6 | row, col = matrix.shape 7 | loose_matrix = np.zeros((row, row + col)) 8 | for i, _ in enumerate(loose_matrix): 9 | loose_matrix[i, 0: col] = matrix[i] 10 | loose_matrix[i, col + i] = 1.0 # 对角线 11 | return loose_matrix 12 | # 松弛形式的系数矩阵A、约束矩阵B和目标函数矩阵C组合为一个矩阵 13 | def join_matrix(a, b, c): 14 | row, col = a.shape 15 | s = np.zeros((row + 1, col + 1)) 16 | s[1:, 1:] = a # 右下角是松弛系数矩阵A 17 | s[1:, 0] = b # 左下角是约束条件值矩阵B 18 | s[0, 1: len(c) + 1] = c # 右上角是目标函数矩阵C 19 | return s 20 | # 旋转矩阵—替换替出替入变量的角色位置 21 | def pivot_matrix(matrix, k, j): 22 | # 单独处理替出变量所在行,需要除以替入变量的系数matrix[k][j] 23 | matrix[k] = matrix[k] / matrix[k][j] 24 | # 循环除了替出变量所在行之外的所有行 25 | for i, _ in enumerate(matrix): 26 | if i != k: 27 | matrix[i] = matrix[i] - matrix[k] * matrix[i][j] 28 | # 根据旋转后的矩阵,从基本变量数组中得到一组基解 29 | def get_base_solution(matrix, base_ids): 30 | X = [0.0] * (matrix.shape[1]) # 解空间 31 | for i, _ in enumerate(base_ids): 32 | X[base_ids[i]] = matrix[i + 1][0] 33 | return X 34 | # 构造辅助线性规划 35 | def Laux(matrix, base_ids): 36 | l_matrix = np.copy(matrix) 37 | # 辅助矩阵的最后一列存放x0的系数,初始化为-1 38 | l_matrix = np.column_stack((l_matrix, [-1] * l_matrix.shape[0])) 39 | # 辅助线性函数的目标函数为z = x0 40 | l_matrix[0, :-1] = 0.0 41 | l_matrix[0, -1] = 1 42 | k = l_matrix[1:, 0].argmin() + 1 # 选择一个b最小的那一行的基本变量作为替出变量 43 | j = l_matrix.shape[1] - 1 # 选择x0作为替入变量 44 | # 第一次旋转矩阵,使得所有b为正数 45 | pivot_matrix(l_matrix, k=k, j=j) 46 | base_ids[k - 1] = j # 维护基本变量索引数组 47 | # 用单纯形算法求解该辅助线性规划 48 | l_matrix = simplex(l_matrix, base_ids) 49 | # 如果求解后的辅助线性规划中x0仍然是基本变量,需要再次旋转消去x0 50 | if l_matrix.shape[1] - 1 in base_ids: 51 | j = np.where(l_matrix[0, 1:] != 0)[0][0] + 1 # 找到矩阵第一行(目标函数)系数不为0的变量作为替入变量 52 | k = base_ids.index(l_matrix.shape[1] - 1) + 1 # 找到x0作为基本变量所在的那一行,将x0作为替出变量 53 | pivot_matrix(l_matrix, k=k, j=j) # 旋转矩阵消去基本变量x0 54 | base_ids[k - 1] = j # 维护基本变量索引数组 55 | return l_matrix, base_ids 56 | # 从辅助函数中恢复原问题的目标函数 57 | def resotr_from_Laux(l_matrix, z, base_ids): 58 | z_ids = np.where(z != 0)[0] - 1 # 得到目标函数系数不为0的索引数组(即基本变量索引数组) 59 | restore_matrix = np.copy(l_matrix[:, 0:-1]) # 去掉x0那一列 60 | restore_matrix[0] = z # 初始化矩阵的第一行为原问题的目标函数向量 61 | for i, base_v in enumerate(base_ids): 62 | # 如果原问题的基本变量存在新基本变量数组中,说明需要替换消去 63 | if base_v in z_ids: 64 | restore_matrix[0] -= restore_matrix[0, base_v + 1] * restore_matrix[i + 1] # 消去原目标函数中的基本变量 65 | return restore_matrix 66 | # 单纯形算法求解线性规划 67 | def simplex(matrix, base_ids): 68 | matrix = matrix.copy() 69 | # 如果目标系数向量里有负数,则旋转矩阵 70 | while matrix[0, 1:].min() < 0: 71 | # 在目标函数向量里,选取系数为负数的第一个变量索引,作为替入变量 72 | j = np.where(matrix[0, 1:] < 0)[0][0] + 1 73 | # 在约束集合里,选取对替入变量约束最紧的约束行,那一行的基本变量作为替出变量 74 | k = np.array([matrix[i][0] / matrix[i][j] if matrix[i][j] > 0 else 0x7fff for i in 75 | range(1, matrix.shape[0])]).argmin() + 1 76 | # 说明原问题无界 77 | if matrix[k][j] <= 0: 78 | print('原问题无界') 79 | return None, None 80 | pivot_matrix(matrix, k, j) # 旋转替换替入变量和替出变量 81 | base_ids[k - 1] = j - 1 # 维护当前基本变量索引数组 82 | return matrix 83 | # 单纯形算法求解步骤入口 84 | def solve(a, b, c, equal=None): 85 | loose_matrix = get_loose_matrix(a) # 转化得到松弛矩阵 86 | if equal is not None: 87 | loose_matrix = np.insert(loose_matrix, 0, equal, axis=0) 88 | matrix = join_matrix(loose_matrix, b, c) # 得到ABC的组合矩阵 89 | base_ids = list(range(len(c), len(b) + len(c))) # 初始化基本变量的索引数组 90 | # 约束系数矩阵有负数约束,证明没有可行解,需要辅助线性函数 91 | if matrix[:, 0].min() < 0: 92 | print('构造求解辅助线性规划函数...') 93 | l_matrix, base_ids = Laux(matrix, base_ids) # 构造辅助线性规划函数并旋转求解之 94 | if l_matrix is not None: 95 | matrix = resotr_from_Laux(l_matrix, matrix[0], base_ids) # 恢复原问题的目标函数 96 | else: 97 | print('辅助线性函数的原问题没有可行解') 98 | return None, None, None 99 | ret_matrix = simplex(matrix, base_ids) # 单纯形算法求解拥有基本可行解的线性规划 100 | X = get_base_solution(ret_matrix, base_ids) # 得到当前最优基本可行解 101 | if ret_matrix is not None: 102 | return matrix, ret_matrix, X 103 | else: 104 | print('原线性规划问题无界') 105 | return None, None, None 106 | if __name__ == '__main__': 107 | equal = None 108 | # 不带等式约束的线性规划测试 109 | # a = np.array([[4, -1], [2, 1], [-5, 2]]) 110 | # b = [8, 10, 2] 111 | # c = [-1, -1] 112 | # a = np.array([[1, 1], [-1, -1]]) 113 | # b = [2, -1] 114 | # c = [1, 2] 115 | # a = np.array([[1, -1], [-1.5, 1], [50, 20]]) 116 | # b = [0, 0, 2000] 117 | # c = [-1, -1] 118 | # a = np.array([[1, 1, 1, 1], [4, 8, 2, 5], [4, 2, 5, 5], [6, 4, 8, 4]]) 119 | # b = [480, 2400, 2000, 3000] 120 | # c = [-9, -6, -11, -8] 121 | # a = np.array([[1, -1], [-1, -1], [-1, 4]]) 122 | # b = [8, -3, 2] 123 | # c = [-1, -3] 124 | # a = np.array([[-21, 0, 0, 0], [0, -28, -4, 0], [-2, -1, -10, -11]]) 125 | # b = [-500, -600, -250] 126 | # c = [1, 1, 1, 1] 127 | # a = np.array([[2, -1], [1, -5]]) 128 | # b = [2, -4] 129 | # c = [-2, 1] 130 | # 带等式约束的线性规划测试 131 | # a = np.array([[1, -2]]) 132 | # equal = [1, 1] + [0] * a.shape[0] 133 | # b = [7, 4] 134 | # c = [-2, 3] 135 | # a = np.array([[1, -2, 1], [4, -1, -2]]) 136 | # equal = [-2, 0, 1] + [0] * a.shape[0] 137 | # b = [1, 11, -3] 138 | # c = [-3, 1, 1] 139 | a = np.array([[-2, 5, -1], [1, 3, 1]]) 140 | equal = [1, 1, 1] + [0] * a.shape[0] 141 | b = [7, -10, 12] 142 | c = [-2, -3, 5] 143 | matrix, ret_matrix, X = solve(a, b, c, equal=equal) 144 | print('本次迭代的最优解为:{}'.format(np.round(X[0: len(c)], 4))) 145 | print('该线性规划的最优值是:{}'.format(np.round(-ret_matrix[0][0], 4))) 146 | -------------------------------------------------------------------------------- /LP_math_model2.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 线性规划实战—连续投资问题 3 | 考虑下列投资项目: 4 | 项目A:在第1~4年每年年初可以投资,并于次年年末收回本利115%; 5 | 项目B:第3年年初可以投资,一直到第5年年末能收回本利125%,且规定最大投资额不超过4万元; 6 | 项目C:第2年年初可以投资,一直到第5年年末能收回本利140%,且规定最大投资额不超过3万元; 7 | 项目D:5年内每一年年初均可以购买公债,并于当年年末归还本金,并加获得利息6%。 8 | 如果你有10万元本金,求确定一个有效的投资方案,使得第5年年末你拥有的资金的本利总额最大? 9 | ''' 10 | import numpy as np 11 | from copy import deepcopy 12 | np.set_printoptions(precision=4, suppress=True, threshold=np.inf) 13 | # 线性规划转化为松弛形式 14 | def get_loose_matrix(matrix): 15 | row, col = matrix.shape 16 | loose_matrix = np.zeros((row, row + col)) 17 | for i, _ in enumerate(loose_matrix): 18 | loose_matrix[i, 0: col] = matrix[i] 19 | loose_matrix[i, col + i] = 1.0 # 对角线 20 | return loose_matrix 21 | # 松弛形式的系数矩阵A、约束矩阵B和目标函数矩阵C组合为一个矩阵 22 | def join_matrix(a, b, c): 23 | row, col = a.shape 24 | s = np.zeros((row + 1, col + 1)) 25 | s[1:, 1:] = a # 右下角是松弛系数矩阵A 26 | s[1:, 0] = b # 左下角是约束条件值矩阵B 27 | s[0, 1: len(c) + 1] = c # 右上角是目标函数矩阵C 28 | return s 29 | # 旋转矩阵—替换替出替入变量的角色位置 30 | def pivot_matrix(matrix, k, j): 31 | # 单独处理替出变量所在行,需要除以替入变量的系数matrix[k][j] 32 | matrix[k] = matrix[k] / matrix[k][j] 33 | # 循环除了替出变量所在行之外的所有行 34 | for i, _ in enumerate(matrix): 35 | if i != k: 36 | matrix[i] = matrix[i] - matrix[k] * matrix[i][j] 37 | # 根据旋转后的矩阵,从基本变量数组中得到一组基解 38 | def get_base_solution(matrix, base_ids): 39 | X = [0.0] * (matrix.shape[1]) # 解空间 40 | for i, _ in enumerate(base_ids): 41 | X[base_ids[i]] = matrix[i + 1][0] 42 | return X 43 | # 构造辅助线性规划 44 | def Laux(matrix, base_ids): 45 | l_matrix = np.copy(matrix) 46 | # 辅助矩阵的最后一列存放x0的系数,初始化为-1 47 | l_matrix = np.column_stack((l_matrix, [-1] * l_matrix.shape[0])) 48 | # 辅助线性函数的目标函数为z = x0 49 | l_matrix[0, :-1] = 0.0 50 | l_matrix[0, -1] = 1 51 | k = l_matrix[1:, 0].argmin() + 1 # 选择一个b最小的那一行的基本变量作为替出变量 52 | j = l_matrix.shape[1] - 1 # 选择x0作为替入变量 53 | # 第一次旋转矩阵,使得所有b为正数 54 | pivot_matrix(l_matrix, k=k, j=j) 55 | base_ids[k - 1] = j # 维护基本变量索引数组 56 | # 用单纯形算法求解该辅助线性规划 57 | l_matrix = simplex(l_matrix, base_ids) 58 | # 如果求解后的辅助线性规划中x0仍然是基本变量,需要再次旋转消去x0 59 | if l_matrix.shape[1] - 1 in base_ids: 60 | j = np.where(l_matrix[0, 1:] != 0)[0][0] + 1 # 找到矩阵第一行(目标函数)系数不为0的变量作为替入变量 61 | k = base_ids.index(l_matrix.shape[1] - 1) + 1 # 找到x0作为基本变量所在的那一行,将x0作为替出变量 62 | pivot_matrix(l_matrix, k=k, j=j) # 旋转矩阵消去基本变量x0 63 | base_ids[k - 1] = j # 维护基本变量索引数组 64 | return l_matrix, base_ids 65 | # 从辅助函数中恢复原问题的目标函数 66 | def resotr_from_Laux(l_matrix, z, base_ids): 67 | z_ids = np.where(z != 0)[0] - 1 # 得到目标函数系数不为0的索引数组(即基本变量索引数组) 68 | restore_matrix = np.copy(l_matrix[:, 0:-1]) # 去掉x0那一列 69 | restore_matrix[0] = z # 初始化矩阵的第一行为原问题的目标函数向量 70 | for i, base_v in enumerate(base_ids): 71 | # 如果原问题的基本变量存在新基本变量数组中,说明需要替换消去 72 | if base_v in z_ids: 73 | restore_matrix[0] -= restore_matrix[0, base_v + 1] * restore_matrix[i + 1] # 消去原目标函数中的基本变量 74 | return restore_matrix 75 | # 单纯形算法求解线性规划 76 | def simplex(matrix, base_ids): 77 | matrix = matrix.copy() 78 | # 如果目标系数向量里有负数,则旋转矩阵 79 | while matrix[0, 1:].min() < 0: 80 | # 在目标函数向量里,选取系数为负数的第一个变量索引,作为替入变量 81 | j = np.where(matrix[0, 1:] < 0)[0][0] + 1 82 | # 在约束集合里,选取对替入变量约束最紧的约束行,那一行的基本变量作为替出变量 83 | k = np.array([matrix[i][0] / matrix[i][j] if matrix[i][j] > 0 else 0x7fff for i in 84 | range(1, matrix.shape[0])]).argmin() + 1 85 | # print('替出变量为:{},替入变量为:{}, 值为:{}'.format(k, j, matrix[k][j])) 86 | # 说明原问题无界 87 | if matrix[k][j] <= 0: 88 | print('原问题无界') 89 | return None, None 90 | pivot_matrix(matrix, k, j) # 旋转替换替入变量和替出变量 91 | base_ids[k - 1] = j - 1 # 维护当前基本变量索引数组 92 | return matrix 93 | # 单纯形算法求解步骤入口 94 | def solve(a, b, c, equal=None): 95 | loose_matrix = get_loose_matrix(a) # 转化得到松弛矩阵 96 | if equal is not None: 97 | for i, e in enumerate(equal): 98 | loose_matrix = np.insert(loose_matrix, i, e, axis=0) 99 | matrix = join_matrix(loose_matrix, b, c) # 得到ABC的组合矩阵 100 | base_ids = list(range(len(c), len(b) + len(c))) # 初始化基本变量的索引数组 101 | # 约束系数矩阵有负数约束,证明没有可行解,需要辅助线性函数 102 | if matrix[:, 0].min() < 0: 103 | print('构造求解辅助线性规划函数...') 104 | l_matrix, base_ids = Laux(matrix, base_ids) # 构造辅助线性规划函数并旋转求解之 105 | if l_matrix is not None: 106 | matrix = resotr_from_Laux(l_matrix, matrix[0], base_ids) # 恢复原问题的目标函数 107 | else: 108 | print('辅助线性函数的原问题没有可行解') 109 | return None, None, None 110 | ret_matrix = simplex(matrix, base_ids) # 单纯形算法求解拥有基本可行解的线性规划 111 | X = get_base_solution(ret_matrix, base_ids) # 得到当前最优基本可行解 112 | if ret_matrix is not None: 113 | return matrix, ret_matrix, X 114 | else: 115 | print('原线性规划问题无界') 116 | return None, None, None 117 | if __name__ == '__main__': 118 | x = [0 for _ in range(20)] # 定义决策变量 119 | e1, e2, e3, e4, e5 = deepcopy(x), deepcopy(x), deepcopy(x), deepcopy(x), deepcopy(x) # 等式约束 120 | e1[0], e1[15] = 1, 1 121 | e2[1], e2[11], e2[16], e2[15] = 1, 1, 1, -1.06 122 | e3[2], e3[7], e3[17], e3[0], e3[16] = 1, 1, 1, -1.15, -1.06 123 | e4[3], e4[18], e4[1], e4[17] = 1, 1, -1.15, -1.06 124 | e5[19], e5[2], e5[18] = 1, -1.15, -1.06 125 | a1, a2 = deepcopy(x), deepcopy(x) # 不等式约束 126 | a1[7] = 1 127 | a2[11] = 1 128 | a = np.array([a1, a2]) 129 | b = [10, 0, 0, 0, 0] + [4, 3] 130 | equal = [] 131 | equal.append(e1 + [0] * a.shape[0]) 132 | equal.append(e2 + [0] * a.shape[0]) 133 | equal.append(e3 + [0] * a.shape[0]) 134 | equal.append(e4 + [0] * a.shape[0]) 135 | equal.append(e5 + [0] * a.shape[0]) 136 | c = deepcopy(x) # 目标函数 137 | c[3], c[7], c[11], c[19] = -1.15, -1.25, -1.4, -1.06 138 | # 单纯形法求解数学模型 139 | matrix, ret_matrix, X = solve(a, b, c, equal=equal) 140 | Y = np.round(np.array(X[0: len(c)]).reshape(4, -1).T, 4) # 得到最优投资方案 141 | print(Y) 142 | for i, y in enumerate(Y): 143 | print('第{}年年初投资组合:项目A:{}万元,项目B:{}万元,项目C:{}万元,项目D:{}万元,该年总投入:{}万元'.format( 144 | i + 1, y[-4], y[-3], y[-2], y[-1], np.sum(y))) 145 | total_money = np.abs(np.round(-ret_matrix[0][0], 4)) # 总收入本息 146 | profit = np.round((total_money - b[0]) / b[0] * 100, 4) # 总赢利 147 | print('第5年年末总收入本金+利息为:{}万元,总赢利:{}%'.format(total_money, profit)) 148 | -------------------------------------------------------------------------------- /LP_math_model.py: -------------------------------------------------------------------------------- 1 | # 线性规划实战—投资的收益和风险 2 | import numpy as np 3 | from copy import deepcopy 4 | import matplotlib.pyplot as plt 5 | np.set_printoptions(precision=4, suppress=True, threshold=np.inf) 6 | # 线性规划转化为松弛形式 7 | def get_loose_matrix(matrix): 8 | row, col = matrix.shape 9 | loose_matrix = np.zeros((row, row + col)) 10 | for i, _ in enumerate(loose_matrix): 11 | loose_matrix[i, 0: col] = matrix[i] 12 | loose_matrix[i, col + i] = 1.0 # 对角线 13 | return loose_matrix 14 | # 松弛形式的系数矩阵A、约束矩阵B和目标函数矩阵C组合为一个矩阵 15 | def join_matrix(a, b, c): 16 | row, col = a.shape 17 | s = np.zeros((row + 1, col + 1)) 18 | s[1:, 1:] = a # 右下角是松弛系数矩阵A 19 | s[1:, 0] = b # 左下角是约束条件值矩阵B 20 | s[0, 1: len(c) + 1] = c # 右上角是目标函数矩阵C 21 | return s 22 | # 旋转矩阵—替换替出替入变量的角色位置 23 | def pivot_matrix(matrix, k, j): 24 | # 单独处理替出变量所在行,需要除以替入变量的系数matrix[k][j] 25 | matrix[k] = matrix[k] / matrix[k][j] 26 | # 循环除了替出变量所在行之外的所有行 27 | for i, _ in enumerate(matrix): 28 | if i != k: 29 | matrix[i] = matrix[i] - matrix[k] * matrix[i][j] 30 | # 根据旋转后的矩阵,从基本变量数组中得到一组基解 31 | def get_base_solution(matrix, base_ids): 32 | X = [0.0] * (matrix.shape[1]) # 解空间 33 | for i, _ in enumerate(base_ids): 34 | X[base_ids[i]] = matrix[i + 1][0] 35 | return X 36 | # 构造辅助线性规划 37 | def Laux(matrix, base_ids): 38 | l_matrix = np.copy(matrix) 39 | # 辅助矩阵的最后一列存放x0的系数,初始化为-1 40 | l_matrix = np.column_stack((l_matrix, [-1] * l_matrix.shape[0])) 41 | # 辅助线性函数的目标函数为z = x0 42 | l_matrix[0, :-1] = 0.0 43 | l_matrix[0, -1] = 1 44 | k = l_matrix[1:, 0].argmin() + 1 # 选择一个b最小的那一行的基本变量作为替出变量 45 | j = l_matrix.shape[1] - 1 # 选择x0作为替入变量 46 | # 第一次旋转矩阵,使得所有b为正数 47 | pivot_matrix(l_matrix, k=k, j=j) 48 | base_ids[k - 1] = j # 维护基本变量索引数组 49 | # 用单纯形算法求解该辅助线性规划 50 | l_matrix = simplex(l_matrix, base_ids) 51 | # 如果求解后的辅助线性规划中x0仍然是基本变量,需要再次旋转消去x0 52 | if l_matrix.shape[1] - 1 in base_ids: 53 | j = np.where(l_matrix[0, 1:] != 0)[0][0] + 1 # 找到矩阵第一行(目标函数)系数不为0的变量作为替入变量 54 | k = base_ids.index(l_matrix.shape[1] - 1) + 1 # 找到x0作为基本变量所在的那一行,将x0作为替出变量 55 | pivot_matrix(l_matrix, k=k, j=j) # 旋转矩阵消去基本变量x0 56 | base_ids[k - 1] = j # 维护基本变量索引数组 57 | return l_matrix, base_ids 58 | # 从辅助函数中恢复原问题的目标函数 59 | def resotr_from_Laux(l_matrix, z, base_ids): 60 | z_ids = np.where(z != 0)[0] - 1 # 得到目标函数系数不为0的索引数组(即基本变量索引数组) 61 | restore_matrix = np.copy(l_matrix[:, 0:-1]) # 去掉x0那一列 62 | restore_matrix[0] = z # 初始化矩阵的第一行为原问题的目标函数向量 63 | for i, base_v in enumerate(base_ids): 64 | # 如果原问题的基本变量存在新基本变量数组中,说明需要替换消去 65 | if base_v in z_ids: 66 | restore_matrix[0] -= restore_matrix[0, base_v + 1] * restore_matrix[i + 1] # 消去原目标函数中的基本变量 67 | return restore_matrix 68 | # 单纯形算法求解线性规划 69 | def simplex(matrix, base_ids): 70 | matrix = matrix.copy() 71 | # 如果目标系数向量里有负数,则旋转矩阵 72 | while matrix[0, 1:].min() < 0: 73 | # 在目标函数向量里,选取系数为负数的第一个变量索引,作为替入变量 74 | j = np.where(matrix[0, 1:] < 0)[0][0] + 1 75 | # 在约束集合里,选取对替入变量约束最紧的约束行,那一行的基本变量作为替出变量 76 | k = np.array([matrix[i][0] / matrix[i][j] if matrix[i][j] > 0 else 0x7fff for i in 77 | range(1, matrix.shape[0])]).argmin() + 1 78 | # 说明原问题无界 79 | if matrix[k][j] <= 0: 80 | print('原问题无界') 81 | return None, None 82 | pivot_matrix(matrix, k, j) # 旋转替换替入变量和替出变量 83 | base_ids[k - 1] = j - 1 # 维护当前基本变量索引数组 84 | return matrix 85 | # 单纯形算法求解步骤入口 86 | def solve(a, b, c, equal=None): 87 | loose_matrix = get_loose_matrix(a) # 转化得到松弛矩阵 88 | if equal is not None: 89 | loose_matrix = np.insert(loose_matrix, 0, equal, axis=0) 90 | matrix = join_matrix(loose_matrix, b, c) # 得到ABC的组合矩阵 91 | base_ids = list(range(len(c), len(b) + len(c))) # 初始化基本变量的索引数组 92 | # 约束系数矩阵有负数约束,证明没有可行解,需要辅助线性函数 93 | if matrix[:, 0].min() < 0: 94 | print('构造求解辅助线性规划函数...') 95 | l_matrix, base_ids = Laux(matrix, base_ids) # 构造辅助线性规划函数并旋转求解之 96 | if l_matrix is not None: 97 | matrix = resotr_from_Laux(l_matrix, matrix[0], base_ids) # 恢复原问题的目标函数 98 | else: 99 | print('辅助线性函数的原问题没有可行解') 100 | return None, None, None 101 | ret_matrix = simplex(matrix, base_ids) # 单纯形算法求解拥有基本可行解的线性规划 102 | X = get_base_solution(ret_matrix, base_ids) # 得到当前最优基本可行解 103 | if ret_matrix is not None: 104 | return matrix, ret_matrix, X 105 | else: 106 | print('原线性规划问题无界') 107 | return None, None, None 108 | # 画图显示结果 109 | def draw_result(x, y): 110 | plt.plot(x, y, color='r', linestyle=':', marker='*', label='Profit / Risk') 111 | plt.legend() 112 | plt.xlabel('Risk') 113 | plt.ylabel('Profit') 114 | plt.plot([x[6], x[6]], [y[0], y[6]], color='g', linestyle='--') 115 | plt.scatter([x[6], ], [y[6], ], 50, color='red') 116 | plt.annotate('Risk={0}\nProfit={1}'.format(round(x[6], 4), round(y[6], 4)), xy=(x[6], y[6]), xytext=(-20, 20), 117 | textcoords='offset points', fontsize=12) 118 | plt.plot([x[25], x[25]], [y[0], y[25]], color='g', linestyle='--') 119 | plt.scatter([x[25], ], [y[25], ], 50, color='red') 120 | plt.annotate('Risk={0}\nProfit={1}'.format(round(x[25], 4), round(y[25], 4)), xy=(x[25], y[25]), xytext=(-20, -40), 121 | textcoords='offset points', fontsize=12) 122 | plt.show() 123 | if __name__ == '__main__': 124 | a = np.array([[0, 0.025, 0, 0, 0], [0, 0, 0.015, 0, 0], 125 | [0, 0, 0, 0.055, 0], [0, 0, 0, 0, 0.026]]) # 不等式约束系数 126 | equal = [1, 1.01, 1.02, 1.045, 1.065] + [0] * a.shape[0] # 等式约束系数 127 | c = [-0.05, -0.27, -0.19, -0.185, -0.185] # 目标函数系数 128 | M = 1 # 总投资 129 | risk = 0.0 / M # 风险率 130 | x_point, y_point = [], [] # 不同风险对应的收益点 131 | while risk < 0.05: 132 | b = [M] + [risk] * a.shape[0] # M为等式约束,其余为不等式约束 133 | matrix, ret_matrix, X = solve(np.copy(a), deepcopy(b), deepcopy(c), deepcopy(equal)) # 单纯形算法求解目标函数 134 | if ret_matrix is not None: 135 | print('等式约束检查', np.dot(equal, X[0:-1])) 136 | print('当风险率为{}时,本次迭代的最优解为:{}'.format(np.round(risk, 4), np.round(X[0: len(c)], 4).tolist())) 137 | print('该线性规划的最优值是:{}'.format(np.round(ret_matrix[0][0], 4))) 138 | x_point.append(risk) 139 | y_point.append(ret_matrix[0][0]) 140 | risk += 0.001 141 | draw_result(x_point, y_point) 142 | 143 | --------------------------------------------------------------------------------