lingshu-solver 1.0.4 → 1.0.7
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/index.html +71 -10
- package/package.json +2 -2
package/index.html
CHANGED
|
@@ -4737,7 +4737,7 @@ function suan7(state) {
|
|
|
4737
4737
|
for (var kb in known) ibox[kb] = { min: known[kb], max: known[kb] };
|
|
4738
4738
|
ibox[uv] = box;
|
|
4739
4739
|
var iF = intervalEval(eq, ibox);
|
|
4740
|
-
if (iF && (iF
|
|
4740
|
+
if (iF && _ivExcludesZero(iF)) {
|
|
4741
4741
|
state.done = true;
|
|
4742
4742
|
var knownList = Object.keys(known).sort().map(function(v) { return v + "=" + known[v]; }).join(", ");
|
|
4743
4743
|
state.result = { solutions: [], error: "NO_SOLUTION", message: "前向传播检测到矛盾:代入已知值后,方程在变量 " + uv + " 的全域上 f 的严格区间包络不含 0(包络=[" + iF.min.toExponential(2) + "," + iF.max.toExponential(2) + "]),严格证明无根", detail: "已知值: " + knownList, executionPath: "前向传播矛盾检测", timeMs: performance.now() - state.startTime, confidence: "high", varNames: state.varNames, resultType: 1, resultTypeName: "空结果", resultTypeDesc: "前向传播检测到矛盾" };
|
|
@@ -5833,6 +5833,9 @@ function suan22(state) {
|
|
|
5833
5833
|
_walk1(_eq);
|
|
5834
5834
|
})();
|
|
5835
5835
|
if (_lo < _hi) {
|
|
5836
|
+
var _dense = false; // 修3:根稠密/超时提前终止扫描(防宽域周期方程穷举挂起)
|
|
5837
|
+
var _denseByCount = false; // 修3:仅由"根数超阈值"触发的稠密标记(用于无限/截断判定,区别于超时触发)
|
|
5838
|
+
var _denseNonPeriodic = false; // 修3:非周期稠密截断标记(与 periodic→无限 分支互补)
|
|
5836
5839
|
// ---- 周期感知步长(issue A 修复 2026-09-01):高频/多周期方程用 < 周期/2 的网格,
|
|
5837
5840
|
// 确保不漏根;非周期方程回退到 4096 点默认细网格。点数上限 _NMAX 护栏防宽域爆炸。 ----
|
|
5838
5841
|
var _P = _detectPeriod1D(_eq, _vn);
|
|
@@ -5902,8 +5905,11 @@ function suan22(state) {
|
|
|
5902
5905
|
_recScanInterval(_eq, _vn, _gxP, _gx, state, allSolutions, resultVarNames, 0);
|
|
5903
5906
|
}
|
|
5904
5907
|
}
|
|
5908
|
+
if (allSolutions.length > 200) { _dense = true; _denseByCount = true; break; }
|
|
5909
|
+
if ((performance.now() - state.startTime) > 1500) { _dense = true; break; }
|
|
5905
5910
|
_gxP = _gx; _gfP = _gf;
|
|
5906
5911
|
}
|
|
5912
|
+
if (_dense) break;
|
|
5907
5913
|
// 终止端点若有根也记录
|
|
5908
5914
|
if (_gfP !== null && Math.abs(_gfP) < 1e-7) {
|
|
5909
5915
|
var _fbV = reconstructSolution(state, [_B]).map(roundToGrid);
|
|
@@ -5951,6 +5957,31 @@ function suan22(state) {
|
|
|
5951
5957
|
if (_dedupMap[_mi]) mergedSolutions.push(_dedupMap[_mi]);
|
|
5952
5958
|
}
|
|
5953
5959
|
|
|
5960
|
+
// 修3(2026-09-04):稠密根防护——单变量周期方程在宽域内根稠密,
|
|
5961
|
+
// 继续穷举既耗时(曾致 solve 挂起 >110s)又产出无用的海量解集。
|
|
5962
|
+
// 含周期函数且根数超阈值 ⇒ 解集实际为无限(周期平移),如实标 rt=3 无限解集(代表解);
|
|
5963
|
+
// 非周期但稠密(如高次多项式)⇒ 不谎称无限,置 truncated 并后续告警,诚实返回部分代表根。
|
|
5964
|
+
if (_denseByCount) {
|
|
5965
|
+
if (_P !== null) {
|
|
5966
|
+
state.done = true;
|
|
5967
|
+
state.result = {
|
|
5968
|
+
solutions: mergedSolutions,
|
|
5969
|
+
error: null,
|
|
5970
|
+
message: "单变量周期方程在声明域内出现大量(>" + 200 + ")孤立根,呈周期性稠密分布,解集实际为无限(如 x = x₀ + k·" + _P.toFixed(4) + ")。已给出 " + mergedSolutions.length + " 个代表根;如需有限个解请收窄变量定义域。",
|
|
5971
|
+
executionPath: "单变量稠密周期根判定(无限解集)",
|
|
5972
|
+
timeMs: performance.now() - state.startTime,
|
|
5973
|
+
confidence: "high",
|
|
5974
|
+
varNames: resultVarNames,
|
|
5975
|
+
resultType: 3,
|
|
5976
|
+
resultTypeName: "无限解集(代表解)",
|
|
5977
|
+
resultTypeDesc: "周期方程在宽域内根稠密,解集为周期平移的无穷集合,已给出代表根"
|
|
5978
|
+
};
|
|
5979
|
+
return;
|
|
5980
|
+
}
|
|
5981
|
+
state.truncated = true; // 非周期稠密:诚实截断(避免海量/不完整解集),下方 domainFiltered 产出部分代表根
|
|
5982
|
+
_denseNonPeriodic = true;
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5954
5985
|
// 2) 原始方程回代验证:对每组候选解,代入全部原始方程重新计算残差
|
|
5955
5986
|
// 二分查找得到的解(_bisect=true)跳过残差验证(区间收敛保证精度)
|
|
5956
5987
|
var _origEqs = state.originalEquations || state.equations;
|
|
@@ -6082,6 +6113,12 @@ function suan22(state) {
|
|
|
6082
6113
|
}
|
|
6083
6114
|
}
|
|
6084
6115
|
}
|
|
6116
|
+
// 修3:非周期稠密截断告警(与上方 periodic→无限 分支互补)
|
|
6117
|
+
if (_denseNonPeriodic && state.result) {
|
|
6118
|
+
state.result.warnings = (state.result.warnings || []).concat([
|
|
6119
|
+
"方程在声明域内根数量过多(>" + 200 + "),已截断扫描;结果不完整,缩小变量范围或确认方程规模可获完整解集。"
|
|
6120
|
+
]);
|
|
6121
|
+
}
|
|
6085
6122
|
}
|
|
6086
6123
|
}
|
|
6087
6124
|
|
|
@@ -6557,6 +6594,16 @@ var _affSym = 0;
|
|
|
6557
6594
|
function _Aff(c, e) { return { c: c, e: e || {} }; }
|
|
6558
6595
|
function _affRad(a) { if (!a) return 0; var r = 0; for (var k in a.e) r += Math.abs(a.e[k]); return r; }
|
|
6559
6596
|
function _affToInterval(a) { if (!a) return null; var r = _affRad(a); return _iNorm({ min: a.c - r, max: a.c + r }); }
|
|
6597
|
+
// sound 容差:区间求值受浮点舍入影响,包络可能偏离真值几个 ulp(如 12/5 经 12*(1/5)
|
|
6598
|
+
// 算得 2.4000000000000001,与字面 2.4 差 ~2e-16,加仿射半径后包络中心落正侧)。
|
|
6599
|
+
// 判"严格不含 0 → 证明无解/严格单调"时,必须要求包络离 0 超过此容差;否则保守地
|
|
6600
|
+
// 不判无解(降级为继续求解 / 诚实报未找到),绝不因舍入把真解误杀为假阴性(sound-safe,
|
|
6601
|
+
// 绝不引入假阳性)。容差随量级缩放(相对 1e-12)+ 1e-12 绝对下限。
|
|
6602
|
+
function _ivExcludesZero(iv) {
|
|
6603
|
+
if (!iv || !isFinite(iv.min) || !isFinite(iv.max)) return false;
|
|
6604
|
+
var pad = Math.max(1e-12, 1e-12 * Math.max(1, Math.abs(iv.min), Math.abs(iv.max)));
|
|
6605
|
+
return iv.max < -pad || iv.min > pad;
|
|
6606
|
+
}
|
|
6560
6607
|
function _affAdd(a, b) { var e = {}; for (var k in a.e) e[k] = a.e[k]; for (var k in b.e) e[k] = (e[k] || 0) + b.e[k]; return _Aff(a.c + b.c, e); }
|
|
6561
6608
|
function _affSub(a, b) { var e = {}; for (var k in a.e) e[k] = a.e[k]; for (var k in b.e) e[k] = (e[k] || 0) - b.e[k]; return _Aff(a.c - b.c, e); }
|
|
6562
6609
|
function _affMul(a, b) {
|
|
@@ -6573,14 +6620,18 @@ function _affMul(a, b) {
|
|
|
6573
6620
|
}
|
|
6574
6621
|
function _affInv(b) {
|
|
6575
6622
|
// 1/b 一阶泰勒,误差保守界 |(b-b0)^2|/(2 b0^2 ξ^2),ξ∈盒,min|ξ|=|b0|-rb
|
|
6623
|
+
// ⚠️ 修正(sound 正确性,2026-09-07):旧实现 r=0-b=-b,lin=(-1/b.c²)·(-b) 的中心 lin.c 已是 1/b.c,
|
|
6624
|
+
// return 又写 1/b.c + lin.c → 中心被双重计数为 2/b.c(如 1/5 算成 0.4、12/5 算成 4.8),
|
|
6625
|
+
// 导致所有含除法的区间包络 / 中值定理判无解(suan7/suan29/suan35 等)系统性假阴性。
|
|
6626
|
+
// 正确:dev = b - b.c(中心 0)做一阶泰勒,lin.c=0,return 中心恰为 1/b.c,且噪声符号正确。
|
|
6576
6627
|
var rb = _affRad(b); if (b.c === 0) return null;
|
|
6577
|
-
var
|
|
6578
|
-
var lin = _affMul(
|
|
6628
|
+
var dev = _affSub(b, _Aff(b.c, {})); // b - b0,中心为 0
|
|
6629
|
+
var lin = _affMul(dev, _Aff(-1 / (b.c * b.c), {})); // 一阶项,中心为 0
|
|
6579
6630
|
var e = {}; for (var k in lin.e) e[k] = lin.e[k];
|
|
6580
6631
|
var m = Math.abs(b.c) - rb; if (m <= 0) return null;
|
|
6581
6632
|
var err = (rb * rb) / (2 * b.c * b.c * m * m);
|
|
6582
6633
|
var sym = _affSym++; e[sym] = err;
|
|
6583
|
-
return _Aff(1 / b.c + lin.c, e);
|
|
6634
|
+
return _Aff(1 / b.c + lin.c, e); // 现 lin.c=0 → 中心 = 1/b.c
|
|
6584
6635
|
}
|
|
6585
6636
|
function _affDiv(a, b) { var ib = _affInv(b); return ib ? _affMul(a, ib) : null; }
|
|
6586
6637
|
function _buildAffEnv(intervals) {
|
|
@@ -6624,7 +6675,13 @@ function _affineEval(ast, env) {
|
|
|
6624
6675
|
// 超越函数降级:仿射自变量 → 保守区间函数包围(复用 _rangeEval,无递归环)
|
|
6625
6676
|
var tmp = { type: 'func', name: ast.name, arg: { type: 'var', name: '__a' } };
|
|
6626
6677
|
var rv = _rangeEval(tmp, { __a: iv });
|
|
6627
|
-
|
|
6678
|
+
if (!rv || !isFinite(rv.min) || !isFinite(rv.max)) return null; // 含 ±Inf:交还 _rangeEval 直接给出保守区间
|
|
6679
|
+
// 关键修复(P0-2):旧实现 return _Aff((rv.min+rv.max)/2, {}) 把合法区间宽度丢成 0,
|
|
6680
|
+
// 致 intervalEval(sin x)@[-2,2] 塌成 [0,0](unsound:真值须含 [-1,1])。
|
|
6681
|
+
// 正确做法:用半径 (rv.max-rv.min)/2 的噪声符号把 rv 完整编码为仿射,
|
|
6682
|
+
// 使 _affToInterval 还原为 [rv.min, rv.max](sound 且紧致),Krawczyk 雅可比随之可信。
|
|
6683
|
+
var e = {}; e[_affSym++] = (rv.max - rv.min) / 2;
|
|
6684
|
+
return _Aff((rv.min + rv.max) / 2, e);
|
|
6628
6685
|
}
|
|
6629
6686
|
if (ast.type === 'unary') {
|
|
6630
6687
|
var u = _affineEval(ast.operand, env);
|
|
@@ -6662,7 +6719,7 @@ function suan29(state) {
|
|
|
6662
6719
|
|
|
6663
6720
|
// 严格测试①(最强):f 在区间上的区间包络不含 0 → 由中值定理严格证明该盒内无根
|
|
6664
6721
|
var F = intervalEval(state.equations[0], box);
|
|
6665
|
-
if (F && (F
|
|
6722
|
+
if (F && _ivExcludesZero(F)) {
|
|
6666
6723
|
state.done = true;
|
|
6667
6724
|
state.result = { solutions: [], error: "NO_SOLUTION", provenEmpty: true, message: "f 在 [" + a + "," + b + "] 上的严格区间包络不含 0(包络=[" + F.min.toExponential(2) + "," + F.max.toExponential(2) + "]),由中值定理严格证明该盒内无根", executionPath: "导数单调性剪枝", timeMs: performance.now() - state.startTime, confidence: "high", varNames: state.varNames, resultType: 1, resultTypeName: "空结果", resultTypeDesc: "区间包络严格证明区间内无根" };
|
|
6668
6725
|
return;
|
|
@@ -6673,7 +6730,7 @@ function suan29(state) {
|
|
|
6673
6730
|
// 用符号微分+区间求值得到【紧致】导数包络,取代原“3 条割线同号”启发式(会漏根,见评审 unsound)。
|
|
6674
6731
|
var dAST = _diffAST(state.equations[0], vn);
|
|
6675
6732
|
var dI = dAST ? intervalEval(dAST, box) : null;
|
|
6676
|
-
if (dI && (dI
|
|
6733
|
+
if (dI && _ivExcludesZero(dI)) {
|
|
6677
6734
|
var faBox = {}, fbBox = {}; faBox[vn] = { min: a, max: a }; fbBox[vn] = { min: b, max: b };
|
|
6678
6735
|
var faI = intervalEval(state.equations[0], faBox);
|
|
6679
6736
|
var fbI = intervalEval(state.equations[0], fbBox);
|
|
@@ -6827,7 +6884,7 @@ function suan35(state) {
|
|
|
6827
6884
|
// 故仅在“不含 0”时返回 false(不可行)。
|
|
6828
6885
|
for (var r = 0; r < subEqs.length; r++) {
|
|
6829
6886
|
var iF = intervalEval(subEqs[r], box);
|
|
6830
|
-
if (iF &&
|
|
6887
|
+
if (iF && _ivExcludesZero(iF)) {
|
|
6831
6888
|
return false; // 该方程在 used 全域上严格无根 ⇒ 子问题不可行 ⇒ 全局不可行
|
|
6832
6889
|
}
|
|
6833
6890
|
}
|
|
@@ -11040,7 +11097,7 @@ function _runTail(state) {
|
|
|
11040
11097
|
|
|
11041
11098
|
// —— 可审计结构化溯源(切片A):每个结果附带完整证据链元数据 ——
|
|
11042
11099
|
// 设计目标:Agent / 上层系统拿到的不只是裸数字,而是"为什么是这个解"的可读证据链。
|
|
11043
|
-
var SOLVER_VERSION = "lingshu-solver/1.0.
|
|
11100
|
+
var SOLVER_VERSION = "lingshu-solver/1.0.7-auditable";
|
|
11044
11101
|
|
|
11045
11102
|
// Movability 完整读取(切片B):每变量携带 status + width,供 Agent 读懂"为何是这个解"
|
|
11046
11103
|
function _movabilityFull(state) {
|
|
@@ -11378,7 +11435,11 @@ function _newtonRefine(eqs, vns, x0, box) {
|
|
|
11378
11435
|
var F = []; for (var e = 0; e < n; e++) { var fe = evalAST(eqs[e], vmap); if (!isFinite(fe)) return null; F.push(fe); }
|
|
11379
11436
|
var rms = 0; for (var i2 = 0; i2 < n; i2++) rms += F[i2] * F[i2]; rms = Math.sqrt(rms / n);
|
|
11380
11437
|
if (rms < 1e-11) return x;
|
|
11381
|
-
|
|
11438
|
+
// 雅可比区间求导:必须喂退化的点区间 {min:x,max:x}(而非裸点值)。
|
|
11439
|
+
// 旧实现 intervalEval(d, vmap) 把裸数当 iv,iv.min/iv.max 为 undefined → _buildAffEnv 算出 NaN 噪声
|
|
11440
|
+
// → 雅可比整行 NaN → realMatInv 失败 → 本函数对一切良置问题恒返 null(P0-1)。
|
|
11441
|
+
var pmap = {}; for (var i3 = 0; i3 < n; i3++) pmap[vns[i3]] = { min: x[i3], max: x[i3] };
|
|
11442
|
+
var J = []; for (var a = 0; a < n; a++) { J.push([]); for (var b = 0; b < n; b++) { var d = _diffAST(eqs[a], vns[b]); var dv = intervalEval(d, pmap); if (!dv) return null; J[a].push((dv.min + dv.max) / 2); } }
|
|
11382
11443
|
var Y = realMatInv(J); if (!Y) return null;
|
|
11383
11444
|
var dX = rMatVec(Y, F);
|
|
11384
11445
|
for (var j = 0; j < n; j++) x[j] = x[j] - dX[j];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lingshu-solver",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "灵数求解器 · 确定性实数方程组求解 MCP 工具(≤6变量):区间收缩 + Krawczyk 认证,离线零依赖零数据,诚实标记 truncated。",
|
|
5
5
|
"homepage": "https://genesis-plan.github.io/lingshu-solver/",
|
|
6
6
|
"repository": {
|
|
@@ -50,6 +50,6 @@
|
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"start": "node mcp-server.js",
|
|
53
|
-
"test": "node test/
|
|
53
|
+
"test": "node test/p0_fix_regression.js"
|
|
54
54
|
}
|
|
55
55
|
}
|