news 2026/10/13 5:57:59

Kruise calculator-helper 表达式生成器实战:用 Python 把折线数据点转为 max/min 分段线性数学表达式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kruise calculator-helper 表达式生成器实战:用 Python 把折线数据点转为 max/min 分段线性数学表达式
  • 云原生
  • 容器编排
  • 微服务
  • 运维

【免费下载链接】kruise

Automated management of large-scale applications on Kubernetes (incubating project under CNCF)

项目地址:https://gitcode.com/gh_mirrors/kr/kruise
点击查看免费下载

导读

本文围绕 OpenKruise 仓库 hack/calculator-helper/generator 目录下的表达式生成器(Expression Generator)展开,讲解如何用纯 Python 标准库、通过给定的一组 [x, y] 数据点,自动生成仅使用+ - * / ( ) max min运算符的分段线性函数数学表达式。读完本文,你将掌握该工具的完整命令行用法、输入输出格式、凸/凹/混合函数三类算法的判断逻辑与源码实现、自动验证机制,以及如何用仓库自带的测试脚本回归验证;文中同时对照 Go 端 calculator 包与 SidecarSet 动态资源表达式场景,帮助你理解这个工具在 Kruise 资源计算体系中的定位。

一、工具定位:calculator-helper 里的"表达式生成器"

在 OpenKruise 的 hack/calculator-helper 目录下,维护着一对配套工具:

  • generator(表达式生成器):Python 实现,输入折线数据点,输出数学表达式字符串;
  • validator(表达式验证器):Go 实现,针对 pkg/util/calculator 包的cpu/memory表达式做语法验证并绘制可视化曲线。

两者的共同背景是 Kruise 的 SidecarSet 动态资源能力——Pod 创建时,sidecar 容器的resources可以由max(cpu*50%, 50m)这类表达式根据主容器资源动态计算(详见 docs/proposals/20250913-sidecarset-dynamic-resources-when-creating.md)。分段线性函数天然适合表达"按主容器规格分档取值"的资源策略,而 generator 的作用正是:当你有一组离散的折线数据点时,自动把它翻译成 calculator 能解析的数学表达式。

本工具的核心文件是 generate_expression.py,它不依赖任何第三方库,可直接运行。

二、功能特性概览

根据 README_zh.md 和源码实现,工具具备以下能力:

  • 生成表达式仅使用受限运算符集:+、-、*、/、()、max、min;
  • 支持自定义变量名(默认x),适合映射到 calculator 侧的cpu/memory变量;
  • 覆盖全类型分段线性函数:
    • 线性函数(恒定斜率);
    • 凸函数(斜率递增);
    • 凹函数(斜率递减);
    • 混合/锯齿形(斜率交替变化);
  • 默认开启自动验证,生成的表达式会逐一检查是否精确通过所有输入点,可用--no-verify关闭;
  • 简洁的纯命令行界面,无需额外依赖。

三、环境配置:用 uv 管理 Python 环境

工具依赖 Python 3.8+,仓库推荐使用 uv 管理虚拟环境(README 原文链接,本文不再展开外部站点)。

安装 uv

# macOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh # 或使用 pip pip install uv

创建并激活虚拟环境

# 创建 Python 虚拟环境 (Python 3.8+) uv venv # 激活环境 # macOS/Linux: source .venv/bin/activate # Windows: .venv\Scripts\activate

安装依赖

本工具仅使用 Python 标准库(argparse、json、typing),无需额外依赖。用完后可执行deactivate退出虚拟环境。

四、使用方法与命令行选项

基础用法

python3 generate_expression.py "[[0,0], [1,1], [2,2], [3,3]]"

输出:x

自定义变量名

python3 generate_expression.py "[[0,0], [1,1], [2,3]]" --var mem

输出:max(mem,2*mem-1.0)

完整命令行选项

参数说明默认值
points(必需)JSON 数组格式的点,如"[[0,0], [1,1], [2,2]]"-
-v, --var表达式中使用的变量名x
--no-verify跳过生成表达式的自动验证关闭(即默认验证)

上述参数解析对应源码 generate_expression.py 中main()的argparse定义。此外:

  • 脚本可直接以chmod +x generate_expression.py设为可执行后通过./generate_expression.py ...运行;
  • 运行python3 generate_expression.py --help可查看内嵌的帮助与示例(epilog)。

五、输入格式与输出约定

输入格式

