当前位置: 首页 > news >正文

Gurobi基础语法之addVar 和 addVars

addVar 和 addVars作为 Gurobi模型对象中的方法,常常用来生成变量,本文介绍了Python中的这两个接口的使用

addVar

addVar(lb=0.0, ub=float('inf'), obj=0.0, vtype=GRB.CONTINUOUS, name='', column=None) 

 lb 和 ub让变量在生成的时候就有下界和上届,

obj 确定了生成的变量在 目标函数的系数的取值

vtype 确定了变量取值的类型 (GRB.CONTINUOUS, GRB.BINARY, GRB.INTEGER, GRB.SEMICONT, or GRB.SEMIINT)

name 确定了这个参数的名字

column这个参数可以用来确定在已经存在的约束条件中这个变量的系数,但是由于在新版本中可以直接在生成约束条件(即调用addConstr)的时候就直接指定具体的约束条件,所以column参数并不经常使用,但是下面的代码还是给出这个参数的使用方法:

max 3x + 2y

   x + y <= 10

   2x + y <= 15

   x >= 0, y >= 0

m = gp.Model("example")
m.setParam('OutputFlag', 0) # 优化完成后不打印许可和/或计算服务器信息
# 添加约束
c1 = m.addConstr(0, GRB.LESS_EQUAL, 10, name="c1")
c2 = m.addConstr(0, GRB.LESS_EQUAL, 15, name="c2")# 使用column参数添加变量
x = m.addVar(lb=0, ub=GRB.INFINITY, obj=3, vtype=GRB.CONTINUOUS, name="x", column=gp.Column([1, 2], [c1, c2]))
y = m.addVar(lb=0, ub=GRB.INFINITY, obj=2, vtype=GRB.CONTINUOUS, name="y", column=gp.Column([1, 1], [c1, c2]))# 设置目标函数:最大化 3x + 2y,由于所有的决策变量和约束条件都以已经确定,
# 而且gurobi中是默认最大化目标函数,所以下面这句话可以选择不打
# m.setObjective(3 * x + 2 * y, GRB.MAXIMIZE)# 优化模型
m.optimize()if m.status == GRB.OPTIMAL:# 打印结果
else:# 无解

有了新版的设计,可以直接写成如下形式

m = gp.Model("example")
m.setParam('OutputFlag', 0)
x = m.addVar(lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, obj=3, name='x')
y = m.addVar(lb=0, ub=GRB.INFINITY, vtype=GRB.CONTINUOUS, obj=2, name='y')m.addConstr(x + y <= 10, name="c1")
m.addConstr(2 * x + y <= 15, name="c2")m.optimize()if m.Status == GRB.OPTIMAL:print(f'Optimal solution is {x.x}, {y.x}')print(f'Optimal value is {m.objVal}')
else:print("No solution!")

值得注意的是:

1. 调用addVar变量之后,返回值是与addVar中传入的参数不同的,比如 写下 x = m.addVar() 这句代码之后,这个变量名 x 是你在Python代码中用来操作和引用这个变量的标识符。

而调用y = model.addVar(vtype=GRB.INTEGER, obj=1.0, name="y"),其中name = "y"的参数就是在Gurobi模型内部使用,用于在模型的输出、日志文件或错误消息中标识该变量

2.调用 addVar接口,其返回值的类型是 gurobipy.Var,返回的这个变量可以直接和整数进行加减乘除运算,运算的结果可以作为目标函数或者约束条件,但是不能直接与浮点数进行非线性运算,如  x = m.addVar(); x ** 0.5; 但是可以使用其他方法实现非线性约束的效果,具体可以看我其他的博客

addVars

addVars ( *indices , lb=0.0 , ub=float('inf') , obj=0.0 , vtype=GRB.CONTINUOUS , name='' )

与addVar不同的是,addVars的第一个参数是一个参数包,对这个参数包,可以传入多种形式的参数,包括:

1. 数字序列: x = m.addVars(2, 3, 2),x 是一个包含 2 * 3 * 2 个键值对的 tupledict

2. 单个list: x = m.addVars( [1, 2, 3, 4] ),x 是以 1, 2, 3, 4 为key 的 tupledict

3. 多个list: x = m.addVars( [1, 2], ['a', 'b'] ),x 是以(1, 'a') 和 (2, 'b')为 key 的tupledict

4. tuplelist: x = m.addVars( [ (3, 'a'), (7, 'b') ] ),x 是分别以这两个元组为 key 的 tupledict

可以看到addVars在调用的过程中会生成很多变量,这些变量应该怎么配合lb, ub, obj, vtype, name 这些参数,实现不同的变量设置不同的属性?

使用列表即可,比如如下代码

z = m.addVars(3, obj=[1.0, 2.0, 1.2], name=["a", "b", "c"])

