Article directory
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+x3≤484x _1+2x _2+1.5x _3≤202x _1+1.5x _2+0.5x _3≤8x1,x2,x3≥0,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 _3≥600Through
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.5w3≥300,w1+1.5w2+0.5w3≥200
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,w3≥0
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 _3≥6006w1+2w _2+1.5w3≥300w1+1.5w2+0.5w3≥200w1,w2,w3≥0
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=bx≥0
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=cBTB−1b−(cBTB−1N−cNT)xN
Definition
R = c BTB − 1 N − c NT \pmb R=\pmb c_B^T\pmb B^{-1}\pmb N-\pmb c_N^TR=cBTB−1N−cNT
If the linear programming has reached the optimal solution, then R ≤ 0 \pmb R≤\pmb 0R≤0 . At this time, letw T = c BTB − 1 \pmb w^T = \pmb c_B^T\pmb B^{-1}wT=cBTB− 1 , the above formula can be written as
w TN ≤ c NT w^T\pmb N≤\pmb c_N^TwTN≤cNT
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=cBTB−1B=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 A≤c
Add a transpose to T
to get AT w ≤ c A^T \pmb w ≤ \pmb cATw≤c
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=wTAx≤cTx
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.tATw≤c
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 ≥ 0x≥0butw \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 wcTx≥bTw。
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=xTc≥xT 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^\astcTx≥bTw∗
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=ATw−c≤0so 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=cBTB−1b=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=w1∗b1+w2∗b2+⋅⋅⋅+wm∗bm
对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 ∂bi∂f=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 _1−4x _2s.tx1+3x _2+x3=902x _1+x2+x4=80x1+x2+x5=45x1,x2,x3,x4,x5≥0Call
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+w3≤−53w1+w2+we3≤−4w1,w2,w3≤0
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_ictri∗cvri∗ri
Among them, ctri ctr_ictri、 c v r i cvr_i cvri和ri 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)ctri∗cvri∗(ri−ai)
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