@ohtaman/washi 0.3.0 → 0.5.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 (97) hide show
  1. package/README.ja.md +111 -118
  2. package/README.md +109 -116
  3. package/README.zh-CN.md +112 -119
  4. package/dist/browser/highs-worker.js +21 -3
  5. package/dist/browser/loader-CtaDHef_.js +273 -0
  6. package/dist/browser/solvers/glpk.js +433 -286
  7. package/dist/browser/solvers/glpk.min.js +1 -1
  8. package/dist/browser/solvers/z3.js +1002 -981
  9. package/dist/browser/solvers/z3.min.js +2 -2
  10. package/dist/browser/washi.js +2178 -622
  11. package/dist/browser/washi.min.js +4 -4
  12. package/dist/lib/highs-worker.js +21 -3
  13. package/dist/lib/loader-DmNC_UNk.js +279 -0
  14. package/dist/lib/registry-BEfvpZW3.js +951 -0
  15. package/dist/lib/solvers/glpk.js +201 -90
  16. package/dist/lib/solvers/z3.js +399 -259
  17. package/dist/lib/washi.js +1674 -932
  18. package/dist/types/index.d.ts +4 -4
  19. package/dist/types/index.d.ts.map +1 -1
  20. package/dist/types/modeler/big-m.d.ts +75 -0
  21. package/dist/types/modeler/big-m.d.ts.map +1 -0
  22. package/dist/types/modeler/boolean-expr.d.ts +103 -14
  23. package/dist/types/modeler/boolean-expr.d.ts.map +1 -1
  24. package/dist/types/modeler/constraint.d.ts +36 -9
  25. package/dist/types/modeler/constraint.d.ts.map +1 -1
  26. package/dist/types/modeler/expression.d.ts +117 -27
  27. package/dist/types/modeler/expression.d.ts.map +1 -1
  28. package/dist/types/modeler/index.d.ts +10 -6
  29. package/dist/types/modeler/index.d.ts.map +1 -1
  30. package/dist/types/modeler/lp-writer.d.ts +27 -2
  31. package/dist/types/modeler/lp-writer.d.ts.map +1 -1
  32. package/dist/types/modeler/model.d.ts +491 -140
  33. package/dist/types/modeler/model.d.ts.map +1 -1
  34. package/dist/types/modeler/objective.d.ts +59 -0
  35. package/dist/types/modeler/objective.d.ts.map +1 -0
  36. package/dist/types/modeler/parser.d.ts +39 -14
  37. package/dist/types/modeler/parser.d.ts.map +1 -1
  38. package/dist/types/modeler/quad-expr.d.ts +28 -7
  39. package/dist/types/modeler/quad-expr.d.ts.map +1 -1
  40. package/dist/types/modeler/solution-validator.d.ts +93 -0
  41. package/dist/types/modeler/solution-validator.d.ts.map +1 -0
  42. package/dist/types/modeler/solvers/glpk/solver.d.ts +26 -2
  43. package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -1
  44. package/dist/types/modeler/solvers/highs/loader.d.ts +36 -11
  45. package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -1
  46. package/dist/types/modeler/solvers/highs/solver.d.ts +11 -4
  47. package/dist/types/modeler/solvers/highs/solver.d.ts.map +1 -1
  48. package/dist/types/modeler/solvers/highs/worker-client.d.ts.map +1 -1
  49. package/dist/types/modeler/solvers/mock.d.ts +14 -5
  50. package/dist/types/modeler/solvers/mock.d.ts.map +1 -1
  51. package/dist/types/modeler/solvers/types.d.ts +71 -11
  52. package/dist/types/modeler/solvers/types.d.ts.map +1 -1
  53. package/dist/types/modeler/solvers/z3/loader.d.ts +2 -3
  54. package/dist/types/modeler/solvers/z3/loader.d.ts.map +1 -1
  55. package/dist/types/modeler/solvers/z3/solver.d.ts +15 -5
  56. package/dist/types/modeler/solvers/z3/solver.d.ts.map +1 -1
  57. package/dist/types/modeler/types.d.ts +60 -2
  58. package/dist/types/modeler/types.d.ts.map +1 -1
  59. package/dist/types/modeler/validation.d.ts +56 -0
  60. package/dist/types/modeler/validation.d.ts.map +1 -0
  61. package/dist/types/modeler/variable.d.ts +53 -13
  62. package/dist/types/modeler/variable.d.ts.map +1 -1
  63. package/docs/examples/diet-sensitivity.md +90 -0
  64. package/docs/examples/ecommerce-coupons.md +106 -0
  65. package/docs/examples/index.md +53 -0
  66. package/docs/examples/knapsack.md +60 -0
  67. package/docs/examples/portfolio-qp.md +83 -0
  68. package/docs/examples/production.md +51 -0
  69. package/docs/examples/shift-scheduling.md +175 -0
  70. package/docs/examples/smt-security.md +74 -0
  71. package/docs/examples/transportation.md +90 -0
  72. package/docs/examples/unsat-core.md +64 -0
  73. package/docs/getting-started/ai-agents.md +267 -0
  74. package/docs/getting-started/cross-origin.md +87 -0
  75. package/docs/getting-started/index.md +116 -0
  76. package/docs/getting-started/runtimes.md +227 -0
  77. package/docs/guide/constraints.md +177 -0
  78. package/docs/guide/expressions.md +204 -0
  79. package/docs/guide/objectives.md +170 -0
  80. package/docs/guide/unsat-core.md +147 -0
  81. package/docs/guide/variables.md +188 -0
  82. package/docs/ja/getting-started/ai-agents.md +266 -0
  83. package/docs/solvers/custom-solver.md +525 -0
  84. package/docs/solvers/glpk.md +66 -0
  85. package/docs/solvers/highs.md +93 -0
  86. package/docs/solvers/index.md +42 -0
  87. package/docs/solvers/z3.md +78 -0
  88. package/docs/zh/getting-started/ai-agents.md +266 -0
  89. package/llms-full.txt +3249 -0
  90. package/llms.txt +197 -0
  91. package/package.json +19 -6
  92. package/skills/washi/SKILL.md +197 -0
  93. package/dist/browser/loader-CVt4CloI.js +0 -58
  94. package/dist/lib/async-mutex-Duo4jwzn.js +0 -195
  95. package/dist/lib/constraint-BRuB3ooC.js +0 -90
  96. package/dist/lib/loader-Dti0v9yC.js +0 -50
  97. package/dist/lib/registry-DksqCSjI.js +0 -32
