Linear programming dual problems: theoretical derivation and practical applications

Dual problem example

I have seen the word "dual" in many places before, and I always felt that this word was very high-end. The Baidu Encyclopedia of Dual Theory even writes: "The most important discovery in the early development of linear programming was the dual problem." Therefore, now that we have reached linear programming, the dual problem is naturally worth studying in depth.

I have a general understanding of the introduction of dual problems on the Internet, which can be roughly divided into two categories: one is to directly introduce the dual problem of linear programming, and the other is to start from the Lagrangian dual problem, and then express linear programming as a special The optimization problem has special properties. Since this period of time is all about linear programming, I personally feel that the first category is more suitable for me.

Let’s first give an example to intuitively understand the dual problem.

Furniture Company A produces desks, dining tables, and chairs. The production of each type of furniture requires wood and two types of skilled labor: polishing and carpentry. The quantities of various resources required to craft each type of furniture, the amount of available resources, and the selling price of each type of furniture are shown in the table below.

resource desk dining table Chair Amount of available resources
Timber (cubic meters) 8 6 1 48
Polishing time (hours) 4 2 1.5 20
Carpentry time (hours) 2 1.5 0.5 8
Selling price (yuan) 600 300 200

Find out how the company should arrange production to maximize revenue.

The solution of this problem is not difficult. Let the output of desks be x 1 x_1x1, the output of the dining table is x 2 x_2x2, the output of chairs is x 3 x_3x3, at this time the model can be described as
maxf = 600 x 1 + 300 x 2 + 200 x 3 st 8 x 1 + 6 x 2 + x 3 ≤ 48 4 x 1 + 2 x 2 + 1.5 x 3 ≤ 20 2 x 1 + 1.5 x 2 + 0.5 x 3 ≤ 8 x 1 , x 2 , x 3 ≥ 0 , and take the integer max \quad f=600x_1+300x_2+200x_3 \\ \text{st} \quad 8x_1+6x_2+x_3≤48 \ \\nonumber \quad \quad \quad4x_1+2x_2+1.5x_3≤20\\\nonumber \quad\quad\quad 2x_1+1.5x_2+0.5x_3≤8\\\nonumber \quad\quad\quad x_1,x_2,x_3 ≥0, and take an integer\\maxf=600x1+300x2+200x3s.t8x _1+6x _2+x3484x _1+2x _2+1.5x _3202x _1+1.5x _2+0.5x _38x1,x2,x30,And take an integer
Obviously this problem is an integer programming problem. We use ortools to solve it. The code is as follows

from ortools.linear_solver import pywraplp


if __name__ == '__main__':
    # 声明ortools求解器,使用SCIP算法
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # 优化变量,连续值
    x1 = solver.NumVar(0, solver.infinity(), 'x1')
    x2 = solver.NumVar(0, solver.infinity(), 'x2')
    x3 = solver.NumVar(0, solver.infinity(), 'x3')

    # 目标函数
    solver.Maximize(600 * x1 + 300 * x2 + 200 * x3)
    # 约束条件
    solver.Add(8 * x1 + 6 * x2 + x3 <= 48)
    solver.Add(4 * x1 + 2 * x2 + 1.5 * x3 <= 20)
    solver.Add(2 * x1 + 1.5 * x2 + 0.5 * x3 <= 8)

    # 模型求解
    status = solver.Solve()

    # 模型求解成功, 打印结果
    if status == pywraplp.Solver.OPTIMAL:
        # 变量最优解
        print('x1: {}, x2: {}, x3: {}'.format(x1.solution_value(), x2.solution_value(), x3.solution_value()))

        # 最优目标函数值
        print('best_f =', solver.Objective().Value())

    else:
        print('not converge.')

After running the code, the optimal solution can be obtained as follows

x1: 1.9999999999999996, x2: 0.0, x3: 8.0
best_f = 2800.0

It should be noted that the problem itself is an integer programming, but the code does not restrict the variables to only take integers. However, since the optimal solution to this linear programming problem is also an integer, the results are not affected. This is mainly done to facilitate subsequent comparison with dual problems.

