GLPK(GNU线性规划工具包)介绍

news2025/7/8 20:56:50

      GLPK全称为GNU Linear Programming Kit(GNU线性规划工具包),可从 https://sourceforge.net/projects/winglpk/ 下载源码及二进制库,最新版本为4.65。也可从 https://ftp.gnu.org/gnu/glpk/ 下载,仅包含源码,最新版本为5.0。

      GLPK是用C实现的,旨在解决线性规划(LP, Linear Programming)、混合整数线性规划(MIP, Mixed Integer linear Programming)和其他相关问题。MIP问题是一种LP问题,其中某些变量需要额外满足整数条件。

      之前在 https://blog.csdn.net/fengbingchun/article/details/146341096 中介绍过通过Pyomo调用glpk解决饮食问题,这里通过调用GLPK API接口实现,测试代码如下:

int test_glpk()
{
	constexpr int total_foods{ 9 };
	const std::vector<std::string> foods{ "food1", "food2", "food3", "food4", "food5", "food6", "food7", "food8", "food9" };
	const std::vector<float> unit_prices{ 0.886, 0.863, 0.855, 0.917, 0.237, 0.856, 0.833, 0.904, 0.876 };
	const std::vector<std::array<float, 2>> bounds{ {1.0, 55.0}, {1.0, 55.0}, {1.0, 55.0}, {1.0, 55.0}, {7.0, 9.0}, {1.0, 55.0}, {1.0, 55.0}, {1.0, 55.0}, {1.0, 55.0} };

	constexpr int num_nutrients{ 4 };
	const std::vector<std::string> nutrients{ "nutrient1", "nutrient2", "nutrient3", "nutrient4" };
	const std::vector<std::array<float, 4>> nutrient_values{ {0.21, 65.10, 0.72, 88.5}, {0.08, 64.58, 0.63, 76.9}, {0.22, 64.81, 0.53, 86.1}, {0.58, 65.84, 1.09, 57.8}, {0.033, 46.07, 14.15, 0},
																{0.059, 65.25, 0.39, 87.2}, {0.14, 64.25, 0.57, 93.7}, {0.033, 63.06, 1.36, 79.0}, {0.076, 65.20, 0.59, 99.0} };
	const std::vector<std::array<float, 2>> nutrient_limit{ {0., 49.}, {6200., 6230.}, {9.9, 782.}, {6500., 7000.} };

	constexpr float total_quantity{ 99. };
	const std::string mandatory_food{ "food5" };
	constexpr int num_select_foods{ 5 };

	if (foods.size() != total_foods) {
		std::cerr << "Error: number of foods mismatch" << std::endl;
		return -1;
	}
	if (unit_prices.size() != total_foods) {
		std::cerr << "Error: number of unit_prices mismatch" << std::endl;
		return -1;
	}
	if (bounds.size() != total_foods) {
		std::cerr << "Error: number of bounds mismatch" << std::endl;
		return -1;
	}
	if (nutrient_values.size() != total_foods) {
		std::cerr << "Error: number of nutrient_values mismatch" << std::endl;
		return -1;
	}

	if (nutrients.size() != num_nutrients) {
		std::cerr << "Error: number of nutrients mismatch" << std::endl;
		return -1;
	}
	if (nutrient_limit.size() != num_nutrients) {
		std::cerr << "Error: number of nutrient_limit mismatch" << std::endl;
		return -1;
	}

	int mandatroy_food_index{ 0 };
	for (auto i = 0; i < total_foods; ++i) {
		if (mandatory_food == foods[i]) {
			mandatroy_food_index = i;
			break;
		}
	}

	auto lp = glp_create_prob(); // create problem object
	glp_set_prob_name(lp, "diet problem");
	glp_set_obj_dir(lp, GLP_MIN); // minimize objective function

	// add col variables
	glp_add_cols(lp, 2 * total_foods); // first total_foods: number of each food; last total_foods: binary variables, whether the food is selected

	for (auto j = 0; j < total_foods; ++j) {
		// set food number variable
		glp_set_col_name(lp, j + 1, foods[j].c_str());
		glp_set_col_kind(lp, j + 1, GLP_CV); // GLP_IV: number of foods can only be an integer, use MIP; default is GLP_CV
		glp_set_col_bnds(lp, j + 1, GLP_LO, 0.0, 0.0);
		glp_set_obj_coef(lp, j + 1, unit_prices[j]); // set cost coefficient

		// set binary select variables
		std::string name = "S_" + foods[j];
		glp_set_col_name(lp, total_foods + j + 1, name.c_str());
		glp_set_col_kind(lp, total_foods + j + 1, GLP_BV);
		glp_set_obj_coef(lp, total_foods + j + 1, 0.);
	}

	// add row constraints
	glp_add_rows(lp, num_nutrients);

	for (auto i = 0; i < num_nutrients; ++i) {
		glp_set_row_name(lp, i + 1, nutrients[i].c_str());
		glp_set_row_bnds(lp, i + 1, GLP_DB, nutrient_limit[i][0], nutrient_limit[i][1]);
	}

	// add select constraints
	glp_add_rows(lp, 2);
	glp_set_row_name(lp, num_nutrients + 1, "select_total");
	glp_set_row_bnds(lp, num_nutrients + 1, GLP_FX, num_select_foods, num_select_foods);

	// add mandatory food constraint
	glp_set_row_name(lp, num_nutrients + 2, "must_have_food");
	glp_set_row_bnds(lp, num_nutrients + 2, GLP_FX, 1., 1.);

	// add total_quantity constraint
	glp_add_rows(lp, 1);
	glp_set_row_name(lp, num_nutrients + 3, "total_quantity");
	glp_set_row_bnds(lp, num_nutrients + 3, GLP_FX, total_quantity, total_quantity);

	// constraint matrix:
	// glp_load_matrix(lp, ne, ia, ja, ar): for k = 1,..., ne, where ia[k] is the row index, ja[k] is the column index, and ar[k] is a numeric value of corresponding constraint coefficient
	// parameter ne specifies the total number of (non-zero) elements in the matrix to be loaded
	int ia[1 + 1000]{}, ja[1 + 1000]{}, k{ 0 };
	double ar[1 + 1000]{};

	// nutrients constraint
	for (auto i = 0; i < num_nutrients; ++i) {
		for (auto j = 0; j < total_foods; ++j) {
			k++;
			ia[k] = i + 1, ja[k] = j + 1;
			ar[k] = nutrient_values[j][i];
		}
	}

	// select total constraint
	for (auto j = 0; j < total_foods; ++j) {
		k++;
		ia[k] = num_nutrients + 1, ja[k] = total_foods + j + 1;
		ar[k] = 1.;
	}

	// mandatory food constraint
	k++;
	ia[k] = num_nutrients + 2, ja[k] = total_foods + mandatroy_food_index + 1;
	ar[k] = 1.;

	// total_quantity constraint
	for (auto j = 0; j < total_foods; ++j) {
		k++;
		ia[k] = num_nutrients + 3, ja[k] = j + 1;
		ar[k] = 1.;
	}

	// add relationship constraint between food quantity and select variable
	for (auto j = 0; j < total_foods; ++j) {
		// lower constraint: quantity_j >= min_j * select_j
		glp_add_rows(lp, 1);
		glp_set_row_name(lp, num_nutrients + 4 + 2 * j, "quantity_min");
		glp_set_row_bnds(lp, num_nutrients + 4 + 2 * j, GLP_LO, 0., 0.);
		
		// quantity_j coefficient: 1.0
		k++;
		ia[k] = num_nutrients + 4 + 2 * j, ja[k] = j + 1;
		ar[k] = 1.;

		// select_j cofficient: -min_j
		k++;
		ia[k] = num_nutrients + 4 + 2 * j, ja[k] = total_foods + j + 1;
		ar[k] = -bounds[j][0];

		// upper constraint: quantity_j <= max_j * select_j
		glp_add_rows(lp, 1);
		glp_set_row_name(lp, num_nutrients + 4 + 2 * j + 1, "quantity_max");
		glp_set_row_bnds(lp, num_nutrients + 4 + 2 * j + 1, GLP_UP, 0., 0.);

		k++;
		ia[k] = num_nutrients + 4 + 2 * j + 1, ja[k] = j + 1;
		ar[k] = 1.;

		k++;
		ia[k] = num_nutrients + 4 + 2 * j + 1, ja[k] = total_foods + j + 1;
		ar[k] = -bounds[j][1];
	}

	glp_load_matrix(lp, k, ia, ja, ar);

	// verify constraint matrix and variables
	std::cout << "number of constraints: " << glp_get_num_rows(lp) << std::endl;
	for (auto i = 1; i <= glp_get_num_rows(lp); ++i)
		std::cout << "i: " << i << "; type: " << glp_get_row_type(lp, i) << "; lower: " << glp_get_row_lb(lp, i) << "; upper: " << glp_get_row_ub(lp, i) << std::endl;

	std::cout << "number of variables: " << glp_get_num_cols(lp) << std::endl;
	for (auto j = 1; j <= glp_get_num_cols(lp); ++j) // Note: the value of glp_get_col_prim is different in different positions
		std::cout << "j: " << j << "; kind: " << glp_get_col_kind(lp, j) << "; primal value: " << glp_get_col_prim(lp, j) << "; lower: " << glp_get_col_lb(lp, j) << "; upper: " << glp_get_col_ub(lp, j) << "; coef: " << glp_get_obj_coef(lp, j) << std::endl;

	auto ret = glp_write_lp(lp, nullptr, "../../../testdata/model.lp");
	if (ret != 0) {
		std::cerr << "Error: failed to write problem data, error code: " << ret << std::endl;
		glp_delete_prob(lp);
		return -1;
	}

	double quantity_sum{ 0. };
	if (0) { // LP(Linear Programming)
		glp_smcp parm{};
		glp_init_smcp(&parm);
		parm.msg_lev = GLP_MSG_ERR; // warning and error messages only
		parm.presolve = GLP_ON;
		ret = glp_simplex(lp, &parm); // solve LP problem with the primal or dual simplex method
		if (ret != 0) {
			std::cerr << "Error: failed to solve: error code: " << ret << std::endl;
			glp_delete_prob(lp);
			return -1;
		}

		ret = glp_get_status(lp);
		if (ret != GLP_OPT) {
			std::cerr << "Error: there is no optimal solution, status: " << ret << std::endl;
			glp_delete_prob(lp);
			return -1;
		}

		std::cout << "minimum cost: " << glp_get_obj_val(lp) << std::endl;
		for (auto j = 0; j < total_foods; ++j) {
			auto qty = glp_get_col_prim(lp, j + 1);
			auto selected = glp_get_col_prim(lp, total_foods + j + 1);
			if (selected > 0.5) {
				std::cout << foods[j] << ": quantity: " << qty << ", limit: [" << bounds[j][0] << "," << bounds[j][1] << "]" << std::endl;
				quantity_sum += qty;
			}
		}
	}
	else { // MIP(Mixed Integer linear Programming)
		glp_iocp parm;
		glp_init_iocp(&parm);
		parm.presolve = GLP_ON;
		parm.msg_lev = GLP_MSG_ERR; // close information output prompt
		ret = glp_intopt(lp, &parm);
		if (ret != 0) {
			std::cerr << "Error: failed to solve: error code: " << ret << std::endl;
			glp_delete_prob(lp);
			return -1;
		}

		ret = glp_mip_status(lp);
		if (ret != GLP_OPT) {
			std::cerr << "Error: there is no optimal solution, status: " << ret << std::endl;
			glp_delete_prob(lp);
			return -1;
		}

		std::cout << "minimum cost: " << glp_mip_obj_val(lp) << std::endl;
		for (auto j = 0; j < total_foods; ++j) {
			auto qty = glp_mip_col_val(lp, j + 1);
			auto selected = glp_mip_col_val(lp, total_foods + j + 1);
			if (selected > 0.5) {
				std::cout << foods[j] << ": quantity: " << qty << ", limit: [" << bounds[j][0] << "," << bounds[j][1] << "]" << std::endl;
				quantity_sum += qty;
			}
		}
	}

	std::cout << "result quantity sum: " << quantity_sum << "; require quantity sum: " << total_quantity << std::endl;

	glp_delete_prob(lp);
	return 0;
}

      测试数据说明:饮食问题,目标是选择以最低成本满足每日营养需求的食物,测试数据无实际意义

      total_foods:食物种类总数。

      foods:每种食物的名称。

      unit_prices:每种食物的价格。

      bounds:每种食物可取的食物份数限制,变量的界限。

      num_nutrients:每种食物含有的营养成分个数,每种食物含有相同的营养成分个数。

      nutrients:每种食物含有的营养成分名称。

      nutrient_values:每种食物含有的营养成分含量。

      nutrient_limit:每种营养成分消耗总量约束。

      total_quantity:被选中食物总份数约束。

      mandatory_food:被选中食物中必选要包含的食物约束。

      num_select_foods:被选中食物种类数约束。

      使用到的GLPK函数:接口详细描述参考源码中的doc/glpk.pdf

      glp_create_prob:创建一个新的问题对象(problem object),该对象最初是"empty",即没有行和列。该函数返回指向所创建对象的指针,该指针应在对该对象的任何后续操作中使用。

      glp_delete_prob:删除问题对象,释放分配给该对象的所有内存。

      glp_set_prob_name:给问题对象分配问题名,长度要求1至255个字符,如果参数名称为nullptr或空字符串,则将删除问题对象的现有问题名。

      glp_set_obj_dir:设置(更改)目标函数优化方向标志,GLP_MIN表示最小化目标函数;GLP_MAX表示最大化目标函数。默认情况,最小化目标函数。

      glp_add_cols:将新列添加到问题对象。新列始终添加到列表的末尾,因此现有列的序数不会改变。每个新添加的列初始值固定为零,并且约束系数列表为空。

      glp_set_col_name:分配(更改)第j列列名,长度要求1至255个字符,如果参数名称为nullptr或空字符串,则将删除第j列的现有名称。

      glp_set_col_kind:按照参数类型指定的方式设置(更改)第j列的类型(kind)。GLP_CV表示连续变量;GLP_IV表示整数变量;GLP_BV表示二元变量。

      glp_get_col_kind:返回第j列的类型(kind)。

      glp_set_col_bnds(lp,j,type,lb,ub):设置(更改)第j列类型和界限。支持的类型如下图所示:如果列没有下限(lower bound),则忽略参数lb。如果列没有上限(upper bound),则忽略参数ub。如果列是固定(fixed)类型,则仅使用参数lb,而忽略参数ub。添加到问题对象后,每列的初始值都固定为零,即其类型为GLP_FX,且两个界限均为0。

      glp_get_num_cols:返回指定问题对象中的列数。

      glp_set_obj_coef(lp,j,coef):设置(更改)第j列目标系数(objective coefficient)。新的目标系数值由参数coef指定。

      glp_get_obj_coef:返回第j列的目标系数。

      glp_get_col_prim:返回与第j列关联变量的原始值(primal value)。注:此函数在调用glp_simplex前后得到值不同

      glp_get_col_lb:返回第j列的下限,即相应变量的下限。如果该列没有下限,则返回-DBL_MAX。

      glp_get_col_ub:返回第j列的上限,即相应变量的上限。如果该列没有上限,则返回+DBL_MAX。

      glp_add_rows:将新行添加到问题对象。新行始终添加到行列表的末尾,因此现有行的序号不会改变。添加的每个新行最初都是free(unbounded),并且约束系数列表为空。

      glp_set_row_name:分配(更改)第i行行名,长度要求1至255个字符,如果参数名称为nullptr或空字符串,则将删除第i行的现有名称。

      glp_set_row_bnds(lp,i,type,lb,ub):设置(更改)第i行类型和界限。支持的类型与glp_set_col_bnds相同。如果行没有下限(lower bound),则忽略参数lb。如果行没有上限(upper bound),则忽略参数ub。如果行是固定(fixed)类型,则仅使用参数lb,而忽略参数ub。添加到问题对象中的每一行最初都是free,即其类型为GLP_FR。

      glp_get_num_rows:返回指定问题对象中的行数。

      glp_get_row_type:返回第i行的类型,支持的类型与glp_set_col_bnds相同。

      glp_get_row_lb:返回第i行的下限,如果该行没有下限,则返回-DBL_MAX。

      glp_get_row_ub:返回第i行的上限,如果该行没有上限,则返回+DBL_MAX。

      glp_load_matrix(lp,ne,ia,ja,ar):加载(替换)整个约束矩阵(constraint matrix),将传入数组ia,ja和ar的约束矩阵加载到指定的问题对象中。加载前,约束矩阵的当前内容将被销毁。

      约束系数(约束矩阵的元素)应指定为三元组(triplets)(ia[k], ja[k], ar[k]),其中k=1, ..., ne,其中ia[k]是行索引,ja[k]是列索引,ar[k]是相应约束系数(constraint coefficient)的数值。参数ne指定要加载的矩阵中(非零)元素的总数。不允许使用索引相同的系数(同一行和列的索引组合只能出现一次)。允许使用零系数,但是,它们不会存储在约束矩阵中。如果参数ne为0,则参数ia、ja和/或ar可以指定为nullptr。

      glp_write_lp:将LP/MIP问题数据以CPLEX LP格式写入文本文件。可用于检查约束是否正确。

      glp_init_smcp:使用默认值初始化simplex求解器(solver)使用的控制参数。

      glp_simplex:使用simplex方法求解线性规划问题,并将计算结果存储回问题对象

      glp_get_status:报告指定问题对象当前基本解的通用状态,返回可能的状态如下图所示:

      glp_get_obj_val:返回目标函数的当前值。求目标函数的最小值或最大值,由glp_set_obj_dir指定。

      glp_init_iocp:使用默认值初始化branch-and-cut求解器使用的控制参数。

      glp_intopt:使用branch-and-cut方法求解混合整数线性规划问题

      glp_mip_status:报告MIP求解器找到的MIP解决方案的状态,返回可能的状态如下图所示:

      glp_mip_obj_val:返回MIP解决方案的目标函数值。求目标函数的最小值或最大值,由glp_set_obj_dir指定。

      glp_mip_col_val:返回与MIP解决方案的第j列关联变量的值。

      使用到的MIP接口包括:glp_set_col_kind/glp_get_col_kind、glp_init_iocp、glp_intopt、glp_mip_status、glp_mip_obj_val、glp_mip_col_val。

      按照以上给的测试数据,共需18个变量(cols);共需25个约束(rows)。执行结果如下图所示:

      注:在GLPK中,C API要求矩阵元素从索引1开始,row[i]对应第i个约束条件,col[j]对应第j个决策变量。通过约束矩阵即ia(行)、ja(列)、ar(系数)关联二者。

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

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

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

