@ohtaman/washi 0.4.0 → 0.6.0

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 (130) hide show
  1. package/README.ja.md +149 -121
  2. package/README.md +149 -121
  3. package/README.zh-CN.md +150 -122
  4. package/THIRD_PARTY_LICENSES.md +3 -4
  5. package/dist/browser/_washi-node-only-BvRk9kiK.js +0 -0
  6. package/dist/browser/browser-runtime-TLCY0hkc.js +1793 -0
  7. package/dist/browser/highs-worker.js +21 -3
  8. package/dist/browser/highs.wasm +0 -0
  9. package/dist/browser/highs.wasm.LICENSE +1 -2
  10. package/dist/browser/loader-DewlSho8.js +643 -0
  11. package/dist/browser/solvers/glpk.js +433 -286
  12. package/dist/browser/solvers/glpk.min.js +1 -1
  13. package/dist/browser/solvers/z3.js +1008 -981
  14. package/dist/browser/solvers/z3.min.js +2 -2
  15. package/dist/browser/washi.js +2778 -673
  16. package/dist/browser/washi.min.js +3 -4
  17. package/dist/lib/_washi-node-only-BvRk9kiK.js +0 -0
  18. package/dist/lib/highs-browser-runtime.js +2120 -4124
  19. package/dist/lib/highs-node-runtime.js +24 -1
  20. package/dist/lib/highs-runtime.js +2 -0
  21. package/dist/lib/highs-worker.js +21 -3
  22. package/dist/lib/highs.wasm +0 -0
  23. package/dist/lib/highs.wasm.LICENSE +1 -2
  24. package/dist/lib/loader-BZUQNvh4.js +649 -0
  25. package/dist/lib/registry-C20sxTwm.js +964 -0
  26. package/dist/lib/solvers/glpk.js +201 -90
  27. package/dist/lib/solvers/z3.js +399 -259
  28. package/dist/lib/washi.js +2363 -1056
  29. package/dist/types/decomposition/benders.d.ts +32 -0
  30. package/dist/types/decomposition/benders.d.ts.map +1 -0
  31. package/dist/types/decomposition/column-generation.d.ts +34 -0
  32. package/dist/types/decomposition/column-generation.d.ts.map +1 -0
  33. package/dist/types/decomposition/index.d.ts +4 -0
  34. package/dist/types/decomposition/index.d.ts.map +1 -0
  35. package/dist/types/decomposition/types.d.ts +230 -0
  36. package/dist/types/decomposition/types.d.ts.map +1 -0
  37. package/dist/types/index.d.ts +5 -4
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/types/modeler/big-m.d.ts +75 -0
  40. package/dist/types/modeler/big-m.d.ts.map +1 -0
  41. package/dist/types/modeler/boolean-expr.d.ts +103 -14
  42. package/dist/types/modeler/boolean-expr.d.ts.map +1 -1
  43. package/dist/types/modeler/constraint.d.ts +47 -9
  44. package/dist/types/modeler/constraint.d.ts.map +1 -1
  45. package/dist/types/modeler/expression.d.ts +123 -28
  46. package/dist/types/modeler/expression.d.ts.map +1 -1
  47. package/dist/types/modeler/index.d.ts +11 -6
  48. package/dist/types/modeler/index.d.ts.map +1 -1
  49. package/dist/types/modeler/linearizer.d.ts +15 -0
  50. package/dist/types/modeler/linearizer.d.ts.map +1 -0
  51. package/dist/types/modeler/lp-writer.d.ts +30 -3
  52. package/dist/types/modeler/lp-writer.d.ts.map +1 -1
  53. package/dist/types/modeler/model.d.ts +623 -131
  54. package/dist/types/modeler/model.d.ts.map +1 -1
  55. package/dist/types/modeler/objective.d.ts +59 -0
  56. package/dist/types/modeler/objective.d.ts.map +1 -0
  57. package/dist/types/modeler/parser.d.ts +34 -10
  58. package/dist/types/modeler/parser.d.ts.map +1 -1
  59. package/dist/types/modeler/quad-expr.d.ts +26 -7
  60. package/dist/types/modeler/quad-expr.d.ts.map +1 -1
  61. package/dist/types/modeler/solution-validator.d.ts +93 -0
  62. package/dist/types/modeler/solution-validator.d.ts.map +1 -0
  63. package/dist/types/modeler/solvers/glpk/solver.d.ts +26 -2
  64. package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -1
  65. package/dist/types/modeler/solvers/highs/browser-runtime.d.ts +2 -1
  66. package/dist/types/modeler/solvers/highs/browser-runtime.d.ts.map +1 -1
  67. package/dist/types/modeler/solvers/highs/driver.d.ts +232 -0
  68. package/dist/types/modeler/solvers/highs/driver.d.ts.map +1 -0
  69. package/dist/types/modeler/solvers/highs/index.d.ts +1 -0
  70. package/dist/types/modeler/solvers/highs/index.d.ts.map +1 -1
  71. package/dist/types/modeler/solvers/highs/loader.d.ts +38 -13
  72. package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -1
  73. package/dist/types/modeler/solvers/highs/node-runtime.d.ts +2 -1
  74. package/dist/types/modeler/solvers/highs/node-runtime.d.ts.map +1 -1
  75. package/dist/types/modeler/solvers/highs/solver.d.ts +12 -5
  76. package/dist/types/modeler/solvers/highs/solver.d.ts.map +1 -1
  77. package/dist/types/modeler/solvers/highs/worker-client.d.ts.map +1 -1
  78. package/dist/types/modeler/solvers/mock.d.ts +14 -5
  79. package/dist/types/modeler/solvers/mock.d.ts.map +1 -1
  80. package/dist/types/modeler/solvers/types.d.ts +73 -11
  81. package/dist/types/modeler/solvers/types.d.ts.map +1 -1
  82. package/dist/types/modeler/solvers/z3/loader.d.ts +2 -3
  83. package/dist/types/modeler/solvers/z3/loader.d.ts.map +1 -1
  84. package/dist/types/modeler/solvers/z3/solver.d.ts +15 -5
  85. package/dist/types/modeler/solvers/z3/solver.d.ts.map +1 -1
  86. package/dist/types/modeler/types.d.ts +86 -1
  87. package/dist/types/modeler/types.d.ts.map +1 -1
  88. package/dist/types/modeler/validation.d.ts +56 -0
  89. package/dist/types/modeler/validation.d.ts.map +1 -0
  90. package/dist/types/modeler/variable.d.ts +48 -14
  91. package/dist/types/modeler/variable.d.ts.map +1 -1
  92. package/docs/examples/diet-sensitivity.md +90 -0
  93. package/docs/examples/ecommerce-coupons.md +106 -0
  94. package/docs/examples/index.md +57 -0
  95. package/docs/examples/knapsack.md +60 -0
  96. package/docs/examples/portfolio-qp.md +83 -0
  97. package/docs/examples/production.md +51 -0
  98. package/docs/examples/shift-scheduling.md +175 -0
  99. package/docs/examples/smt-security.md +74 -0
  100. package/docs/examples/transportation.md +90 -0
  101. package/docs/examples/traveling-salesperson.md +173 -0
  102. package/docs/examples/unsat-core.md +64 -0
  103. package/docs/examples/vehicle-routing.md +206 -0
  104. package/docs/getting-started/ai-agents.md +271 -0
  105. package/docs/getting-started/cross-origin.md +87 -0
  106. package/docs/getting-started/index.md +116 -0
  107. package/docs/getting-started/runtimes.md +227 -0
  108. package/docs/guide/constraints.md +177 -0
  109. package/docs/guide/decomposition.md +399 -0
  110. package/docs/guide/expressions.md +204 -0
  111. package/docs/guide/objectives.md +170 -0
  112. package/docs/guide/unsat-core.md +154 -0
  113. package/docs/guide/variables.md +188 -0
  114. package/docs/ja/getting-started/ai-agents.md +270 -0
  115. package/docs/solvers/custom-solver.md +525 -0
  116. package/docs/solvers/glpk.md +66 -0
  117. package/docs/solvers/highs.md +115 -0
  118. package/docs/solvers/index.md +42 -0
  119. package/docs/solvers/z3.md +78 -0
  120. package/docs/zh/getting-started/ai-agents.md +270 -0
  121. package/llms-full.txt +4065 -0
  122. package/llms.txt +201 -0
  123. package/package.json +32 -16
  124. package/skills/washi/SKILL.md +197 -0
  125. package/dist/browser/browser-runtime-D13gHOT5.js +0 -4189
  126. package/dist/browser/loader-CVt4CloI.js +0 -58
  127. package/dist/lib/async-mutex-Duo4jwzn.js +0 -195
  128. package/dist/lib/constraint-BRuB3ooC.js +0 -90
  129. package/dist/lib/loader-Dti0v9yC.js +0 -50
  130. package/dist/lib/registry-DksqCSjI.js +0 -32