So what is the duality problem? Dual questions can be understood from another perspective.

The new problem is described as follows: Suppose Company B wants to purchase all the resources of Company A. At this time, it needs to determine the unit price of each resource. Set the unit price of wood purchased to w 1 w_1w1(yuan/cubic meter), the unit price of polishing time is w 2 w_2w2(yuan/hour), the unit price of carpentry time is w 3 w_3w3(yuan/hour).

On the one hand, B naturally hopes that the lower the total price, the better, so the objective function is
minz = 48 w 1 + 20 w 2 + 8 w 3 min \quad z=48w_1+20w_2+8w_3minz=48 w1+20w2+8w3
On the other hand, the condition for A's willingness to sell its own resources is that the selling price cannot be lower than the profit achieved when the same amount of resources is produced by its own organization. For the desk, B needs to pay at least 600 yuan to buy 8 cubic meters of wood, 4 hours of polishing time and 2 hours of carpentry time. This constraint can be described as
8 w 1 + 4 w 2 + 2 w 3 ≥ 600 8w_1+4w_2+2w_3≥6008w1+4w2+2w _3600Through
similar reasoning, we can also get two other constraints
6 w 1 + 2 w 2 + 1.5 w 3 ≥ 300 , w 1 + 1.5 w 2 + 0.5 w 3 ≥ 200 6w_1+2w_2+1.5w_3≥300, \quad w_1+1.5w_2+0.5w_3≥2006w1+2w _2+1.5w3300,w1+1.5w2+0.5w3200

Obviously, the unit price cannot be negative, so the constraints are
w 1 , w 2 , w 3 ≥ 0 w_1,w_2,w_3≥0w1,w2,w30
In summary, a new linear programming problem is obtained as follows
minz = 48 w 1 + 20 w 2 + 8 w 3 st 8 w 1 + 4 w 2 + 2 w 3 ≥ 600 6 w 1 + 2 w 2 + 1.5 w 3 ≥ 300 w 1 + 1.5 w 2 + 0.5 w 3 ≥ 200 w 1 , w 2 , w 3 ≥ 0 min \quad z=48w_1+20w_2+8w_3 \\ \text{st} \quad 8w_1+4w_2+ 2w_3≥600 \\\nonumber \quad \quad \quad 6w_1+2w_2+1.5w_3≥300\\\nonumber \quad \quad \quad w_1+1.5w_2+0.5w_3≥200\\\nonumber w_1,w_2,w_3≥ 0\\minz=48 w1+20w2+8w3s.t8w1+4w2+2w _36006w1+2w _2+1.5w3300w1+1.5w2+0.5w3200w1,w2,w30
The above linear programming problem is the dual problem of the original problem.

To solve the dual problem, the code is as follows

from ortools.linear_solver import pywraplp


if __name__ == '__main__':
    # 声明ortools求解器,使用SCIP算法
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # 优化变量,连续值
    x1 = solver.NumVar(0, solver.infinity(), 'x1')
    x2 = solver.NumVar(0, solver.infinity(), 'x2')
    x3 = solver.NumVar(0, solver.infinity(), 'x3')

    # 目标函数
    solver.Minimize(48 * x1 + 20 * x2 + 8 * x3)
    # 约束条件
    solver.Add(8 * x1 + 4 * x2 + 2 * x3 >= 600)
    solver.Add(6 * x1 + 2 * x2 + 1.5 * x3 >= 300)
    solver.Add(1 * x1 + 1.5 * x2 + 0.5 * x3 >= 200)

    # 模型求解
    status = solver.Solve()

    # 模型求解成功, 打印结果
    if status == pywraplp.Solver.OPTIMAL:
        # 变量最优解
        print('x1: {}, x2: {}, x3: {}'.format(x1.solution_value(), x2.solution_value(), x3.solution_value()))

        # 最优目标函数值
        print('best_f =', solver.Objective().Value())

    else:
        print('not converge.')

Running the code, you can get the optimal solution as follows