@@ -0,0 +1,42 @@
1
+ # Solvers Overview
2
+
3
+ WaSHI is designed around a pluggable, decoupled solver architecture. You formulate mathematical models using a unified algebraic API, then solve them with the engine best suited for your problem class.
4
+
5
+ ---
6
+
7
+ ## ⚡ Solvers Matrix & Comparison
8
+
9
+ | Solver | Engine License | Problem Classes | Best For | Status in WaSHI |
10
+ | :--- | :--- | :--- | :--- | :--- |
11
+ | **HiGHS** | **MIT** | **LP, MIP, Convex QP** | Industrial-scale optimization, operations research, finance | **Built-in default** (zero configuration) |
12
+ | **Z3** | **MIT** | **SMT, SAT, Logic, MIP** | Propositional logic, conflict diagnosis (`unsatCore`), rule engines | Optional plugin (`@ohtaman/washi/solvers/z3`) |
13
+ | **GLPK** | **GPL-3.0** | **LP, MIP** | Academic benchmarks, legacy GLPK compatibility | Optional plugin (`@ohtaman/washi/solvers/glpk`) |
14
+ | **Mock** | **MIT** | *Any* | Ultra-fast unit testing in CI without loading WebAssembly | Built-in |
15
+
16
+ ---
17
+
18
+ ## Selecting a Solver
19
+
20
+ Specify the solver by name when creating your `Model`:
21
+
22
+ ```typescript
23
+ // 1. Built-in HiGHS (default)
24
+ const m1 = new Model({ solver: "highs" });
25
+
26
+ // 2. Z3 SMT solver
27
+ import "@ohtaman/washi/solvers/z3";
28
+ const m2 = new Model({ solver: "z3" });
29
+
30
+ // 3. GLPK solver
31
+ import "@ohtaman/washi/solvers/glpk";
32
+ const m3 = new Model({ solver: "glpk" });
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Solver Guides
38
+
39
+ - [HiGHS Guide](./highs.md): Web Worker multithreading, MIP tolerances, and QP solving.
40
+ - [Z3 Guide](./z3.md): SMT assertions, logic modeling, and Unsat Core analysis.
41
+ - [GLPK Guide](./glpk.md): GLPK adapter, GPL-3.0 licensing considerations, and browser usage.
42
+ - [Custom Solvers](./custom-solver.md): Step-by-step developer tutorial for integrating proprietary or cloud REST solvers.
@@ -0,0 +1,78 @@
1
+ # Z3 SMT Solver Engine
2
+
3
+ **Z3** is a theorem prover and Satisfiability Modulo Theories (SMT) solver developed by Microsoft Research. In WaSHI, Z3 provides advanced propositional logic reasoning and conflict diagnosis.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ Z3 is provided as an optional peer dependency:
10
+
11
+ ```bash
12
+ npm install z3-solver
13
+ ```
14
+
15
+ ---
16
+
17
+ ## When to Use Z3?
18
+
19
+ 1. **Unsat Core Conflict Diagnosis**:
20
+ When your MIP model is infeasible and you need to isolate which constraints are contradictory.
21
+ 2. **Boolean / Logical Formulations**:
22
+ When solving problems containing complex logical relations (implications, XOR, nested Boolean expressions).
23
+ 3. **Exact Mathematical Guarantees**:
24
+ Z3 can perform exact rational arithmetic without floating-point inaccuracies.
25
+
26
+ ---
27
+
28
+ ## Basic Usage
29
+
30
+ ```typescript
31
+ import { Model, expr } from "@ohtaman/washi";
32
+ import "@ohtaman/washi/solvers/z3";
33
+
34
+ const model = new Model({ solver: "z3" });
35
+
36
+ const x = model.integer("x", { lb: 0, ub: 10 });
37
+ const y = model.integer("y", { lb: 0, ub: 10 });
38
+
39
+ model.constraint(expr`${x} + ${y} == 15`, "sum_15");
40
+ model.constraint(expr`${x} >= 8`, "x_at_least_8");
41
+
42
+ await model.solve();
43
+ console.log(`x = ${x.value}, y = ${y.value}`);
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Unsat Core Extraction (`model.check()`)
49
+
50
+ Use `await model.check()` with Z3 to verify satisfiability and extract the conflicting subset of named constraints (`conflicts` / `unsatCore`) when a model is unsatisfiable:
51
+
52
+ ```typescript
53
+ const model = new Model({ solver: "z3" });
54
+ const a = model.continuous("a");
55
+
56
+ model.constraint(expr`${a} >= 10`, "req_A");
57
+ model.constraint(expr`${a} <= 5`, "req_B");
58
+
59
+ const result = await model.check();
60
+
61
+ if (result.status === "Unsat") {
62
+ console.log("Conflicting constraints:", result.conflicts); // or model.conflicts / model.unsatCore
63
+ // ["req_A", "req_B"]
64
+ }
65
+ ```
66
+
67
+ ---
68
+
69
+ ## Browser Security Note
70
+
71
+ In browser environments, the Z3 WASM engine relies on pthreads and `SharedArrayBuffer`, which require cross-origin isolation headers (`COOP` / `COEP`). See the [Cross-Origin Isolation Guide](../getting-started/cross-origin.md) for detailed setup.
72
+
73
+ ## Runtime Failures and Thread Cleanup
74
+
75
+ If a Z3 worker encounters a fatal runtime error, pending operations on that instance reject with an error and the broken runtime is invalidated; subsequent `solve()` or `check()` calls automatically initialize a fresh Z3 runtime rather than misclassifying failures as `Sat` or `Unsat`.
76
+
77
+ To explicitly terminate Z3 pthread workers when tearing down a browser view or worker pool, call `killZ3Threads()` from `@ohtaman/washi/solvers/z3`.
78
+
@@ -0,0 +1,266 @@
1
+ # AI 编程助手快速参考指南
2
+
3
+ > **范围说明**:本文档是面向使用 `@ohtaman/washi` 构建数理优化或可满足性(SAT/SMT)模型的 AI 编程助手与开发者的**使用端建模快速参考**。
4
+ > - **可移植 Agent Skill (`SKILL.md`)**:如需涵盖端到端建模、`toLpString()` 导出检查、`validateSolution()` 解验证以及 Z3 `unsatCore` 冲突诊断的完整工作流技能(兼容 Claude Code、Antigravity、Cursor、Codex 等支持 `SKILL.md` 的代理),请使用 [`skills/washi/SKILL.md`](https://github.com/ohtaman/washi/blob/main/skills/washi/SKILL.md)(同时随 npm 包分发于 `node_modules/@ohtaman/washi/skills/washi/SKILL.md`):
5
+ > ```bash
6
+ > # 将随包附带的技能复制到项目的代理技能目录中
7
+ > mkdir -p .agents/skills/washi
8
+ > cp node_modules/@ohtaman/washi/skills/washi/SKILL.md .agents/skills/washi/SKILL.md
9
+ > ```
10
+ > - **仓库审查规范**:关于仓库贡献规范与 Pull Request 代码审查规则,请参阅仓库根目录下的 [`AGENTS.md`](https://github.com/ohtaman/washi/blob/main/AGENTS.md)。
11
+
12
+ ---
13
+
14
+ ## 1. 包导入与部署规范
15
+
16
+ ### Node.js / 构建工具 (Vite, Webpack, Next.js, Bun)
17
+
18
+ ```ts
19
+ import {
20
+ Model,
21
+ expr,
22
+ sum,
23
+ dot,
24
+ maximize,
25
+ minimize,
26
+ and,
27
+ or,
28
+ not,
29
+ implies,
30
+ xor,
31
+ setHighsWasmUrl,
32
+ } from "@ohtaman/washi";
33
+
34
+ // 可选求解器插件(需先安装对应的 peer dependencies):
35
+ // npm install z3-solver
36
+ import "@ohtaman/washi/solvers/z3";
37
+ // npm install glpk.js
38
+ import "@ohtaman/washi/solvers/glpk";
39
+ ```
40
+
41
+ ### 浏览器原生 ESM 与普通 `<script>` 标签
42
+
43
+ - **浏览器 ESM**:
44
+ - 核心包(内置 HiGHS): `import { Model, expr, maximize } from "./washi/washi.js";`
45
+ - GLPK 插件: `import "./washi/solvers/glpk.js";`
46
+ - Z3 插件: `import "./washi/solvers/z3.js";`
47
+ - **普通 `<script>` / CodePen (IIFE)**:
48
+ - 核心包: `<script src="./washi/washi.min.js"></script>`(挂载全局变量 `Washi`)
49
+ - GLPK 插件: `<script src="./washi/solvers/glpk.min.js"></script>`(注册 `"glpk"`,挂载 `WashiGLPK`)
50
+ - Z3 插件: `<script src="./washi/solvers/z3.min.js"></script>`(注册 `"z3"`,挂载 `WashiZ3`)
51
+
52
+ ### WebAssembly 资源与运行时规则
53
+
54
+ 1. **默认使用随包内置的 WASM(无隐式 CDN 回退)**:
55
+ - 在 Node.js 和现代构建工具中,WebAssembly 资源会自动相对于模块路径解析。
56
+ - 在浏览器部署中,请将完整的 `dist/browser/` 目录(包含 JS、Worker 和 `.wasm` 文件)一起部署。如果本地 WASM URL 缺失或返回了 HTML SPA 回退页面,初始化会立即失败并报告所尝试的 URL——**绝不会**静默切换到公共 CDN。
57
+ - 在浏览器运行时中,若需从自定义位置加载 `highs.wasm`,请调用 `setHighsWasmUrl("https://.../highs.wasm")` 或传入 `await m.solve({ wasmUrl: "https://.../highs.wasm" })`(在 Node.js 中会被忽略,Node.js 始终加载本地安装的 `highs` 包运行时)。
58
+ 2. **浏览器中运行 Z3 需要安全上下文、跨源隔离(Cross-Origin Isolation)与 CORS**:
59
+ - Z3 WebAssembly 依赖 `SharedArrayBuffer` 多线程。运行 Z3 的浏览器页面必须处于安全上下文(`window.isSecureContext === true`,即 HTTPS 或 `localhost`)且开启跨源隔离(`window.crossOriginIsolated === true`),服务端需配置以下响应头:
60
+ - `Cross-Origin-Opener-Policy: same-origin`(主文档响应)
61
+ - `Cross-Origin-Embedder-Policy: require-corp`(主文档响应)
62
+ - `Cross-Origin-Resource-Policy: cross-origin` 与 `Access-Control-Allow-Origin`(跨域脚本 / WASM 资源响应)
63
+ - 导入 `@ohtaman/washi` 绝不会自动注入 Service Worker。当浏览器缺少安全上下文或跨源隔离时,Z3 会立即以明确说明原因的错误 reject。
64
+ 3. **Web Worker 与取消控制 (`AbortSignal`)**:
65
+ - 求解前取消(执行开始前 `signal.aborted` 已为真)在所有求解器中均受支持。
66
+ - 在支持 `Worker` 的浏览器环境中,HiGHS 默认在专用 Web Worker 中运行(`useWorker: true`)。向 `m.solve({ signal })` 传入 `{ signal }` 可以抢占式终止正在运行的 Worker 求解(或取消排队中的 Worker 请求)。
67
+ - 在主线程运行 HiGHS 时(`useWorker: false` 或在 Node.js 中),支持在求解器中断检查点触发的 `onProgress` 回调内同步调用 `abort()` 实现协作式中途取消;来自外部的任意异步取消在同步 WASM 线程到达检查点或执行完成前无法抢占阻塞线程。无中断钩子的单线程 WASM 求解器(GLPK、Z3)会在执行开始前检查 `signal`。
68
+
69
+ ---
70
+
71
+ ## 2. 标准建模流程
72
+
73
+ 构建并求解一个模型包含四个明确步骤:
74
+
75
+ ### 步骤 1:创建模型与决策变量
76
+
77
+ ```ts
78
+ const m = new Model("ExampleModel");
79
+
80
+ // 标量变量
81
+ const x = m.continuous("x", { lb: 0, ub: 100 });
82
+ const n = m.integer("n", { lb: 0, ub: 10 });
83
+ const b = m.binary("b");
84
+ const flag = m.bool("flag"); // 命题布尔变量(用于 Z3 / 逻辑约束)
85
+
86
+ // 多维索引变量容器:
87
+ // - 数字维度 -> Array
88
+ // - 键数组维度 -> Record
89
+ const vec = m.continuous(4, { lb: 0, prefix: "v" }); // Var[] (长度 4)
90
+ const grid = m.binary(2, 3, { prefix: "g" }); // Var[][] (2x3)
91
+ const byItem = m.integer(["desk", "chair"] as const, { lb: 0 }); // Record<"desk" | "chair", Var>
92
+ const mixed = m.binary(["A", "B"] as const, 3); // Record<"A" | "B", Var[]>
93
+ ```
94
+
95
+ - **可选的原问题初始值提示 (`initialValue?: number`)**:
96
+ - 数值变量构造函数(`m.continuous`、`m.integer`、`m.binary` 与 `new Var`)以及可变的 `v.initialValue` 属性支持传入可选的有限原问题初始值提示(以 `1e-6` 容差校验上下界 `[lb, ub]` 及整数/二元域),并与求解结果 `v.value` 保持独立。
97
+ - 初始值可以是完整的或部分的(例如在重建 MIP 模型时按固定变量名传递)。提供 `initialValue` 仅作为求解提示——**不会**固定变量、添加硬约束,也不保证被求解器采纳或加速求解。
98
+ - 受 **HiGHS**(`supportsWarmStart: true`)支持;不支持热启动的求解器(**GLPK**、**Z3**)在任何变量设置了 `initialValue !== undefined` 时会抛出错误。
99
+
100
+ ### 步骤 2:构建表达式 (`expr`, `sum`, `dot`)
101
+
102
+ - **统一 `expr` 模板标签**:
103
+ - 线性表达式(`LinExpr`): `` expr`30 * ${x} + 50 * ${n} - 10` ``
104
+ - 二次表达式(`QuadExpr`): `` expr`${x}^2 + 2 * ${x} * ${n} + ${n}^2` ``(支持凸 QP 目标函数中的变量相乘与平方项)。
105
+ - 线性约束(`Constraint`): `` expr`${x} + 2 * ${n} <= 40` ``(支持 `<=`、`>=`、`==` 和 `=`)。
106
+ - **聚合函数**:
107
+ - `sum(iterable, mapper?)` 对 `Var` / `LinExpr` / `number` 的 `Iterable`(例如 `Var[]`、`grid.flat()` 或 `Object.values(record)`)求和。
108
+ - `dot(a, b)` 计算匹配的一维数组、二维数组(`number[][]` / `Var[][]`)、普通字典(`Record<string, ...>`)或混合 Array/Record 容器的内积,操作数顺序不限。
109
+ - **链式方法**:
110
+ - 算术运算(在 `LinExpr` 和 `QuadExpr` 上支持;`Var` 支持 `.add()`、`.sub()`、`.mul()`、`.neg()`): `.add(other)`、`.sub(other)`、`.mul(other)`、`.div(scalar)`、`.neg()`
111
+ - 比较运算(在 `Var` 和 `LinExpr` 上支持): `.le(rhs, name?)`、`.ge(rhs, name?)`、`.eq(rhs, name?)`
112
+ - 布尔逻辑(面向 Z3 的 `BoolVar`、`BoolExpr` 和 `Constraint`): 独立函数 `and(...)`、`or(...)`、`not(...)`、`implies(a, b)`、`xor(a, b)` 以及链式方法 `.and(...)`、`.or(...)`、`.not()`、`.implies(...)`、`.xor(...)`
113
+
114
+ ### 步骤 3:向模型注册目标函数与约束条件
115
+
116
+ 仅构造 `expr` 或 `.le()` 对象**不会**将其挂载到模型上,必须传入 `m.constraint(...)` 或 `m.objective(...)` 完成注册:
117
+
118
+ ```ts
119
+ // 使用 maximize() 或 minimize() 设置目标函数
120
+ m.objective(maximize(expr`30 * ${x} + 50 * ${n}`));
121
+
122
+ // 将约束注册到模型
123
+ m.constraint(expr`${x} + 2 * ${n} <= 40`, "resource_limit");
124
+
125
+ // 指示约束 (MIP Big-M 转化: b === 1 => x <= 50)
126
+ m.indicator(b, expr`${x} <= 50`, { activeValue: 1, name: "cap_when_b" });
127
+ ```
128
+
129
+ ### 步骤 4:执行求解 (`solve` 或 `check`) 与校验解 (`validateSolution`)
130
+
131
+ - **数理优化 (`await m.solve(options?)`)**:
132
+ - 返回 `SolverStatus`(`"Optimal"`、`"Feasible"`、`"Infeasible"`、`"Unbounded"`、`"TimeLimit"`、`"IterationLimit"`、`"Error"`、`"Unknown"`、`"NotSolved"`、`"Sat"` 或 `"Unsat"`)。内置优化求解器返回优化状态(`"Optimal"`、`"Feasible"`、`"Infeasible"`、`"Unbounded"`、`"TimeLimit"`、`"IterationLimit"`、`"Error"`、`"Unknown"`、`"NotSolved"`),其中因时间、迭代或解数量上限(或中断)停止但已找到合法可行解(Incumbent)的运行会返回 `"Feasible"`;`"Sat"` 与 `"Unsat"` 包含在 `SolverStatus` 中以供可满足性/自定义求解器适配器(如 `MockSolver`)使用。
133
+ - 通过 `x.value`、`expr`...`.value`、`m.getValues(x)`、`m.getValues(container)`、`m.objectiveValue`、`constr.dual`、`constr.slack` 和 `x.reducedCost` 读取结果。
134
+ - 求解后调用 `m.validateSolution()` 可独立校验变量有限性、变量上下界(`lb`/`ub`)、整数/二元/布尔域、线性约束残差以及逻辑约束(`SolutionValidationReport`:`{ valid, complete, maxViolation, violations, ... }`)。注意:`validateSolution()` 校验变量与约束的原问题可行性,不会重新计算或比对 `m.objectiveValue`。
135
+ - **可满足性检查与 Unsat Core (`await m.check(options?)`)**:
136
+ - 返回 `CheckResult`(`{ status: "Sat" | "Unsat" | "Unknown", values: Record<string, number | boolean>, conflicts?: readonly string[], unsatCore?: readonly string[], runTime?: number }`),其中 `conflicts` 和 `unsatCore` 为可选字段,仅在支持不可行核提取的求解器(如 Z3)返回 `"Unsat"` 时填充。
137
+ - 对于仅包含线性算术约束的模型,`m.check()` 会回退为可行性 `solve()`,因此可用于任何求解器(包括默认的 HiGHS 和 GLPK)。逻辑约束(`BoolVar`、`and`、`or`、`implies` 等)以及不可行核提取(`result.conflicts` / `result.unsatCore`)需要支持 SMT 的求解器(`{ solver: "z3" }`)。由于 Z3 在跟踪已注册约束的同时直接断言变量边界(`lb`/`ub`)和二元 `{0, 1}` 域,`conflicts` / `unsatCore` 报告的是*结合模型固定变量边界/域时*发生冲突的已注册约束名称子集(不保证最小性)。
138
+ - **异步 `solve` / `check` 期间禁止并发修改模型**:
139
+ - 在 `await m.solve()` 或 `await m.check()` 挂起期间修改变量、约束或目标函数会使当前执行失效,并使过期的 Promise 被 reject。
140
+
141
+ ---
142
+
143
+ ## 3. 可直接运行的示例
144
+
145
+ ### 示例 A:使用多维容器与解校验的混合整数线性规划 (MIP)
146
+
147
+ ```ts
148
+ import { Model, expr, dot, sum, maximize } from "@ohtaman/washi";
149
+
150
+ export async function runMipExample() {
151
+ const m = new Model("ProductionMIP");
152
+ const products = ["desk", "chair"] as const;
153
+ const profit = { desk: 30, chair: 50 };
154
+ const woodPerUnit = { desk: 1, chair: 2 };
155
+ const laborPerUnit = { desk: 2, chair: 1 };
156
+
157
+ const qty = m.integer(products, { lb: 0, ub: 100 });
158
+ const setup = m.binary("setup");
159
+
160
+ m.objective(maximize(expr`${dot(profit, qty)} - 20 * ${setup}`));
161
+ m.constraint(expr`${dot(woodPerUnit, qty)} <= 40`, "wood_cap");
162
+ m.constraint(expr`${dot(laborPerUnit, qty)} <= 50`, "labor_cap");
163
+ m.constraint(expr`${sum(Object.values(qty))} <= 30 * ${setup}`, "require_setup");
164
+
165
+ const status = await m.solve();
166
+ const report = m.validateSolution();
167
+ const values = m.getValues(qty);
168
+
169
+ return {
170
+ status,
171
+ objectiveValue: m.objectiveValue,
172
+ values,
173
+ setup: setup.value,
174
+ valid: report.valid,
175
+ maxViolation: report.maxViolation,
176
+ };
177
+ }
178
+ ```
179
+
180
+ ### 示例 B:凸二次规划 (QP)
181
+
182
+ 二次目标函数支持在 `expr` 中直接书写变量乘积(`${x} * ${y}`)与平方项(`${x}^2`):
183
+
184
+ ```ts
185
+ import { Model, expr, minimize } from "@ohtaman/washi";
186
+
187
+ export async function runQpExample() {
188
+ const m = new Model("PortfolioQP");
189
+ const x = m.continuous("x", { lb: 0 });
190
+ const y = m.continuous("y", { lb: 0 });
191
+
192
+ // 在 x + y >= 4 约束下最小化 x^2 + y^2
193
+ m.objective(minimize(expr`${x}^2 + ${y}^2`));
194
+ m.constraint(expr`${x} + ${y} >= 4`, "budget");
195
+
196
+ const status = await m.solve();
197
+ const report = m.validateSolution();
198
+
199
+ return {
200
+ status,
201
+ objectiveValue: m.objectiveValue,
202
+ x: x.value,
203
+ y: y.value,
204
+ valid: report.valid,
205
+ };
206
+ }
207
+ ```
208
+
209
+ ### 示例 C:Z3 可满足性检查与 Unsat Core 冲突诊断
210
+
211
+ ```ts
212
+ import { Model, expr, implies } from "@ohtaman/washi";
213
+ import "@ohtaman/washi/solvers/z3";
214
+
215
+ export async function runZ3Example() {
216
+ const m = new Model("PolicyCheck", { solver: "z3" });
217
+ const vip = m.bool("vip");
218
+ const discount = m.integer("discount", { lb: 0, ub: 50 });
219
+
220
+ m.constraint(vip, "customer_is_vip");
221
+ m.constraint(implies(vip, expr`${discount} >= 20`), "vip_min_discount");
222
+ m.constraint(expr`${discount} <= 10`, "campaign_cap");
223
+
224
+ const unsatResult = await m.check();
225
+ return {
226
+ status: unsatResult.status,
227
+ conflicts: unsatResult.conflicts,
228
+ };
229
+ }
230
+ ```
231
+
232
+ ---
233
+
234
+ ## 4. 反面示例与常见陷阱
235
+
236
+ 请避免以下无效写法和已废弃的旧别名:
237
+
238
+ ```ts
239
+ import { Model, expr, maximize } from "@ohtaman/washi";
240
+
241
+ export function verifyNegativePatterns() {
242
+ const m = new Model("NegativeExamples");
243
+ const x = m.continuous("x", { lb: 0 });
244
+ const y = m.continuous("y", { lb: 0 });
245
+
246
+ // 1. 切勿将 Constraint 传给 m.objective() 或算术运算方法:
247
+ // 错误: m.objective(maximize(expr`${x} <= 10` as any)); -> 抛出 Error
248
+ // 错误: expr`${x} + 1`.add(expr`${y} <= 5` as any); -> 抛出 Error
249
+
250
+ // 2. 切勿将不含比较运算符 (<=, >=, ==) 的算术表达式传给 m.constraint():
251
+ // 错误: m.constraint(expr`${x} + ${y}` as any); -> 抛出 Error
252
+
253
+ // 3. 切勿在线性约束中包含二次项:
254
+ // 错误: expr`${x}^2 <= 10`; -> 抛出 Error ("Quadratic constraints are not supported")
255
+
256
+ // 4. 切勿使用已移除的旧别名(已在 #59 / #81 中移除):
257
+ // - 使用 `expr` 代替已废弃的 `c` 模板标签
258
+ // - 使用 `m.constraint(...)` 代替 `m.constrain(...)` 或 `m.add(...)`
259
+ // - 使用 `m.objective(maximize(...))` / `m.objective(minimize(...))` 代替 `m.maximize(...)` / `m.minimize(...)` / `m.setObjective(...)`
260
+ // - 使用 `await m.solve()` 代替 `await m.optimize()`
261
+ // - 使用 `.le()`, `.ge()`, `.eq()` 代替 `.lessThanOrEqual()`, `.greaterThanOrEqual()`, `.equalTo()`
262
+ // - 使用 `.value` 或 `m.getValues(...)` 代替 `expr.getValue()`
263
+ // - 使用 `m.variables` / `m.constraints` 代替 `m.vars` / `m.constrs`
264
+ return { m, x, y, maximize };
265
+ }
266
+ ```