点以 JSON 数组形式提供,每个点为[x, y]对:

"[[x1,y1], [x2,y2], [x3,y3], ...]"

解析逻辑在源码parse_points()(generate_expression.py):先用json.loads解析,再逐项转换为float。若解析失败会抛出Invalid points format错误;另外两点 x 坐标相同时(源码calculate_slope()中检测x2 == x1)会抛出Points have same x-coordinate错误。

输出约定

工具输出一个数学表达式字符串,该表达式:

  • 通过所有输入点;
  • 仅使用允许的运算符+ - * / ( ) max min;
  • 仅包含指定的变量名(其他数值均为常量);
  • 表示分段线性函数;
  • 默认经过自动验证确保正确。

六、算法原理:从数据点到表达式

工具在 generate_expression.py 中按以下步骤工作:

  1. 按 x 坐标排序点:generate_piecewise_expression()入口处sorted(points, key=lambda p: p[0]);
  2. 计算每个线段的线性方程:calculate_slope()计算两点斜率(y2-y1)/(x2-x1),line_equation()结合截距y1 - slope*x1生成形如2*x-1.0的字符串,并对斜率为1、-1、整数、小数以及截距正负做格式化简化;
  3. 判断函数类型:
    • 凸函数(斜率递增):对全部线段使用max(...)包裹;
    • 凹函数(斜率递减):对全部线段使用min(...)包裹;
    • 混合函数(斜率交替):从第一个线段开始,依次按相邻斜率变化用max(斜率上升)或min(斜率下降)嵌套拼接;
  4. 特殊情形:仅 2 个点直接返回直线方程;所有点共线(各段斜率完全相同)时也简化为一条直线(generate_expression.py);
  5. 自动验证:逐点代入检查表达式是否通过所有输入点。

算法中"斜率单调性"的判定(generate_expression.py)为:

slope_increasing = all(slopes[i] <= slopes[i + 1] for i in range(len(slopes) - 1)) slope_decreasing = all(slopes[i] >= slopes[i + 1] for i in range(len(slopes) - 1))

当两者都不成立时进入混合分支,按斜率升降逐段嵌套max/min。

从工程语义看,这与 Go 端 calculator 包支持的运算符集合(+ - * /、max()、min()、百分比、K8s Quantity 等,见 pkg/util/calculator/README.md)高度对齐:generator 生成的表达式可以直接作为 SidecarSetresourcesPolicy.resourcesExpr中cpu/memory表达式的前身素材,再经 pkg/webhook/pod/mutating/sidecarset_resources.go 中calculator.NewCalculator()+Parse()求值。

七、四类函数与运行示例

示例 1:线性函数(恒定斜率)

$ python3 generate_expression.py "[[0,0], [1,1], [2,2], [3,3]]" x

示例 2:分段线性函数(凸,斜率递增)

$ python3 generate_expression.py "[[0,0], [1,1], [2,3]]" max(x,2*x-1.0)

验证:

  • 当 x=0:max(0, 0-1) = max(0, -1) = 0✓
  • 当 x=1:max(1, 2-1) = max(1, 1) = 1✓
  • 当 x=2:max(2, 4-1) = max(2, 3) = 3✓

示例 3:凹函数(斜率递减)

$ python3 generate_expression.py "[[0,10], [5,20], [10,15]]" min(2*x+10.0,-x+25.0)

示例 4:混合斜率(锯齿形)

$ python3 generate_expression.py "[[0,0], [1,2], [2,1], [3,3]]" max(min(2*x,-x+3.0),2*x-3.0)

验证:

  • 当 x=0:max(min(0,3),−3) = max(0,−3) = 0✓
  • 当 x=1:max(min(2,2),−1) = max(2,−1) = 2✓
  • 当 x=2:max(min(4,1),1) = max(1,1) = 1✓
  • 当 x=3:max(min(6,0),3) = max(0,3) = 3✓

以上示例正是"通过所有输入点"这一约束的直接体现:max保证凸段取上包络,min保证凹段取下包络,嵌套后即可贴合锯齿形折线。

八、自动验证机制

默认情况下,工具会自动验证生成表达式是否通过所有点:

$ python3 generate_expression.py "[[0,0], [1,1], [2,2]]" x # 自动验证通过,静默输出

验证实现位于verify_expression()(generate_expression.py):对每个点,构造命名空间{变量名: x_val, 'max': max, 'min': min},用受限的eval(__builtins__置空)求值,并以abs(actual_y - expected_y) < 1e-10作为浮点容差判定。