将会生成以0, 1, 2为key的三个键值对为tupledict对象的内容,其中z1的系数是1.0,在 gurobi 内部的名称是“a”, 以此类推,这样一下生成3个变量的同时,还可以规定这三个变量的系数和名称

addVar 和 addVars的返回值

addVar 的返回值类型是 <class 'gurobipy.Var'>

addVars 的返回值类型是 <class 'gurobipy.tupledict'>

所以想要使用这两种方法的返回值构建一个表达式,需要将 addVars 的返回值转成其他形式

可以使用 sum() 方法,代码示例如下

y = m.addVar(vtype=GRB.CONTINUOUS, name="y1")
z = m.addVars(3, obj=[1.0, 2.0, 1.2], name=["z1", "z2", "z3"])
m.update()
print(y + z.sum())

代码将打印 y1 + z1 + z2 + z3

添加变量到底是在干什么?

        我们知道,Gurobi 作为一个优化问题的求解器,构建模型的过程实际上就是在声明和定义变量,调用 addVar(s) 方法实际上就是将这些声明和定义后的变量进行暂存,

        暂存过程包括对变量的暂存和对约束条件的暂存,

在调用addVar(s) 和 addConstr系列方法之后

1. 变量会被暂存到模型的内部变量列表中。这些变量在暂存状态下不会被完全初始化,但Gurobi会记录它们的基本信息,如变量类型、上下界、目标函数系数等,

2. 约束条件会被暂存到模型的内部约束列表中。这些约束在暂存状态下不会被完全初始化,但Gurobi会记录它们的基本信息,如约束类型、左侧表达式、右侧常数等

然后这些变量 / 表达式将 处于暂存状态

暂存状态的可视化

添加变量,并直接打印这个变量

z = m.addVars(3, obj=[1.0, 2.0, 1.2])
print(z)

 打印结果

{0: <gurobi.Var *Awaiting Model Update*>, 1: <gurobi.Var *Awaiting Model Update*>, 2: <gurobi.Var *Awaiting Model Update*>}

暂存的意义

  • 性能优化

        Gurobi在内部进行了优化,避免在每次添加变量或约束时立即进行更新,因为这可能会导致不必要的性能开销。通过将这些操作暂存起来,Gurobi可以在适当的时候一次性进行更新,提高效率。

  • 批量处理

        在添加大量变量和约束时,批量更新可以显著提高性能。例如,当你在循环中添加大量变量和约束时,调用一次 model.update() 比每次添加一个变量或约束后都调用 model.update() 要高效得多。 

Gurobi 模型的 update() 方法

        Gurobi 会遍历这些暂存的变量和约束,将它们完全初始化并添加到模型的内部数据结构中,所谓的添加到内部数据结构,就是给变量 / 约束分配一个唯一的索引

在调用 update() 方法之后,这些变量 / 表达式将 处于完全初始化状态

完全初始化状态的可视化

添加变量,更新之后再打印这个变量

z = m.addVars(3, obj=[1.0, 2.0, 1.2], name=["z1", "z2", "z3"])
m.update()
print(z)

 打印结果

{0: <gurobi.Var z1>, 1: <gurobi.Var z2>, 2: <gurobi.Var z3>}

http://www.lryc.cn/news/527424.html

相关文章:

  • C语言学习阶段性总结(五)---函数
  • K8S 快速实战
  • java后端之事务管理
  • 【Redis】缓存+分布式锁
  • 二分查找题目:寻找两个正序数组的中位数
  • 网络安全 | F5-Attack Signatures详解
  • Redis --- 分布式锁的使用
  • LeetCode100之全排列(46)--Java
  • goframe 博客分类文章模型文档 主要解决关联
  • 【JavaWeb06】Tomcat基础入门:架构理解与基本配置指南
  • 安卓日常问题杂谈(一)
  • Kitchen Racks 2
  • 嵌入式学习笔记-杂七杂八
  • 14-7C++STL的stack容器
  • Vue 3 中的响应式系统:ref 与 reactive 的对比与应用
  • 物业巡更系统助推社区管理智能化与服务模式创新的研究与应用
  • windows蓝牙驱动开发-生成和发送蓝牙请求块 (BRB)
  • Linux网络之序列化和反序列化
  • linux设置mysql远程连接
  • react-native网络调试工具Reactotron保姆级教程
  • erase() 【删数函数】的使用
  • 性能测试丨内存火焰图 Flame Graphs
  • AIGC的企业级解决方案架构及成本效益分析
  • Linux 入门 常用指令 详细版
  • 【R语言】流程控制
  • 猿人学第一题 js混淆源码乱码
  • 计算机组成原理(2)王道学习笔记
  • 【AI日记】25.01.26
  • 三. Redis 基本指令(Redis 快速入门-03)
  • 设计模式的艺术-代理模式