之前在 FastAPI介绍-CSDN博客 中介绍过FastAPI,在 Pyomo中线性规划接口的使用-CSDN博客 中使用Pyomo解决饮食问题,这里将两者组合,即FastAPI在服务器端启动,通过Pyomo实现线性回归;客户端通过浏览器获取饮食的最优解。
这里服务器端的diet.json是已存在的,后期调整为从客户端传过来,以及其它可变参数也从客户端通过json格式传给服务器端。
实现如下:
from fastapi import FastAPI
from pyomo.environ import *
import math
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
def linear_programming_diet(file, number):
model = parse_json(file)
model.x = Var(model.F, within=NonNegativeIntegers)
model.y = Var(model.F, within=Binary)
model.cost = Objective(expr=sum(model.c[i]*model.x[i] for i in model.F), sense=minimize)
def 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.Vmax
model.volume = Constraint(rule=volume_rule)
def select_rule(model):
return sum(model.y[i] for i in model.F) == number
model.select = Constraint(rule=select_rule)
def linking_upper_rule(model, f):
return model.x[f] <= model.y[f] * 1e6
model.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)
solver = SolverFactory('glpk')
results = solver.solve(model)
if results.solver.termination_condition != TerminationCondition.optimal:
return {"result":"no optimal solution"}
results = {}
results["total const"] = f"{value(model.cost):.2f}"
foods = {}
count = 0
for f in model.F:
v = int(value(model.x[f]))
if v != 0:
foods[f] = v
count += 1
results["selected food"] = foods
if count != number:
return {"result":"solution result is wrong, number of food types does not match"}
nutrients = {}
for n in model.N:
actual = sum(value(model.a[f,n] * model.x[f]) for f in model.F)
nutrients[n] = f"{actual:.2f}"
results["nutrients"] = nutrients
return results
app = FastAPI()
@app.get("/diet")
def diet_optimization():
return linear_programming_diet("../test_data/diet.json", 5)
通过以下命令启动:
fastapi dev test_fastapi_pyomo.py
在浏览器中输入:http://127.0.0.1:8000/diet ,结果如下图所示:
GitHub:https://github.com/fengbingchun/Python_Test