相关文章

PCB设计实践(十三)PCB设计中差分线间距与线宽设置的深度解析

一、差分信号的基本原理与物理背景 差分信号技术通过两条等幅反相的传输线实现信号传输&#xff0c;其核心优势体现在电磁场耦合的对称性上。根据麦克斯韦方程组的对称解原理&#xff0c;两条线产生的电磁场在远场区域相互抵消&#xff0c;形成以下特性&#xff1a; 1. 共模噪…

2025python学习笔记

一.Python语言基础入门 第一章 01.初识Python Python的起源&#xff1a; 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum吉多范罗苏姆&#xff08;龟叔&#xff09;决心开发一个新的解释程序&#xff08;Python维形&#xff09;1991年&#xff0c;第一个…

【并发编程】基于 Redis 手写分布式锁

目录 一、基于 Redis 演示超卖现象 1.1 Redis 超卖现象 1.2 超卖现象解决方案 二、Redis 的乐观锁机制 2.1 原生客户端演示 2.2 业务代码实现 三、单机部署 Redis 实现分布式锁 3.1 分布式锁的演变和升级 3.2 setnx 实现分布式锁 3.2.1 递归调用实现分布式锁 3.2.2 循…

Jsp技术入门指南【十二】自定义标签

Jsp技术入门指南【十二】自定义标签 前言一、什么是标签二、标签的类型有哪些&#xff1f;1. 空标签2. 带有属性的标签3. 带主体的标签 三、自定义标签的部件3.1 自定义标签的四步骤3.2 标签处理程序3.3 自定义标签的开发及使用步骤第一步&#xff1a;创建标签助手类第二步&…

