Google OR-Tools(二) 线性优化Linear Optimization
本文参考Google OR-Tools官网文档介绍OR-Tools的使用方法。
1 线性规划问题
线性规划是优化问题里最简单的一种形式,需要极大化或极小化的目标函数是线性的,而约束条件由一组线性等式或不等式组成。很多复杂的非线性规划问题都会需要将其转换成线性规划问题来求解。求解线性规划问题最常用的算法是单纯形法(包括了单纯形表、修正单纯形法、对偶单纯形法等),除此之外还有内点法、灵敏度分析等算法。
线性规划问题的一般形式:
m a x i m i z e c 1 x 1 + c 2 x 2 + c 3 x 3 + . . . + c n x n s u b j e c t t o a i 1 x 1 + a i 2 x 2 + a i 3 x 3 + . . . + a i n x n ≤ b i , i = 1 , . . . , l a j 1 x 1 + a j 2 x 2 + a j 3 x 3 + . . . + a j n x n ≥ b j , j = l + 1 , . . . , l + r a k 1 x 1 + a k 2 x 2 + a k 3 x 3 + . . . + a k n x n = b k , k = l + r + 1 , . . . , l + r + q x 1 ≥ 0 , x 2 ≥ 0 , . . . , x n ≥ 0 \begin{aligned} maximize\quad& c_1x_1+c_2x_2+c_3x_3+...+c_n x_n\\ subject\ to\quad& a_{i1} x_1+a_{i2} x_2+a_{i3} x_3+...+a_{in} x_n\leq b_i, \ i=1,...,l\\ & a_{j1} x_1+a_{j2} x_2+a_{j3} x_3+...+a_{jn} x_n\geq b_j, \ j=l+1,...,l+r\\ & a_{k1} x_1+a_{k2} x_2+a_{k3} x_3+...+a_{kn} x_n= b_k, \ k=l+r+1,...,l+r+q\\ & x_1\geq0,x_2\geq0,...,x_n\geq0 \end{aligned} maximizesubject toc1x1+c2x2+c3x3+...+cnxnai1x1+ai2x2+ai3x3+...+ainxn≤bi, i=1,...,laj1x1+aj2x2+aj3x3+...+ajnxn≥bj, j=l+1,...,l+rak1x1+ak2x2+ak3x3+...+aknxn=bk, k=l+r+1,...,l+r+qx1≥0,x2≥0,...,xn≥0
其中约束条件的个数为 m = l + r + q m=l+r+q m=l+r+q, c j c_j cj和 a i j a_{ij} aij为常系数, b i b_i bi也是常数,需要调整为非负数; x j x_j xj为决策变量。如果线性规划是凸规划,则局部极大值就是全局极大值。
2 典型案例
营养搭配问题(Stigler diet)是由诺贝尔经济学奖获得者乔治·斯蒂格勒(George Joseph Stigler)在上世纪三四十年代提出的一个数学问题,就是要以最小的成本采购食物,同时各个营养指标都要满足。
下面这个表给出了所有的食谱信息(当然这不是斯蒂格勒当时列出的食谱,原始的食谱内容太多,我们简化一下),最后一行是各个营养的每周需求量,最终指定的食谱必须要满足这个需求:
食物 | 蛋白质 | 脂肪 | 碳水化合物 | 价格($/100g) |
---|---|---|---|---|
1 面包 | 8% | 1% | 55% | 0.25 |
2 黄油 | - | 90% | - | 0.5 |
3 奶酪 | 25% | 36% | - | 1.2 |
4 谷物 | 12% | 3% | 75% | 0.6 |
5 巧克力 | 8% | - | 50% | 1.5 |
每周需求量(g) | 550 | 600 | 2000 |
根据上面表格的信息,我们可以建立一个线性规划模型。令 x 1 , x 2 , x 3 , x 4 , x 5 x_1,x_2,x_3,x_4,x_5 x1,x2,x3,x4,x5表示五种食物的采购量(g),则有:
m i n i m i z e 0.25 x 1 + 0.5 x 2 + 1.2 x 3 + 0.6 x 4 + 1.5 x 5 s u b j e c t t o 0.08 x 1 + 0.25 x 3 + 0.12 x 4 + 0.08 x 5 ≥ 550 0.01 x 1 + 0.9 x 2 + 0.36 x 3 + 0.03 x 4 ≥ 600 0.55 x 1 + 0.75 x 4 + 0.5 x 5 ≥ 2000 x 1 ≥ 0 , x 2 ≥ 0 , x 3 ≥ 0 , x 4 ≥ 0 , x 5 ≥ 0 \begin{aligned} minimize\quad& 0.25x_1+0.5x_2+1.2x_3+0.6x_4+1.5x_5\\ subject\ to\quad& 0.08x_1+0.25x_3+0.12x_4+0.08x_5\geq 550 \\ & 0.01x_1+0.9x_2+0.36x_3+0.03x_4\geq 600 \\ & 0.55x_1+0.75x_4+0.5x_5\geq 2000 \\ & x_1\geq0,x_2\geq0,x_3\geq0,x_4\geq0, x_5\geq0 \end{aligned} minimizesubject to0.25x1+0.5x2+1.2x3+0.6x4+1.5x50.08x1+0.25x3+0.12x4+0.08x5≥5500.01x1+0.9x2+0.36x3+0.03x4≥6000.55x1+0.75x4+0.5x5≥2000x1≥0,x2≥0,x3≥0,x4≥0,x5≥0
在斯蒂格勒提出这个问题的年代,线性规划算法还尚未出现,因此尽管在1944年他本人计算出了这个问题的可行答案,但他使用的是比较原始的方法计算的。直到1947年,Jack Laderman提出了单纯形算法,才有有效的方法来计算这个问题,不过由于当时还没计算机,需要9个工作人员花了120个工作日才能算出结果。幸运的是我们现在可以利用计算机强大的运算能力和OR-Tools很方便地处理这种问题。
3 OR-Tools程序
我们写个.Net Core控制台应用来解算这个问题。首先把上边表格的食谱信息用DataTable对象存储
//已知量DataTable foodTable = new DataTable();foodTable.Columns.Add("FoodName", typeof(string));foodTable.Columns.Add("Protein", typeof(double));foodTable.Columns.Add("Fat", typeof(double));foodTable.Columns.Add("Carbohydrate", typeof(double));foodTable.Columns.Add("Price", typeof(double));DataRow dr = foodTable.NewRow();dr["FoodName"] = "Bread";dr["Protein"] = 0.08;//蛋白质dr["Fat"] = 0.01;//脂肪dr["Carbohydrate"] = 0.55;//碳水化合物dr["Price"] = 0.25;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Butter";dr["Protein"] = 0;dr["Fat"] = 0.9;dr["Carbohydrate"] = 0;dr["Price"] = 0.5;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Cheese";dr["Protein"] = 0.25;dr["Fat"] = 0.36;dr["Carbohydrate"] = 0;dr["Price"] = 1.2;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Grain";dr["Protein"] = 0.12;dr["Fat"] = 0.03;dr["Carbohydrate"] = 0.75;dr["Price"] = 0.6;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Chocolate Bar";dr["Protein"] = 0.08;dr["Fat"] = 0;dr["Carbohydrate"] = 0.5;dr["Price"] = 1.5;foodTable.Rows.Add(dr);double minPorten = 550;double minFat = 600;double minCarbohydrate = 2000;
新建一个Linear Solver对象:
//Create a Linear Solver objectvar solver= Solver.CreateSolver("DietSolver", "GLOP_LINEAR_PROGRAMMING");
定义决策变量
//Create variablesList<Variable> variables = new List<Variable>();foreach (DataRow row in foodTable.Rows){variables.Add(solver.MakeNumVar(0, double.PositiveInfinity, row["FoodName"].ToString()));}
定义三条线性约束
//Create linear constraintsGoogle.OrTools.LinearSolver.Constraint ct1 = solver.MakeConstraint(minPorten, double.PositiveInfinity, "minPorten");for(int i=0;i<foodTable.Rows.Count;i++){var variable = variables[i];ct1.SetCoefficient(variable, (double)foodTable.Rows[i]["Protein"]);}Google.OrTools.LinearSolver.Constraint ct2 = solver.MakeConstraint(minFat, double.PositiveInfinity, "minFat");for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];ct2.SetCoefficient(variable, (double)foodTable.Rows[i]["Fat"]);}Google.OrTools.LinearSolver.Constraint ct3 = solver.MakeConstraint(minCarbohydrate, double.PositiveInfinity, "minCarbohydrate");for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];ct3.SetCoefficient(variable, (double)foodTable.Rows[i]["Carbohydrate"]);}
定义目标
//Create objectiveObjective objective = solver.Objective();for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];objective.SetCoefficient(variable, (double)foodTable.Rows[i]["Price"]);}objective.SetMinimization();
最后求解
//Solvevar status=solver.Solve();Console.WriteLine("Solution:");Console.WriteLine("Objective value = " + solver.Objective().Value()+" $");for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];Console.WriteLine(foodTable.Rows[i]["FoodName"].ToString() +" : "+ variable.SolutionValue());}
完整的程序:
using System;
using Google.OrTools.LinearSolver;
using System.Data;
using System.Collections.Generic;namespace Demo2
{class Program{static void Main(string[] args){//已知量DataTable foodTable = new DataTable();foodTable.Columns.Add("FoodName", typeof(string));foodTable.Columns.Add("Protein", typeof(double));foodTable.Columns.Add("Fat", typeof(double));foodTable.Columns.Add("Carbohydrate", typeof(double));foodTable.Columns.Add("Price", typeof(double));DataRow dr = foodTable.NewRow();dr["FoodName"] = "Bread";dr["Protein"] = 0.08;//蛋白质dr["Fat"] = 0.01;//脂肪dr["Carbohydrate"] = 0.55;//碳水化合物dr["Price"] = 0.25;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Butter";dr["Protein"] = 0;dr["Fat"] = 0.9;dr["Carbohydrate"] = 0;dr["Price"] = 0.5;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Cheese";dr["Protein"] = 0.25;dr["Fat"] = 0.36;dr["Carbohydrate"] = 0;dr["Price"] = 1.2;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Grain";dr["Protein"] = 0.12;dr["Fat"] = 0.03;dr["Carbohydrate"] = 0.75;dr["Price"] = 0.6;foodTable.Rows.Add(dr);dr = foodTable.NewRow();dr["FoodName"] = "Chocolate Bar";dr["Protein"] = 0.08;dr["Fat"] = 0;dr["Carbohydrate"] = 0.5;dr["Price"] = 1.5;foodTable.Rows.Add(dr);double minPorten = 550;double minFat = 600;double minCarbohydrate = 2000;//Create a Linear Solver objectvar solver= Solver.CreateSolver("DietSolver", "GLOP_LINEAR_PROGRAMMING");//Create variablesList<Variable> variables = new List<Variable>();foreach (DataRow row in foodTable.Rows){variables.Add(solver.MakeNumVar(0, double.PositiveInfinity, row["FoodName"].ToString()));}//Create linear constraintsGoogle.OrTools.LinearSolver.Constraint ct1 = solver.MakeConstraint(minPorten, double.PositiveInfinity, "minPorten");for(int i=0;i<foodTable.Rows.Count;i++){var variable = variables[i];ct1.SetCoefficient(variable, (double)foodTable.Rows[i]["Protein"]);}Google.OrTools.LinearSolver.Constraint ct2 = solver.MakeConstraint(minFat, double.PositiveInfinity, "minFat");for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];ct2.SetCoefficient(variable, (double)foodTable.Rows[i]["Fat"]);}Google.OrTools.LinearSolver.Constraint ct3 = solver.MakeConstraint(minCarbohydrate, double.PositiveInfinity, "minCarbohydrate");for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];ct3.SetCoefficient(variable, (double)foodTable.Rows[i]["Carbohydrate"]);}//Create objectiveObjective objective = solver.Objective();for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];objective.SetCoefficient(variable, (double)foodTable.Rows[i]["Price"]);}objective.SetMinimization();//Solvevar status=solver.Solve();Console.WriteLine("Solution:");Console.WriteLine("Objective value = " + solver.Objective().Value()+" $");for (int i = 0; i < foodTable.Rows.Count; i++){var variable = variables[i];Console.WriteLine(foodTable.Rows[i]["FoodName"].ToString() +" : "+ variable.SolutionValue());}}}
}
Google OR-Tools(二) 线性优化Linear Optimization相关推荐
- OR-Tools:1-线性优化,整数优化和约束优化(Linear optimization,Mixed-integer optimization,Constraint optimization)
OR-Tools 解决的问题类型: Linear optimization Constraint optimization Mixed-integer optimization Bin packing ...
- 线性电机(linear motor)
线性马达一般指线性电机 线性马达是一种将电能直接转换成直线运动机械能,而不需要任何中间转换机构的传动装置.它可以看成是一台旋转电机按径向剖开,并展成平面而成. 直线电机也称线性电机,线性马达,直线马达 ...
- Introduction to Linear Optimization 2.2 极点,顶角与基可行解
1.极点 极点的定义及理解 Definition 2.6 Let P be a polyhedron. A vector x ∈ P is an extreme point of P if we ca ...
- 从零开始学数据结构和算法(二)线性表的链式存储结构
链表 链式存储结构 定义 线性表的链式存储结构的特点是用一组任意的存储单元的存储线性表的数据元素,这组存储单元是可以连续的,也可以是不连续的. 种类 结构图 单链表 应用:MessageQueue 插 ...
- R语言分类算法之线性判别分析(Linear Discriminant Analysis)
1.线性判别原理解析 基本思想是"投影",即高纬度空间的点向低纬度空间投影,从而简化问题的处理.在原坐标系下,空间中的点可能很难被分开,如图8-1,当类别Ⅰ和类别Ⅱ中的样本点都投影 ...
- Google Perf Tools安装以及使用
Google Performance Tools安装以及使用 这边文章都记录在github:https://github.com/NIGHTFIGHTING/gperftools-tutorial 一 ...
- 贝叶斯优化算法python实例_贝叶斯优化/Bayesian Optimization
最近心情不好,写篇文章让大家开心一下吧.介绍一下世界上最好的算法:贝叶斯优化. 背景介绍 近年来深度神经网络大火,可是神经网络的超参(hyperparameters)选择一直是一个问题,因为大部分时候 ...
- 多变量线性优化_使用线性上下文强盗进行多变量Web优化
多变量线性优化 Expedia Group Technology -数据 (EXPEDIA GROUP TECHNOLOGY - DATA) Or how you can run full webpa ...
- 【机器学习】一文看懂贝叶斯优化/Bayesian Optimization
点击上方,选择星标,每天给你送干货! 来自:AI部落联盟 今天想谈的问题是:什么是贝叶斯优化/Bayesian Optimization,基本用法是什么? 本文的定位是:帮助未接触.仅听说过.初次接触 ...
最新文章
- 面试程序员总结的通病!
- python怎么打开文档_python打开怎么运行
- java oj主机名排序_oj教程--排序算法(Java)
- github 档案馆(是不是那个把code放到北极的那个项目。。。)
- python3扫盲系列-(3)
- 【kafka】kafka 建立很多很多消费组 会怎么样
- arc科学计算机在线应用使用,ArcMap字段计算器(Field Calculator)的妙用
- 小程序_小程序开发,小程序定制开发,小程序搭建,小程序系统开发
- python之__repr__
- 解决摹客iDoc插件在Sketch中无法正常使用,切图和标注尺寸不一致的问题
- mysql二进制文件如何查看_使用mysqlbinlog查看MySQL二进制文件内容
- 1元云购网站建设,一元云购网站制作,夺宝网站定制公司,一元云购源码开发
- git diffmerge tool 配置
- 美创科技出席世界信息安全大会:多维数据安全框架体系,护航新基建发展
- 美丽的日本与我(川端康成在诺贝尔文学奖颁奖典礼上的演讲词)
- mx250 计算能力_mx250显卡性能怎么样,mx250显卡性能相当于GTX多少
- 三种查看文件MD5 SHA*等校验值的方法
- 数据类型与堆栈内存练习数据类型检测
- lottie实现动画效果
- 南京理工大学电子与通信工程考研上岸经验分享