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

线性规划饮食问题求解:FastAPI作为服务端+libhv作为客户端实现

      之前在 Pyomo介绍-CSDN博客 中介绍过通过Pyomo求解线性规划问题,这里使用FastAPI作为服务端,开源网络库libhv作为客户端,求解饮食成本最小化问题。

      服务端测试代码test_fastapi_pyomo_server.py如下:

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pyomo.environ import *
import math
import jsondef parse_json(data):model = ConcreteModel()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.infmodel.Nmax = Param(model.N, initialize=parse_Nmax, within=NonNegativeReals)model.Vmax = Param(initialize=data['params']['Vmax'], within=PositiveReals)return modeldef linear_programming(data):model = parse_json(data)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.Vmaxmodel.volume = Constraint(rule=volume_rule)def select_rule(model):return sum(model.y[i] for i in model.F) == data['number']model.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)solver = SolverFactory('glpk')ret = solver.solve(model)if ret.solver.termination_condition != TerminationCondition.optimal:return JSONResponse(status_code=400, content={"error": "no optimal solution"})results = {"selected_food": [], "nutrients": []}results["cost"] = f"{value(model.cost):.2f}"count = 0for f in model.F:v = int(value(model.x[f]))if v != 0:results["selected_food"].append({f:v})count += 1if count != data['number']:return JSONResponse(status_code=400, content={"error": "unmatched number", "count": count, "number": data['number']})def inf_convert(val):if val == math.inf:return "INF"elif val == -math.inf:return "-INF"return valfor n in model.N:actual = sum(value(model.a[f,n] * model.x[f]) for f in model.F)results["nutrients"].append({n:f"{actual:.4f}","boundary":[inf_convert(value(model.Nmin[n])), inf_convert(value(model.Nmax[n]))]})return JSONResponse(status_code=200, content=results)app = FastAPI()@app.post("/api/optimize")
async def optimize_diet(request: Request):json_bytes = await request.body()json_str = json_bytes.decode('utf-8')data = json.loads(json_str)if not isinstance(data, dict):return JSONResponse(status_code=400, content={"error": "Invalid JSON format"})return linear_programming(data)

      执行以下命令启动服务:

fastapi run test_fastapi_pyomo_server.py

      执行结果如下图所示:

      客户端测试代码如下所示:

int test_libhv_http_client_diet()
{constexpr char file_name[]{ "../../../testdata/diet.json" };std::ifstream in_file(file_name);if (!in_file.is_open()) {std::cerr << "Error: failed to open json file: " << file_name << std::endl;return -1;}auto j = hv::Json::parse(in_file);constexpr int number{ 5 };j["number"] = number;const std::string server_url{ "http://192.168.1.28:8000" };HttpRequest request{};request.method = HTTP_POST;request.url = server_url + "/api/optimize";request.body = j.dump();request.headers["Content-Type"] = "application/json";request.timeout = 2;hv::HttpClient client{};HttpResponse response{};if (auto ret = client.send(&request, &response); ret == 0) {if (response.status_code == HTTP_STATUS_OK) {hv::Json j = hv::Json::parse(response.body);std::cout << "result: " << j.dump() << std::endl;constexpr char result_name[]{ "../../../testdata/result.json" };std::ofstream out_file(result_name);if (!out_file.is_open()) {std::cerr << "Error: faild to open file: " << result_name << std::endl;return -1;}out_file << j.dump(2);} else {std::cerr << "status code: " << response.status_code << ", status message: " << response.status_message() << ", body: " << response.body << std::endl;return -1;}} else {std::cerr << "Error: failed to send, error code: " << ret << std::endl;return -1;}return 0;
}

      执行结果如下图所示:与之前结果一致

      与服务端在同一局域网内的任何机子都可以作为客户端。

      diet.json内容如下:也可以完全通过nlohmann/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}}}
}

      GitHub

            服务端:https://github.com/fengbingchun/Python_Test

            客户端:https://github.com/fengbingchun/OpenSSL_Test

相关文章:

  • Web应用安全漏洞全解析:从原理到实战防御
  • 词法分析和词性标注 自然语言处理
  • 【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
  • day27-shell编程(自动化)
  • 食养有方:进行性核上性麻痹患者的健康饮食指南
  • Java线程同步技术深度解析与实践
  • 【2025年6月8日】Claude 4 国内使用全攻略
  • LLMs基础学习(八)强化学习专题(1)
  • android binder(四)binder驱动详解2
  • MyBatis中include标签用法详解
  • ARM SMMUv3 STE表和CD表数据格式分析(三)
  • 利用Pandas AI完成Excel大模型的结合实现自然语言问数
  • AtCoder Beginner Contest 409
  • OD 算法题 B卷【正整数到Excel编号之间的转换】
  • BERT
  • 自然语言处理——文本表示
  • NLP学习路线图(三十四): 命名实体识别(NER)
  • Mac M芯片 RAG 极简流程 安装 ragflow + LM studio
  • 嵌入式面试提纲
  • 网约车平台(预约打车)
  • 企业网站设计注意事项/适合企业员工培训的课程
  • 淄博高端网站建设/网站优化网站优化
  • 电脑自带的做网站叫什么软件/怎样自己制作网站
  • 新疆乌鲁木齐/云优化seo软件
  • 河北省城乡建设培训网官方网站/成品ppt网站国外
  • 网站做流量的论坛贴吧/搜索引擎排名机制