Java—— 泛型详解

泛型概述 泛型是JDK5中引入的特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。 泛型的格式&#xff1a;<数据类型> 注意&#xff1a;泛型只能支持引用数据类型。 泛型的好处 没有泛型的时候&#xff0c;可以往集合中添加任意类型的数据&#x…

GPT-4o, GPT 4.5, GPT 4.1, O3, O4-mini等模型的区别与联系

大模型时代浪潮汹涌,作为其中的领军者,OpenAI 其推出的系列模型以强大的能力深刻影响着整个行业,并常常成为业界其他公司对标和比较的基准。因此,深入了解 OpenAI 的大模型,不仅是为了使用它们,更是为了理解当前大模型的能力边界和发展趋势,这对于我们评估和选择其他各类…

Kubernetes生产实战(十二):无工具容器网络连接数暴增指南

当线上容器突然出现TCP连接数暴涨&#xff0c;而容器内又没有安装任何调试工具时&#xff0c;如何快速定位问题&#xff1f;本文将分享一套经过大型互联网公司验证的排查方案&#xff0c;涵盖从快速应急到根因分析的全流程。 一、快速锁定问题容器 查看pod 连接数方式&#x…

MySQL的Order by与Group by优化详解!

目录 前言核心思想&#xff1a;让索引帮你“排好序”或“分好组”Part 1: ORDER BY 优化详解1.1 什么是 Filesort&#xff1f;为什么它慢&#xff1f;1.2 如何避免 Filesort&#xff1f;—— 利用索引的有序性1.3 EXPLAIN 示例 (ORDER BY) Part 2: GROUP BY 优化详解2.1 什么是…