x1: 0.0, x2: 100.00000000000003, x3: 99.99999999999993
best_f = 2799.9999999999995

Comparing the optimal solutions of the original problem and the dual problem, we found an interesting phenomenon
f ∗ = z ∗ f^{\ast}=z^{\ast}f=z
That is, the optimal objective function values ​​of the original problem and the dual problem are equal. In fact, this is not a special case, it is just one of the properties of the dual problem of linear programming.

Dual problem definition and properties

definition

The examples in the previous chapter gave us some intuitive understanding of the dual problem. This section uses some partial theoretical derivation to study the relationship and properties between the dual problem and the original problem in linear programming.

Review the standard form of linear programming
minf ( x ) = c T x st A x = bx ≥ 0 min \quad f(\pmb x)=\pmb c^T\pmb x \\ \text{st} \quad \ pmb A\pmb x=\pmb b \\\nonumber \quad \quad \pmb x ≥ 0\\minf(x)=cTxs.tAx=bx0

When deriving the simplex method, there is the following formula
f = c BTB − 1 b − ( c BTB − 1 N − c NT ) x N f=\pmb c_B^T\pmb B^{-1}\pmb b- (\pmb c_B^T\pmb B^{-1}\pmb N-\pmb c_N^T)\pmb x_Nf=cBTB1b(cBTB1NcNT)xN
Definition
R = c BTB − 1 N − c NT \pmb R=\pmb c_B^T\pmb B^{-1}\pmb N-\pmb c_N^TR=cBTB1NcNT
If the linear programming has reached the optimal solution, then R ≤ 0 \pmb R≤\pmb 0R0 . At this time, letw T = c BTB − 1 \pmb w^T = \pmb c_B^T\pmb B^{-1}wT=cBTB1 , the above formula can be written as
w TN ≤ c NT w^T\pmb N≤\pmb c_N^TwTNcNT
Take another look at w TB \pmb w^T\pmb BwTB
w T B = c B T B − 1 B = c B T \pmb w^T\pmb B=\pmb c_B^T\pmb B^{-1} \pmb B=\pmb c_B^T wTB=cBTB1B=cBT
Because A = [ B , N ] \pmb A=[\pmb B,\pmb N]A=[B,N ] , combining the above two formulas, we can get
w TA ≤ c T \pmb w^T\pmb A≤\pmb c^TwT Ac
Add a transpose to T
to get AT w ≤ c A^T \pmb w ≤ \pmb cATwc

Let’s look at another set of derivation
w T b = w TA x ≤ c T x \pmb w^T \pmb b=\pmb w^T \pmb A \pmb x≤\pmb c^T\pmb xwTb=wTAxcTx

Based on the above two formulas, if we put w \pmb wAs w is a variable, a new optimization problem
maxb T w st AT w ≤ c max \quad \pmb b^T\pmb w \\ \text{st} \quad \pmb A^T\pmb w≤\ pmbcmaxbTws.tATwc

This optimization problem is the dual problem of the original linear programming problem. Compared with the original question, A , b \pmb A,\pmb bA,b andc \pmb cc is still there, just changed its position; at the same time,x ≥ 0 \pmb x ≥ 0x0butw \pmb ww has no constraints.

nature

Since the dual problem can be derived from the original problem, there are naturally some interrelationships between them.

Personally, the most basic relationship should be the weak duality theorem: if x \pmb xx is a feasible solution to the original problem,w \pmb ww is a feasible solution to the dual problem, thenc T x ≥ b T w \pmb c^T\pmb x ≥ \pmb b^T \pmb wcTxbTw

This theorem has actually been proven from the previous deduction. Here it is described again through the following process:
c T x = x T c ≥ x TAT w = b T w \pmb c^T\pmb x = \pmb x^T \pmb c ≥ \pmb x^T\pmb A^T\pmb w=\pmb b^T \pmb wcTx=xTcxT ATw=bTw

An inference can be obtained based on the weak duality theorem: if x ∗ \pmb x^\astx is a feasible solution to the original problem,w ∗ \pmb w^\astw is a feasible solution to the dual problem, and we havec TcTx=bTw , thenx ∗ \pmb x^\astx is the optimal solution to the original problem,w ∗ \pmb w^\astw is the optimal solution to the dual problem.

