@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.
- package/README.ja.md +149 -121
- package/README.md +149 -121
- package/README.zh-CN.md +150 -122
- package/THIRD_PARTY_LICENSES.md +3 -4
- package/dist/browser/_washi-node-only-BvRk9kiK.js +0 -0
- package/dist/browser/browser-runtime-TLCY0hkc.js +1793 -0
- package/dist/browser/highs-worker.js +21 -3
- package/dist/browser/highs.wasm +0 -0
- package/dist/browser/highs.wasm.LICENSE +1 -2
- package/dist/browser/loader-DewlSho8.js +643 -0
- package/dist/browser/solvers/glpk.js +433 -286
- package/dist/browser/solvers/glpk.min.js +1 -1
- package/dist/browser/solvers/z3.js +1008 -981
- package/dist/browser/solvers/z3.min.js +2 -2
- package/dist/browser/washi.js +2778 -673
- package/dist/browser/washi.min.js +3 -4
- package/dist/lib/_washi-node-only-BvRk9kiK.js +0 -0
- package/dist/lib/highs-browser-runtime.js +2120 -4124
- package/dist/lib/highs-node-runtime.js +24 -1
- package/dist/lib/highs-runtime.js +2 -0
- package/dist/lib/highs-worker.js +21 -3
- package/dist/lib/highs.wasm +0 -0
- package/dist/lib/highs.wasm.LICENSE +1 -2
- package/dist/lib/loader-BZUQNvh4.js +649 -0
- package/dist/lib/registry-C20sxTwm.js +964 -0
- package/dist/lib/solvers/glpk.js +201 -90
- package/dist/lib/solvers/z3.js +399 -259
- package/dist/lib/washi.js +2363 -1056
- package/dist/types/decomposition/benders.d.ts +32 -0
- package/dist/types/decomposition/benders.d.ts.map +1 -0
- package/dist/types/decomposition/column-generation.d.ts +34 -0
- package/dist/types/decomposition/column-generation.d.ts.map +1 -0
- package/dist/types/decomposition/index.d.ts +4 -0
- package/dist/types/decomposition/index.d.ts.map +1 -0
- package/dist/types/decomposition/types.d.ts +230 -0
- package/dist/types/decomposition/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modeler/big-m.d.ts +75 -0
- package/dist/types/modeler/big-m.d.ts.map +1 -0
- package/dist/types/modeler/boolean-expr.d.ts +103 -14
- package/dist/types/modeler/boolean-expr.d.ts.map +1 -1
- package/dist/types/modeler/constraint.d.ts +47 -9
- package/dist/types/modeler/constraint.d.ts.map +1 -1
- package/dist/types/modeler/expression.d.ts +123 -28
- package/dist/types/modeler/expression.d.ts.map +1 -1
- package/dist/types/modeler/index.d.ts +11 -6
- package/dist/types/modeler/index.d.ts.map +1 -1
- package/dist/types/modeler/linearizer.d.ts +15 -0
- package/dist/types/modeler/linearizer.d.ts.map +1 -0
- package/dist/types/modeler/lp-writer.d.ts +30 -3
- package/dist/types/modeler/lp-writer.d.ts.map +1 -1
- package/dist/types/modeler/model.d.ts +623 -131
- package/dist/types/modeler/model.d.ts.map +1 -1
- package/dist/types/modeler/objective.d.ts +59 -0
- package/dist/types/modeler/objective.d.ts.map +1 -0
- package/dist/types/modeler/parser.d.ts +34 -10
- package/dist/types/modeler/parser.d.ts.map +1 -1
- package/dist/types/modeler/quad-expr.d.ts +26 -7
- package/dist/types/modeler/quad-expr.d.ts.map +1 -1
- package/dist/types/modeler/solution-validator.d.ts +93 -0
- package/dist/types/modeler/solution-validator.d.ts.map +1 -0
- package/dist/types/modeler/solvers/glpk/solver.d.ts +26 -2
- package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/browser-runtime.d.ts +2 -1
- package/dist/types/modeler/solvers/highs/browser-runtime.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/driver.d.ts +232 -0
- package/dist/types/modeler/solvers/highs/driver.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs/index.d.ts +1 -0
- package/dist/types/modeler/solvers/highs/index.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/loader.d.ts +38 -13
- package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/node-runtime.d.ts +2 -1
- package/dist/types/modeler/solvers/highs/node-runtime.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/solver.d.ts +12 -5
- package/dist/types/modeler/solvers/highs/solver.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/worker-client.d.ts.map +1 -1
- package/dist/types/modeler/solvers/mock.d.ts +14 -5
- package/dist/types/modeler/solvers/mock.d.ts.map +1 -1
- package/dist/types/modeler/solvers/types.d.ts +73 -11
- package/dist/types/modeler/solvers/types.d.ts.map +1 -1
- package/dist/types/modeler/solvers/z3/loader.d.ts +2 -3
- package/dist/types/modeler/solvers/z3/loader.d.ts.map +1 -1
- package/dist/types/modeler/solvers/z3/solver.d.ts +15 -5
- package/dist/types/modeler/solvers/z3/solver.d.ts.map +1 -1
- package/dist/types/modeler/types.d.ts +86 -1
- package/dist/types/modeler/types.d.ts.map +1 -1
- package/dist/types/modeler/validation.d.ts +56 -0
- package/dist/types/modeler/validation.d.ts.map +1 -0
- package/dist/types/modeler/variable.d.ts +48 -14
- package/dist/types/modeler/variable.d.ts.map +1 -1
- package/docs/examples/diet-sensitivity.md +90 -0
- package/docs/examples/ecommerce-coupons.md +106 -0
- package/docs/examples/index.md +57 -0
- package/docs/examples/knapsack.md +60 -0
- package/docs/examples/portfolio-qp.md +83 -0
- package/docs/examples/production.md +51 -0
- package/docs/examples/shift-scheduling.md +175 -0
- package/docs/examples/smt-security.md +74 -0
- package/docs/examples/transportation.md +90 -0
- package/docs/examples/traveling-salesperson.md +173 -0
- package/docs/examples/unsat-core.md +64 -0
- package/docs/examples/vehicle-routing.md +206 -0
- package/docs/getting-started/ai-agents.md +271 -0
- package/docs/getting-started/cross-origin.md +87 -0
- package/docs/getting-started/index.md +116 -0
- package/docs/getting-started/runtimes.md +227 -0
- package/docs/guide/constraints.md +177 -0
- package/docs/guide/decomposition.md +399 -0
- package/docs/guide/expressions.md +204 -0
- package/docs/guide/objectives.md +170 -0
- package/docs/guide/unsat-core.md +154 -0
- package/docs/guide/variables.md +188 -0
- package/docs/ja/getting-started/ai-agents.md +270 -0
- package/docs/solvers/custom-solver.md +525 -0
- package/docs/solvers/glpk.md +66 -0
- package/docs/solvers/highs.md +115 -0
- package/docs/solvers/index.md +42 -0
- package/docs/solvers/z3.md +78 -0
- package/docs/zh/getting-started/ai-agents.md +270 -0
- package/llms-full.txt +4065 -0
- package/llms.txt +201 -0
- package/package.json +32 -16
- package/skills/washi/SKILL.md +197 -0
- package/dist/browser/browser-runtime-D13gHOT5.js +0 -4189
- package/dist/browser/loader-CVt4CloI.js +0 -58
- package/dist/lib/async-mutex-Duo4jwzn.js +0 -195
- package/dist/lib/constraint-BRuB3ooC.js +0 -90
- package/dist/lib/loader-Dti0v9yC.js +0 -50
- 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 -
|
|
5
|
+
<img alt="WaSHI - 适用于数理优化与约束编程的代数建模器 (TypeScript & JavaScript)" src="./assets/washi-header-light.png" width="420" />
|
|
6
6
|
</picture>
|
|
7
|
-
<p><strong
|
|
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
|
|
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.
|
|
42
|
-
m.
|
|
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.
|
|
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
|
|
53
|
-
2. **求解器适配器**:通过共同的建模 API 使用 HiGHS、Z3 或 GLPK,也可以[注册自己的适配器](https://github.com/ohtaman/washi/blob/main/docs/custom-solver
|
|
54
|
-
3. **本地执行与 WebAssembly
|
|
55
|
-
4.
|
|
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.
|
|
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("
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
218
|
-
m.
|
|
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.
|
|
222
|
-
m.
|
|
223
|
-
m.
|
|
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.
|
|
232
|
+
### 4. 冲突诊断 (`conflicts` / `unsatCore`)
|
|
235
233
|
|
|
236
|
-
|
|
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(
|
|
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.
|
|
247
|
+
m.constraint(expr`8000 * ${engineers} <= ${budget}`, "budget_limit");
|
|
249
248
|
|
|
250
249
|
// 规则 2: 客户要求加急交付
|
|
251
|
-
m.
|
|
250
|
+
m.constraint(rushDelivery, "rush_required");
|
|
252
251
|
|
|
253
252
|
// 规则 3: 加急交付需至少配备 8 名工程师
|
|
254
|
-
m.
|
|
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.
|
|
256
|
+
m.constraint(expr`${budget} <= 50000`, "strict_board_budget_cap");
|
|
258
257
|
|
|
259
258
|
// 规则 5: 最低 1 名员工用工底线(无关规则)
|
|
260
|
-
m.
|
|
259
|
+
m.constraint(expr`${engineers} >= 1`, "minimum_one_employee");
|
|
261
260
|
|
|
262
|
-
|
|
261
|
+
// 1. 使用默认 HiGHS 进行弹性修复诊断
|
|
262
|
+
const res = await m.check();
|
|
263
263
|
|
|
264
264
|
console.log(`求解状态: ${res.status}`); // "Unsat"
|
|
265
|
-
console.log("
|
|
266
|
-
// 输出: ["
|
|
267
|
-
//
|
|
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.
|
|
286
|
-
m.
|
|
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.
|
|
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.
|
|
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
|
|
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/`
|
|
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`)
|
|
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
|
|
408
|
+
完整独立的 ESM、Script 标签与 CodePen 示例请参阅 [`examples/distribution/`](examples/distribution/README.md)。
|
|
419
409
|
|
|
420
|
-
|
|
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
|
-
|
|
412
|
+
## 🛠️ 自定义求解器开发与架构扩展
|
|
428
413
|
|
|
429
|
-
|
|
414
|
+
WaSHI 采用完全解耦的插件式求解器架构。你可以轻松编写并注册自定义求解器适配器(如云端 REST 求解服务、定制 WebAssembly 引擎或商业求解器):
|
|
430
415
|
|
|
431
|
-
|
|
416
|
+
- 完整开发指南、接口契约(`Solver`, `SolveModelData`, `CheckModelData`, `SolverResult`)与测试实践详见 [自定义求解器开发指南](docs/zh/solvers/custom-solver.md)。
|
|
432
417
|
|
|
433
418
|
---
|
|
434
419
|
|
|
435
|
-
##
|
|
420
|
+
## 📚 文档指南
|
|
436
421
|
|
|
437
|
-
|
|
422
|
+
完整文档可在 **[ohtaman.github.io/washi/zh/](https://ohtaman.github.io/washi/zh/)** 及仓库的 [`docs/zh/`](docs/zh/)([英文版 `docs/`](docs/))中查阅:
|
|
438
423
|
|
|
439
|
-
-
|
|
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
|
|
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
|
|
498
|
-
- **Z3
|
|
499
|
-
- **GLPK
|
|
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)。
|
package/THIRD_PARTY_LICENSES.md
CHANGED
|
@@ -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)
|
|
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)
|
|
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
|