软件测试——用例篇(3)

目录 一、设计测试用例的具体方法 1.1等价类 1.1.1等价类概念介绍 1.1.2等价类分类 1.2边界值 1.2.1边界值分析法 1.2.2边界值分类 1.3正交法 1.3.1正交表 1.3.2正交法设计测试用例步骤 1.4判定表法 1.4.1判定表 1.4.2判定表方法设计测试用例 1.5 场景法 1.6错误…

在 Win11 下安装 Wireshark 的详细步骤

目录 一、了解 Wireshark1. 作用和功能2. 使用步骤 二、下载安装包三、运行安装包四、使用 Wireshark1. 抓包2. 窗口介绍3. 过滤器&#xff08;显示 / 捕获过滤器&#xff09;4. 保存过滤后的报文1&#xff09;显示过滤器表达式&#xff08;了解&#xff09;2&#xff09;过滤表…

AI编程: 使用Trae1小时做成的音视频工具,提取音频并识别文本

背景 在上个月&#xff0c;有网页咨询我怎么才能获取视频中的音频并识别成文本&#xff0c;我当时给他的回答是去问一下AI&#xff0c;让AI来给你答案。 他觉得我在敷衍他&#xff0c;大骂了我一顿&#xff0c;大家觉得我的回答对吗&#xff1f; 小编心里委屈&#xff0c;我…