From the weak duality theorem, we know that
c T x ≥ b T w ∗ \pmb c^T\pmb x≥\pmb b^T\pmb w^\astcTxbTw
While
c T x ∗ = b T w ∗ \pmb c^T\pmb x^\ast=\pmb b^T\pmb w^\astcTx=bTw
Sox ∗ \pmb x^\astx is the optimal solution to the original problem.

In the same way, it can be proved that w ∗ \pmb w^\astw is the optimal solution to the dual problem.

Finally, there is the most important strong duality theorem in practical applications: if the original problem has an optimal solution, then the dual problem also has an optimal solution, and the objective function values ​​are equal.

Assume that the optimal solution to the original problem is x ∗ \pmb x^\astx , dual variablew T = c BTB − 1 \pmb w^T = \pmb c_B^T\pmb B^{-1}wT=cBTB−1 . _ Becausex ∗ \pmb x^\astx is the optimal solution, so
R = AT w − c ≤ 0 \pmb R=\pmb A^T\pmb w-\pmb c≤0R=ATwc0so w \pmb
ww is a feasible solution to the dual problem. At the same timex \pmb xx is a basic feasible solution, which can be deduced as follows
c T x = c BT x B = c BTB − 1 b = w T b = b T w \pmb c^T\pmb x=\pmb c_B^T\pmb x_B =\pmb c_B^T\pmb B^{-1}\pmb b=\pmb w^T\pmb b=\pmb b^T\pmb wcTx=cBTxB=cBTB1b=wTb=bT w
combined with the previous inference can be seen,w \pmb ww is the optimal solution to the dual problem.

Dual problem application

There are many applications of dual problems, but most of them are used for theoretical derivation and proof. In practical applications, shadow prices are more common.

shadow price

According to the strong duality theorem, when the original problem and the dual problem have optimal solutions at the same time, the objective function values ​​​​of the two are equal, that is,
f = c T x ∗ = z = b T w ∗ f=\pmb c^T\pmb x^ \ast=z=\pmb b^T\pmb w^\astf=cTx=z=bTw
Written in the form of components
f = w 1 ∗ b 1 + w 2 ∗ b 2 + ⋅ ⋅ ⋅ + wm ∗ bmf=w_1^\ast b_1+w_2^\ast b_2+···+w_m^\ast b_mf=w1b1+w2b2+⋅⋅⋅+wmbm
bi b_ibi求导
∂ f ∂ b i = w i ∗ , i = 1 , 2 , ⋅ ⋅ ⋅ , m \frac{\partial f}{\partial b_i}=w_i^\ast, \quad i=1,2,···,m bif=wi,i=1,2,⋅⋅⋅,The right side of m
is obviously the optimal solution we get when solving the dual problem; while the left side can be intuitively understood as the gradient value of the objective function value relative to the resource variable. The smaller the value, the smaller the value of the objective function value that can be brought about by the increase of the corresponding resource. The greater the reduction.

Next, we will give an example to visually illustrate the meaning of shadow price.

原问题:
m i n f ( x ) = − 5 x 1 − 4 x 2 s.t x 1 + 3 x 2 + x 3 = 90 2 x 1 + x 2 + x 4 = 80 x 1 + x 2 + x 5 = 45 x 1 , x 2 , x 3 , x 4 , x 5 ≥ 0 min \quad f(\pmb x)= -5x_1-4x_2 \\ \text{s.t} \quad x_1+3x_2+x_3=90 \\ \nonumber \quad \quad 2x_1+x_2+x_4=80 \\ \nonumber \quad \quad x_1+x_2+x_5=45 \\ \nonumber \quad \quad \quad x_1,x_2,x_3,x_4,x_5≥0 minf(x)=5x _14x _2s.tx1+3x _2+x3=902x _1+x2+x4=80x1+x2+x5=45x1,x2,x3,x4,x50Call
ortools to solve

