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

news2025/6/9 19:29:54

      之前在 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 json

def 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.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(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.Vmax
	model.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] * 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')
	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 = 0
	for f in model.F:
		v = int(value(model.x[f]))
		if v != 0:
			results["selected_food"].append({f:v})
			count += 1

	if 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 val

	for 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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2405751.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端验证下跨域问题(npm验证)

文章目录 一、背景二、效果展示三、代码展示3.1&#xff09;index.html3.2&#xff09;package.json3.3&#xff09; service.js3.4&#xff09;service2.js 四、使用说明4.1&#xff09;安装依赖4.2&#xff09;启动服务器4.3&#xff09;访问前端页面 五、跨域解决方案说明六…

Linux Docker的简介

参考资料 30分钟Docker入门教程 ◀ 本篇博客所有图片皆来自于该视频截图阮一峰 - Docker 入门教程 目录 一. 环境配置时可能会遇到的问题二. 什么是Docker三. 虚拟机 与 Docker 的区别3.1 虚拟机3.2 Docker 四. Docker的基本架构五. Dockerfile 一. 环境配置时可能会遇到的问题…

极昆仑智慧与数元灵科技达成战略合作

近日&#xff0c;北京极昆仑智慧科技有限公司与北京数元灵科技有限公司正式签署产品级融合战略合作协议&#xff0c;双方将围绕 "AIBI商业智能分析" " Hybrid RAG 大模型问答" 等核心大模型应用&#xff0c;实现技术架构与业务场景的深度集成&#xff0c;…

第四讲:类和对象(下)

1. 再探构造函数 • 之前我们实现构造函数时&#xff0c;初始化成员变量主要使⽤函数体内赋值&#xff0c;构造函数初始化还有⼀种⽅ 式&#xff0c;就是初始化列表&#xff0c;初始化列表的使⽤⽅式是以⼀个冒号开始&#xff0c;接着是⼀个以逗号分隔的数据成 员列表&#xff…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Dad Jokes(冷笑话卡片)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— DadJokes 组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 豆包翻译确实可以&#xff0c;冷笑话应该属于各类语言比较难理解的…

Spring AOP执行原理源码解析

对【com.example.demo.TestAspect#aopTest】连接点增加了五个通知 在调用【com.example.demo.A#testAop()】&#xff08;用户自定义&#xff09;方法时&#xff0c;Cglib拦截器对其进行了拦截 可以看到执行顺序分别是环绕前置&#xff0c;前置&#xff0c;环绕后置&#xff0c;…

基于FPGA的超声波显示水位距离,通过蓝牙传输水位数据到手机,同时支持RAM存储水位数据,读取数据。

基于FPGA的超声波显示水位距离 前言一、整体框架二、代码架构1.超声波测距模块2.蓝牙数据发送模块3.数码管数据切换模块4.数码管驱动模块6.串口驱动7.顶层模块8.RAM ip核 仿真相关截图 前言 随着工业化进程的加速和环境保护意识的提升&#xff0c;对水资源管理和水位监测的需求…

在Windows下利用LoongArch-toolchain交叉编译Qt

文章目录 0.交叉编译的必要性1.下载交叉编译工具链1.1.直接在Windows下使用mingw&#xff08;不使用虚拟机&#xff09;编译&#xff08;还没成功&#xff0c;无法编译&#xff09;1.2.在虚拟机中的Ubuntu中进行交叉编译 2.下载qt源码3.编译Qt3.1.创建loongarch64的mkspec3.2.创…

AIRIOT无人机安防解决方案

随着无人机技术的飞速发展和广泛应用&#xff0c;其在安防领域的价值日益凸显&#xff0c;从关键设施巡检、大型活动安保到边境巡防、应急救援&#xff0c;无人机正成为立体化安防体系不可或缺的“空中哨兵”。然而&#xff0c;无人机安防应用蓬勃发展的同时&#xff0c;其自身…

华为OD机考 - 水仙花数 Ⅰ(2025B卷 100分)