RTC实时时钟DS1337S/PT7C4337WEX国产替代FRTC1337S

NYFEA徕飞公司的FRTC1337S串行实时时钟是一种低功耗时钟/日历&#xff0c;被设计成可以无缝替代市场上流行的DS1337S和PT7C4337WEX(SOP8)两种型号, 具有两个可编程的时钟闹钟和一个可编程方波输出。 地址和数据通过2线双向总线串行传输。时钟/日历提供秒、分钟、小时、天、日期…

Vue3.5 企业级管理系统实战(十七):角色管理

本篇主要探讨角色管理功能&#xff0c;其中菜单权限这里先不实现&#xff0c;后续在菜单管理中再进行实现。接口部分依然是使用 Apifox mock 的。 1 角色 api 在 src/api/role.ts 中添加角色相关 api&#xff0c;代码如下&#xff1a; //src/api/role.ts import service fro…

QTableWidget实现多级表头、表头冻结效果

最终效果&#xff1a; 实现思路&#xff1a;如果只用一个表格的话写起来比较麻烦&#xff0c;可以考虑使用两个QTableWidget组合&#xff0c;把复杂的表头一个用QTableWidget显示&#xff0c;其他内容用另一个QTableWidget。 #include "mainwindow.h" #include &qu…

A2A大模型协议及Java示例

