@ohtaman/washi 0.6.0 → 0.7.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 +103 -421
- package/README.md +103 -421
- package/README.zh-CN.md +103 -421
- package/THIRD_PARTY_LICENSES.md +5 -3
- package/dist/browser/solvers/glpk.js +2 -2
- package/dist/browser/solvers/glpk.min.js +1 -1
- package/dist/browser/washi.js +777 -261
- package/dist/browser/washi.min.js +3 -3
- package/dist/lib/{registry-C20sxTwm.js → registry-D7TZ3Wh_.js} +88 -18
- package/dist/lib/solvers/glpk.js +3 -3
- package/dist/lib/solvers/z3.js +1 -1
- package/dist/lib/washi.js +864 -421
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modeler/expression.d.ts +47 -26
- package/dist/types/modeler/expression.d.ts.map +1 -1
- package/dist/types/modeler/index.d.ts +2 -2
- package/dist/types/modeler/index.d.ts.map +1 -1
- package/dist/types/modeler/model.d.ts +12 -6
- package/dist/types/modeler/model.d.ts.map +1 -1
- package/dist/types/modeler/parser.d.ts +25 -5
- package/dist/types/modeler/parser.d.ts.map +1 -1
- package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -1
- 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/types.d.ts +2 -0
- package/dist/types/modeler/solvers/types.d.ts.map +1 -1
- package/docs/examples/diet-sensitivity.md +15 -14
- package/docs/examples/ecommerce-coupons.md +15 -22
- package/docs/examples/index.md +14 -12
- package/docs/examples/knapsack.md +8 -7
- package/docs/examples/portfolio-qp.md +11 -4
- package/docs/examples/production.md +4 -4
- package/docs/examples/shift-scheduling.md +20 -7
- package/docs/examples/smt-security.md +16 -4
- package/docs/examples/transportation.md +46 -19
- package/docs/examples/traveling-salesperson.md +28 -44
- package/docs/examples/unsat-core.md +15 -5
- package/docs/examples/vehicle-routing.md +10 -8
- package/docs/getting-started/ai-agents.md +25 -14
- package/docs/getting-started/cross-origin.md +56 -28
- package/docs/getting-started/index.md +40 -69
- package/docs/getting-started/runtimes.md +66 -61
- package/docs/guide/constraints.md +46 -40
- package/docs/guide/decomposition.md +127 -259
- package/docs/guide/expressions.md +90 -39
- package/docs/guide/formulation-tips.md +212 -0
- package/docs/guide/objectives.md +7 -4
- package/docs/guide/unsat-core.md +18 -6
- package/docs/guide/variables.md +33 -38
- package/docs/ja/getting-started/ai-agents.md +24 -14
- package/docs/solvers/highs.md +27 -6
- package/docs/solvers/index.md +1 -1
- package/docs/solvers/z3.md +3 -0
- package/docs/zh/getting-started/ai-agents.md +24 -14
- package/llms-full.txt +929 -687
- package/llms.txt +21 -19
- package/package.json +3 -3
- package/skills/washi/SKILL.md +14 -10
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 数理优化建模器" src="./assets/washi-header-light.png" width="420" />
|
|
6
6
|
</picture>
|
|
7
|
-
<p><strong
|
|
7
|
+
<p><strong>TypeScript 数理优化建模器</strong></p>
|
|
8
8
|
<p>
|
|
9
9
|
<em>线性规划 (LP) • 混合整数规划 (MIP) • 凸二次规划 (QP) • SMT逻辑约束与冲突诊断</em>
|
|
10
10
|
</p>
|
|
@@ -16,512 +16,194 @@
|
|
|
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.
|
|
20
|
-
<a href="https://ohtaman.
|
|
19
|
+
<a href="https://washi.ohtaman.dev/zh/"><img src="https://img.shields.io/badge/docs-online-blue" alt="docs" /></a>
|
|
20
|
+
<a href="https://washi.ohtaman.dev/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>
|
|
23
23
|
</div>
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
**WaSHI** (WebAssembly-backed, Solver-independent, High-level modeling Interface) 是面向 TypeScript / JavaScript 的数理优化与约束编程代数建模器,受到 Python **PuLP**
|
|
27
|
+
**WaSHI** (WebAssembly-backed, Solver-independent, High-level modeling Interface) 是面向 TypeScript / JavaScript 的数理优化与约束编程代数建模器,受到 Python **PuLP** 的启发。你可以在应用代码中定义变量、目标函数和约束,并在 Node.js 或浏览器本地使用 **HiGHS**(默认)、**Z3** 或 **GLPK** 求解。
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
## ✨ 核心特性
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
- **直观的代数语法**:通过 `` expr`30 * ${x} + 50 * ${y} <= 40` `` 与求和、点积(`sum`, `dot`)清晰编写公式与约束。
|
|
32
|
+
- **跨 Node.js 与浏览器本地运行**:基于 WebAssembly,无需单独部署 Python 服务或本地编译 C/C++。
|
|
33
|
+
- **求解器无关**:内置 **HiGHS**,支持按需加载 **Z3**、**GLPK** 插件或自定义求解器适配器。
|
|
34
|
+
- **可满足性判定与冲突诊断**:支持逻辑与算术约束的可满足性判定,并在模型不可行时定位矛盾约束。
|
|
35
|
+
- **大规模分解算法**:内置列生成法与 Benders 分解支持。
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
import { Model, expr, maximize } from "@ohtaman/washi";
|
|
35
|
-
|
|
36
|
-
const m = new Model("木工产品利润最大化");
|
|
37
|
-
const x = m.integer("桌子", { lb: 0 });
|
|
38
|
-
const y = m.integer("椅子", { lb: 0 });
|
|
39
|
-
|
|
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
|
-
|
|
44
|
-
await m.solve();
|
|
45
|
-
console.log(`生产计划: x=${x.value}, y=${y.value} (最大利润: $${m.objectiveValue})`);
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
## 🎯 WaSHI 提供的功能
|
|
51
|
-
|
|
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(...)`)的清晰回调编排,协同对偶定价、割平面生成与整数解复原。
|
|
57
|
-
|
|
58
|
-
模型构建与转换由 WaSHI 负责。支持的问题类型、数值行为和求解时间取决于所选求解器、配置及具体问题。建模开销与求解器执行时间应分别测量;某个模型上的结果并不构成通用性能保证。
|
|
37
|
+
## 📚 文档与链接
|
|
59
38
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
| 适配器 | 引擎许可证 | 支持的问题类型 | 引擎作用 | 集成方式 |
|
|
65
|
-
| :--- | :--- | :--- | :--- | :--- |
|
|
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`) |
|
|
69
|
-
| **Mock** | **MIT** | — | 为集成测试提供模拟响应 | 内置;不实际求解模型 |
|
|
39
|
+
- **[在线文档](https://washi.ohtaman.dev/zh/)**:建模指南、求解器说明与运行环境配置
|
|
40
|
+
- **[案例展示](https://washi.ohtaman.dev/zh/showcase/) & [浏览器演示](https://washi.ohtaman.dev/demo/)**:在线体验交互式应用与浏览器建模演练场
|
|
41
|
+
- **[示例目录](https://washi.ohtaman.dev/zh/examples/)**:各类问题的建模示例与可运行源码([`examples/`](examples/README.md))
|
|
42
|
+
- **[AI 编程助手快速参考](docs/zh/getting-started/ai-agents.md) · [Agent Skill (`SKILL.md`)](skills/washi/SKILL.md) · [`llms.txt`](https://washi.ohtaman.dev/llms.txt) / [`llms-full.txt`](https://washi.ohtaman.dev/llms-full.txt)**:面向 AI 编程助手的速查指南、技能定义与机器可读文档
|
|
70
43
|
|
|
71
44
|
---
|
|
72
45
|
|
|
73
|
-
## 📦
|
|
46
|
+
## 📦 安装与快速开始
|
|
74
47
|
|
|
75
48
|
```bash
|
|
76
|
-
# npm
|
|
77
49
|
npm install @ohtaman/washi
|
|
78
50
|
|
|
79
|
-
#
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# yarn
|
|
83
|
-
yarn add @ohtaman/washi
|
|
51
|
+
# 可选求解器插件
|
|
52
|
+
npm install z3-solver # 用于 SMT 逻辑与冲突诊断
|
|
53
|
+
npm install glpk.js # 用于 GLPK 求解器 (GPL-3.0)
|
|
84
54
|
|
|
85
|
-
#
|
|
86
|
-
bun add @ohtaman/washi
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
*(可选)* 若需使用 Z3 或 GLPK 求解器,可按需安装对应依赖包:
|
|
90
|
-
|
|
91
|
-
```bash
|
|
92
|
-
npm install z3-solver # 用于 SMT 与冲突诊断
|
|
93
|
-
npm install glpk.js # 用于 GLPK 求解器 (GPL-3.0)
|
|
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) 安装
|
|
55
|
+
# 可选:为 AI 编程助手(Claude Code, Cursor, Codex 等)安装建模技能
|
|
100
56
|
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
57
|
```
|
|
106
58
|
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## 🚀 快速上手指南
|
|
110
|
-
|
|
111
|
-
### 1. 多维变量、条件指示约束 (`m.indicator`) 与解验证 (`m.validateSolution`)
|
|
112
|
-
|
|
113
|
-
一行代码声明一维字典或二维变量矩阵,通过 `m.indicator()` 表达 Big-M 条件规则,结合 `onProgress` / `AbortSignal` 控制求解过程,并通过 `m.validateSolution()` 独立校验解的合法性:
|
|
114
|
-
|
|
115
59
|
```ts
|
|
116
|
-
import { Model, expr } from "@ohtaman/washi";
|
|
117
|
-
|
|
118
|
-
const m = new Model("FacilityPlanning");
|
|
119
|
-
|
|
120
|
-
// 1D 字典形式的二元变量
|
|
121
|
-
const openCity = m.binary(["Tokyo", "Osaka", "Nagoya"]);
|
|
122
|
-
|
|
123
|
-
// 2D 运输量矩阵: [工厂] x [门店]
|
|
124
|
-
const flow = m.continuous(["F1", "F2"], ["StoreA", "StoreB"], { lb: 0, ub: 1000 });
|
|
125
|
-
|
|
126
|
-
// 2D 网格坐标 (例如 8x8 棋盘)
|
|
127
|
-
const board = m.binary(8, 8, { prefix: "queen" });
|
|
128
|
-
|
|
129
|
-
// Big-M 条件约束: 若工厂关闭 (openCity['Tokyo'] == 0),则 flow <= 0
|
|
130
|
-
// (省略 M 时,WaSHI 会根据变量的有限上下界自动推导紧凑安全的 Big-M)
|
|
131
|
-
m.indicator(openCity["Tokyo"], expr`${flow["F1"]["StoreA"]} <= 0`, {
|
|
132
|
-
activeValue: 0,
|
|
133
|
-
name: "tokyo_closed_no_flow",
|
|
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);
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
---
|
|
151
|
-
|
|
152
|
-
### 2. 投资组合风险最小化 (凸二次规划: QP)
|
|
60
|
+
import { Model, expr, maximize } from "@ohtaman/washi";
|
|
153
61
|
|
|
154
|
-
|
|
62
|
+
const m = new Model("木工产品利润最大化");
|
|
63
|
+
const x = m.integer("桌子", { lb: 0 });
|
|
64
|
+
const y = m.integer("椅子", { lb: 0 });
|
|
155
65
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const m = new Model("MarkowitzPortfolio");
|
|
160
|
-
const assets = ["Tech", "Bonds", "RealEstate"];
|
|
161
|
-
const returns = [0.14, 0.04, 0.08];
|
|
162
|
-
|
|
163
|
-
// 决策变量: 各资产投资权重 (0.0 ~ 1.0)
|
|
164
|
-
const w = m.continuous(assets, { lb: 0, ub: 1 });
|
|
165
|
-
|
|
166
|
-
// 1. 预算约束: 资金分配总额 100%
|
|
167
|
-
m.constraint(expr`${sum(assets, (a) => w[a])} == 1.0`, "budget");
|
|
168
|
-
|
|
169
|
-
// 2. 目标回报率: 组合最低回报率 >= 8.5%
|
|
170
|
-
const retMap = Object.fromEntries(assets.map((a, i) => [a, returns[i]]));
|
|
171
|
-
m.constraint(expr`${dot(retMap, w)} >= 0.085`, "min_return");
|
|
172
|
-
|
|
173
|
-
// 3. 资产协方差矩阵 (风险与相关性)
|
|
174
|
-
const cov = [
|
|
175
|
-
[0.040, 0.002, 0.015],
|
|
176
|
-
[0.002, 0.005, 0.002],
|
|
177
|
-
[0.015, 0.002, 0.025],
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
// 二次目标函数: w^T * Cov * w
|
|
181
|
-
let risk = new QuadExpr();
|
|
182
|
-
for (let i = 0; i < assets.length; i++) {
|
|
183
|
-
for (let j = 0; j < assets.length; j++) {
|
|
184
|
-
risk = risk.add(w[assets[i]].mul(w[assets[j]]).mul(cov[i][j]));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
m.objective(minimize(risk));
|
|
66
|
+
m.objective(maximize(expr`30 * ${x} + 50 * ${y}`));
|
|
67
|
+
m.constraint(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
|
|
68
|
+
m.constraint(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
|
|
188
69
|
|
|
189
70
|
await m.solve();
|
|
190
|
-
console.log(
|
|
191
|
-
assets.forEach((name) => {
|
|
192
|
-
console.log(` ${name}: ${((w[name].value || 0) * 100).toFixed(2)}%`);
|
|
193
|
-
});
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
---
|
|
197
|
-
|
|
198
|
-
### 3. SMT 逻辑与规则引擎 (集成 Z3)
|
|
199
|
-
|
|
200
|
-
原生支持布尔命题变量(`BoolVar`)、逻辑连接词(`and`, `or`, `implies`, `not`, `xor`)与数值算术约束的混合表达:
|
|
201
|
-
|
|
202
|
-
```ts
|
|
203
|
-
import { Model, not, expr } from "@ohtaman/washi";
|
|
204
|
-
import "@ohtaman/washi/solvers/z3";
|
|
205
|
-
|
|
206
|
-
const m = new Model({ name: "SmartSecurityRules" });
|
|
207
|
-
|
|
208
|
-
const isNight = m.bool("isNight");
|
|
209
|
-
const motion = m.bool("motion");
|
|
210
|
-
const alarm = m.bool("alarm");
|
|
211
|
-
const siren = m.bool("siren");
|
|
212
|
-
const lux = m.integer("lux", { lb: 0 });
|
|
213
|
-
|
|
214
|
-
// 规则定义
|
|
215
|
-
m.constraint(lux.le(50).implies(isNight), "dark_implies_night");
|
|
216
|
-
m.constraint(motion.and(isNight).and(alarm).implies(siren), "alarm_rule");
|
|
217
|
-
|
|
218
|
-
// 传感器当前输入数据
|
|
219
|
-
m.constraint(expr`${lux} <= 10`, "sensor_dark");
|
|
220
|
-
m.constraint(motion, "sensor_motion");
|
|
221
|
-
m.constraint(alarm, "alarm_on");
|
|
222
|
-
|
|
223
|
-
// 无目标函数直接判定可满足性 (SAT)
|
|
224
|
-
const res = await m.check({ solver: "z3" });
|
|
225
|
-
|
|
226
|
-
console.log(`系统状态满足? ${res.status === "Sat"}`); // true
|
|
227
|
-
console.log(`警报响起? ${m.values.get("siren")}`); // true
|
|
71
|
+
console.log(`生产计划: x=${x.value}, y=${y.value} (最大利润: $${m.objectiveValue})`);
|
|
228
72
|
```
|
|
229
73
|
|
|
230
74
|
---
|
|
231
75
|
|
|
232
|
-
|
|
233
|
-
|
|
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
|
-
|
|
238
|
-
```ts
|
|
239
|
-
import { Model, expr } from "@ohtaman/washi";
|
|
240
|
-
|
|
241
|
-
const m = new Model("ConflictDiagnosis");
|
|
242
|
-
const engineers = m.integer("engineers", { lb: 0, ub: 20 });
|
|
243
|
-
const budget = m.continuous("budget", { lb: 0, ub: 100000 });
|
|
244
|
-
const rushDelivery = m.bool("rushDelivery");
|
|
245
|
-
|
|
246
|
-
// 规则 1: 每位工程师成本 $8,000
|
|
247
|
-
m.constraint(expr`8000 * ${engineers} <= ${budget}`, "budget_limit");
|
|
248
|
-
|
|
249
|
-
// 规则 2: 客户要求加急交付
|
|
250
|
-
m.constraint(rushDelivery, "rush_required");
|
|
251
|
-
|
|
252
|
-
// 规则 3: 加急交付需至少配备 8 名工程师
|
|
253
|
-
m.constraint(rushDelivery.implies(engineers.ge(8)), "rush_staffing_rule");
|
|
254
|
-
|
|
255
|
-
// 规则 4: 董事会严格预算上限 $50,000 (冲突点: 8人 * $8,000 = $64,000 > $50,000!)
|
|
256
|
-
m.constraint(expr`${budget} <= 50000`, "strict_board_budget_cap");
|
|
257
|
-
|
|
258
|
-
// 规则 5: 最低 1 名员工用工底线(无关规则)
|
|
259
|
-
m.constraint(expr`${engineers} >= 1`, "minimum_one_employee");
|
|
76
|
+
## ⚙️ 求解器概览
|
|
260
77
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
// (松弛 rush_required 即可恢复可行性;无关的 minimum_one_employee 不受影响)
|
|
78
|
+
| 求解器 | 许可证 | 支持问题类型 | 主要用途 | 引入方式 |
|
|
79
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
80
|
+
| **[HiGHS](https://github.com/ERGO-Code/HiGHS)** | MIT | LP, MIP, 凸QP | 数值优化与弹性冲突修复诊断 | 默认内置 |
|
|
81
|
+
| **[Z3](https://github.com/Z3Prover/z3)** | MIT | SMT, SAT, 逻辑, MIP | 逻辑规则、可满足性判定与精确 `unsatCore` | `import "@ohtaman/washi/solvers/z3"` |
|
|
82
|
+
| **[GLPK](https://www.gnu.org/software/glpk/)** | GPL-3.0 | LP, MIP | 线性与混合整数规划 | `import "@ohtaman/washi/solvers/glpk"` |
|
|
83
|
+
| **Mock** | MIT | — | 单元与集成测试模拟响应 | 内置 (`MockSolver`) |
|
|
268
84
|
|
|
269
|
-
|
|
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"]
|
|
273
|
-
```
|
|
85
|
+
导入对应插件后,可在 `new Model(...)`、`m.solve(...)` 或 `m.check(...)` 中传入 `{ solver: "z3" }` 或 `{ solver: "glpk" }`。
|
|
274
86
|
|
|
275
87
|
---
|
|
276
88
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
使用 GNU Linear Programming Kit (GLPK) 求解器插件:
|
|
280
|
-
|
|
281
|
-
```ts
|
|
282
|
-
import { Model, expr, maximize } from "@ohtaman/washi";
|
|
283
|
-
import "@ohtaman/washi/solvers/glpk";
|
|
89
|
+
## 🚀 常用用法示例
|
|
284
90
|
|
|
285
|
-
|
|
286
|
-
const x = m.integer("x", { lb: 0 });
|
|
287
|
-
const y = m.integer("y", { lb: 0 });
|
|
91
|
+
### 1. 求和、点积(`sum` / `dot`)与条件约束
|
|
288
92
|
|
|
289
|
-
|
|
290
|
-
m.constraint(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
|
|
291
|
-
m.constraint(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
|
|
292
|
-
|
|
293
|
-
const status = await m.solve();
|
|
294
|
-
console.log(`求解状态: ${status}`); // "Optimal"
|
|
295
|
-
console.log(`目标函数值: ${m.objectiveValue}`); // 1100
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
---
|
|
299
|
-
|
|
300
|
-
### 6. 向量运算与高效点积 (`dot`)
|
|
301
|
-
|
|
302
|
-
无需嵌套循环,一行代码完成一维和二维变量的线性组合:
|
|
93
|
+
使用 `dot` / `sum` 组合线性表达式,并通过 `m.indicator()` 表达条件规则:
|
|
303
94
|
|
|
304
95
|
```ts
|
|
305
|
-
import { Model,
|
|
96
|
+
import { Model, expr, minimize } from "@ohtaman/washi";
|
|
306
97
|
|
|
307
|
-
const m = new Model();
|
|
98
|
+
const m = new Model("TransportPlanning");
|
|
308
99
|
const factories = ["Tokyo", "Osaka"];
|
|
309
100
|
const stores = ["StoreA", "StoreB"];
|
|
310
|
-
|
|
311
101
|
const costs = {
|
|
312
102
|
Tokyo: { StoreA: 4, StoreB: 7 },
|
|
313
103
|
Osaka: { StoreA: 8, StoreB: 3 },
|
|
314
104
|
};
|
|
315
105
|
|
|
316
|
-
const
|
|
106
|
+
const open = m.binary(factories);
|
|
107
|
+
const ship = m.continuous(factories, stores, { lb: 0, ub: 500 });
|
|
317
108
|
|
|
318
|
-
//
|
|
319
|
-
m.
|
|
109
|
+
// 若东京工厂关闭 (open["Tokyo"] == 0),从东京工厂发出的总运输量必须为 0
|
|
110
|
+
m.indicator(open["Tokyo"], expr`sum(${ship["Tokyo"]}) <= 0`, { activeValue: 0 });
|
|
111
|
+
m.constraint(expr`${ship["Tokyo"]["StoreA"]} + ${ship["Osaka"]["StoreA"]} >= 100`, "demand_A");
|
|
112
|
+
|
|
113
|
+
m.objective(minimize(expr`dot(${costs}, ${ship})`));
|
|
320
114
|
await m.solve();
|
|
321
115
|
|
|
322
|
-
|
|
323
|
-
const solution = m.getValues(ship);
|
|
324
|
-
console.log(solution);
|
|
116
|
+
console.log("Tokyo -> StoreA:", ship["Tokyo"]["StoreA"].value);
|
|
325
117
|
```
|
|
326
118
|
|
|
327
|
-
|
|
119
|
+
### 2. 凸二次规划 (QP)
|
|
328
120
|
|
|
329
|
-
|
|
121
|
+
在线性约束下最小化二次目标函数:
|
|
330
122
|
|
|
331
|
-
|
|
123
|
+
```ts
|
|
124
|
+
import { Model, expr, minimize } from "@ohtaman/washi";
|
|
332
125
|
|
|
333
|
-
|
|
126
|
+
const m = new Model("PortfolioQP");
|
|
127
|
+
const x = m.continuous("tech", { lb: 0, ub: 1 });
|
|
128
|
+
const y = m.continuous("bonds", { lb: 0, ub: 1 });
|
|
334
129
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
// 定义变量、目标函数和约束
|
|
339
|
-
await model.solve();
|
|
340
|
-
```
|
|
130
|
+
m.constraint(expr`${x} + ${y} == 1`, "budget");
|
|
131
|
+
m.constraint(expr`0.14 * ${x} + 0.04 * ${y} >= 0.08`, "min_return");
|
|
132
|
+
m.objective(minimize(expr`0.04 * ${x}^2 + 0.005 * ${y}^2`));
|
|
341
133
|
|
|
342
|
-
|
|
134
|
+
await m.solve();
|
|
135
|
+
console.log(`Tech: ${x.value?.toFixed(2)}, Bonds: ${y.value?.toFixed(2)}`);
|
|
136
|
+
```
|
|
343
137
|
|
|
344
|
-
###
|
|
138
|
+
### 3. SMT 逻辑规则与冲突诊断 (`m.check`)
|
|
345
139
|
|
|
346
|
-
|
|
140
|
+
表达逻辑蕴含规则并排查不可行原因:
|
|
141
|
+
- **HiGHS(默认)**:提取**弹性修复集合**(`res.conflicts`),即松弛后可恢复可行性的约束。
|
|
142
|
+
- **Z3**:提取精确的 **SMT 不可满足核心**(`res.unsatCore` / `res.conflicts`),即相互矛盾的约束子集。
|
|
347
143
|
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const model = new Model();
|
|
352
|
-
// 定义变量、目标函数和约束
|
|
353
|
-
await model.solve({ useWorker: false });
|
|
354
|
-
</script>
|
|
355
|
-
```
|
|
144
|
+
```ts
|
|
145
|
+
import { Model, implies, expr } from "@ohtaman/washi";
|
|
146
|
+
// import "@ohtaman/washi/solvers/z3"; // 可选:使用 Z3 提取精确 SMT unsatCore
|
|
356
147
|
|
|
357
|
-
|
|
148
|
+
const m = new Model("StaffingRules");
|
|
149
|
+
const engineers = m.integer("engineers", { lb: 0, ub: 20 });
|
|
150
|
+
const budget = m.continuous("budget", { lb: 0, ub: 100000 });
|
|
151
|
+
const rush = m.bool("rush");
|
|
358
152
|
|
|
359
|
-
|
|
153
|
+
m.constraint(expr`8000 * ${engineers} <= ${budget}`, "budget_limit");
|
|
154
|
+
m.constraint(rush, "rush_required");
|
|
155
|
+
m.constraint(implies(rush, expr`${engineers} >= 8`), "rush_staffing");
|
|
156
|
+
m.constraint(expr`${budget} <= 50000`, "budget_cap"); // 冲突: 8人 * $8,000 > $50,000
|
|
157
|
+
m.constraint(expr`${engineers} >= 1`, "min_staff"); // 无关规则
|
|
360
158
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
const model = new Washi.Model();
|
|
365
|
-
// 定义变量、目标函数和约束
|
|
366
|
-
model.solve({ useWorker: false }).then(status => console.log(status));
|
|
367
|
-
</script>
|
|
159
|
+
const res = await m.check(); // 或 await m.check({ solver: "z3" })
|
|
160
|
+
console.log(res.status); // "Unsat"
|
|
161
|
+
console.log(res.conflicts); // HiGHS: ["rush_required"]
|
|
368
162
|
```
|
|
369
163
|
|
|
370
|
-
|
|
164
|
+
---
|
|
371
165
|
|
|
372
|
-
|
|
166
|
+
## 🌐 浏览器与 Web Worker 使用指南
|
|
373
167
|
|
|
374
|
-
|
|
375
|
-
-
|
|
376
|
-
- **Z3**: `dist/browser/solvers/z3.js` (ESM) 与 `dist/browser/solvers/z3.min.js` (IIFE,挂载全局 `WashiZ3`),附带 `z3-built.js` 和 `z3-built.wasm`
|
|
168
|
+
- **打包工具 (Vite / webpack 5)**:直接 `import { Model } from "@ohtaman/washi"` 即可。浏览器默认在 Web Worker 中求解;传入 `{ useWorker: false }` 可在主线程执行。
|
|
169
|
+
- **原生 ESM / Script 标签 / CDN**:部署 `dist/browser/` 目录(含 `highs.wasm` 与 Worker 资源)或从 CDN 加载。
|
|
377
170
|
|
|
378
|
-
#### 浏览器 ESM 使用 GLPK
|
|
379
171
|
```html
|
|
172
|
+
<!-- 浏览器原生 ESM -->
|
|
380
173
|
<script type="module">
|
|
381
|
-
import { Model
|
|
382
|
-
import "./washi/solvers/glpk.js"
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const x = model.continuous("x", { lb: 0, ub: 10 });
|
|
386
|
-
model.objective(maximize(x));
|
|
387
|
-
await model.solve();
|
|
388
|
-
console.log("GLPK 求解状态:", model.status);
|
|
174
|
+
import { Model } from "./washi/washi.js";
|
|
175
|
+
// 可选求解器插件: import "./washi/solvers/glpk.js" 或 "./washi/solvers/z3.js"
|
|
176
|
+
const m = new Model();
|
|
177
|
+
await m.solve();
|
|
389
178
|
</script>
|
|
390
|
-
```
|
|
391
179
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
<script src="./washi/washi.min.js"></script>
|
|
395
|
-
<script src="./washi/solvers/glpk.min.js"></script>
|
|
396
|
-
<script>
|
|
397
|
-
const model = new Washi.Model({ solver: "glpk" });
|
|
398
|
-
const x = model.continuous("x", { lb: 0, ub: 10 });
|
|
399
|
-
model.objective(Washi.maximize(x));
|
|
400
|
-
model.solve().then(status => console.log("GLPK 求解状态:", status));
|
|
401
|
-
</script>
|
|
180
|
+
<!-- Script 标签 / CodePen (挂载全局变量 Washi) -->
|
|
181
|
+
<script src="https://cdn.jsdelivr.net/npm/@ohtaman/washi/dist/browser/washi.min.js"></script>
|
|
402
182
|
```
|
|
403
183
|
|
|
404
184
|
> [!NOTE]
|
|
405
|
-
>
|
|
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)。
|
|
407
|
-
|
|
408
|
-
完整独立的 ESM、Script 标签与 CodePen 示例请参阅 [`examples/distribution/`](examples/distribution/README.md)。
|
|
185
|
+
> **浏览器中使用 Z3**:Z3 的 WebAssembly 引擎依赖 `SharedArrayBuffer`,需要配置跨源隔离响应头(`COOP: same-origin` 与 `COEP: require-corp`)。详见[跨源隔离指南](docs/zh/getting-started/cross-origin.md)与 [`examples/distribution/`](examples/distribution/README.md)。
|
|
409
186
|
|
|
410
187
|
---
|
|
411
188
|
|
|
412
|
-
##
|
|
413
|
-
|
|
414
|
-
WaSHI 采用完全解耦的插件式求解器架构。你可以轻松编写并注册自定义求解器适配器(如云端 REST 求解服务、定制 WebAssembly 引擎或商业求解器):
|
|
189
|
+
## 🤝 参与开发与贡献
|
|
415
190
|
|
|
416
|
-
|
|
191
|
+
关于本地开发、运行测试与基准测试、重新构建 WebAssembly 资源以及发布流程,请参阅 [CONTRIBUTING.md](./CONTRIBUTING.md)。
|
|
417
192
|
|
|
418
193
|
---
|
|
419
194
|
|
|
420
|
-
##
|
|
195
|
+
## 🙏 致谢
|
|
421
196
|
|
|
422
|
-
|
|
197
|
+
WaSHI 的诞生离不开数理优化与自动推理开源社区的卓越工作:
|
|
423
198
|
|
|
424
|
-
-
|
|
425
|
-
-
|
|
426
|
-
-
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
## 💻 示例与浏览器演示
|
|
431
|
-
|
|
432
|
-
[示例目录](https://github.com/ohtaman/washi/blob/main/examples/README.md)与[在线案例与 API 索引](https://ohtaman.github.io/washi/zh/examples/)按问题类别和 WaSHI API 功能汇总了源码链接及本地运行方法。
|
|
433
|
-
|
|
434
|
-
| 类别 | 示例 | 展示内容 | 求解器 |
|
|
435
|
-
| :--- | :--- | :--- | :--- |
|
|
436
|
-
| **基础模型** | [生产计划](https://github.com/ohtaman/washi/blob/main/examples/node/01-production-planning.ts) | 整数变量、利润目标与资源约束 (`expr`) | HiGHS |
|
|
437
|
-
| **基础模型** | [运输与分配网络](https://github.com/ohtaman/washi/blob/main/examples/node/09-transportation-problem.ts) | 二维矩阵变量 (`continuous(rows, cols)`) 与供需平衡 | HiGHS |
|
|
438
|
-
| **基础模型** | [营养问题与灵敏度分析](https://github.com/ohtaman/washi/blob/main/examples/node/10-diet-sensitivity.ts) | 影子价格 (`constr.dual`)、松弛量 (`constr.slack`) 与缩减成本 (`var.reducedCost`) | HiGHS |
|
|
439
|
-
| **实战应用** | [员工排班与冲突诊断](https://github.com/ohtaman/washi/blob/main/examples/node/11-shift-scheduling.ts) | 周排班优化与周六休假冲突诊断 | HiGHS + Z3 |
|
|
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 |
|
|
443
|
-
| **实战应用** | [投资组合分配](https://github.com/ohtaman/washi/blob/main/examples/node/03-portfolio-qp.ts) | 凸二次目标函数 (`QuadExpr`) 与分配约束 | HiGHS |
|
|
444
|
-
| **逻辑 / SMT** | [业务规则检查](https://github.com/ohtaman/washi/blob/main/examples/node/04-smt-security-rules.ts) | 算术与逻辑约束 (`bool`, `implies`) 的可满足性检查 | Z3 |
|
|
445
|
-
| **逻辑 / SMT** | [冲突诊断](https://github.com/ohtaman/washi/blob/main/examples/node/05-unsat-core-diagnosis.ts) | 命名约束与 Unsat Core (`unsatCore`) | Z3 |
|
|
446
|
-
|
|
447
|
-
在[在线浏览器演示](https://ohtaman.github.io/washi/demo/)中可以编辑并运行模型。浏览器 ESM、script 标签和 CodePen 的用法请参阅[分发示例](https://github.com/ohtaman/washi/blob/main/examples/distribution/README.md)。Z3 需要跨源隔离;具体要求见上方浏览器说明。
|
|
448
|
-
|
|
449
|
-
本地运行前,请克隆仓库并安装开发依赖:
|
|
450
|
-
|
|
451
|
-
```bash
|
|
452
|
-
git clone https://github.com/ohtaman/washi.git
|
|
453
|
-
cd washi
|
|
454
|
-
npm ci
|
|
455
|
-
npx tsx examples/node/01-production-planning.ts
|
|
456
|
-
npx tsx examples/node/09-transportation-problem.ts
|
|
457
|
-
npx tsx examples/node/10-diet-sensitivity.ts
|
|
458
|
-
npx tsx examples/node/11-shift-scheduling.ts
|
|
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
|
|
462
|
-
|
|
463
|
-
# 本地浏览器演示: http://localhost:5173/demo/
|
|
464
|
-
npm run dev
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
示例导入仓库的 `src/` 模块。使用已发布软件包的应用应改为导入 `@ohtaman/washi` 及所需的求解器插件。
|
|
468
|
-
|
|
469
|
-
---
|
|
470
|
-
|
|
471
|
-
## 🧪 自动化测试与可复现基准测试
|
|
472
|
-
|
|
473
|
-
运行仓库的单元测试与集成测试,并构建分发版本:
|
|
474
|
-
|
|
475
|
-
```bash
|
|
476
|
-
# 运行全部单元与集成测试
|
|
477
|
-
npm test
|
|
478
|
-
|
|
479
|
-
# 构建生产级依赖包与 TypeScript 类型定义
|
|
480
|
-
npm run build
|
|
481
|
-
```
|
|
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。
|
|
199
|
+
- **[HiGHS](https://highs.dev/)**([`ERGO-Code/HiGHS`](https://github.com/ERGO-Code/HiGHS))— 发源于爱丁堡大学、由 Julian Hall、Qi Huangfu、Ivet Galabova、Leona Gottwald、Michael Feldmeier 及社区贡献者共同打造的高性能开源 LP / MIP / 凸 QP 求解器,驱动了 WaSHI 的内置默认引擎(*Huangfu & Hall, Mathematical Programming Computation, 2018*, [DOI: 10.1007/s12532-017-0130-5](https://doi.org/10.1007/s12532-017-0130-5))。
|
|
200
|
+
- **[Z3 Theorem Prover](https://github.com/Z3Prover/z3)**([`z3-solver`](https://www.npmjs.com/package/z3-solver))— 由 Microsoft Research 研发,驱动了 WaSHI 可选的 SMT 可满足性判定与精确 `unsatCore` 冲突诊断插件。
|
|
201
|
+
- **[GLPK](https://www.gnu.org/software/glpk/) & [`glpk.js`](https://github.com/jvail/glpk.js)** — 驱动了 WaSHI 可选的 GPL-3.0 LP / MIP 求解器插件。
|
|
202
|
+
- **[PuLP](https://github.com/coin-or/pulp)** — 启发了 WaSHI 声明式代数建模 API 的设计。
|
|
517
203
|
|
|
518
204
|
---
|
|
519
205
|
|
|
520
206
|
## 📄 许可证
|
|
521
207
|
|
|
522
208
|
- **`@ohtaman/washi`**: [MIT 许可证](./LICENSE)
|
|
523
|
-
-
|
|
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)。
|
|
209
|
+
- **内置与可选引擎**: HiGHS (MIT)、Z3 (MIT)、GLPK (GPL-3.0)。完整许可说明请参阅 [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md)。
|