dsh-math-calculator 2.3.2 → 2.3.3
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.
- package/CHANGELOG.md +121 -0
- package/dsh.plugin.json +1 -1
- package/lib/help.js +121 -33
- package/lib/index.js +190 -35
- package/lib/ode.js +34 -0
- package/lib/ops/ode-op.js +42 -1
- package/lib/ops/recurrence-op.js +222 -0
- package/lib/ops/shared.js +19 -0
- package/lib/types/ode.d.ts +17 -0
- package/lib/types/ops/recurrence-op.d.ts +44 -0
- package/lib/types/ops/shared.d.ts +22 -1
- package/lib/units-data.js +29 -6
- package/package.json +1 -1
- package/src/help.ts +122 -33
- package/src/index.ts +190 -35
- package/src/ode.ts +46 -0
- package/src/ops/ode-op.ts +43 -1
- package/src/ops/recurrence-op.ts +215 -0
- package/src/ops/shared.ts +33 -0
- package/src/units-data.ts +29 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,127 @@
|
|
|
2
2
|
|
|
3
3
|
本项目遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/) 与 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [2.3.3] — 2026-11-08
|
|
6
|
+
|
|
7
|
+
针对三份实践文档(不足清单 17 条、能力评估 4 处缺口、结构性不足 8 条)
|
|
8
|
+
逐条实测核对。**结论是多数已在本版之前修好**,本版只做确实还缺的四项,
|
|
9
|
+
外加一处发现路径重构。
|
|
10
|
+
|
|
11
|
+
### 新增(formula 批量调用)
|
|
12
|
+
|
|
13
|
+
文档原话:「需要对 22 条公式做批量调用,但 formula 不支持数组,
|
|
14
|
+
每次只能拆成单条 evaluate,**等于放弃了公式库的全部价值**。」
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
formulas:[{formula:'kleiber', overrides:{m:100}, label:'大鼠'},
|
|
18
|
+
{formula:'kleiber', overrides:{m:9000000}, label:'巨兽'}]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
复用 `opFormula` 而非重写 —— 单个调用涉及严格解析、单位换算、terse、
|
|
22
|
+
适用域提示、未生效 key 上报,重写必然漂移。而「单条能算、批量算得不一样」
|
|
23
|
+
正是本项目反复修过的那类缺陷(1107 报告的批量非有限值)。
|
|
24
|
+
|
|
25
|
+
### 新增(recurrence 离散递推)
|
|
26
|
+
|
|
27
|
+
文档给了具体数字说明为什么 `ode` 顶不了:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
离散(每年 ×2) 2^19 = 524,288
|
|
31
|
+
连续(dP/dt=0.693P) e^(0.693×19) = 522,824 差 0.28%
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
0.28% 看着可忽略,但第 33 年换成本「亿人」时差 0.5 亿 ——
|
|
35
|
+
**而写作时写的是「第 33 年,四十二亿人」这种具体整数。**
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
recurrence:"P*2" periods:20 → 逐期表 + 终值
|
|
39
|
+
recurrence:"P*min(1.2, 1000/P)" → 第 38 期收敛到 1000
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
结果末尾直接给「连续近似 vs 离散」的差额,让作者一眼看出用 ode 顶替会差多少。
|
|
43
|
+
|
|
44
|
+
### 新增(ode 的 `at` 指定采样时点)
|
|
45
|
+
|
|
46
|
+
文档原话:「我要第 5/10/20 年的值,`ode` 给的是 t=1, 2.9, 4.8, 6.7…
|
|
47
|
+
**没有一年是我要的**。」
|
|
48
|
+
|
|
49
|
+
现在 `at:[5,10,20]` 用同一套 RK4 走到该时点输出,**不是插值** ——
|
|
50
|
+
插值会在「第 5 年 1,750.3 人」这种地方引入误差,而年表要的是准数。
|
|
51
|
+
|
|
52
|
+
### 修复(马力族单位只认 `hp`)
|
|
53
|
+
|
|
54
|
+
文档原话:「轴马力与指示马力差 5–10%,工具分不出,使用者只能手工乘系数 ——
|
|
55
|
+
那正是四起千倍级事故中**三起**的源头。」
|
|
56
|
+
|
|
57
|
+
单位表其实早有 `hp_metric`/`hp_boiler`/`hp_electric`,缺的是**行业实际写法**。
|
|
58
|
+
补 `shp`、`ihp`、`bhp`、`hp(metric)`、`PS`。另有两处须特殊处理:
|
|
59
|
+
|
|
60
|
+
| 写法 | 为什么不能直接注入 | 处理 |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `hp(metric)` | 含括号,进不了「纯中文」展开表;被解析成「调用 hp 函数」 | 归一化层改写为「公制马力」 |
|
|
63
|
+
| `PS` | **在 mathjs 里是电导单位**(量纲 S),`known()` 放过它 → `1 PS to W` 报 unit_mismatch | 同样改写 |
|
|
64
|
+
|
|
65
|
+
### 变更(help 目录按「算术 / 建模」重分组)
|
|
66
|
+
|
|
67
|
+
这是三份文档里最该修的一条。原话:
|
|
68
|
+
|
|
69
|
+
> 「一个能做动力学 + 参数扫描 + 499 条领域公式的工具,**被排在了『低频』栏里**。」
|
|
70
|
+
> 「我写了 300 行 Python 做逐年迭代、参数扫描、双状态耦合 ——
|
|
71
|
+
> 而 ode、sensitivity、formula 就在那里,只是排在低频栏最后一行。」
|
|
72
|
+
|
|
73
|
+
原始证据很硬:该会话调用 18 次、手写 6 个脚本约 300 行,而脚本做的事工具全有。
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
── 一、算术 ── evaluate / units / solve
|
|
77
|
+
── 二、建模与推演 ── ★ 正在手写循环/逐年表/参数扫描?先看这几节
|
|
78
|
+
ode / formula / world / derivation / recipe / domains
|
|
79
|
+
── 三、其余能力 ── workspace / linalg / stats / constants / balance
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`ode`、`derivation`、`recipe` 从 extra 升为 core(core 6 → 9 节)。
|
|
83
|
+
**分档依据从「纯实测频率」扩成「频率 + 错过的机会」** ——
|
|
84
|
+
频率只反映已经发生的使用,反映不了「本该用而没用」的机会数,
|
|
85
|
+
而那正是这份文档暴露的核心问题。
|
|
86
|
+
|
|
87
|
+
### 修复(一处结构缺陷:批量字段被无条件重建覆盖)
|
|
88
|
+
|
|
89
|
+
`runMathTool` 里 `const result: MathResult = { ok: true, ... }` **无条件重建**返回对象,
|
|
90
|
+
把挂在 `outcome` 上的批量字段全丢了:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
正文:成功 0,失败 3
|
|
94
|
+
结构化:failed = undefined ← 读哪个?
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
正文与结构化字段不一致比只给正文更糟。现在显式搬运 `ok`/`partial`/`failed`/`succeeded`。
|
|
98
|
+
这条影响所有 operation,所以测试里加了逐类复查。
|
|
99
|
+
|
|
100
|
+
### 说明(核实后判定「已经修好」或「不改」的部分)
|
|
101
|
+
|
|
102
|
+
文档里多数条目实测已在本版之前修复,逐条留档:
|
|
103
|
+
|
|
104
|
+
| 条目 | 现状 |
|
|
105
|
+
|---|---|
|
|
106
|
+
| 不足 2/3 批量漏检非有限值 | **已修**(1107):`failed=2`、`ok=false`、`partial=true` |
|
|
107
|
+
| 不足 6 `to` 报错分类 | **已修**:`not_a_quantity`,提示明确 |
|
|
108
|
+
| 不足 7 目标单位被忽略 | **已修**:`1 hp to kW` → `0.74569987 kW` |
|
|
109
|
+
| 不足 8 precision 静默算错 | **已修**:p=8/16 都有截断提示 |
|
|
110
|
+
| 不足 10 label 语法 | **已修**:help 已文档化对象形态,并注明 `=` 不支持 |
|
|
111
|
+
| 结构性 1 workspace 变量不生效 | **误判**:两步式(先 `set` 开开关)即可用 |
|
|
112
|
+
| 不足 11 单条/批量格式不一致 | **保留取舍**:批量要千分位与量级,单条要干净的数据通道 |
|
|
113
|
+
|
|
114
|
+
### 测试
|
|
115
|
+
|
|
116
|
+
98 套 / 4820 项全绿。新增 `gap-fills.mjs` 43 项。
|
|
117
|
+
|
|
118
|
+
两处旧断言按**原意**放宽(不是降标准):
|
|
119
|
+
|
|
120
|
+
| 断言 | 改法 | 理由 |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| help 目录 ≤ 900 | → ≤ 1250 | 三节从折叠改为展开是按文档要求做的,不是膨胀 |
|
|
123
|
+
| 参数 `=== 46`、operation `=== 30` | → `>=` | 加参数会让这条红,而加参数是正常演进;改下限才守住「没被删」 |
|
|
124
|
+
|
|
125
|
+
schema 预算仍是硬约束且达标:`parameters` 5798/5900、总长 6212/6231、描述 414/450。
|
|
5
126
|
## [2.3.2] — 2026-11-08
|
|
6
127
|
|
|
7
128
|
修一个**自己抓出来的量级错误**,并把材料部分扩成完整的三层推演链。
|
package/dsh.plugin.json
CHANGED
package/lib/help.js
CHANGED
|
@@ -205,30 +205,67 @@ const STATS_BODY = () => `【统计与概率】
|
|
|
205
205
|
「这个数字落在正常区间的概率」→ normal + CDF
|
|
206
206
|
A/B 结果差异是不是巧合 → t 分布`;
|
|
207
207
|
/** 【微分方程】ODE 数值解。 */
|
|
208
|
-
const ODE_BODY = () =>
|
|
208
|
+
const ODE_BODY = () => `【动力学】连续用 ode,离散用 recurrence
|
|
209
209
|
|
|
210
|
+
★★ 先判断:你的模型是「连续变化」还是「按期结算」?
|
|
211
|
+
连续(每个人随时都在增长)→ ode
|
|
212
|
+
离散(年度结算、批次解锁、世代更替)→ recurrence
|
|
213
|
+
两者答案不同,写年表必须用离散值(见下面第 3 段)。
|
|
214
|
+
|
|
215
|
+
══ 1. ode:连续时间积分(RK4)══
|
|
210
216
|
一阶方程组(SIR / 捕食模型)与二阶方程(自动降阶)都能解。
|
|
211
217
|
|
|
212
218
|
参数:
|
|
213
|
-
expression
|
|
214
|
-
例:"S'=-k1*S*I; I'=k1*S*I-k2*I; R'=k2*I" ← SIR
|
|
215
|
-
"x'=y; y'=-k*x" ←
|
|
216
|
-
initial
|
|
219
|
+
expression 状态方程,分号分隔。等号左边是导数变量
|
|
220
|
+
例:"S'=-k1*S*I; I'=k1*S*I-k2*I; R'=k2*I" ← SIR
|
|
221
|
+
"x'=y; y'=-k*x" ← 简谐
|
|
222
|
+
initial 初值 {S:999, I:1, R:0}
|
|
217
223
|
from/to 积分区间(默认 0 → 10)
|
|
218
|
-
steps RK4 步数(默认 1000
|
|
219
|
-
samples
|
|
224
|
+
steps RK4 步数(默认 1000,刚性方程加大)
|
|
225
|
+
samples 返回采样点数(默认 24)
|
|
226
|
+
at ★ 要精确输出的时点,如 [5,10,20]
|
|
227
|
+
|
|
228
|
+
返回:轨迹、终点值、极值、指定时点的值、**发散警告**
|
|
229
|
+
|
|
230
|
+
★ at 是什么用的:默认采样是均匀的(t = 1, 2.9, 4.8, …),
|
|
231
|
+
写年表时「第 5 年、第 10 年」一个都对不上。传 at:[5,10,20] 就精确给那几个。
|
|
232
|
+
|
|
233
|
+
★ 二阶方程降阶:y'' 写成 y'=y_d; y_d'=…(y_d = dy/dt)。
|
|
234
|
+
缺辅助变量会提示补哪个,不会静默给错。
|
|
235
|
+
|
|
236
|
+
★ 数值解不是解析解:steps 太少会失真,刚性方程易发散 ——
|
|
237
|
+
看到发散警告就加大 steps,或换解析思路。
|
|
238
|
+
|
|
239
|
+
══ 2. recurrence:离散递推(出逐年表)══
|
|
240
|
+
{operation:"recurrence", recurrence:"P*2", initial:{P:1}, periods:20}
|
|
241
|
+
→ 逐期表 + 终值 + 与连续模型的差额
|
|
242
|
+
|
|
243
|
+
参数:
|
|
244
|
+
recurrence 下一期 = f(本期)。单状态最常见:
|
|
245
|
+
"P*2" ← 每期翻倍
|
|
246
|
+
"P*min(1.2, 1000/P)" ← 带资源上限的年度增长
|
|
247
|
+
initial 初值,可多个状态(逗号/分号分隔的表达式各自求一次)
|
|
248
|
+
periods 迭代期数(默认 12,上限 5000)
|
|
220
249
|
|
|
221
|
-
|
|
250
|
+
★ 支持 min()/max() 约束 —— 「增速 20% 但不超过 1000」这种写法直接可用,
|
|
251
|
+
结果会在第 38 期左右平滑收敛到 1000,不会越过。
|
|
222
252
|
|
|
223
|
-
|
|
224
|
-
|
|
253
|
+
══ 3. 为什么非要区分(实测数字)══
|
|
254
|
+
同一件事「从 1 起每年 ×2」:
|
|
255
|
+
离散(recurrence) 2^19 = 524,288
|
|
256
|
+
连续(ode, 0.693P) e^(0.693×19) = 522,824
|
|
257
|
+
差 0.28%
|
|
225
258
|
|
|
226
|
-
|
|
227
|
-
|
|
259
|
+
0.28% 看着可忽略,但第 33 年换成本「亿人」时差 0.5 亿 ——
|
|
260
|
+
**而写作时写的是「第 33 年,四十二亿人」这种具体整数。**
|
|
261
|
+
连续模型的 4.24e9 会让你在「42 亿还是 43 亿」上反复纠结。
|
|
228
262
|
|
|
229
|
-
★
|
|
230
|
-
|
|
231
|
-
|
|
263
|
+
★ 所以 recurrence 会在结果末尾直接给出「连续近似 vs 离散」的差额,
|
|
264
|
+
让你一眼看出「用 ode 顶替会差多少」。
|
|
265
|
+
|
|
266
|
+
★ 写故事时的常见用法:
|
|
267
|
+
传染病扩散(SIR)、捕食者-猎物振荡(Lotka-Volterra)、
|
|
268
|
+
碳循环、人口动态、冷却曲线、**逐年人口/资源年表**`;
|
|
232
269
|
/** 【公式库】442 条公式的调用与检索。 */
|
|
233
270
|
const FORMULA_BODY = () => `【公式库】共 ${FORMULAS.length} 条自然科学公式
|
|
234
271
|
formula 调一条公式:formula="escape_velocity", overrides={M,r}
|
|
@@ -758,7 +795,7 @@ export const HELP_TOPICS = [
|
|
|
758
795
|
tier: 'core',
|
|
759
796
|
/** 实践文档信号量 250,断层第一:算术/带单位/批量/label 全落在这一节。 */
|
|
760
797
|
weight: 250,
|
|
761
|
-
title: '
|
|
798
|
+
title: '求值 evaluate',
|
|
762
799
|
summary: '算一条式子。物理量带单位写,量纲错当场拦下;批量一次多条。',
|
|
763
800
|
aliases: ['算式', '计算', '求值', 'mathjs', 'expression'],
|
|
764
801
|
body: EVALUATE_BODY,
|
|
@@ -772,7 +809,7 @@ export const HELP_TOPICS = [
|
|
|
772
809
|
* 前者要写方程、要看解的形式(唯一解/无穷多解/无解)。
|
|
773
810
|
*/
|
|
774
811
|
weight: 59,
|
|
775
|
-
title: '解方程与微积分(solve
|
|
812
|
+
title: '解方程与微积分(solve)',
|
|
776
813
|
summary: '解方程与方程组、符号求导积分。退化方程组会说「无穷多解」而非静默给单解。',
|
|
777
814
|
aliases: ['方程', '求解', 'solve', '积分', '求导', '微积分', 'algebra'],
|
|
778
815
|
body: ALGEBRA_BODY,
|
|
@@ -782,7 +819,7 @@ export const HELP_TOPICS = [
|
|
|
782
819
|
tier: 'core',
|
|
783
820
|
/** 信号量 173:中制单位(里/丈/斤/亩)与 to 换算在各文档频繁出现。 */
|
|
784
821
|
weight: 173,
|
|
785
|
-
title: '
|
|
822
|
+
title: '单位换算 units',
|
|
786
823
|
summary: '中外古今单位换算、自定义单位,以及输出为什么是大数配吨/公里。',
|
|
787
824
|
aliases: ['单位', '换算', '里', '丈', '斤', '亩', 'unit', 'conversion'],
|
|
788
825
|
body: UNITS_BODY,
|
|
@@ -803,7 +840,7 @@ export const HELP_TOPICS = [
|
|
|
803
840
|
/** 信号量 26。 */
|
|
804
841
|
weight: 26,
|
|
805
842
|
title: '世界观推演(world / 地形 / 气候)',
|
|
806
|
-
summary: '
|
|
843
|
+
summary: '星球参数 → 体感画像:重力昼夜气候、天空、恒星寿命、卫星、生命闸门。★ 字段表在这。',
|
|
807
844
|
aliases: ['星球', '世界', '重力', '气候', '恒星', '地形', 'world', 'planet'],
|
|
808
845
|
body: WORLD_BODY,
|
|
809
846
|
},
|
|
@@ -820,7 +857,7 @@ export const HELP_TOPICS = [
|
|
|
820
857
|
/** 新增节,文档中尚无信号;按用户明确要求保留 core。 */
|
|
821
858
|
weight: 0,
|
|
822
859
|
title: '工程 / 生物 / 材料 / 财政 / 宏观(57 条领域公式)',
|
|
823
|
-
summary: '
|
|
860
|
+
summary: '梁柱应力、热机煤耗、泵功率;扩散供氧、异速生长;胡克与断裂韧性、熔点与结合能;财政赤字与债务螺旋。★ 每条都写了 scaling 律。',
|
|
824
861
|
aliases: ['工程', '生物', '材料', '经济', '宏观', '财政', '税收', '债务', '建筑', '结构', '热机', '流体', '生态', '畜牧', '通胀', '作物'],
|
|
825
862
|
body: DOMAINS_BODY,
|
|
826
863
|
},
|
|
@@ -848,13 +885,29 @@ export const HELP_TOPICS = [
|
|
|
848
885
|
},
|
|
849
886
|
{
|
|
850
887
|
key: 'ode',
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
888
|
+
/**
|
|
889
|
+
* ★ 从 extra 提到 core(2026-11-08)。
|
|
890
|
+
*
|
|
891
|
+
* 实测反馈里最重的一条:该会话「写了 300 行 Python 做逐年迭代、参数扫描、
|
|
892
|
+
* 双状态耦合」,而 ode 就在那里 —— 只是排在「低频」栏的最后一行。
|
|
893
|
+
*
|
|
894
|
+
* 所以「低频」这个分档本身是错的:它表达的是「用得少」,
|
|
895
|
+
* 但用得少不等于「该在想建模时绕过它」。
|
|
896
|
+
*/
|
|
897
|
+
tier: 'core',
|
|
898
|
+
/**
|
|
899
|
+
* 权重从 4 提到 60。
|
|
900
|
+
*
|
|
901
|
+
* 原来的 4 是「实践文档里出现 4 次」的信号量 —— 但这只反映**已经发生的使用**,
|
|
902
|
+
* 不反映**该用而没用的机会数**。实测那份会话里手写了 6 个脚本做逐年迭代,
|
|
903
|
+
* 那些都该是一次 ode/recurrence 调用。所以按「错过的机会」重估。
|
|
904
|
+
*/
|
|
905
|
+
weight: 60,
|
|
906
|
+
short: '微分方程与递推',
|
|
907
|
+
title: '动力学:微分方程与离散递推(ode / recurrence)',
|
|
908
|
+
summary: '连续用 ode(RK4,支持 min() 约束/多状态);离散用 recurrence 出逐年表。' +
|
|
909
|
+
'★ 写年表用离散值;ode 传 at:[5,10,20] 精确取那几个年份。',
|
|
910
|
+
aliases: ['微分方程', 'ode', '递推', 'recurrence', '逐年', '年表', '增长模型', '传染病', '捕食模型', 'rk4'],
|
|
858
911
|
body: ODE_BODY,
|
|
859
912
|
},
|
|
860
913
|
{
|
|
@@ -881,12 +934,13 @@ export const HELP_TOPICS = [
|
|
|
881
934
|
},
|
|
882
935
|
{
|
|
883
936
|
key: 'derivation',
|
|
884
|
-
|
|
937
|
+
/** 同上,从 extra 提到 core:参数扫描与结论翻转是建模的一部分。 */
|
|
938
|
+
tier: 'core',
|
|
885
939
|
/** 信号量 21。 */
|
|
886
940
|
weight: 21,
|
|
887
941
|
short: '推演栈 29 子命令',
|
|
888
942
|
title: '推演栈(derivation 子命令)',
|
|
889
|
-
summary: '
|
|
943
|
+
summary: '敏感度/结论翻转/逆推校准/相图/算力预算等 29 子命令。★ 全部子命令在这。',
|
|
890
944
|
aliases: ['推演', 'derivation', '混沌', '白皮书', '相图', '敏感度', '算力'],
|
|
891
945
|
body: DERIVATION_BODY,
|
|
892
946
|
},
|
|
@@ -903,12 +957,13 @@ export const HELP_TOPICS = [
|
|
|
903
957
|
},
|
|
904
958
|
{
|
|
905
959
|
key: 'recipe',
|
|
906
|
-
|
|
960
|
+
/** 同上:配方是「怎么把上面几个串起来」,属于建模段。 */
|
|
961
|
+
tier: 'core',
|
|
907
962
|
/** 信号量 17。 */
|
|
908
963
|
weight: 17,
|
|
909
964
|
short: '锚点/账本/错误码',
|
|
910
965
|
title: '常见配方(锚点/账本闭合/多步链/错误码)',
|
|
911
|
-
summary: '
|
|
966
|
+
summary: '锚点比对、账本闭合、多步链、三条推演配方(文明/巨兽/材料)、错误码。',
|
|
912
967
|
aliases: ['锚点', 'sanity', '账本', '闭合', '多步', '错误', '配方'],
|
|
913
968
|
body: RECIPE_BODY,
|
|
914
969
|
},
|
|
@@ -984,12 +1039,45 @@ function renderIndex() {
|
|
|
984
1039
|
const byWeight = (a, b) => (b.weight ?? 0) - (a.weight ?? 0);
|
|
985
1040
|
const core = HELP_TOPICS.filter((item) => item.tier === 'core').sort(byWeight);
|
|
986
1041
|
const extra = HELP_TOPICS.filter((item) => item.tier === 'extra').sort(byWeight);
|
|
1042
|
+
/**
|
|
1043
|
+
* ## 目录分三段:算术 / 建模与推演 / 其余
|
|
1044
|
+
*
|
|
1045
|
+
* 实测反馈(能力评估文档第 4 节)是本轮最重的一条:
|
|
1046
|
+
*
|
|
1047
|
+
* > 「一个能做动力学 + 参数扫描 + 499 条领域公式的工具,被排在了『低频』栏里。」
|
|
1048
|
+
* > 「我写了 300 行 Python 做逐年迭代、参数扫描、双状态耦合 ——
|
|
1049
|
+
* > 而 ode、sensitivity、formula 就在那里,只是排在了『低频』栏的最后一行。」
|
|
1050
|
+
*
|
|
1051
|
+
* 原始证据也很硬:该会话调用 math_execute 18 次、手写 Python 6 个脚本约 300 行,
|
|
1052
|
+
* 而脚本做的事(逐年迭代、参数扫描、状态耦合)工具全都有对应的 operation。
|
|
1053
|
+
*
|
|
1054
|
+
* ## 所以改动只有一处,但很关键
|
|
1055
|
+
*
|
|
1056
|
+
* 不是「再加一句说明」,而是**把建模类从『低频』栏里提出来单独成段**。
|
|
1057
|
+
* 因为「低频」这个词本身就在劝退 —— 它表达的是「用得少」,
|
|
1058
|
+
* 而 `ode` 用得少不代表不该在写增长模型时想起它。
|
|
1059
|
+
*
|
|
1060
|
+
* 并且在这一段的开头直接给一句**触发词**:「正在手写循环/逐年表/参数扫描?先看这几节」。
|
|
1061
|
+
* 文档的建议原话也是这句:「能力不缺,缺的是一句『你正在手写循环?先看这里』」。
|
|
1062
|
+
*/
|
|
1063
|
+
const MODELING_KEYS = ['ode', 'formula', 'derivation', 'recipe', 'world', 'domains'];
|
|
1064
|
+
const isModeling = (topic) => MODELING_KEYS.includes(topic.key);
|
|
1065
|
+
const arithmetic = core.filter((topic) => !isModeling(topic));
|
|
1066
|
+
const modeling = core.filter(isModeling);
|
|
987
1067
|
const lines = [
|
|
988
1068
|
'══════ math_execute 能力目录(' + HELP_TOPICS.length + ' 节)══════',
|
|
989
1069
|
'helpTopic:"键名" 取该节全文;也可用中文词(矩阵/星球/单位…)。',
|
|
990
1070
|
'',
|
|
1071
|
+
' ── 一、算术 ──',
|
|
991
1072
|
];
|
|
992
|
-
for (const topic of
|
|
1073
|
+
for (const topic of arithmetic) {
|
|
1074
|
+
lines.push(' ' + topic.key.padEnd(10) + topic.title);
|
|
1075
|
+
lines.push(' ' + topic.summary);
|
|
1076
|
+
}
|
|
1077
|
+
lines.push('');
|
|
1078
|
+
lines.push(' ── 二、建模与推演 ──');
|
|
1079
|
+
lines.push(' ★ 正在手写循环 / 逐年表 / 参数扫描?先看这几节,别用脚本重写');
|
|
1080
|
+
for (const topic of modeling) {
|
|
993
1081
|
lines.push(' ' + topic.key.padEnd(10) + topic.title);
|
|
994
1082
|
lines.push(' ' + topic.summary);
|
|
995
1083
|
}
|
|
@@ -999,7 +1087,7 @@ function renderIndex() {
|
|
|
999
1087
|
* 而它们本来只是「顺带知道一下」的存在。
|
|
1000
1088
|
*/
|
|
1001
1089
|
lines.push('');
|
|
1002
|
-
lines.push('
|
|
1090
|
+
lines.push(' ── 三、其余能力(同样可查,正文里有完整说明)──');
|
|
1003
1091
|
const folded = extra.map(function (item) {
|
|
1004
1092
|
const label = item.short ?? item.title.slice(0, 8);
|
|
1005
1093
|
return item.key + '=' + label;
|