最优化问题-线性优化(LP)

这里最优化问题的讨论,主要指在给定某个确认的目标函数以及该函数的自变量的一些约束条件,求函数的最大或最小值的问题,通用的数学表达式:

  1. 目标函数 :
    f(x)
  2. 约束条件 :
    s.t.g(x)0,h(x)=0
  3. 求解:
    minf(x)maxf(x)

根据约束条件以及目标函数性质不同,最优化问题求解的思路也有很大的不同,其中无约束优化问题的方法是基础,而带约束优化问题则在一定条件下可以转化为无约束优化问题来求解。

名词解释 (Terminology)

凸函数 (convex function) [1] 定义:

f(tx1+(1t)x2)tf(x1)+(1t)f(x2)

x1,x2X,t[0,1]

线性优化最优解 (LP - Linear Programming)

当优化问题满足以下条件时,
1) 线性目标函数 (linear objective function)
2) 线性约束条件 (linear constraints)
3) 自变量大于零

我们称该优化问题为线性优化问题(LP - Linear Programming) , 数学表达式为[3]:

Linear_Programming_Mathematic

在这我们更关注如何通过计算程序/代码解决线性优化问题, 主流思路是单纯形算法 (Simplex Algorithm) [4] [George Dantzig, 1947], 该算法的基本思路是,
1) 为待求解目标函数和约束条件添加宽松变量(slack varibles),使其成为等式
2) 设定 m个 (m < n, n 为待求解自变量)主成分变量 (basis)
3) 将n-m个非主成分变量设置为零,解出m个主成分值
4) 从该m个主成分极值(extreme point) 移到下一个主成分极值
5) 最优解为可行域中的极值点(extreme point)

具体例子, 膳食问题 (The Diet Problem) 表述已知人体所需元素列表

N1,...,Nn
, 在给定多样食物
F1,...,Fm
,和对应每样食物的单元价格为
b1,...,bm
, 以及每样食物单元F_i所对应的人体所需元素N_j 含量
aij
, 为满足人体日常对各种元素需求
cj
, 并最小化日常开销

1) 目标函数:

b1y1+...+bmym=(bTY)

2) 约束条件:
i=0maijyicj

3) 求解:
min(bTY)

问题具体化 (例子中的数据没有任何实际意义,可以为任何整数),假设人体所需元素有钙(480),锌(160),钠(1190), 市场上含有该元素的材料有红豆 (单价13),猪肉(单价23), 其中每种单位材料对应元素含量见下表:

红豆 猪肉
5 15
4 4
35 20

1) 目标函数

13x+23y

2) 约束条件
5x+15y4804x+4y16035x+20y1190

解法[ 2]:
Step One - 添加宽松变量 (slack variable)
这里写图片描述 图中a, b, c 为宽松变量, z 为待求解目标值;

Step Two - 设置主成分变量,初始化时以宽松变量为主成分,即a, b, c, 并初始化非主成分元素为0, x=0, y=0, z=0, 求解得a,b,c分别为480, 160, 1190,该点一定为可行域极点;

Step Three - 随机选取待求解等式中的非主成分变量{x, y},如y, 后将y作为主成分成员,移除任意一个主成分成员{a, b, c}, 如a, 非主成分x, a为0,主成分变量y=32, b=32, c=550, z=736
这里写图片描述

Step Four - 重复主成分替换过程,将x移入主成分, {x, y, b},非主成分 {a, c, z}=0, 得x=12, y=28, z=800, c=110;
这里写图片描述

Step Five 何时停止?当第一行的系数全不为零, 因为a,c 大于等于0,z=800-a-c, z小于等于800,即为最优解
步骤 主成分 非主成分
Step One a=480,b=160,c=1190 x,y=0
Step Two y=32,b=32,c=550 x,a=0
Step Three x=12,y=28,c=110 a,b=0

代码部分:

# -*- encoding: utf-8 -*-
import re, sys
import numpy as np
import copy

class SimplexAlgorithm(object):
    """
    Implement of Simplex Algorithm
    """

    def __init__(self, A, b, c):
        """
        A = constraint Matrix
        I = slack Matrix
        b = constraint 
        c = objective coefficient
        """
        A = np.array(A)
        b = np.array(b)
        c = np.array(c)
        assert len(A.shape) == 2
        assert A.shape[0] == len(b)
        assert A.shape[1] == len(c)
        M = A.shape[0]
        N = len(c)

        a = []
        for i in range(M):
            _temp = []
            for j in range(N):
                _temp.append(A[i, j])

            # I part
            _I = [0] * M
            _I[i] = 1.

            # b Part
            _b = [b[i]]

            _temp += _I + _b 
            a.append(_temp)

        # c part
        a.append(list(c) + [0] * (M + 1))
        print "Construct Matrix: "
        for ele in a:
            print "\t".join([str(ent) for ent in ele])
        print "---------"

        self.matrix = a
        self.N = N
        self.M = M

    def pivot(self, x, y):
        """
        """
        for i in range(self.M + 1):
            for j in range(self.M + self.N + 1):
                if (x != i and j != y):
                    self.matrix[i][j] -= self.matrix[x][j] * self.matrix[i][y] / self.matrix[x][y]

        # zero out column y
        for i in range(self.M + 1):
            if (i != x): self.matrix[i][y] = 0.0

        # scale row x
        for j in range(self.M + self.N + 1):
            if (j != y): self.matrix[x][j] /= self.matrix[x][y]

        self.matrix[x][y] = 1.

    def solve(self):
        """
        """
        while True:
            p, q = 0, 0
            for q in range(self.M + self.N + 1):
                if (self.matrix[self.M][q] > 0): break # positive objective coefficient
            if (q >= self.M + self.N): break

            for p in range(self.M):
                if self.matrix[p][q] > 0: break

            for i in range(p+1, self.M):
                if self.matrix[i][q] > 0:
                    # min ratio test
                    if (self.matrix[i][self.M + self.N] / self.matrix[i][q] < 
                        self.matrix[p][self.M + self.N] / self.matrix[p][q]):
                        p = i

            self.pivot(p, q)
        return self.matrix

if __name__ == "__main__":
    reload(sys)
    sys.setdefaultencoding("utf-8")

    # value should be float type
    A = [[5., 15.], [4., 4.], [35., 20.]]
    c = [13., 23.]
    b = [480., 160., 1190.]

    instance = SimplexAlgorithm(A, b, c)
    res = instance.solve()

    print "Result: "
    for ele in res:
        print "\t".join([str(ent) for ent in ele])

1 https://en.wikipedia.org/wiki/Convex_function
2 https://www.cs.princeton.edu/~rs/AlgsDS07/22LinearProgramming.pdf
3 https://en.wikipedia.org/wiki/Linear_programming
4 https://en.wikipedia.org/wiki/Simplex_algorithm

你可能感兴趣的:(最优化问题)