package/README.zh-CN.md CHANGED
@@ -2,9 +2,9 @@
2
2
  <picture>
3
3
  <source media="(prefers-color-scheme: dark)" srcset="./assets/washi-header-dark.png">
4
4
  <source media="(prefers-color-scheme: light)" srcset="./assets/washi-header-light.png">
5
- <img alt="WaSHI - 面向 TypeScript 与 JavaScript 的数理优化代数建模器 (Modeler)" src="./assets/washi-header-light.png" width="420" />
5
+ <img alt="WaSHI - 适用于数理优化与约束编程的代数建模器 (TypeScript &amp; JavaScript)" src="./assets/washi-header-light.png" width="420" />
6
6
  </picture>
7
- <p><strong>面向 TypeScript 与 JavaScript 的代数建模器</strong></p>
7
+ <p><strong>适用于数理优化与约束编程的代数建模器</strong></p>
8
8
  <p>
9
9
  <em>线性规划 (LP) • 混合整数规划 (MIP) • 凸二次规划 (QP) • SMT逻辑约束与冲突诊断</em>
10
10
  </p>
@@ -16,7 +16,7 @@
16
16
  <p>
17
17
  <a href="https://www.npmjs.com/package/@ohtaman/washi"><img src="https://img.shields.io/npm/v/@ohtaman/washi?color=crimson&label=npm" alt="npm version" /></a>
18
18
  <a href="https://github.com/ohtaman/washi/actions/workflows/distribution.yml"><img src="https://github.com/ohtaman/washi/actions/workflows/distribution.yml/badge.svg" alt="CI Status" /></a>
19
- <a href="https://ohtaman.github.io/washi/"><img src="https://img.shields.io/badge/docs-online-blue" alt="docs" /></a>
19
+ <a href="https://ohtaman.github.io/washi/zh/"><img src="https://img.shields.io/badge/docs-online-blue" alt="docs" /></a>
20
20
  <a href="https://ohtaman.github.io/washi/demo/"><img src="https://img.shields.io/badge/demo-playground-brightgreen" alt="live demo" /></a>
21
21
  <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="license" /></a>
22
22
  </p>
@@ -24,24 +24,24 @@
24
24
 
25
25
  ---
26
26
 
27
- **WaSHI** (WebAssembly-backed, Solver-independent, High-level modeling Interface) 是面向 TypeScript / JavaScript 的代数建模器,受到 Python **PuLP** 和 Julia **JuMP** 的启发。你可以在应用代码中定义变量、目标函数、算术约束和逻辑约束。WaSHI 负责构建模型、转换为求解器输入,并将结果映射回变量;优化与可满足性检查由 **HiGHS**、**Z3** 和 **GLPK** 完成。
27
+ **WaSHI** (WebAssembly-backed, Solver-independent, High-level modeling Interface) 是面向 TypeScript / JavaScript 的数理优化与约束编程代数建模器,受到 Python **PuLP** 和 Julia **JuMP** 的启发。你可以在应用代码中定义变量、目标函数、算术约束和逻辑约束。WaSHI 负责构建模型、转换为求解器输入,并将结果映射回变量;优化与可满足性检查由 **HiGHS**、**Z3** 和 **GLPK** 完成。
28
28
 