如果验证失败,会向stderr输出错误信息:

$ python3 generate_expression.py "[[invalid points]]" Verification FAILED at x=1: expected=1, actual=0.9 WARNING: Generated expression failed verification! Expression: incorrect_expression

此时进程以退出码 1 结束(generate_expression.py)。如果确认表达式可用、想跳过验证:

$ python3 generate_expression.py "[[0,0], [1,1]]" --no-verify x

九、回归测试:用 test_advanced.sh 一键验证

仓库提供了覆盖多种形态的 shell 测试脚本 test_advanced.sh:

chmod +x test_advanced.sh ./test_advanced.sh

脚本内每个用例都调用python3 generate_expression.py "<points>",并依据退出码判定"PASSED(含自动验证)"或"FAILED"。覆盖的测试类型包括:

  • 线性函数:[[0,0],[1,1],[2,2],[3,3]]
  • 凸函数(斜率递增):[[0,0],[1,1],[2,3]]
  • 凹函数(斜率递减):[[0,10],[5,20],[10,15]]
  • 混合斜率(上-下-上模式):[[0,0],[1,2],[2,1],[3,3]]
  • 复杂锯齿形:[[0,0],[1,3],[2,1],[3,4],[4,2]]
  • 自定义变量名:--var mem
  • 负值:[[-2,-4],[-1,-1],[0,0],[1,1]]
  • 大数值:[[0,100],[10,200],[20,150]]

这些用例与文章第七节的手工验证形成呼应,可作为工具改动后的基础回归集。

十、故障排除

问题原因解决
Invalid points format输入格式不正确确保使用 JSON 数组格式,如"[[0,0], [1,1]]"
Points have same x-coordinate两个点的 x 坐标相同确保所有点的 x 坐标唯一
Verification FAILED生成的表达式未通过验证(属于工具 bug)报告此问题,并附上输入的点

其中前两类错误均由源码显式抛出(parse_points()与calculate_slope()中的raise ValueError),第三类则依赖自动验证兜底捕获。

十一、技术细节速查

  • Python 版本:3.8+
  • 依赖:仅标准库(argparse、json、typing)
  • 支持的运算符:+ - * / ( ) max min
  • 数值精度:浮点数比较容差为1e-10

相关文件

  • 生成器源码:hack/calculator-helper/generator/generate_expression.py
  • 测试脚本:hack/calculator-helper/generator/test_advanced.sh
  • 英文文档:hack/calculator-helper/generator/README.md
  • 配套验证器文档:hack/calculator-helper/validator/README_zh.md
  • Go 端表达式求值引擎:pkg/util/calculator/calculator.go(含 LALR(1) 文法 pkg/util/calculator/calculator.y 与词法分析器 pkg/util/calculator/lexer.go)
  • 运行时调用侧:pkg/webhook/pod/mutating/sidecarset_resources.go
  • 功能提案:docs/proposals/20250913-sidecarset-dynamic-resources-when-creating.md

简而言之:generator 负责"把折线变成表达式",validator 与 calculator 包负责"把表达式变成资源数值",两者串联构成了 Kruise 动态资源表达式从设计、验证到落地的完整链路。

  • 云原生
  • 容器编排
  • 微服务
  • 运维

【免费下载链接】kruise

Automated management of large-scale applications on Kubernetes (incubating project under CNCF)

项目地址:https://gitcode.com/gh_mirrors/kr/kruise
点击查看免费下载
上一篇:diffvg:革命性2D矢量图形可微光栅化工具,彻底改变图形编辑与AI训练流程
下一篇:MLX-Whisper 语音转文字上手指南:5 分钟本地部署、参数调优与实战(附核心参数表)

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 5:55:29

基于价值认同的分布式电能共享交易Matlab仿真与ADMM实现

1. 项目整体设计&#xff1a;价值认同如何嵌入电能共享交易1.1 需求侧电能共享到底解决什么问题传统电力系统里&#xff0c;用户只是被动的“买电者”&#xff0c;电价由电网或售电公司统一定价&#xff0c;用户几乎没有选择空间。但随着分布式光伏、储能、电动汽车这些“产消者…

作者头像 李华
网站建设 2026/10/13 5:53:55

快速幂算法原理与工程实践:从LeetCode 50题看健壮性设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/13 5:52:32

C++内联函数深度解析:从编译器行为到工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华