import java.util.*; public static Integer get(int count,int c){if(count<3||count>7){return -1;}//存储每位数的最高位……最低位int[] arr new int[count];List<Integer> res new ArrayList<>();for(int i(int) Math.pow(10,count-1);i<(int) Math…

php apache构建 Web 服务器

虚拟机配置流程winsever2016配置Apache、Mysql、php_windows server 2016配置web服务器-CSDN博客 PHP 和 Apache 通过 ​​模块化协作​​ 共同构建 Web 服务器&#xff0c;以下是它们的交互机制和工作流程&#xff1a; ​​一、核心组件分工​​ 组件角色​​Apache​​Web …

打通印染车间“神经末梢”:DeviceNet转Ethernet/IP连接机器人的高效方案

在印染行业自动化升级中&#xff0c;设备联网需求迫切。老旧印染设备多采用Devicenet协议&#xff0c;而新型工业机器人普遍支持Ethernet/IP协议&#xff0c;协议不兼容导致数据交互困难&#xff0c;设备协同效率低、生产监控滞后&#xff0c;成了行业数字化转型的阻碍。本文将…

2025-06-02-IP 地址规划及案例分析

IP 地址规划及案例分析 参考资料 Plan for IP addressing - Cloud Adoption Frameworkwww.cnblogs.comimage-hosting/articles at master jonsam-ng/image-hosting 概述 在网络通信中&#xff0c;MAC 地址与 IP 地址分别位于 OSI 模型的数据链路层和网络层&#xff0c;二者协…

AUTOSAR实战教程--开放式通用DoIP刷写工具OpenOTA开发计划

目录 软件概述 安装与运行 界面说明 3.1 功能区划分 3.2 状态显示 基本操作流程 4.1 DoIP连接配置 4.2 服务配置&#xff08;刷写流程&#xff09; 4.3 执行操作 4.4 保存配置 4.5 加载配置 功能详解 5.1 核心功能模块 诊断服务配置 通信设置 文件下载 工具功…

AI赋能的浏览器自动化:Playwright MCP安装配置与实操案例

以下是对Playwright MCP的简单介绍&#xff1a; Playwright MCP 是一个基于 Playwright 的 MCP 工具&#xff0c;提供浏览器自动化功能不要求视觉模型支持&#xff0c;普通的文本大语言模型就可以通过结构化数据与网页交互支持多种浏览器操作&#xff0c;包括截图、点击、拖动…

【技术笔记】MSYS2 指定 Python 版本安装方案

#工作记录 MSYS2 指定 Python 版本安装 一、前置条件 安装指定版本需要在干净的 MSYS2 环境中执行&#xff0c;为保证工具链的兼容性&#xff0c;若已安装 Python&#xff0c;需先卸载 Python 及与该版本深度绑定的工具链。具体操作如下&#xff1a; 卸载 Python&#xff1a…

《校园生活平台从 0 到 1 的搭建》第一篇:创建项目与构建目录结构

在本系列第一篇中&#xff0c;我们将从项目初始化开始&#xff0c;搭建基本的目录结构&#xff0c;并完成四个主页面的创建与 TabBar 设置。 &#xff08;tip&#xff1a;你可能会觉得有点 ai 化&#xff0c;因为这个文案是我自己写了一遍文案之后让 ai 去优化输出的&#xff0…

1 Studying《蓝牙核心规范5.3》

目录 [Vol 0][Part B 蓝牙规范要求] 3 定义 3.1 蓝牙产品类型 4 核心配置 4.1 基本速率核心配置 4.2 增强型数据速率核心配置 4.4 低功耗核心配置 4.5 基本速率和低功耗结合的核心配置 4.6 主机控制器接口核心配置 [Vol 1][Part A 架构]1 概述 1.1 BR/EDR操作概述 …

STM32+MPU6050传感器

#创作灵感## 在嵌入式系统开发中&#xff0c;STM32F103C8T6单片机与MPU6050传感器的组合因其高性能、低功耗以及丰富的功能而备受青睐。本文将简单介绍如何在Keil 5开发环境中实现STM32F103C8T6与MPU6050的连接和基本数据采集&#xff0c;带你快速入门智能硬件开发。 一、硬件…

26考研——数据的表示和运算_整数和实数的表示(2)

408答疑 文章目录 二、整数和实数的表示1、整数的表示1.1、无符号整数的表示1.2、有符号整数的表示1.3、C 语言中的整数类型及类型转换1.3.1、C 语言中的整型数据类型1.3.2、有符号数和无符号数的转换1.3.3、不同字长整数之间的转换 2、实数的表示2.1、浮点数的相关概念2.2、浮…