from ortools.linear_solver import pywraplp


if __name__ == '__main__':
    # 声明ortools求解器,使用SCIP算法
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # 优化变量
    x1 = solver.NumVar(0, solver.infinity(), 'x1')
    x2 = solver.NumVar(0, solver.infinity(), 'x2')
    x3 = solver.NumVar(0, solver.infinity(), 'x3')
    x4 = solver.NumVar(0, solver.infinity(), 'x4')
    x5 = solver.NumVar(0, solver.infinity(), 'x5')

    # 目标函数
    solver.Minimize(-5 * x1 - 4 * x2)
    # 约束条件
    solver.Add(1 * x1 + 3 * x2 + x3 == 90)
    solver.Add(2 * x1 + 1 * x2 + x4 == 80)
    solver.Add(1 * x1 + 1 * x2 + x5 == 45)

    # 模型求解
    status = solver.Solve()

    # 模型求解成功, 打印结果
    if status == pywraplp.Solver.OPTIMAL:
        # 变量最优解
        print('x1: {}, x2: {}, x3: {}, x4: {}, x5: {}'.format(
            x1.solution_value(), x2.solution_value(), x3.solution_value(),
            x4.solution_value(), x5.solution_value()))

        # 最优目标函数值
        print('best_f =', solver.Objective().Value())

    else:
        print('not converge.')

After running the code, the optimal solution is

x1: 35.0, x2: 10.000000000000007, x3: 24.99999999999998, x4: -7.105427357601002e-15, x5: -7.105427357601002e-15
best_f = -215.00000000000003

对偶问题:
m a x z ( w ) = 90 w 1 + 80 w 2 + 45 w 3 s.t w 1 + 2 w 2 + w 3 ≤ − 5 3 w 1 + w 2 + w e 3 ≤ − 4 w 1 , w 2 , w 3 ≤ 0 max \quad z(\pmb w)= 90w_1+80w_2+45w_3 \\ \text{s.t} \quad w_1+2w_2+w_3≤-5 \\ \nonumber \quad \quad 3w_1+w_2+w_e3≤-4 \\ \nonumber w_1,w_2,w_3≤0 maxz(w)=90w _1+80 w2+45 in3s.tw1+2w _2+w353w1+w2+we34w1,w2,w30
or call ortools to solve

from ortools.linear_solver import pywraplp


if __name__ == '__main__':
    # 声明ortools求解器,使用SCIP算法
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # 优化变量
    x1 = solver.NumVar(-solver.infinity(), solver.infinity(), 'x1')
    x2 = solver.NumVar(-solver.infinity(), solver.infinity(), 'x2')
    x3 = solver.NumVar(-solver.infinity(), solver.infinity(), 'x3')

    # 目标函数
    solver.Maximize(90 * x1 + 80 * x2 + 45 * x3)
    # 约束条件
    solver.Add(1 * x1 + 2 * x2 + x3 <= -5)
    solver.Add(3 * x1 + 1 * x2 + x3 <= -4)
    solver.Add(1 * x1 <= 0)
    solver.Add(1 * x2 <= 0)
    solver.Add(1 * x3 <= 0)

    # 模型求解
    status = solver.Solve()

    # 模型求解成功, 打印结果
    if status == pywraplp.Solver.OPTIMAL:
        # 变量最优解
        print('x1: {}, x2: {}, x3: {} '.format(x1.solution_value(), x2.solution_value(), x3.solution_value()))

        # 最优目标函数值
        print('best_f =', solver.Objective().Value())

    else:
        print('not converge.')

After running the code, the optimal solution is

x1: 0.0, x2: -1.0000000000000002, x3: -3.0 
best_f = -215.00000000000006

Obviously, the optimal objective function values ​​are the same.

If the first constraint in the original problem code is modified: 90->91, that is, the first resource variable is increased by 1 unit, and the optimal solution is recalculated as

x1: 35.0, x2: 10.000000000000005, x3: 25.999999999999986, x4: -5.329070518200751e-15, x5: -5.329070518200751e-15
best_f = -215.0

