algobench-sdk 2.0.4__tar.gz → 2.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/PKG-INFO +1 -1
  2. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/__init__.py +1 -1
  3. algobench_sdk-2.0.6/algobench/config/metric_keywords.py +516 -0
  4. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/optimization/knee_point.py +3 -3
  5. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/parsers/csv_parser.py +68 -10
  6. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/core.py +16 -6
  7. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/qvalue.py +7 -1
  8. algobench_sdk-2.0.6/algobench/stats/sample_processing.py +150 -0
  9. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/tests/data_type.py +3 -1
  10. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/tests/nonparametric.py +14 -1
  11. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/tests/smart.py +1 -1
  12. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench_sdk.egg-info/PKG-INFO +1 -1
  13. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/pyproject.toml +1 -1
  14. algobench_sdk-2.0.4/algobench/config/metric_keywords.py +0 -231
  15. algobench_sdk-2.0.4/algobench/stats/sample_processing.py +0 -102
  16. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/README.md +0 -0
  17. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/__main__.py +0 -0
  18. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/api.py +0 -0
  19. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/cli.py +0 -0
  20. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/config/__init__.py +0 -0
  21. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/config/analysis_criteria.py +0 -0
  22. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/config/business.py +0 -0
  23. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/config/metrics.py +0 -0
  24. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/config/thresholds.py +0 -0
  25. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/exceptions.py +0 -0
  26. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/models.py +0 -0
  27. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/optimization/__init__.py +0 -0
  28. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/optimization/decision_tree.py +0 -0
  29. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/optimization/feature_importance.py +0 -0
  30. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/optimization/response_surface.py +0 -0
  31. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/parsers/__init__.py +0 -0
  32. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/__init__.py +0 -0
  33. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/diagnosis.py +0 -0
  34. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/tests/__init__.py +0 -0
  35. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/tests/effect_size.py +0 -0
  36. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/stats/tests/t_tests.py +0 -0
  37. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/utils/__init__.py +0 -0
  38. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/utils/improvement.py +0 -0
  39. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/utils/math_utils.py +0 -0
  40. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench/utils/numbers.py +0 -0
  41. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench_sdk.egg-info/SOURCES.txt +0 -0
  42. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench_sdk.egg-info/dependency_links.txt +0 -0
  43. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench_sdk.egg-info/requires.txt +0 -0
  44. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/algobench_sdk.egg-info/top_level.txt +0 -0
  45. {algobench_sdk-2.0.4 → algobench_sdk-2.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: algobench-sdk
3
- Version: 2.0.4
3
+ Version: 2.0.6
4
4
  Summary: AlgoBench - 算法基准测试分析工具的 Python SDK 与 CLI
5
5
  Author: DuanxiangLiu
6
6
  License-Expression: AGPL-3.0-only
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "2.0.4"
5
+ __version__ = "2.0.6"
6
6
 
7
7
  from algobench.api import analyze, compute_statistics_only as compute_statistics
8
8
  from algobench.models import (
@@ -0,0 +1,516 @@
1
+ """指标关键词库,对应 JS 的 src/config/metricKeywords.js。
2
+
3
+ 由 JS keyword 文件自动生成,确保与前端 DEFAULT_KEYWORD_LIBRARY 1:1 对齐。
4
+ 包含 ML_KEYWORDS + FINANCE_KEYWORDS + EDA_KEYWORDS + GENERAL_KEYWORDS。
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import re
10
+
11
+ # 默认关键词库(与 JS DEFAULT_KEYWORD_LIBRARY 完全一致)
12
+ # 顺序:ML → Finance → EDA → General(与 JS metricKeywords.js 合并顺序一致)
13
+ DEFAULT_KEYWORD_LIBRARY: dict[str, dict] = {
14
+
15
+ # ===== 机器学习指标 (ML_KEYWORDS) =====
16
+ "accuracy": {"better": "higher", "description": "准确率"},
17
+ "precision": {"better": "higher", "description": "精确率"},
18
+ "recall": {"better": "higher", "description": "召回率"},
19
+ "f1": {"better": "higher", "description": "F1分数"},
20
+ "auc": {"better": "higher", "description": "AUC值"},
21
+ "map": {"better": "higher", "description": "平均精度均值"},
22
+ "iou": {"better": "higher", "description": "交并比"},
23
+ "dice": {"better": "higher", "description": "Dice系数"},
24
+ "bleu": {"better": "higher", "description": "BLEU分数"},
25
+ "rouge": {"better": "higher", "description": "ROUGE分数"},
26
+ "perplexity": {"better": "lower", "description": "困惑度"},
27
+ "success": {"better": "higher", "description": "成功"},
28
+ "hit": {"better": "higher", "description": "命中"},
29
+ "win": {"better": "higher", "description": "胜利"},
30
+ "pass": {"better": "higher", "description": "通过"},
31
+ "correct": {"better": "higher", "description": "正确"},
32
+ "valid": {"better": "higher", "description": "有效"},
33
+ "coverage": {"better": "higher", "description": "覆盖率"},
34
+ "yield": {"better": "higher", "description": "产出率"},
35
+ "utilization": {"better": "higher", "description": "利用率"},
36
+ "occupancy": {"better": "higher", "description": "占用率"},
37
+ "availability": {"better": "higher", "description": "可用性"},
38
+ "reliability": {"better": "higher", "description": "稳定性"},
39
+ "stability": {"better": "higher", "description": "稳定性"},
40
+ "loss": {"better": "lower", "description": "损失"},
41
+ "error": {"better": "lower", "description": "错误"},
42
+ "mistake": {"better": "lower", "description": "错误"},
43
+ "fail": {"better": "lower", "description": "失败"},
44
+ "failure": {"better": "lower", "description": "失败"},
45
+ "miss": {"better": "lower", "description": "未命中"},
46
+ "reject": {"better": "lower", "description": "拒绝"},
47
+ "drop": {"better": "lower", "description": "丢弃"},
48
+ "train_loss": {"better": "lower", "description": "训练损失"},
49
+ "val_loss": {"better": "lower", "description": "验证损失"},
50
+ "test_loss": {"better": "lower", "description": "测试损失"},
51
+ "train_error": {"better": "lower", "description": "训练错误率"},
52
+ "val_error": {"better": "lower", "description": "验证错误率"},
53
+ "test_error": {"better": "lower", "description": "测试错误率"},
54
+ "train_acc": {"better": "higher", "description": "训练准确率"},
55
+ "val_acc": {"better": "higher", "description": "验证准确率"},
56
+ "test_acc": {"better": "higher", "description": "测试准确率"},
57
+ "top1": {"better": "higher", "description": "Top-1 准确率"},
58
+ "top5": {"better": "higher", "description": "Top-5 准确率"},
59
+ "top1_acc": {"better": "higher", "description": "Top-1 准确率"},
60
+ "top5_acc": {"better": "higher", "description": "Top-5 准确率"},
61
+ "wer": {"better": "lower", "description": "词错误率"},
62
+ "cer": {"better": "lower", "description": "字符错误率"},
63
+ "ter": {"better": "lower", "description": "翻译错误率"},
64
+ "mer": {"better": "lower", "description": "匹配错误率"},
65
+ "token_error": {"better": "lower", "description": "Token 错误率"},
66
+ "inference_time": {"better": "lower", "description": "推理时间"},
67
+ "inferencetime": {"better": "lower", "description": "推理时间"},
68
+ "inference_latency": {"better": "lower", "description": "推理延迟"},
69
+ "tokens_per_second": {"better": "higher", "description": "每秒Token数"},
70
+ "tokenspersecond": {"better": "higher", "description": "每秒Token数"},
71
+ "tps": {"better": "higher", "description": "每秒Token数"},
72
+ "reward": {"better": "higher", "description": "奖励"},
73
+ "return": {"better": "higher", "description": "回报"},
74
+ "score": {"better": "higher", "description": "得分"},
75
+ "episode_reward": {"better": "higher", "description": "回合奖励"},
76
+ "cumulative_reward": {"better": "higher", "description": "累积奖励"},
77
+
78
+ # ===== 金融指标 (FINANCE_KEYWORDS) =====
79
+ "alpha_cagr_vs_benchmark": {"better": "higher", "unit": "%", "description": "相对基准年化超额收益", "impDisplayMode": "percent"},
80
+ "max_drawdown_duration_days": {"better": "lower", "description": "最大回撤持续天数", "impDisplayMode": "percent"},
81
+ "annual_volatility": {"better": "lower", "unit": "%", "description": "年化波动率", "impDisplayMode": "percent"},
82
+ "max_drawdown": {"better": "higher", "unit": "%", "description": "最大回撤(负数口径时越高越好)", "impDisplayMode": "percent"},
83
+ "monthly_win_rate": {"better": "higher", "unit": "%", "description": "月度胜率", "impDisplayMode": "percent"},
84
+ "information_ratio": {"better": "higher", "description": "信息比率", "impDisplayMode": "percent"},
85
+ "cost_ratio": {"better": "lower", "unit": "%", "description": "成本率", "impDisplayMode": "percent"},
86
+ "total_return": {"better": "higher", "unit": "%", "description": "总收益率", "impDisplayMode": "percent"},
87
+ "volatility": {"better": "lower", "unit": "%", "description": "波动率", "impDisplayMode": "percent"},
88
+ "drawdown": {"better": "lower", "description": "回撤(正数损失口径时越低越好)", "impDisplayMode": "percent"},
89
+ "turnover": {"better": "lower", "unit": "%", "description": "换手率", "impDisplayMode": "percent"},
90
+ "sortino": {"better": "higher", "description": "Sortino比率", "impDisplayMode": "percent"},
91
+ "sharpe": {"better": "higher", "description": "Sharpe比率", "impDisplayMode": "percent"},
92
+ "calmar": {"better": "higher", "description": "Calmar比率", "impDisplayMode": "percent"},
93
+ "alpha": {"better": "higher", "description": "超额收益", "impDisplayMode": "percent"},
94
+ "cagr": {"better": "higher", "unit": "%", "description": "年化收益率", "impDisplayMode": "percent"},
95
+ "exposure": {"better": "higher", "description": "暴露度", "impDisplayMode": "percent"},
96
+ "final_equity": {"better": "higher", "description": "最终权益", "impDisplayMode": "percent"},
97
+
98
+ # ===== EDA / 芯片设计指标 (EDA_KEYWORDS) =====
99
+ "congestion": {"better": "lower", "description": "拥塞度"},
100
+ "hpwl": {"better": "lower", "description": "半周长线长"},
101
+ "wirelength": {"better": "lower", "description": "线长"},
102
+ "wl": {"better": "lower", "description": "线长"},
103
+ "wire": {"better": "lower", "description": "线长"},
104
+ "drc": {"better": "lower", "description": "设计规则违规"},
105
+ "density": {"better": "lower", "description": "密度"},
106
+ "slack": {"better": "higher", "description": "时序裕量"},
107
+ "wns": {"better": "higher", "description": "最差负裕量"},
108
+ "tns": {"better": "higher", "description": "总负裕量"},
109
+ "d2d": {"better": "lower", "description": "芯片间互联数量"},
110
+ "d2dnum": {"better": "lower", "description": "芯片间互联数量"},
111
+ "hb": {"better": "lower", "description": "混合键合数量"},
112
+ "hybrid bonding": {"better": "lower", "description": "混合键合数量"},
113
+ "hybridbonding": {"better": "lower", "description": "混合键合数量"},
114
+ "gp_tns": {"better": "higher", "description": "全局布局后总负裕量"},
115
+ "gp_wns": {"better": "higher", "description": "全局布局后最差负裕量"},
116
+ "gp_slack": {"better": "higher", "description": "全局布局后时序裕量"},
117
+ "gp_power": {"better": "lower", "description": "全局布局后功耗"},
118
+ "gp_totalpower": {"better": "lower", "description": "全局布局后总功耗"},
119
+ "gp_dynamicpower": {"better": "lower", "description": "全局布局后动态功耗"},
120
+ "gp_leakagepower": {"better": "lower", "description": "全局布局后漏电功耗"},
121
+ "gp_area": {"better": "lower", "description": "全局布局后面积"},
122
+ "gp_utilization": {"better": "lower", "description": "全局布局后利用率"},
123
+ "gp_congestion": {"better": "lower", "description": "全局布局后拥塞度"},
124
+ "gp_overflow": {"better": "lower", "description": "全局布局后溢出"},
125
+ "gp_hpwl": {"better": "lower", "description": "全局布局后半周长线长"},
126
+ "gp_wirelength": {"better": "lower", "description": "全局布局后线长"},
127
+ "gp_density": {"better": "lower", "description": "全局布局后密度"},
128
+ "dp_tns": {"better": "higher", "description": "详细布局后总负裕量"},
129
+ "dp_wns": {"better": "higher", "description": "详细布局后最差负裕量"},
130
+ "dp_slack": {"better": "higher", "description": "详细布局后时序裕量"},
131
+ "dp_power": {"better": "lower", "description": "详细布局后功耗"},
132
+ "dp_totalpower": {"better": "lower", "description": "详细布局后总功耗"},
133
+ "dp_dynamicpower": {"better": "lower", "description": "详细布局后动态功耗"},
134
+ "dp_leakagepower": {"better": "lower", "description": "详细布局后漏电功耗"},
135
+ "dp_area": {"better": "lower", "description": "详细布局后面积"},
136
+ "dp_utilization": {"better": "lower", "description": "详细布局后利用率"},
137
+ "dp_congestion": {"better": "lower", "description": "详细布局后拥塞度"},
138
+ "dp_overflow": {"better": "lower", "description": "详细布局后溢出"},
139
+ "dp_hpwl": {"better": "lower", "description": "详细布局后半周长线长"},
140
+ "dp_wirelength": {"better": "lower", "description": "详细布局后线长"},
141
+ "dp_density": {"better": "lower", "description": "详细布局后密度"},
142
+ "cts_tns": {"better": "higher", "description": "时钟树综合后总负裕量"},
143
+ "cts_wns": {"better": "higher", "description": "时钟树综合后最差负裕量"},
144
+ "cts_slack": {"better": "higher", "description": "时钟树综合后时序裕量"},
145
+ "cts_power": {"better": "lower", "description": "时钟树综合后功耗"},
146
+ "cts_totalpower": {"better": "lower", "description": "时钟树综合后总功耗"},
147
+ "cts_dynamicpower": {"better": "lower", "description": "时钟树综合后动态功耗"},
148
+ "cts_leakagepower": {"better": "lower", "description": "时钟树综合后漏电功耗"},
149
+ "cts_area": {"better": "lower", "description": "时钟树综合后面积"},
150
+ "cts_utilization": {"better": "lower", "description": "时钟树综合后利用率"},
151
+ "cts_skew": {"better": "lower", "description": "时钟树综合后时钟偏斜"},
152
+ "cts_latency": {"better": "lower", "description": "时钟树综合后时钟延迟"},
153
+ "route_tns": {"better": "higher", "description": "绕线后总负裕量"},
154
+ "route_wns": {"better": "higher", "description": "绕线后最差负裕量"},
155
+ "route_slack": {"better": "higher", "description": "绕线后时序裕量"},
156
+ "route_power": {"better": "lower", "description": "绕线后功耗"},
157
+ "route_totalpower": {"better": "lower", "description": "绕线后总功耗"},
158
+ "route_dynamicpower": {"better": "lower", "description": "绕线后动态功耗"},
159
+ "route_leakagepower": {"better": "lower", "description": "绕线后漏电功耗"},
160
+ "route_area": {"better": "lower", "description": "绕线后面积"},
161
+ "route_utilization": {"better": "lower", "description": "绕线后利用率"},
162
+ "route_wirelength": {"better": "lower", "description": "绕线后线长"},
163
+ "route_hpwl": {"better": "lower", "description": "绕线后半周长线长"},
164
+ "route_drc": {"better": "lower", "description": "绕线后设计规则违规"},
165
+ "route_violation": {"better": "lower", "description": "绕线后违规数量"},
166
+ "route_short": {"better": "lower", "description": "绕线后短路数量"},
167
+ "route_open": {"better": "lower", "description": "绕线后开路数量"},
168
+ "postroute_tns": {"better": "higher", "description": "绕线优化后总负裕量"},
169
+ "postroute_wns": {"better": "higher", "description": "绕线优化后最差负裕量"},
170
+ "postroute_slack": {"better": "higher", "description": "绕线优化后时序裕量"},
171
+ "postroute_power": {"better": "lower", "description": "绕线优化后功耗"},
172
+ "postroute_totalpower": {"better": "lower", "description": "绕线优化后总功耗"},
173
+ "postroute_dynamicpower": {"better": "lower", "description": "绕线优化后动态功耗"},
174
+ "postroute_leakagepower": {"better": "lower", "description": "绕线优化后漏电功耗"},
175
+ "postroute_area": {"better": "lower", "description": "绕线优化后面积"},
176
+ "postroute_utilization": {"better": "lower", "description": "绕线优化后利用率"},
177
+ "postroute_wirelength": {"better": "lower", "description": "绕线优化后线长"},
178
+ "postroute_hpwl": {"better": "lower", "description": "绕线优化后半周长线长"},
179
+ "postroute_drc": {"better": "lower", "description": "绕线优化后设计规则违规"},
180
+ "postroute_violation": {"better": "lower", "description": "绕线优化后违规数量"},
181
+ "postroute_ir": {"better": "lower", "description": "绕线优化后电压降"},
182
+ "postroute_irdrop": {"better": "lower", "description": "绕线优化后电压降"},
183
+ "setup": {"better": "higher", "description": "建立时间裕量"},
184
+ "hold": {"better": "higher", "description": "保持时间裕量"},
185
+ "setup_time": {"better": "higher", "description": "建立时间裕量"},
186
+ "hold_time": {"better": "higher", "description": "保持时间裕量"},
187
+ "setuptime": {"better": "higher", "description": "建立时间裕量"},
188
+ "holdtime": {"better": "higher", "description": "保持时间裕量"},
189
+ "skew": {"better": "lower", "description": "时钟偏斜"},
190
+ "ir_drop": {"better": "lower", "description": "电压降"},
191
+ "irdrop": {"better": "lower", "description": "电压降"},
192
+ "ir": {"better": "lower", "description": "电压降"},
193
+ "signal integrity": {"better": "higher", "description": "信号完整性"},
194
+ "si": {"better": "higher", "description": "信号完整性"},
195
+ "frequency": {"better": "target", "description": "频率"},
196
+ "voltage": {"better": "target", "description": "电压"},
197
+ "target": {"better": "target", "description": "目标值"},
198
+
199
+ # ===== 通用指标 (GENERAL_KEYWORDS) =====
200
+ "score": {"better": "higher", "description": "得分"},
201
+ "rating": {"better": "higher", "description": "评分"},
202
+ "rank": {"better": "lower", "description": "排名"},
203
+ "grade": {"better": "higher", "description": "等级"},
204
+ "level": {"better": "higher", "description": "级别"},
205
+ "语文": {"better": "higher", "description": "语文成绩"},
206
+ "chinese": {"better": "higher", "description": "语文成绩"},
207
+ "数学": {"better": "higher", "description": "数学成绩"},
208
+ "math": {"better": "higher", "description": "数学成绩"},
209
+ "mathematics": {"better": "higher", "description": "数学成绩"},
210
+ "英语": {"better": "higher", "description": "英语成绩"},
211
+ "english": {"better": "higher", "description": "英语成绩"},
212
+ "物理": {"better": "higher", "description": "物理成绩"},
213
+ "physics": {"better": "higher", "description": "物理成绩"},
214
+ "化学": {"better": "higher", "description": "化学成绩"},
215
+ "chemistry": {"better": "higher", "description": "化学成绩"},
216
+ "生物": {"better": "higher", "description": "生物成绩"},
217
+ "biology": {"better": "higher", "description": "生物成绩"},
218
+ "历史": {"better": "higher", "description": "历史成绩"},
219
+ "history": {"better": "higher", "description": "历史成绩"},
220
+ "地理": {"better": "higher", "description": "地理成绩"},
221
+ "geography": {"better": "higher", "description": "地理成绩"},
222
+ "政治": {"better": "higher", "description": "政治成绩"},
223
+ "politics": {"better": "higher", "description": "政治成绩"},
224
+ "政治学": {"better": "higher", "description": "政治成绩"},
225
+ "science": {"better": "higher", "description": "科学成绩"},
226
+ "理科": {"better": "higher", "description": "理科成绩"},
227
+ "文科": {"better": "higher", "description": "文科成绩"},
228
+ "总分": {"better": "higher", "description": "总分"},
229
+ "total": {"better": "higher", "description": "总分"},
230
+ "综合": {"better": "higher", "description": "综合成绩"},
231
+ "文综": {"better": "higher", "description": "文科综合"},
232
+ "理综": {"better": "higher", "description": "理科综合"},
233
+ "体育": {"better": "higher", "description": "体育成绩"},
234
+ "音乐": {"better": "higher", "description": "音乐成绩"},
235
+ "music": {"better": "higher", "description": "音乐成绩"},
236
+ "美术": {"better": "higher", "description": "美术成绩"},
237
+ "计算机": {"better": "higher", "description": "计算机成绩"},
238
+ "computer": {"better": "higher", "description": "计算机成绩"},
239
+ "信息": {"better": "higher", "description": "信息技术成绩"},
240
+ "throughput": {"better": "higher", "description": "吞吐量"},
241
+ "fps": {"better": "higher", "description": "帧率"},
242
+ "qps": {"better": "higher", "description": "每秒查询数"},
243
+ "tps": {"better": "higher", "description": "每秒事务数"},
244
+ "rps": {"better": "higher", "description": "每秒请求数"},
245
+ "iops": {"better": "higher", "description": "每秒IO操作"},
246
+ "bandwidth": {"better": "higher", "description": "带宽"},
247
+ "speedup": {"better": "higher", "description": "加速比"},
248
+ "speed": {"better": "higher", "description": "速度"},
249
+ "rate": {"better": "higher", "description": "速率"},
250
+ "efficiency": {"better": "higher", "description": "效率"},
251
+ "quality": {"better": "higher", "description": "质量"},
252
+ "performance": {"better": "higher", "description": "性能"},
253
+ "improvement": {"better": "higher", "description": "改进"},
254
+ "optimization": {"better": "higher", "description": "优化"},
255
+ "gain": {"better": "higher", "description": "增益"},
256
+ "benefit": {"better": "higher", "description": "收益"},
257
+ "profit": {"better": "higher", "description": "利润"},
258
+ "reward": {"better": "higher", "description": "奖励"},
259
+ "value": {"better": "higher", "description": "价值"},
260
+ "cost": {"better": "lower", "description": "成本"},
261
+ "expense": {"better": "lower", "description": "费用"},
262
+ "price": {"better": "lower", "description": "价格"},
263
+ "overhead": {"better": "lower", "description": "开销"},
264
+ "penalty": {"better": "lower", "description": "惩罚"},
265
+ "waste": {"better": "lower", "description": "浪费"},
266
+ "consumption": {"better": "lower", "description": "消耗"},
267
+ "runtime": {"better": "lower", "description": "运行时间"},
268
+ "time": {"better": "lower", "description": "时间"},
269
+ "latency": {"better": "lower", "description": "延迟"},
270
+ "delay": {"better": "lower", "description": "延迟"},
271
+ "wait": {"better": "lower", "description": "等待"},
272
+ "duration": {"better": "lower", "description": "持续时间"},
273
+ "elapsed": {"better": "lower", "description": "耗时"},
274
+ "timeout": {"better": "lower", "description": "超时"},
275
+ "memory": {"better": "lower", "description": "内存"},
276
+ "cpu": {"better": "lower", "description": "CPU使用"},
277
+ "gpu": {"better": "lower", "description": "GPU使用"},
278
+ "disk": {"better": "lower", "description": "磁盘"},
279
+ "storage": {"better": "lower", "description": "存储"},
280
+ "cache": {"better": "lower", "description": "缓存"},
281
+ "buffer": {"better": "lower", "description": "缓冲"},
282
+ "heap": {"better": "lower", "description": "堆"},
283
+ "stack": {"better": "lower", "description": "栈"},
284
+ "power": {"better": "lower", "description": "功率"},
285
+ "energy": {"better": "lower", "description": "能量"},
286
+ "thermal": {"better": "lower", "description": "热量"},
287
+ "temperature": {"better": "lower", "description": "温度"},
288
+ "heat": {"better": "lower", "description": "热量"},
289
+ "distance": {"better": "lower", "description": "距离"},
290
+ "deviation": {"better": "lower", "description": "偏差"},
291
+ "variance": {"better": "lower", "description": "方差"},
292
+ "std": {"better": "lower", "description": "标准差"},
293
+ "rmse": {"better": "lower", "description": "均方根误差"},
294
+ "mse": {"better": "lower", "description": "均方误差"},
295
+ "mae": {"better": "lower", "description": "平均绝对误差"},
296
+ "mape": {"better": "lower", "description": "平均绝对百分比误差"},
297
+ "count": {"better": "lower", "description": "计数"},
298
+ "size": {"better": "lower", "description": "大小"},
299
+ "length": {"better": "lower", "description": "长度"},
300
+ "width": {"better": "lower", "description": "宽度"},
301
+ "height": {"better": "lower", "description": "高度"},
302
+ "area": {"better": "lower", "description": "面积"},
303
+ "volume": {"better": "lower", "description": "体积"},
304
+ "weight": {"better": "lower", "description": "权重"},
305
+ "load": {"better": "lower", "description": "负载"},
306
+ "usage": {"better": "lower", "description": "使用量"},
307
+ "traffic": {"better": "lower", "description": "流量"},
308
+ "request": {"better": "lower", "description": "请求"},
309
+ "connection": {"better": "lower", "description": "连接"},
310
+ "session": {"better": "lower", "description": "会话"},
311
+ "overflow": {"better": "lower", "description": "溢出"},
312
+ "violation": {"better": "lower", "description": "违规"},
313
+ "conflict": {"better": "lower", "description": "冲突"},
314
+ "collision": {"better": "lower", "description": "碰撞"},
315
+ "deadlock": {"better": "lower", "description": "死锁"},
316
+ "retry": {"better": "lower", "description": "重试"},
317
+ "rollback": {"better": "lower", "description": "回滚"},
318
+ "p50": {"better": "lower", "description": "P50 延迟"},
319
+ "p90": {"better": "lower", "description": "P90 延迟"},
320
+ "p95": {"better": "lower", "description": "P95 延迟"},
321
+ "p99": {"better": "lower", "description": "P99 延迟"},
322
+ "p999": {"better": "lower", "description": "P99.9 延迟"},
323
+ "percentile": {"better": "lower", "description": "百分位延迟"},
324
+ "tail_latency": {"better": "lower", "description": "尾延迟"},
325
+ "taillatency": {"better": "lower", "description": "尾延迟"},
326
+ "packet_loss": {"better": "lower", "description": "丢包率"},
327
+ "packetloss": {"better": "lower", "description": "丢包率"},
328
+ "jitter": {"better": "lower", "description": "抖动"},
329
+ "ping": {"better": "lower", "description": "Ping延迟"},
330
+ "rtt": {"better": "lower", "description": "往返时延"},
331
+ "retransmit": {"better": "lower", "description": "重传"},
332
+ "snr": {"better": "higher", "description": "信噪比"},
333
+ "psnr": {"better": "higher", "description": "峰值信噪比"},
334
+ "ssim": {"better": "higher", "description": "结构相似度"},
335
+ "nmi": {"better": "higher", "description": "归一化互信息"},
336
+ "correlation": {"better": "higher", "description": "相关性"},
337
+ "wps": {"better": "higher", "description": "每秒写操作"},
338
+ "ops": {"better": "higher", "description": "每秒操作数"},
339
+ "eps": {"better": "higher", "description": "每秒事件数"},
340
+ "lps": {"better": "higher", "description": "每秒行数"},
341
+ "fragmentation": {"better": "lower", "description": "碎片率"},
342
+ "swap": {"better": "lower", "description": "交换区使用"},
343
+ "gc": {"better": "lower", "description": "GC暂停"},
344
+ "gc_pause": {"better": "lower", "description": "GC暂停时间"},
345
+ "gc_count": {"better": "lower", "description": "GC次数"},
346
+
347
+ }
348
+
349
+
350
+ def _build_pattern(keyword: str) -> re.Pattern:
351
+ escaped = re.escape(keyword).replace(r"\?", ".?")
352
+ return re.compile(rf"({escaped})", re.IGNORECASE)
353
+
354
+
355
+ def _matches_with_boundary(name_lower: str, keyword: str) -> bool:
356
+ """边界匹配:关键词前后必须是非字母数字字符或字符串边界。
357
+
358
+ 对应 JS matchesWithBoundary:'area' 匹配 'chip_area' 但不匹配 'hardware'。
359
+ """
360
+ if not keyword:
361
+ return False
362
+ pattern = re.compile(
363
+ r"(?<![a-z0-9])" + re.escape(keyword) + r"(?![a-z0-9])",
364
+ re.IGNORECASE,
365
+ )
366
+ return bool(pattern.search(name_lower))
367
+
368
+
369
+ def match_keyword(metric_name: str, library: dict | None = None) -> dict | None:
370
+ """在关键词库中匹配指标名称,返回匹配到的配置或 None。
371
+
372
+ 优先匹配最长关键词,避免短关键词抢先匹配。
373
+ 使用边界匹配(与 JS matchesWithBoundary 一致),确保 'area' 不误匹配 'hardware'。
374
+ """
375
+ if not metric_name or not isinstance(metric_name, str):
376
+ return None
377
+ lib = library or DEFAULT_KEYWORD_LIBRARY
378
+ name_lower = metric_name.lower()
379
+ # 按关键词长度降序排序,优先匹配最长关键词(与 JS matchKeyword 一致)
380
+ sorted_keywords = sorted(lib.items(), key=lambda x: len(x[0]), reverse=True)
381
+ for keyword, config in sorted_keywords:
382
+ if _matches_with_boundary(name_lower, keyword):
383
+ return {"keyword": keyword, **config}
384
+ return None
385
+
386
+
387
+ # 单位提取模式(按优先级排序)
388
+ _UNIT_PATTERNS = [
389
+ (re.compile(r"\(([^)]+)\)$"), lambda m: m.group(1)), # power(W) → W
390
+ (re.compile(r"\[([^\]]+)\]$"), lambda m: m.group(1)), # latency[ms] → ms
391
+ (re.compile(r"_([a-zμ²³°/·]+)$", re.IGNORECASE), lambda m: m.group(1)), # latency_ms → ms
392
+ (re.compile(r"\s*[-—]\s*([a-zμ²³°]+)$", re.IGNORECASE), lambda m: m.group(1)), # power - W → W
393
+ ]
394
+
395
+ # 已知单位白名单
396
+ _UNIT_WHITELIST = re.compile(
397
+ r"^(ms|s|us|ns|w|kw|mw|v|a|db|hz|khz|mhz|ghz|b|kb|mb|gb|tb|%|fps|rpm|°c|um|um²|nm|mm|cm|m|j|kj|cal)$",
398
+ re.IGNORECASE,
399
+ )
400
+
401
+
402
+ def extract_unit_from_name(metric_name: str) -> str:
403
+ """从指标名称中提取单位。
404
+
405
+ >>> extract_unit_from_name("power(W)")
406
+ 'W'
407
+ >>> extract_unit_from_name("latency_ms")
408
+ 'ms'
409
+ >>> extract_unit_from_name("area")
410
+ ''
411
+ """
412
+ if not metric_name or not isinstance(metric_name, str):
413
+ return ""
414
+ for pattern, extract in _UNIT_PATTERNS:
415
+ m = pattern.search(metric_name)
416
+ if m:
417
+ unit = extract(m).strip()
418
+ if _UNIT_WHITELIST.match(unit):
419
+ return unit
420
+ return ""
421
+
422
+
423
+ # 后缀方向推断规则(关键词库未匹配时的兜底)
424
+ _SUFFIX_DIRECTIONS = [
425
+ {
426
+ "better": "lower",
427
+ "suffixes": [
428
+ "time", "latency", "delay", "duration", "runtime", "elapsed",
429
+ "cost", "price", "expense",
430
+ "error", "err", "loss", "fail", "failure",
431
+ "power", "energy", "consumption",
432
+ "area", "size", "memory", "mem", "footprint",
433
+ "violations", "violation", "overflow", "congestion", "density",
434
+ "iterations", "iteration", "count",
435
+ ],
436
+ },
437
+ {
438
+ "better": "higher",
439
+ "suffixes": [
440
+ "accuracy", "acc", "precision", "recall", "f1", "auc", "iou",
441
+ "score", "rating", "gain", "profit", "reward", "yield",
442
+ "throughput", "tps", "qps", "fps", "iops", "bandwidth",
443
+ "util", "utilization", "coverage", "efficiency", "quality",
444
+ "speedup", "speed", "improvement",
445
+ "slack", "wns", "tns",
446
+ ],
447
+ },
448
+ ]
449
+
450
+
451
+ def infer_direction_by_suffix(metric_name: str) -> dict | None:
452
+ """基于列名后缀推断方向(关键词库未匹配时的兜底)。
453
+
454
+ 返回 {"better": "lower"|"higher", "matched_suffix": str} 或 None。
455
+ """
456
+ if not metric_name or not isinstance(metric_name, str):
457
+ return None
458
+ name_lower = metric_name.lower()
459
+ # 按长度降序匹配,优先匹配更长的后缀
460
+ all_suffixes = sorted(
461
+ [{"suffix": s, "better": g["better"]} for g in _SUFFIX_DIRECTIONS for s in g["suffixes"]],
462
+ key=lambda x: len(x["suffix"]),
463
+ reverse=True,
464
+ )
465
+ for item in all_suffixes:
466
+ suffix = item["suffix"]
467
+ idx = name_lower.rfind(suffix)
468
+ if idx == -1:
469
+ continue
470
+ if idx + len(suffix) != len(name_lower):
471
+ continue
472
+ # 前一个字符必须是分隔符或字符串开始
473
+ if idx == 0 or name_lower[idx - 1] in "_- /.":
474
+ return {"better": item["better"], "matched_suffix": suffix}
475
+ return None
476
+
477
+
478
+ def infer_better_direction(metric_name: str) -> dict:
479
+ """根据指标名称推断优化方向。
480
+
481
+ 优先匹配关键词库;未匹配时尝试从列名提取单位并基于后缀推断方向。
482
+ """
483
+ if not metric_name or not isinstance(metric_name, str):
484
+ return {"better": None, "target": None, "description": "", "is_keyword_matched": False}
485
+ matched = match_keyword(metric_name)
486
+ if matched:
487
+ return {
488
+ "better": matched["better"],
489
+ "target": matched.get("target"),
490
+ "description": matched.get("description", ""),
491
+ "is_keyword_matched": True,
492
+ "matched_keyword": matched["keyword"],
493
+ }
494
+ # 兜底 1:从列名提取单位
495
+ fallback_unit = extract_unit_from_name(metric_name)
496
+ # 如果提取到单位,去除单位部分再做后缀推断
497
+ # 例如 'carbon_footprint_ms' → 'carbon_footprint' → 'footprint' 后缀匹配
498
+ name_for_suffix = metric_name
499
+ if fallback_unit:
500
+ name_for_suffix = re.sub(r"\s*\([^)]+\)\s*$", "", metric_name)
501
+ name_for_suffix = re.sub(r"\s*\[[^\]]+\]\s*$", "", name_for_suffix)
502
+ name_for_suffix = re.sub(r"[_\-\s/][a-zμ²³°]+$", "", name_for_suffix, flags=re.IGNORECASE)
503
+ name_for_suffix = name_for_suffix.strip()
504
+ # 兜底 2:基于后缀推断方向(在去除单位后的名称上)
505
+ suffix_dir = infer_direction_by_suffix(name_for_suffix)
506
+ return {
507
+ "better": suffix_dir["better"] if suffix_dir else None,
508
+ "target": None,
509
+ "description": "",
510
+ "is_keyword_matched": False,
511
+ "is_suffix_inferred": bool(suffix_dir),
512
+ "matched_suffix": suffix_dir["matched_suffix"] if suffix_dir else None,
513
+ "is_suffix_extracted": bool(fallback_unit),
514
+ "unit": fallback_unit,
515
+ "confidence": 0.5 if suffix_dir else 0,
516
+ }
@@ -61,18 +61,18 @@ def detect_knee_point(
61
61
  frontier_points: 前沿点数组,每个点包含 { x, y, caseName, raw, algo }
62
62
  options: 选项
63
63
  - x_reversed: X 轴是否反转(higher is better)
64
- - y_reversed: Y 轴是否反转(higher is better)
65
64
 
66
65
  Returns:
67
66
  拐点信息 { point, index, distance, extremes, sorted_frontier } 或 None
67
+
68
+ 注:y_reversed 不参与拐点算法(最大距离法只按 X 排序,Y 方向不影响距离几何),
69
+ 与 JS detectKneePoint 保持一致,不暴露该参数。
68
70
  """
69
71
  if not frontier_points or len(frontier_points) < 3:
70
72
  return None
71
73
 
72
74
  opts = options or {}
73
75
  x_reversed = opts.get("x_reversed", False)
74
- # y_reversed 在 JS 中存在但未影响本算法逻辑,保持参数一致性
75
- # y_reversed = opts.get("y_reversed", False)
76
76
 
77
77
  # 按 X 排序(考虑方向:如果反转,则降序)
78
78
  sorted_points = sorted(