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

Pyomo中线性规划接口的使用

      之前在 Pyomo介绍-CSDN博客 中以饮食为例介绍过Pyomo的使用,执行以下命令:

pyomo solve --solver=glpk test_pyomo_linear_programming.py ../test_data/diet.dat

      直接执行以上命令,不便之处有以下几点:

      (1).不能直接解析python文件,不便于后期与FastAPI集成;

      (2).不支持传入额外参数;

      (3).不能直接获取需要的结果,需要额外解析results.yml

      针对以上问题,对原始代码进行了重新实现,包括:支持解析dat文件和json文件、支持输入参数、结果可直接通过print打印输出:

      1.解析dat文件的实现如下:

def parse_dat(file):# creating a model objectmodel = ConcreteModel()# load data filedata = DataPortal()data.load(filename=file)# define sets and parametersmodel.F = Set(initialize=data['F'])model.N = Set(initialize=data['N'])model.c = Param(model.F, initialize=data['c'], within=PositiveReals)model.a = Param(model.F, model.N, initialize=data['a'], within=NonNegativeReals)model.V = Param(model.F, initialize=data['V'], within=PositiveReals)model.Nmin = Param(model.N, initialize=data['Nmin'], within=NonNegativeReals, default=0.0)model.Nmax = Param(model.N, initialize=data['Nmax'], within=NonNegativeReals, default=float('inf'))model.Vmax = Param(initialize=data['Vmax'], within=PositiveReals)return model

     diet.dat文件内容如下:

param:  F:                          c     V  :="Cheeseburger"                 1.84   4.0  "Ham Sandwich"                 2.19   7.5  "Hamburger"                    1.84   3.5  "Fish Sandwich"                1.44   5.0  "Chicken Sandwich"             2.29   7.3  "Fries"                         .77   2.6  "Sausage Biscuit"              1.29   4.1  "Lowfat Milk"                   .60   8.0 "Orange Juice"                  .72  12.0 ;param Vmax := 75.0;param:  N:       Nmin   Nmax :=Cal      2000      .Carbo     350    375Protein    55      .VitA      100      .VitC      100      .Calc      100      .Iron      100      . ;param a:Cal  Carbo Protein   VitA   VitC  Calc  Iron :="Cheeseburger"               510     34     28     15      6    30    20"Ham Sandwich"               370     35     24     15     10    20    20"Hamburger"                  500     42     25      6      2    25    20"Fish Sandwich"              370     38     14      2      0    15    10"Chicken Sandwich"           400     42     31      8     15    15     8"Fries"                      220     26      3      0     15     0     2"Sausage Biscuit"            345     27     15      4      0    20    15"Lowfat Milk"                110     12      9     10      4    30     0"Orange Juice"                80     20      1      2    120     2     2 ;

      2.解析json文件的实现如下:

def parse_json(file):model = ConcreteModel()data = DataPortal()data.load(filename=file)model.F = Set(initialize=data['sets']['F'])model.N = Set(initialize=data['sets']['N'])model.c = Param(model.F, initialize=data['params']['c'], within=PositiveReals)def parse_a(model, food, nutr):return data['params']['a'][food][nutr]model.a = Param(model.F, model.N, initialize=parse_a, within=NonNegativeReals)model.V = Param(model.F, initialize=data['params']['V'], within=PositiveReals)model.Nmin = Param(model.N, initialize=data['params']['Nmin'], within=NonNegativeReals, default=0.0)def parse_Nmax(model, nutr):val = data['params']['Nmax'][nutr]return val if val != "inf" else math.inf model.Nmax = Param(model.N, initialize=parse_Nmax, within=NonNegativeReals)model.Vmax = Param(initialize=data['params']['Vmax'], within=PositiveReals)return model

      diet.json文件内容如下:

{"sets": {"F": ["Cheeseburger","Ham Sandwich","Hamburger","Fish Sandwich","Chicken Sandwich","Fries","Sausage Biscuit","Lowfat Milk","Orange Juice"],"N": ["Cal","Carbo","Protein","VitA","VitC","Calc","Iron"]},"params": {"c": {"Cheeseburger": 1.84,"Ham Sandwich": 2.19,"Hamburger": 1.84,"Fish Sandwich": 1.44,"Chicken Sandwich": 2.29,"Fries": 0.77,"Sausage Biscuit": 1.29,"Lowfat Milk": 0.6,"Orange Juice": 0.72},"V": {"Cheeseburger": 4.0,"Ham Sandwich": 7.5,"Hamburger": 3.5,"Fish Sandwich": 5.0,"Chicken Sandwich": 7.3,"Fries": 2.6,"Sausage Biscuit": 4.1,"Lowfat Milk": 8.0,"Orange Juice": 12.0},"Vmax": 75.0,"Nmin": {"Cal": 2000.0,"Carbo": 350.0,"Protein": 55.0,"VitA": 100.0,"VitC": 100.0,"Calc": 100.0,"Iron": 100.0},"Nmax": {"Cal": "inf","Carbo": 375.0,"Protein": "inf","VitA": "inf","VitC": "inf","Calc": "inf","Iron": "inf"},"a": {"Cheeseburger": {"Cal": 510.0,"Carbo": 34.0,"Protein": 28.0,"VitA": 15.0,"VitC": 6.0,"Calc": 30.0,"Iron": 20.0},"Ham Sandwich": {"Cal": 370.0,"Carbo": 35.0,"Protein": 24.0,"VitA": 15.0,"VitC": 10.0,"Calc": 20.0,"Iron": 20.0},"Hamburger": {"Cal": 500.0,"Carbo": 42.0,"Protein": 25.0,"VitA": 6.0,"VitC": 2.0,"Calc": 25.0,"Iron": 20.0},"Fish Sandwich": {"Cal": 370.0,"Carbo": 38.0,"Protein": 14.0,"VitA": 2.0,"VitC": 0.0,"Calc": 15.0,"Iron": 10.0},"Chicken Sandwich": {"Cal": 400.0,"Carbo": 42.0,"Protein": 31.0,"VitA": 8.0,"VitC": 15.0,"Calc": 15.0,"Iron": 8.0},"Fries": {"Cal": 220.0,"Carbo": 26.0,"Protein": 3.0,"VitA": 0.0,"VitC": 15.0,"Calc": 0.0,"Iron": 2.0},"Sausage Biscuit": {"Cal": 345.0,"Carbo": 27.0,"Protein": 15.0,"VitA": 4.0,"VitC": 0.0,"Calc": 20.0,"Iron": 15.0},"Lowfat Milk": {"Cal": 110.0,"Carbo": 12.0,"Protein": 9.0,"VitA": 10.0,"VitC": 4.0,"Calc": 30.0,"Iron": 0.0},"Orange Juice": {"Cal": 80.0,"Carbo": 20.0,"Protein": 1.0,"VitA": 2.0,"VitC": 120.0,"Calc": 2.0,"Iron": 2.0}}}
}

      注:pyomo对json二维参数model.a需特殊处理

      3.支持的输入参数如下:

def parse_args():parser = argparse.ArgumentParser(description="pyomo glpk diet")parser.add_argument("--file", required=True, type=str, help="*.dat file or *.json file")parser.add_argument("--number", type=int, default=5, help="must select number of food types from all food types")args = parser.parse_args()return args

      4.主体实现如下:

def main(file, number):if Path(file).suffix.lower() == ".dat":model = parse_dat(file)elif Path(file).suffix.lower() == ".json":model = parse_json(file)else:raise ValueError(colorama.Fore.RED + f"unsupported file format: {file}")# define variablesmodel.x = Var(model.F, within=NonNegativeIntegers)model.y = Var(model.F, within=Binary)# define the cost objectivemodel.cost = Objective(expr=sum(model.c[i]*model.x[i] for i in model.F), sense=minimize)# define constraintdef nutrient_rule(model, j):value = sum(model.a[i,j]*model.x[i] for i in model.F)return inequality(model.Nmin[j], value, model.Nmax[j])model.nutrient_limit = Constraint(model.N, rule=nutrient_rule)def volume_rule(model):return sum(model.V[i]*model.x[i] for i in model.F) <= model.Vmaxmodel.volume = Constraint(rule=volume_rule)def select_rule(model):return sum(model.y[i] for i in model.F) == numbermodel.select = Constraint(rule=select_rule)def linking_upper_rule(model, f):return model.x[f] <= model.y[f] * 1e6model.linking_upper = Constraint(model.F, rule=linking_upper_rule)def linking_lower_rule(model, f):return model.x[f] >= model.y[f]model.linking_lower = Constraint(model.F, rule=linking_lower_rule)# model.pprint() # print model structure# solve the modelsolver = SolverFactory('glpk')results = solver.solve(model)# print(f"results: {results}")if results.solver.termination_condition != TerminationCondition.optimal:raise ValueError(colorama.Fore.RED + f"no optimal solution was found")# print resultprint(f"total cost: {value(model.cost):.2f}")count = 0print("selected food:")for f in model.F:v = int(value(model.x[f]))if v != 0:print(f"  {f}: {v}")count += 1if count != number:raise ValueError(colorama.Fore.RED + f"solution result is wrong, number of food types does not match: {count}:{number}")print("nutrients:")for n in model.N:actual = sum(value(model.a[f,n] * model.x[f]) for f in model.F)print(f"  {n}: actual value: {actual:.2f}; boundary:[{value(model.Nmin[n])},{value(model.Nmax[n])}]")

      模型构建方式:

      (1).AbstractModel:模型定义时不包含具体数据。

      (2).ConcreteModel:模型定义时直接包含具体数据。

      DataPortal类:加载数据到Pyomo模型,支持多种文件格式,如.dat, .json, .csv, Excel等。

      建模组件:Set, Param, Var, Constraint, Objective等。

      SolverFactory类:创建求解器实例,这里使用的是开源求解器glpk。

      5.入口函数实现如下:

if __name__ == "__main__":colorama.init(autoreset=True)args = parse_args()start = time.perf_counter()main(args.file, args.number)end = time.perf_counter()print(f"elapsed time: {end-start:.2f} seconds")print(colorama.Fore.GREEN + "====== execution completed ======")

      6.执行结果如下:与之前的结果一致

      GitHub:https://github.com/fengbingchun/Python_Test

http://www.xdnf.cn/news/10515.html

相关文章:

  • 为什么ping显示connect:network is unreachable,如何排查网络不通问题?
  • LearnOpenGL-笔记-其十三
  • py爬虫的话,selenium是不是能完全取代requests?
  • NodeJS全栈WEB3面试题——P2智能合约与 Solidity
  • 单调栈(打卡)
  • 【C++/Linux】TinyWebServer前置知识之IP协议详解
  • 【iOS】YYModel源码解析
  • 告别printf!嵌入式系统高效日志记录方案
  • 如何评估 RAG 的分块Chunking策略
  • 【沉浸式求职学习day52】【初识Mybaits】
  • 风控研发大数据学习路线
  • Java生态中的NLP框架
  • 【C语言】C语言经典小游戏:贪吃蛇(上)
  • Vortex GPGPU的github流程跑通与功能模块波形探索(四)
  • 解决:install via Git URL失败的问题
  • 【LLM vs Agent】从语言模型到智能体,人工智能迈出的关键一步
  • Java中对象哈希值的解析
  • 力扣HOT100之多维动态规划:64. 最小路径和
  • Langchian - 自定义提示词模板 提取结构化的数据
  • bismark OT CTOT OB CTOB 以及mapping后的bam文件中的XG,XR列的含义
  • 用go从零构建写一个RPC(4)--gonet网络框架重构+聚集发包
  • 【知识点】第3章:基本数据类型
  • Linux之进程间通信
  • 600+纯CSS加载动画一键获取指南
  • NLP学习路线图(十九):GloVe
  • Windows不关防火墙,安全开放端口方法
  • 【图论 拓扑排序 贪心 临项交换】P5603 小 C 与桌游 题解|普及+
  • ubuntu 添加应用到启动菜单
  • Unity中应对高速运动的物体,碰撞组件失效的问题?
  • Android高级开发第四篇 - JNI性能优化技巧和高级调试方法