At this time, the optimal objective function value has not changed; from the optimal solution of the dual problem, w 1 ∗ = 0 w_1^\ast=0w1=0 , which is logical.

If the second constraint in the original problem code is modified: 80->81, the optimal solution is recalculated as

x1: 36.0, x2: 9.000000000000004, x3: 26.99999999999999, x4: -3.552713678800501e-15, x5: -3.552713678800501e-15
best_f = -216.00000000000003

At this time, the optimal objective function value is reduced by 1 unit; from the optimal solution of the dual problem, w 2 ∗ = − 1 w_2^\ast=-1w2=1 , is also logical.

If the third constraint in the original problem code is modified: 45->46, the optimal solution is recalculated as

x1: 34.00000000000001, x2: 11.999999999999995, x3: 20.000000000000007, x4: -8.881784197001252e-15, x5: -1.7763568394002505e-15
best_f = -218.00000000000003

At this time, the optimal objective function value is reduced by 3 units; from the optimal solution of the dual problem, w 3 ∗ = − 3 w_3^\ast=-3w3=3 , so still no problem.

Recently, I happened to come across a case of trying to use shadow prices in an industrial scenario: Inventory Based Recommendation Algorithms
. Let me briefly talk about my understanding.

Let’s first describe the scene: Hema’s shopping cart interface can recommend some perishable items. If these items are not sold out on the same day, they will be scrapped or discounted the next day. The stock quantity of each item is limited. In the most ideal situation, all products should be sold out on the same day. So when each user enters the shopping cart page, which products should the system recommend?

The easiest strategy to think of is: calculate the value that each item can bring when it is recommended
ctri ∗ cvri ∗ ri ctr_i*cvr_i*r_ictricvriri
Among them, ctri ctr_ictri c v r i cvr_i cvriri r_iriRespectively iiClick-through rate, conversion rate and price of i item.

Once you have this value, you can arrange the products from large to small according to this value and recommend the top K.

A potential problem with this strategy is that the inventory of the product is not taken into account, which may cause some high-value products to be sold out early, while medium-value products are not sold out due to reasons such as too few recommendations.

In order to solve this problem, shadow prices can be introduced to fine-tune the above strategy:
ctri ∗ cvri ∗ ( ri − α i ) ctr_i*cvr_i*(r_i-\alpha_i)ctricvri(riai)
where,α i \alpha_iaiThat is the iiThe shadow price corresponding to the inventory constraint of item i .

After adding the shadow price parameter, when the inventory of high-value products is sufficient, the shadow price of the product is 0, which does not affect the original recommendation strategy; when the inventory of high-value products becomes less, the product becomes scarce, and the shadow price will be greater than 0. , thereby lowering the ranking of high-value items to give way to other items of slightly lower value that are more in stock.

Theoretical application

Some of the more theoretical applications are briefly mentioned here:

(1) First, it provides a new method for solving linear programming problems: the dual simplex method;

(2) Secondly, it provides a new idea to prove that the original problem has no solution: Farkas’ lemma;

(3) The last one has some extensions: regardless of whether the original problem is a convex problem, its Lagrangian dual problem must be a convex optimization problem.

references

There is no such chapter in previous articles, but in the process of actual study and summary, I have actually referred to many articles or videos of great experts, and it is difficult to add a quote or link in a sentence to express respect for the original author. A tribute to the achievements, because many new cognitions are scattered in every corner of the article. Therefore, for convenience, they will be placed at this location in the future.

Dual problem example: https://weread.qq.com/web/reader/da232bb072012022da29f24kc7432af0210c74d97b01b1c

Why is the dual problem of linear programming needed: https://www.zhihu.com/question/26658861

Derivation of the dual problem: https://zhuanlan.zhihu.com/p/522590887

Lagrange duality: https://blog.csdn.net/frostime/article/details/90291392?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task- blog-BlogCommendFromBaidu-1

Application of shadow price in Hema: https://ieeexplore.ieee.org/abstract/document/9378261

Guess you like

Origin blog.csdn.net/taozibaby/article/details/132796605