29
29
  HiGHS 是默认求解器;Z3 和 GLPK 是可选插件。软件包提供 Node.js 和浏览器分发版本,并包含 WebAssembly 资源。部署要求请参阅[浏览器使用说明](#-浏览器与-web-worker-使用指南)。
30
30
 
31
- [试用浏览器演示](https://ohtaman.github.io/washi/demo/) · [示例源码与运行方法](https://github.com/ohtaman/washi/blob/main/examples/README.md) · [ESM / script / CodePen 示例](https://github.com/ohtaman/washi/blob/main/examples/distribution/README.md)
31
+ [在线文档](https://ohtaman.github.io/washi/zh/) · [试用浏览器演示](https://ohtaman.github.io/washi/demo/) · [AI 编程助手快速参考](docs/zh/getting-started/ai-agents.md) · [Agent Skill (`SKILL.md`)](skills/washi/SKILL.md) · [示例源码与运行方法](https://github.com/ohtaman/washi/blob/main/examples/README.md) · [ESM / script / CodePen 示例](https://github.com/ohtaman/washi/blob/main/examples/distribution/README.md)
32
32
 
33
33
  ```ts
34
- import { Model, expr } from "@ohtaman/washi";
34
+ import { Model, expr, maximize } from "@ohtaman/washi";
35
35
 
36
36
  const m = new Model("木工产品利润最大化");
37
37
  const x = m.integer("桌子", { lb: 0 });
38
38
  const y = m.integer("椅子", { lb: 0 });
39
39
 
40
- m.maximize(expr`30 * ${x} + 50 * ${y}`);
41
- m.constrain(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
42
- m.constrain(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
40
+ m.objective(maximize(expr`30 * ${x} + 50 * ${y}`));
41
+ m.constraint(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
42
+ m.constraint(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
43
43
 
44
- await m.optimize();
44
+ await m.solve();
45
45
  console.log(`生产计划: x=${x.value}, y=${y.value} (最大利润: $${m.objectiveValue})`);
46
46
  ```
47
47
 
@@ -49,10 +49,11 @@ console.log(`生产计划: x=${x.value}, y=${y.value} (最大利润: $${m.object
49
49
 
50
50
  ## 🎯 WaSHI 提供的功能
51
51
 
52
- 1. **代数模型构建**:使用领域变量构造函数(`m.binary`、`m.integer`、`m.continuous`)、标签模板字面量(`expr`)、向量聚合函数(`dot`、`sum`)以及首选的 `m.constrain()` 约束方法,精确且优雅地描述数学模型。
53
- 2. **求解器适配器**:通过共同的建模 API 使用 HiGHS、Z3 或 GLPK,也可以[注册自己的适配器](https://github.com/ohtaman/washi/blob/main/docs/custom-solver-guide.md)。需要选择支持相应问题类型的求解器;不同求解器的能力并不相同。
54
- 3. **本地执行与 WebAssembly 分发**:使用本地求解器适配器时,可在应用内求解,无需单独的 Python 服务或本地 C/C++ 编译。浏览器部署需要包含生成的 JS、Worker 和 WASM 资源。离线使用还需要这些资源可在本地访问或已缓存。Z3 有额外的浏览器隔离要求。
55
- 4. **命名约束与 SMT 结果**:显式使用 Z3 检查可满足性,并通过 Unsat Core 调查冲突约束。返回的是一个冲突约束子集,不一定是最小子集。
52
+ 1. **代数模型构建**:使用领域变量构造函数(`m.binary`、`m.integer`、`m.continuous`)、标签模板字面量(`expr`)、向量聚合函数(`dot`、`sum`)以及一等约束(`m.constraint`)构建优化模型。由于 JavaScript 不支持运算符重载,`` expr`...` `` 采用类似参数化 SQL 模板的方式,在解析中缀数学运算符(`+`、`-`、`*`、`^2`、`<=`、`>=`、`==`)的同时,将 `${...}` 插值直接绑定为强类型的 `Var` 或表达式对象引用,从而保留静态类型检查、IDE 重命名支持以及多维索引访问(`${flow[i][j]}`)。
53
+ 2. **求解器适配器**:通过共同的建模 API 使用 HiGHS、Z3 或 GLPK,也可以[注册自己的适配器](https://github.com/ohtaman/washi/blob/main/docs/zh/solvers/custom-solver.md)。需要选择支持相应问题类型的求解器;不同求解器的能力并不相同。
54
+ 3. **本地执行与 WebAssembly 分发**:使用本地求解器适配器时,可在应用内直接求解,无需单独的 Python 服务或本地 C/C++ 编译——这消除了在快速开发和交付交互式工具时的后端基础设施瓶颈,也便于在客户端直接与浏览器内 LLM(如 WebGPU / WebLLM)协同工作。浏览器部署需要包含生成的 JS、Worker 和 WASM 资源。离线使用还需要这些资源可在本地访问或已缓存。Z3 有额外的浏览器隔离要求。
55
+ 4. **命名约束与冲突诊断**:通过可满足性检查(`m.check()`),可调查矛盾约束(`conflicts` / `unsatCore`)以排查不可行性原因:内置 HiGHS 分离出**弹性修复集合**(`conflicts`,恢复可行性所需松弛的约束集合),而 Z3 提取 **SMT 不可满足核心**(`unsatCore` / `conflicts`,相互矛盾的约束子集;不保证最小性)。
56
+ 5. **高级分解方法编排**:利用一等分解算法(`master.solveColumnGeneration`、`master.solveBenders`),突破单体 MIP 在特定结构(下料问题、车辆路径/VRP、旅行商/TSP、两阶段设施选址规划等)上的搜索树爆炸瓶颈。结合定价子问题(Pricing)与链接约束(`sub.link(...)`)的清晰回调编排,协同对偶定价、割平面生成与整数解复原。
56
57
 
57
58
  模型构建与转换由 WaSHI 负责。支持的问题类型、数值行为和求解时间取决于所选求解器、配置及具体问题。建模开销与求解器执行时间应分别测量;某个模型上的结果并不构成通用性能保证。
58
59
 
@@ -62,9 +63,9 @@ console.log(`生产计划: x=${x.value}, y=${y.value} (最大利润: $${m.object
62
63
 
63
64
  | 适配器 | 引擎许可证 | 支持的问题类型 | 引擎作用 | 集成方式 |
64
65
  | :--- | :--- | :--- | :--- | :--- |
65
- | **HiGHS** | **MIT** | **LP, MIP, 凸QP** | 数值优化 | 默认内置 |
66
- | **Z3** | **MIT** | **SMT, SAT, 逻辑, MIP** | 可满足性检查、Unsat Core、优化 | 可选插件 (`@ohtaman/washi/solvers/z3`) |
67
- | **GLPK** | **GPL-3.0** | **LP, MIP** | 线性与混合整数优化 | 可选插件 (`@ohtaman/washi/solvers/glpk`) |
66
+ | **[HiGHS](https://github.com/ERGO-Code/HiGHS)** | **MIT** | **LP, MIP, 凸QP** | 数值优化 | 默认内置 |
67
+ | **[Z3](https://github.com/Z3Prover/z3)** (via [`z3-solver`](https://www.npmjs.com/package/z3-solver)) | **MIT** | **SMT, SAT, 逻辑, MIP** | 可满足性检查、Unsat Core、优化 | 可选插件 (`@ohtaman/washi/solvers/z3`) |
68
+ | **[GLPK](https://www.gnu.org/software/glpk/)** (via [`glpk.js`](https://www.npmjs.com/package/glpk.js)) | **GPL-3.0** | **LP, MIP** | 线性与混合整数优化 | 可选插件 (`@ohtaman/washi/solvers/glpk`) |
68
69
  | **Mock** | **MIT** | — | 为集成测试提供模拟响应 | 内置;不实际求解模型 |
69
70
 
70
71
  ---
@@ -92,61 +93,58 @@ npm install z3-solver # 用于 SMT 与冲突诊断
92
93
  npm install glpk.js # 用于 GLPK 求解器 (GPL-3.0)
93
94
  ```
94
95
 
96
+ *(可选)* 面向 AI 编程助手(Claude Code、Antigravity、Cursor、Codex 等),可以通过 `skills` CLI 或随包附带的 [`skills/washi/SKILL.md`](skills/washi/SKILL.md) 引入建模与校验技能:
97
+
98
+ ```bash
99
+ # 通过 skills CLI (skills.sh / vercel-labs/skills) 安装
100
+ npx skills add ohtaman/washi
101
+
102
+ # 或将随包附带的技能手动复制到项目中
103
+ mkdir -p .agents/skills/washi
104
+ cp node_modules/@ohtaman/washi/skills/washi/SKILL.md .agents/skills/washi/SKILL.md
105
+ ```
106
+
95
107
  ---
96
108
 
97
109
  ## 🚀 快速上手指南
98
110
 
99
- ### 1. 混合整数线性规划 (MIP: 生产计划问题)
111
+ ### 1. 多维变量、条件指示约束 (`m.indicator`) 与解验证 (`m.validateSolution`)
100
112
 
101
- 在有限资源约束下实现利润最大化:
113
+ 一行代码声明一维字典或二维变量矩阵,通过 `m.indicator()` 表达 Big-M 条件规则,结合 `onProgress` / `AbortSignal` 控制求解过程,并通过 `m.validateSolution()` 独立校验解的合法性:
102
114
 
103
115
  ```ts
104
116
  import { Model, expr } from "@ohtaman/washi";
105
117
 
106
- const m = new Model("FactoryPlanning");
107
-
108
- // 决策变量(非负整数)
109
- const chairs = m.integer("chairs", { lb: 0 });
110
- const tables = m.integer("tables", { lb: 0 });
111
-
112
- // 借助标签模板字面量自然表达目标函数与约束
113
- m.maximize(expr`30 * ${chairs} + 50 * ${tables}`);
114
- m.constrain(expr`${chairs} + 2 * ${tables} <= 40`, "wood_limit");
115
- m.constrain(expr`2 * ${chairs} + ${tables} <= 50`, "labor_limit");
116
-
117
- // 使用默认的 HiGHS WASM 引擎求解
118
- const status = await m.optimize();
119
-
120
- console.log(`求解状态: ${status}`); // "Optimal"
121
- console.log(`最大利润: $${m.objectiveValue}`); // 1100
122
- console.log(`生产量: 椅子=${chairs.value}, 桌子=${tables.value}`); // 椅子 20, 桌子 10
123
- ```
124
-
125
- #### 🗂 多维变量网格
118
+ const m = new Model("FacilityPlanning");
126
119
 
127
- 一行代码声明变量字典或多维变量矩阵:
128
-
129
- ```ts
130
- // 1D 字典形式的布尔变量
120
+ // 1D 字典形式的二元变量
131
121
  const openCity = m.binary(["Tokyo", "Osaka", "Nagoya"]);
132
122
 
133
123
  // 2D 运输量矩阵: [工厂] x [门店]
134
- const flow = m.continuous(["F1", "F2"], ["StoreA", "StoreB"], { lb: 0 });
124
+ const flow = m.continuous(["F1", "F2"], ["StoreA", "StoreB"], { lb: 0, ub: 1000 });
135
125
 
136
126
  // 2D 网格坐标 (例如 8x8 棋盘)
137
127
  const board = m.binary(8, 8, { prefix: "queen" });
138
- ```
139
128
 
140
- #### 🔀 Big-M 条件指示约束 (`m.indicator`)
141
-
142
- 轻松建模条件触发规则与固定成本启动,无需繁琐的手工 Big-M 代数推导:
143
-
144
- ```ts
145
- // "若工厂关闭 (openCity['Tokyo'] == 0),则产量 flow 必须为 0"
129
+ // Big-M 条件约束: 若工厂关闭 (openCity['Tokyo'] == 0),则 flow <= 0
130
+ // (省略 M 时,WaSHI 会根据变量的有限上下界自动推导紧凑安全的 Big-M)
146
131
  m.indicator(openCity["Tokyo"], expr`${flow["F1"]["StoreA"]} <= 0`, {
147
132
  activeValue: 0,
148
- M: 1000,
133
+ name: "tokyo_closed_no_flow",
149
134
  });
135
+
136
+ // 支持实时进度回调 (onProgress) 与 AbortSignal 取消
137
+ const controller = new AbortController();
138
+ await m.solve({
139
+ signal: controller.signal,
140
+ onProgress: (ev) => {
141
+ // 实时指标: ev.elapsedTime, ev.objectiveValue, ev.objectiveBound, ev.mipGap
142
+ },
143
+ });
144
+
145
+ // 独立校验变量边界、整数性以及线性/逻辑约束
146
+ const report = m.validateSolution();
147
+ console.log("解验证通过?", report.valid);
150
148
  ```
151
149
 
152
150
  ---
@@ -156,7 +154,7 @@ m.indicator(openCity["Tokyo"], expr`${flow["F1"]["StoreA"]} <= 0`, {
156
154
  在满足预期收益与预算约束的前提下,基于协方差矩阵最小化投资组合风险:
157
155
 
158
156
  ```ts
159
- import { Model, QuadExpr, sum, dot, expr } from "@ohtaman/washi";
157
+ import { Model, QuadExpr, sum, dot, minimize, expr } from "@ohtaman/washi";
160
158
 
161
159
  const m = new Model("MarkowitzPortfolio");
162
160
  const assets = ["Tech", "Bonds", "RealEstate"];
@@ -166,11 +164,11 @@ const returns = [0.14, 0.04, 0.08];
166
164
  const w = m.continuous(assets, { lb: 0, ub: 1 });
167
165
 
168
166
  // 1. 预算约束: 资金分配总额 100%
169
- m.constrain(expr`${sum(assets, (a) => w[a])} == 1.0`, "budget");
167
+ m.constraint(expr`${sum(assets, (a) => w[a])} == 1.0`, "budget");
170
168
 
171
169
  // 2. 目标回报率: 组合最低回报率 >= 8.5%
172
170
  const retMap = Object.fromEntries(assets.map((a, i) => [a, returns[i]]));
173
- m.constrain(expr`${dot(retMap, w)} >= 0.085`, "min_return");
171
+ m.constraint(expr`${dot(retMap, w)} >= 0.085`, "min_return");
174
172
 
175
173
  // 3. 资产协方差矩阵 (风险与相关性)
176
174
  const cov = [
@@ -186,9 +184,9 @@ for (let i = 0; i < assets.length; i++) {
186
184
  risk = risk.add(w[assets[i]].mul(w[assets[j]]).mul(cov[i][j]));
187
185
  }
188
186
  }
189
- m.minimize(risk);
187
+ m.objective(minimize(risk));
190
188
 
191
- await m.optimize();
189
+ await m.solve();
192
190
  console.log(`最小方差: ${m.objectiveValue?.toFixed(6)}`);
193
191
  assets.forEach((name) => {
194
192
  console.log(` ${name}: ${((w[name].value || 0) * 100).toFixed(2)}%`);
@@ -214,13 +212,13 @@ const siren = m.bool("siren");
214
212
  const lux = m.integer("lux", { lb: 0 });
215
213
 
216
214
  // 规则定义
217
- m.constrain(lux.le(50).implies(isNight), "dark_implies_night");
218
- m.constrain(motion.and(isNight).and(alarm).implies(siren), "alarm_rule");
215
+ m.constraint(lux.le(50).implies(isNight), "dark_implies_night");
216
+ m.constraint(motion.and(isNight).and(alarm).implies(siren), "alarm_rule");
219
217
 
220
218
  // 传感器当前输入数据
221
- m.constrain(expr`${lux} <= 10`, "sensor_dark");
222
- m.constrain(motion, "sensor_motion");
223
- m.constrain(alarm, "alarm_on");
219
+ m.constraint(expr`${lux} <= 10`, "sensor_dark");
220
+ m.constraint(motion, "sensor_motion");
221
+ m.constraint(alarm, "alarm_on");
224
222
 
225
223
  // 无目标函数直接判定可满足性 (SAT)
226
224
  const res = await m.check({ solver: "z3" });
@@ -231,40 +229,47 @@ console.log(`警报响起? ${m.values.get("siren")}`); // true
231
229
 
232
230
  ---
233
231
 
234
- ### 4. 约束冲突根因诊断 (`unsatCore`)
232
+ ### 4. 冲突诊断 (`conflicts` / `unsatCore`)
235
233
 
236
- 当规则或约束之间存在矛盾时,Z3 能够提取引发冲突的**矛盾约束子集**(Unsat Core,不保证最小性;需使用 Z3):
234
+ 当规则或约束之间存在矛盾时,可定位不可行根因以采取干预措施:
235
+ - **内置 HiGHS 与 GLPK**:`await m.check()` 采用单次求解弹性松弛模型($\min \sum s_i$),无需安装外部求解器即可定位 `res.conflicts`——即恢复可行性所需松弛的**修复集合**。
236
+ - **Z3**:`await m.check({ solver: "z3" })` 提供精确的 SMT **不可满足核心(Unsat Core)** 提取(`res.unsatCore` 与 `res.conflicts`),返回相互矛盾的约束子集。
237
237
 
238
238
  ```ts
239
239
  import { Model, expr } from "@ohtaman/washi";
240
- import "@ohtaman/washi/solvers/z3";
241
240
 
242
- const m = new Model({ name: "ConflictDiagnosis", solver: "z3" });
241
+ const m = new Model("ConflictDiagnosis");
243
242
  const engineers = m.integer("engineers", { lb: 0, ub: 20 });
244
243
  const budget = m.continuous("budget", { lb: 0, ub: 100000 });
245
244
  const rushDelivery = m.bool("rushDelivery");
246
245
 
247
246
  // 规则 1: 每位工程师成本 $8,000
248
- m.constrain(expr`8000 * ${engineers} <= ${budget}`, "budget_limit");
247
+ m.constraint(expr`8000 * ${engineers} <= ${budget}`, "budget_limit");
249
248
 
250
249
  // 规则 2: 客户要求加急交付
251
- m.constrain(rushDelivery, "rush_required");
250
+ m.constraint(rushDelivery, "rush_required");
252
251
 
253
252
  // 规则 3: 加急交付需至少配备 8 名工程师
254
- m.constrain(rushDelivery.implies(engineers.ge(8)), "rush_staffing_rule");
253
+ m.constraint(rushDelivery.implies(engineers.ge(8)), "rush_staffing_rule");
255
254
 
256
255
  // 规则 4: 董事会严格预算上限 $50,000 (冲突点: 8人 * $8,000 = $64,000 > $50,000!)
257
- m.constrain(expr`${budget} <= 50000`, "strict_board_budget_cap");
256
+ m.constraint(expr`${budget} <= 50000`, "strict_board_budget_cap");
258
257
 
259
258
  // 规则 5: 最低 1 名员工用工底线(无关规则)
260
- m.constrain(expr`${engineers} >= 1`, "minimum_one_employee");
259
+ m.constraint(expr`${engineers} >= 1`, "minimum_one_employee");
261
260
 
262
- const res = await m.check({ solver: "z3" });
261
+ // 1. 使用默认 HiGHS 进行弹性修复诊断
262
+ const res = await m.check();
263
263
 
264
264
  console.log(`求解状态: ${res.status}`); // "Unsat"
265
- console.log("冲突约束子集:", res.unsatCore);
266
- // 输出: ["budget_limit", "rush_required", "rush_staffing_rule", "strict_board_budget_cap"]
267
- // 注:无关的 "minimum_one_employee" 被准确排除在外!
265
+ console.log("修复约束集合(需松弛的约束):", res.conflicts);
266
+ // HiGHS 输出: ["rush_required"]
267
+ // (松弛 rush_required 即可恢复可行性;无关的 minimum_one_employee 不受影响)
268
+
269
+ // 2. 或使用 Z3 提取精确 SMT 不可满足核心(需导入 "@ohtaman/washi/solvers/z3")
270
+ // const z3Res = await m.check({ solver: "z3" });
271
+ // console.log("相互矛盾核心:", z3Res.unsatCore);
272
+ // Z3 输出: ["budget_limit", "rush_required", "rush_staffing_rule", "strict_board_budget_cap"]
268
273
  ```
269
274
 
270
275
  ---
@@ -274,18 +279,18 @@ console.log("冲突约束子集:", res.unsatCore);
274
279
  使用 GNU Linear Programming Kit (GLPK) 求解器插件:
275
280
 
276
281
  ```ts
277
- import { Model, expr } from "@ohtaman/washi";
282
+ import { Model, expr, maximize } from "@ohtaman/washi";
278
283
  import "@ohtaman/washi/solvers/glpk";
279
284
 
280
285
  const m = new Model({ solver: "glpk" });
281
286
  const x = m.integer("x", { lb: 0 });
282
287
  const y = m.integer("y", { lb: 0 });
283
288
 
284
- m.maximize(expr`30 * ${x} + 50 * ${y}`);
285
- m.constrain(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
286
- m.constrain(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
289
+ m.objective(maximize(expr`30 * ${x} + 50 * ${y}`));
290
+ m.constraint(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
291
+ m.constraint(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
287
292
 
288
- const status = await m.optimize();
293
+ const status = await m.solve();
289
294
  console.log(`求解状态: ${status}`); // "Optimal"
290
295
  console.log(`目标函数值: ${m.objectiveValue}`); // 1100
291
296
  ```
@@ -297,7 +302,7 @@ console.log(`目标函数值: ${m.objectiveValue}`); // 1100
297
302
  无需嵌套循环,一行代码完成一维和二维变量的线性组合:
298
303
 
299
304
  ```ts
300
- import { Model, dot } from "@ohtaman/washi";
305
+ import { Model, dot, minimize } from "@ohtaman/washi";
301
306
 
302
307
  const m = new Model();
303
308
  const factories = ["Tokyo", "Osaka"];
@@ -311,8 +316,8 @@ const costs = {
311
316
  const ship = m.continuous(factories, stores);
312
317
 
313
318
  // 一行代码最小化总运输成本:
314
- m.minimize(dot(costs, ship));
315
- await m.optimize();
319
+ m.objective(minimize(dot(costs, ship)));
320
+ await m.solve();
316
321
 
317
322
  // 获取所有变量的最优取值结构
318
323
  const solution = m.getValues(ship);
@@ -362,23 +367,23 @@ await model.solve();
362
367
  </script>
363
368
  ```
364
369
 
365
- 若通过 CDN 加载,可使用 `https://cdn.jsdelivr.net/npm/@ohtaman/washi@0.1.2/dist/browser/washi.min.js`(请固定 `0.1.2` 及以上版本号)。ESM 使用同版本的 `dist/browser/washi.js`。选择 CDN URL 就是显式使用 CDN;本地部署不会自动改用外部 CDN。
370
+ 若通过 CDN 加载,可使用 `https://cdn.jsdelivr.net/npm/@ohtaman/washi@<version>/dist/browser/washi.min.js`(待包含相应 API 的版本发布后指定该版本号)。ESM 使用同版本的 `dist/browser/washi.js`。选择 CDN URL 就是显式使用 CDN;本地部署不会自动改用外部 CDN。
366
371
 
367
372
  ### 浏览器环境中的求解器插件(GLPK & Z3)
368
373
 
369
- 浏览器发布包在 `dist/browser/solvers/` 下提供了开箱即用的独立求解器插件(通过 CDN 引入时适用于 `>= 0.2.0` 或 `@latest`):
374
+ 浏览器发布包在 `dist/browser/solvers/` 下提供了开箱即用的独立求解器插件:
370
375
  - **GLPK**: `dist/browser/solvers/glpk.js` (ESM) 与 `dist/browser/solvers/glpk.min.js` (IIFE,挂载全局 `WashiGLPK`)
371
376
  - **Z3**: `dist/browser/solvers/z3.js` (ESM) 与 `dist/browser/solvers/z3.min.js` (IIFE,挂载全局 `WashiZ3`),附带 `z3-built.js` 和 `z3-built.wasm`
372
377
 
373
378
  #### 浏览器 ESM 使用 GLPK
374
379
  ```html
375
380
  <script type="module">
376
- import { Model } from "./washi/washi.js";
381
+ import { Model, maximize } from "./washi/washi.js";
377
382
  import "./washi/solvers/glpk.js";
378
383
 
379
384
  const model = new Model({ solver: "glpk" });
380
385
  const x = model.continuous("x", { lb: 0, ub: 10 });
381
- model.maximize(x);
386
+ model.objective(maximize(x));
382
387
  await model.solve();
383
388
  console.log("GLPK 求解状态:", model.status);
384
389
  </script>
@@ -391,52 +396,34 @@ await model.solve();
391
396
  <script>
392
397
  const model = new Washi.Model({ solver: "glpk" });
393
398
  const x = model.continuous("x", { lb: 0, ub: 10 });
394
- model.maximize(x);
399
+ model.objective(Washi.maximize(x));
395
400
  model.solve().then(status => console.log("GLPK 求解状态:", status));
396
401
  </script>
397
402
  ```
398
403
 
399
404
  > [!NOTE]
400
405
  > **浏览器环境中使用 Z3 的配置要求与跨源隔离**:
401
- > 由于 Z3 的 WebAssembly 引擎依托多线程 (`SharedArrayBuffer`),现代浏览器强制要求 Cross-Origin Isolation。文档响应头必须包含:
402
- > ```http
403
- > Cross-Origin-Opener-Policy: same-origin
404
- > Cross-Origin-Embedder-Policy: require-corp
405
- > ```
406
- > 并且跨源资源必须包含 `Cross-Origin-Resource-Policy: cross-origin` 标头。
407
- >
408
- > 无法自定义响应标头的常见静态托管(如标准 GitHub Pages 或 CodePen 等 iframe 预览环境)在缺少额外配置时无法直接满足条件。引入 `@ohtaman/washi` 核心库绝不会自动向用户项目中注入或注册 Service Worker。
409
- >
410
- > 在 GitHub Pages 部署的 WaSHI 官方 Web Demo 中,通过在同源独立部署作用域严格限定为 `/washi/` 的 `coi-serviceworker.js`,在首次访问时安全自动重载一次以建立 `window.crossOriginIsolated === true` 环境。在不支持 Service Worker 或隔离失败的环境中,Z3 会清晰展示诊断原因并中止执行,防止无限重载或无响应挂起。
411
-
412
- 完整独立的 ESM、Script 标签与 CodePen 示例请参阅 `examples/distribution/`。
413
-
414
- ### 工厂内网、离线部署、Worker 与自定义 URL
415
-
416
- 将应用构建产物或整个 `dist/browser` 目录部署到本地 HTTP / 内网服务器。所有资源可在本地访问时,即使浏览器缓存为空也不需要外部网络。仅保存 HTML 或第一个 JS 文件是不够的。不保证 `file://` 执行,也不自动提供 PWA 缓存。
406
+ > 由于 Z3 的 WebAssembly 引擎依托多线程 (`SharedArrayBuffer`),现代浏览器强制要求跨源隔离(`Cross-Origin-Opener-Policy: same-origin` 与 `Cross-Origin-Embedder-Policy: require-corp`)。关于静态托管(`coi-serviceworker.js`)、离线/内网部署、CSP(`worker-src blob:`)与自定义 WASM URL(`setHighsWasmUrl`)的完整说明,请参阅 [跨源隔离指南](docs/zh/getting-started/cross-origin.md) 与 [运行时环境配置](docs/zh/getting-started/runtimes.md)。
417
407
 
418
- ESM 根据模块 URL 解析资源;script 构建在加载时保存自身的 URL。CDN Worker 使用 Blob 模块启动,需要服务端的跨域资源许可及相应 CSP。CDN Worker 还需允许 `worker-src blob:`。不支持时可使用 `useWorker: false`。Worker 加载或消息处理失败会拒绝求解 Promise。
408
+ 完整独立的 ESM、Script 标签与 CodePen 示例请参阅 [`examples/distribution/`](examples/distribution/README.md)。
419
409
 
420
- 自定义地址仍可通过 `setHighsWasmUrl(url)` 或 `options.wasmUrl` 指定。显式选择现有 HiGHS CDN:
421
-
422
- ```typescript
423
- import { setHighsWasmUrl, OFFICIAL_HIGHS_CDN_WASM_URL } from "@ohtaman/washi";
424
- setHighsWasmUrl(OFFICIAL_HIGHS_CDN_WASM_URL);
425
- ```
410
+ ---
426
411
 
427
- 初始化失败会返回包含请求地址的错误,不会尝试其他主机。依赖旧的域名根目录 / CDN 自动回退的应用需部署生成资源或显式配置 URL。
412
+ ## 🛠️ 自定义求解器开发与架构扩展
428
413
 
429
- ### 验证发布产物
414
+ WaSHI 采用完全解耦的插件式求解器架构。你可以轻松编写并注册自定义求解器适配器(如云端 REST 求解服务、定制 WebAssembly 引擎或商业求解器):
430
415
 
431
- `npm run test:distribution` 安装实际 npm tarball,在没有可选依赖时构建 Vite / webpack 应用,并通过 VM 执行生成的 JS 和真实 WASM。这不等同于浏览器 / CORS 验证。安装 `npx playwright install chromium` 后,运行 `RUN_DISTRIBUTION_BROWSER=1 npm run test:distribution` 以验证 Chromium。CI 使用该模式,验证跨域部署及外部网络请求阻断。
416
+ - 完整开发指南、接口契约(`Solver`, `SolveModelData`, `CheckModelData`, `SolverResult`)与测试实践详见 [自定义求解器开发指南](docs/zh/solvers/custom-solver.md)。
432
417
 
433
418
  ---
434
419
 
435
- ## 🛠️ 自定义求解器开发与架构扩展
420
+ ## 📚 文档指南
436
421
 
437
- WaSHI 采用完全解耦的插件式求解器架构。你可以轻松编写并注册自定义求解器适配器(如云端 REST 求解服务、定制 WebAssembly 引擎或商业求解器):
422
+ 完整文档可在 **[ohtaman.github.io/washi/zh/](https://ohtaman.github.io/washi/zh/)** 及仓库的 [`docs/zh/`](docs/zh/)([英文版 `docs/`](docs/))中查阅:
438
423
 
439
- - 完整开发指南、接口契约(`Solver`, `LpModelData`, `SolverResult`)与测试实践详见 [Custom Solver Developer Guide](docs/custom-solver-guide.md)。
424
+ - **快速上手**: [快速开始](docs/zh/getting-started/index.md) · [AI 编程助手快速参考](docs/zh/getting-started/ai-agents.md) · [运行时环境配置](docs/zh/getting-started/runtimes.md) · [跨源隔离指南 (Z3)](docs/zh/getting-started/cross-origin.md)
425
+ - **建模指南**: [决策变量 (`Var`, `BoolVar`)](docs/zh/guide/variables.md) · [表达式与聚合 (`expr`, `sum`, `dot`)](docs/zh/guide/expressions.md) · [约束与逻辑条件 (`indicator`, SMT)](docs/zh/guide/constraints.md) · [目标函数与求解 (`solve`, `validateSolution`)](docs/zh/guide/objectives.md) · [可满足性与 Unsat Core (`check`)](docs/zh/guide/unsat-core.md) · [分解法 (`solveColumnGeneration`, `solveBenders`)](docs/zh/guide/decomposition.md)
426
+ - **求解器**: [求解器概览](docs/zh/solvers/index.md) · [HiGHS](docs/zh/solvers/highs.md) · [Z3](docs/zh/solvers/z3.md) · [GLPK](docs/zh/solvers/glpk.md) · [自定义求解器](docs/zh/solvers/custom-solver.md)
440
427
 
441
428
  ---
442
429
 
@@ -446,11 +433,13 @@ WaSHI 采用完全解耦的插件式求解器架构。你可以轻松编写并
446
433
 
447
434
  | 类别 | 示例 | 展示内容 | 求解器 |
448
435
  | :--- | :--- | :--- | :--- |
449
- | **基础模型** | [生产计划](https://github.com/ohtaman/washi/blob/main/examples/node/01-production-planning.ts) | 整数变量、利润目标与资源约束 (`expr`, `c`) | HiGHS |
436
+ | **基础模型** | [生产计划](https://github.com/ohtaman/washi/blob/main/examples/node/01-production-planning.ts) | 整数变量、利润目标与资源约束 (`expr`) | HiGHS |
450
437
  | **基础模型** | [运输与分配网络](https://github.com/ohtaman/washi/blob/main/examples/node/09-transportation-problem.ts) | 二维矩阵变量 (`continuous(rows, cols)`) 与供需平衡 | HiGHS |
451
438
  | **基础模型** | [营养问题与灵敏度分析](https://github.com/ohtaman/washi/blob/main/examples/node/10-diet-sensitivity.ts) | 影子价格 (`constr.dual`)、松弛量 (`constr.slack`) 与缩减成本 (`var.reducedCost`) | HiGHS |
452
439
  | **实战应用** | [员工排班与冲突诊断](https://github.com/ohtaman/washi/blob/main/examples/node/11-shift-scheduling.ts) | 周排班优化与周六休假冲突诊断 | HiGHS + Z3 |
453
440
  | **实战应用** | [购物车优惠券最优组合](https://github.com/ohtaman/washi/blob/main/examples/node/12-ecommerce-coupon-optimizer.ts) | 满减门槛条件约束 (`indicator`)、互斥规则与凑单推荐 | HiGHS |
441
+ | **大规模分解** | [车辆路径规划 (CVRP)](https://github.com/ohtaman/washi/blob/main/examples/node/13-vehicle-routing-column-generation.ts) | 列生成法 (Dantzig-Wolfe): 基于对偶影子价格动态定价可行配送路线 | HiGHS |
442
+ | **大规模分解** | [旅行商问题 (TSP)](https://github.com/ohtaman/washi/blob/main/examples/node/14-traveling-salesperson-benders.ts) | Benders 分解 (DFJ 法): 通过可行性割平面延迟生成子回路消除约束 | HiGHS |
454
443
  | **实战应用** | [投资组合分配](https://github.com/ohtaman/washi/blob/main/examples/node/03-portfolio-qp.ts) | 凸二次目标函数 (`QuadExpr`) 与分配约束 | HiGHS |
455
444
  | **逻辑 / SMT** | [业务规则检查](https://github.com/ohtaman/washi/blob/main/examples/node/04-smt-security-rules.ts) | 算术与逻辑约束 (`bool`, `implies`) 的可满足性检查 | Z3 |
456
445
  | **逻辑 / SMT** | [冲突诊断](https://github.com/ohtaman/washi/blob/main/examples/node/05-unsat-core-diagnosis.ts) | 命名约束与 Unsat Core (`unsatCore`) | Z3 |
@@ -468,6 +457,8 @@ npx tsx examples/node/09-transportation-problem.ts
468
457
  npx tsx examples/node/10-diet-sensitivity.ts
469
458
  npx tsx examples/node/11-shift-scheduling.ts
470
459
  npx tsx examples/node/12-ecommerce-coupon-optimizer.ts
460
+ npx tsx examples/node/13-vehicle-routing-column-generation.ts
461
+ npx tsx examples/node/14-traveling-salesperson-benders.ts
471
462
 
472
463
  # 本地浏览器演示: http://localhost:5173/demo/
473
464
  npm run dev
@@ -477,7 +468,7 @@ npm run dev
477
468
 
478
469
  ---
479
470
 
480
- ## 🧪 自动化测试
471
+ ## 🧪 自动化测试与可复现基准测试
481
472
 
482
473
  运行仓库的单元测试与集成测试,并构建分发版本:
483
474
 
@@ -489,11 +480,48 @@ npm test
489
480
  npm run build
490
481
  ```
491
482
 
483
+ ### 可选的可复现基准测试
484
+
485
+ 在不将耗时阈值混入正确性测试断言的前提下,对确定性的 `small-lp`(24 个变量、18 条约束)和 `scheduling-mip`(315 个变量、231 条约束,含重建模型的 `initialValue` 热启动)进行分阶段性能测量:
486
+
487
+ ```bash
488
+ # 运行 Node.js 进程内 WASM 基准测试(HiGHS 与 GLPK,默认 5 次热重复)
489
+ npm run bench
490
+
491
+ # 自定义重复次数或输出 JSON
492
+ node scripts/run-benchmarks.mjs --iterations=10 --json
493
+
494
+ # 同时测量无头 Chromium Web Worker 执行(需要安装 Playwright Chromium)
495
+ node scripts/run-benchmarks.mjs --browser
496
+ ```
497
+
498
+ - **明确的测量边界**:将冷启动初始化(`coldRuntimeInitMs`、`coldFirstSolveMs`)与复用运行时的重复测量(`modelBuildMs`、`validationMs`、LP 字符串适配器的 `lpSerializationMs` 或结构化适配器的 `symbolMapMs`、基于 `MockSolver` 的 `resultMappingMs`、`adapterSolveMs` 以及 `endToEndSolveMs`)分开直接测量,不通过相减来臆造“原生求解器时间”。
499
+ - **区分不同执行环境**:Node.js 进程内 WASM(`usesBrowserWorker: false`)与浏览器 Web Worker 执行(`usesBrowserWorker: true`,包含 Worker 生命周期与 `postMessage` 结构化克隆传输)作为不同执行环境分别报告,不可直接互换作基线。
500
+
501
+ ### HiGHS WebAssembly 重新构建与发布流程
502
+
503
+ 1. **更新 / 重新构建 HiGHS WebAssembly 资源(`highs.config.json`)**:
504
+ ```bash
505
+ # 从 ERGO-Code/HiGHS 编译 public/highs.wasm 与 runtime.js,并更新 highs.config.json 中的 SHA-256 哈希
506
+ npm run build:highs-wasm
507
+
508
+ # 合并到 main 后,将更新后的资源覆盖上传至对应的 highs-<version> GitHub Release 标签,
509
+ # 确保按需下载(scripts/ensure-highs-wasm.mjs)与 highs.config.json 的 SHA-256 校验一致:
510
+ gh release upload highs-v1.15.1 public/highs.wasm src/modeler/solvers/highs/runtime.js --clobber
511
+ ```
512
+ (也可在 GitHub Actions 中手动触发 `.github/workflows/build-wasm.yml` 并启用 `create_release: true`,随后下载工作流产物 `highs-wasm-assets`(含 `public/highs.wasm`、`src/modeler/solvers/highs/runtime.js` 与 `highs.config.json`)并提交至仓库,以确保仓库校验和与已发布的 Release 资产保持同步。)
513
+
514
+ 2. **发布 `@ohtaman/washi` 至 npm**:
515
+ - 合并至 `main` 会自动通过 `.github/workflows/deploy-demo.yml` 部署文档与在线演示到 GitHub Pages,但**不会**自动发布至 npm。
516
+ - 如需发布新版本至 npm,请先在 `main` 上更新 `package.json` 的 `"version"`,然后创建并发布 GitHub Release(例如 `gh release create v0.5.1 --generate-notes`)。发布 Release 会触发 `.github/workflows/publish-npm.yml`,在通过单元测试与 Playwright 分发验证后通过 OIDC Trusted Publishing 自动发布至 npm。
517
+
492
518
  ---
493
519
 
494
520
  ## 📄 许可证
495
521
 
496
522
  - **`@ohtaman/washi`**: [MIT 许可证](./LICENSE)
497
- - **HiGHS**(默认求解器): MIT 许可证
498
- - **Z3**(可选插件): MIT 许可证
499
- - **GLPK**(可选插件): GPL-3.0 许可证
523
+ - **HiGHS**(默认求解器,[ERGO-Code/HiGHS](https://github.com/ERGO-Code/HiGHS)): MIT 许可证
524
+ - **Z3**(可选插件,通过 [`z3-solver`](https://www.npmjs.com/package/z3-solver)): MIT 许可证
525
+ - **GLPK**(可选插件,通过 [`glpk.js`](https://www.npmjs.com/package/glpk.js)): GPL-3.0 许可证
526
+
527
+ 有关内置及外部求解器的完整版权声明和许可信息,请参阅 [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md)。
@@ -9,15 +9,14 @@ Depending on the solver you choose at runtime, WaSHI interacts with the followin
9
9
  ## 1. HiGHS (Default Solver)
10
10
 
11
11
  - **Role**: Default Linear & Mixed-Integer Programming Engine (WebAssembly)
12
- - **Package**: [`highs`](https://www.npmjs.com/package/highs)
13
12
  - **License**: **MIT License**
14
- - **Upstream Repository**: [ERGO-Code/HiGHS](https://github.com/ERGO-Code/HiGHS) / [lovasoa/highs-js](https://github.com/lovasoa/highs-js)
13
+ - **Upstream Repository**: [ERGO-Code/HiGHS](https://github.com/ERGO-Code/HiGHS)
14
+ - **Compilation**: Directly compiled from official upstream source to WebAssembly via native C API (`highs_c_api.h`)
15
15
 
16
16
  ```text
17
17
  MIT License
18
18
 
19
- Copyright (c) 2023 highs-js
20
- Copyright (c) 2026 HiGHS
19
+ Copyright (c) 2026 ERGO-Code / HiGHS developers
21
20
 
22
21
  Permission is hereby granted, free of charge, to any person obtaining a copy
23
22
  of this software and associated documentation files (the "Software"), to deal
File without changes