A2A大模型协议概述 1. 协议作用 A2A协议旨在解决以下问题&#xff1a; 数据交换&#xff1a;不同应用程序之间的数据格式可能不一致&#xff0c;A2A协议通过定义统一的接口和数据格式解决这一问题。模型调用&#xff1a;提供标准化的接口&#xff0c;使得外部应用可以轻松调…

CMake 入门实践

CMake 入门实践 第一章 概念与基础项目1.1 CMake 基础认知1.2 最小 CMake 项目1.3 构建流程验证 第二章 多文件项目管理2.1 项目结构2.2 源码示例2.3 CMake 配置 第三章 库文件管理实战3.1 项目结构3.2 核心配置3.3 接口设计 第四章 构建类型与编译优化4.1 构建类型配置4.2 构建…

异地多活单元化架构下的微服务体系

治理服务间的跨IDC调用&#xff0c;而数据库层面还是要跨IDC 服务注册中心拆开、 金融要求&#xff0c;距离太远&#xff0c;异地备库&#xff0c;如果延迟没读到数据就可能有资损&#xff0c;IDC3平时不能用&#xff0c;IDC1挂了还是有数据同步问题&#xff0c;IDC3日常维护…

HarmonyOS NEXT——DevEco Studio的使用(还没写完)

一、IDE环境的搭建 Windows环境 运行环境要求 为保证DevEco Studio正常运行&#xff0c;建议电脑配置满足如下要求&#xff1a; 操作系统&#xff1a;Windows10 64位、Windows11 64位 内存&#xff1a;16GB及以上 硬盘&#xff1a;100GB及以上 分辨率&#xff1a;1280*8…

Windows系统Jenkins企业级实战

目标 在Windows操作系统上使用Jenkins完成代码的自动拉取、编译、打包、发布工作。 实施 1.安装Java开发工具包&#xff08;JDK&#xff09; Jenkins是基于Java的应用程序&#xff0c;因此需要先安装JDK。可以从Oracle官网或OpenJDK下载适合的JDK版本。推荐java17版本&#x…

C# 方法(ref局部变量和ref返回)

>本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 ref局部变量和ref返回 …