@ohtaman/washi 0.5.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.
Files changed (107) hide show
  1. package/README.ja.md +103 -386
  2. package/README.md +104 -387
  3. package/README.zh-CN.md +103 -386
  4. package/THIRD_PARTY_LICENSES.md +5 -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 +1 -1
  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 +3 -3
  12. package/dist/browser/solvers/glpk.min.js +1 -1
  13. package/dist/browser/solvers/z3.js +7 -1
  14. package/dist/browser/solvers/z3.min.js +1 -1
  15. package/dist/browser/washi.js +1708 -540
  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 +1 -1
  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-BEfvpZW3.js → registry-D7TZ3Wh_.js} +142 -59
  26. package/dist/lib/solvers/glpk.js +4 -4
  27. package/dist/lib/solvers/z3.js +1 -1
  28. package/dist/lib/washi.js +1576 -465
  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 +4 -3
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/types/modeler/boolean-expr.d.ts.map +1 -1
  40. package/dist/types/modeler/constraint.d.ts +11 -0
  41. package/dist/types/modeler/constraint.d.ts.map +1 -1
  42. package/dist/types/modeler/expression.d.ts +57 -26
  43. package/dist/types/modeler/expression.d.ts.map +1 -1
  44. package/dist/types/modeler/index.d.ts +4 -3
  45. package/dist/types/modeler/index.d.ts.map +1 -1
  46. package/dist/types/modeler/linearizer.d.ts +15 -0
  47. package/dist/types/modeler/linearizer.d.ts.map +1 -0
  48. package/dist/types/modeler/lp-writer.d.ts +3 -1
  49. package/dist/types/modeler/lp-writer.d.ts.map +1 -1
  50. package/dist/types/modeler/model.d.ts +159 -8
  51. package/dist/types/modeler/model.d.ts.map +1 -1
  52. package/dist/types/modeler/parser.d.ts +25 -5
  53. package/dist/types/modeler/parser.d.ts.map +1 -1
  54. package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -1
  55. package/dist/types/modeler/solvers/highs/browser-runtime.d.ts +2 -1
  56. package/dist/types/modeler/solvers/highs/browser-runtime.d.ts.map +1 -1
  57. package/dist/types/modeler/solvers/highs/driver.d.ts +232 -0
  58. package/dist/types/modeler/solvers/highs/driver.d.ts.map +1 -0
  59. package/dist/types/modeler/solvers/highs/index.d.ts +1 -0
  60. package/dist/types/modeler/solvers/highs/index.d.ts.map +1 -1
  61. package/dist/types/modeler/solvers/highs/loader.d.ts +4 -4
  62. package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -1
  63. package/dist/types/modeler/solvers/highs/node-runtime.d.ts +2 -1
  64. package/dist/types/modeler/solvers/highs/node-runtime.d.ts.map +1 -1
  65. package/dist/types/modeler/solvers/highs/solver.d.ts +1 -1
  66. package/dist/types/modeler/solvers/highs/solver.d.ts.map +1 -1
  67. package/dist/types/modeler/solvers/highs/worker-client.d.ts.map +1 -1
  68. package/dist/types/modeler/solvers/types.d.ts +4 -0
  69. package/dist/types/modeler/solvers/types.d.ts.map +1 -1
  70. package/dist/types/modeler/types.d.ts +27 -0
  71. package/dist/types/modeler/types.d.ts.map +1 -1
  72. package/docs/examples/diet-sensitivity.md +15 -14
  73. package/docs/examples/ecommerce-coupons.md +15 -22
  74. package/docs/examples/index.md +18 -12
  75. package/docs/examples/knapsack.md +8 -7
  76. package/docs/examples/portfolio-qp.md +11 -4
  77. package/docs/examples/production.md +4 -4
  78. package/docs/examples/shift-scheduling.md +20 -7
  79. package/docs/examples/smt-security.md +16 -4
  80. package/docs/examples/transportation.md +46 -19
  81. package/docs/examples/traveling-salesperson.md +157 -0
  82. package/docs/examples/unsat-core.md +15 -5
  83. package/docs/examples/vehicle-routing.md +208 -0
  84. package/docs/getting-started/ai-agents.md +33 -18
  85. package/docs/getting-started/cross-origin.md +56 -28
  86. package/docs/getting-started/index.md +40 -69
  87. package/docs/getting-started/runtimes.md +66 -61
  88. package/docs/guide/constraints.md +47 -41
  89. package/docs/guide/decomposition.md +267 -0
  90. package/docs/guide/expressions.md +90 -39
  91. package/docs/guide/formulation-tips.md +212 -0
  92. package/docs/guide/objectives.md +7 -4
  93. package/docs/guide/unsat-core.md +28 -9
  94. package/docs/guide/variables.md +33 -38
  95. package/docs/ja/getting-started/ai-agents.md +32 -18
  96. package/docs/solvers/custom-solver.md +1 -1
  97. package/docs/solvers/highs.md +48 -5
  98. package/docs/solvers/index.md +4 -4
  99. package/docs/solvers/z3.md +3 -0
  100. package/docs/zh/getting-started/ai-agents.md +32 -18
  101. package/llms-full.txt +1536 -478
  102. package/llms.txt +28 -22
  103. package/package.json +19 -16
  104. package/skills/washi/SKILL.md +21 -17
  105. package/dist/browser/browser-runtime-D13gHOT5.js +0 -4189
  106. package/dist/browser/loader-CtaDHef_.js +0 -273
  107. package/dist/lib/loader-DmNC_UNk.js +0 -279
package/README.ja.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 のための数理最適化・代数モデラー" src="./assets/washi-header-light.png" width="420" />
5
+ <img alt="WaSHI - TypeScript 数理最適化モデラー" src="./assets/washi-header-light.png" width="420" />
6
6
  </picture>
7
- <p><strong>TypeScript / JavaScript のための代数モデラー</strong></p>
7
+ <p><strong>TypeScript 数理最適化モデラー</strong></p>
8
8
  <p>
9
9
  <em>線形計画 (LP) • 混合整数計画 (MIP) • 凸二次計画 (QP) • SMT論理制約 &amp; 矛盾診断</em>
10
10
  </p>
@@ -16,19 +16,45 @@
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/ja/"><img src="https://img.shields.io/badge/docs-online-blue" alt="docs" /></a>
20
- <a href="https://ohtaman.github.io/washi/demo/"><img src="https://img.shields.io/badge/demo-playground-brightgreen" alt="live demo" /></a>
19
+ <a href="https://washi.ohtaman.dev/ja/"><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)は、Python の **PuLP** や Julia の **JuMP** に着想を得た、TypeScript / JavaScript 向けの代数モデラーです。アプリケーションのコードで変数・目的関数・数値制約や論理制約を記述できます。WaSHI はモデルの構築、ソルバー向けの変換、変数への結果の反映を担当し、最適化や充足可能性の判定は **HiGHS**・**Z3**・**GLPK** が行います。
27
+ **WaSHI**(WebAssembly-backed, Solver-independent, High-level modeling Interface)は、Python の **PuLP** に着想を得た、数理最適化と制約プログラミングのための TypeScript / JavaScript 向け代数モデラーです。変数・目的関数・制約をアプリケーションコードで記述し、Node.js やブラウザ上で **HiGHS**(標準)・**Z3**・**GLPK** を使ってそのまま求解できます。
28
28
 
29
- HiGHS が標準ソルバーで、Z3 と GLPK は任意で追加するプラグインです。Node.js 用とブラウザ用の配布物に WebAssembly アセットを含みます。配信に必要な設定は[ブラウザでの利用方法](#-ブラウザ--web-worker-での利用方法)を参照してください。
29
+ ## ✨ 主な特徴
30
30
 
31
- [ドキュメント](https://ohtaman.github.io/washi/ja/) · [ブラウザデモを試す](https://ohtaman.github.io/washi/demo/) · [AIエージェント向けクイックリファレンス](docs/ja/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)
31
+ - **直感的な数式記述**: `` expr`30 * ${x} + 50 * ${y} <= 40` `` や総和・内積(`sum`, `dot`)で数式と制約を簡潔に書けます。
32
+ - **Node.js・ブラウザで完結**: WebAssembly ベースのため、Python サーバーや C/C++ のネイティブビルドなしで動作します。
33
+ - **ソルバー非依存**: 標準同梱の **HiGHS** に加え、オプションの **Z3**・**GLPK** や独自ソルバーへ切り替えられます。
34
+ - **充足判定と矛盾診断**: 論理・数値制約の充足可能性判定や、実行不能(Infeasible)になった原因制約の特定に対応しています。
35
+ - **大規模問題の分解法**: 列生成法やベンダーズ分解などの分解アルゴリズムをサポートしています。
36
+
37
+ ## 📚 ドキュメント & リンク
38
+
39
+ - **[ドキュメント](https://washi.ohtaman.dev/ja/)**: モデリングガイド・ソルバー仕様・環境別の導入手順
40
+ - **[ショーケース](https://washi.ohtaman.dev/ja/showcase/) & [ブラウザデモ](https://washi.ohtaman.dev/demo/)**: ブラウザ上で動くデモアプリ集とプレイグラウンド
41
+ - **[サンプル集](https://washi.ohtaman.dev/ja/examples/)**: 課題別の実践レシピと実行可能なサンプルコード([`examples/`](examples/README.md))
42
+ - **[AIエージェント向けガイド](docs/ja/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 コーディングエージェント向けのリファレンス・スキル定義・機械可読ドキュメント
43
+
44
+ ---
45
+
46
+ ## 📦 インストール & クイックスタート
47
+
48
+ ```bash
49
+ npm install @ohtaman/washi
50
+
51
+ # オプションのソルバープラグイン
52
+ npm install z3-solver # SMT 論理制約・Unsat Core 診断を使う場合
53
+ npm install glpk.js # GLPK ソルバーを使う場合 (GPL-3.0)
54
+
55
+ # AI コーディングエージェント用スキル (Claude Code, Cursor, Codex 等)
56
+ npx skills add ohtaman/washi
57
+ ```
32
58
 
33
59
  ```ts
34
60
  import { Model, expr, maximize } from "@ohtaman/washi";
@@ -47,446 +73,137 @@ console.log(`生産量: x=${x.value}, y=${y.value} (最大利益: $${m.objective
47
73
 
48
74
  ---
49
75
 
50
- ## 🎯 WaSHI が提供するもの
51
-
52
- 1. **代数的なモデル記述**: ドメイン変数メソッド(`m.binary`, `m.integer`, `m.continuous`)、タグ付きテンプレート(`expr`)、ベクトル集計関数(`dot`, `sum`)、およびファーストクラスの制約(`m.constraint`)によりモデルを記述します。JavaScript には演算子オーバーロードがないため、`` expr`...` `` は SQL のパラメータバインディングと同様に、中置記法の演算子(`+`, `-`, `*`, `^2`, `<=`, `>=`, `==`)を構文解析しつつ `${...}` に渡された値を型付きの `Var` や式のオブジェクト参照として直接バインドします。これにより、TypeScript の型検査、IDE のシンボルリネーム、多次元変数の添字参照(`${flow[i][j]}`)がそのまま機能します。
53
- 2. **ソルバーアダプター**: 共通のモデリング API から HiGHS・Z3・GLPK を利用でき、[独自アダプターも登録できます](https://github.com/ohtaman/washi/blob/main/docs/ja/solvers/custom-solver.md)。モデルの問題クラスを扱えるソルバーを選ぶ必要があり、対応機能はソルバーごとに異なります。
54
- 3. **ローカル実行と WebAssembly の配布**: ローカルソルバーのアダプターでは、別途 Python サービスや C/C++ のネイティブビルドを用意せずアプリケーション内で求解できるため、プロトタイプから Web ツールを公開する際のバックエンド構築のボトルネックを解消でき、ブラウザ内 LLM(WebGPU / WebLLM 等)とのクライアントサイド連携も容易です。ブラウザへの配布には生成された JS・Worker・WASM が必要です。オフライン利用には、これらをローカルに配置するかキャッシュしておく必要があります。Z3 には追加のブラウザ隔離設定があります。
55
- 4. **名前付き制約と SMT の結果**: Z3 を明示的に使って充足可能性を確認し、矛盾する制約の調査に競合制約(`conflicts` / `unsatCore`)を利用できます。返されるのは矛盾する制約の部分集合であり、最小の集合とは限りません。
76
+ ## ⚙️ 対応ソルバー
56
77
 
57
- モデルの構築と変換は WaSHI が担当します。扱える問題クラス、数値計算の挙動、求解時間は、選択したソルバー・設定・問題に依存します。モデル構築のオーバーヘッドとソルバーの実行時間は分けて計測する必要があり、特定のモデルでの結果は一般的な性能保証ではありません。
58
-
59
- ---
60
-
61
- ## ⚙️ ソルバーアダプターと対応範囲
62
-
63
- | アダプター | エンジンのライセンス | 対応する問題クラス | エンジンの役割 | 提供形態 |
78
+ | ソルバー | ライセンス | 対応クラス | 主な用途 | 導入方法 |
64
79
  | :--- | :--- | :--- | :--- | :--- |
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`) |
68
- | **Mock** | **MIT** | — | 統合テスト用の模擬応答 | 標準搭載。モデルの求解は行わない |
69
-
70
- ---
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`) |
71
84
 
72
- ## 📦 インストール
73
-
74
- ```bash
75
- # npm
76
- npm install @ohtaman/washi
77
-
78
- # pnpm
79
- pnpm add @ohtaman/washi
80
-
81
- # yarn
82
- yarn add @ohtaman/washi
83
-
84
- # bun
85
- bun add @ohtaman/washi
86
- ```
87
-
88
- *(任意)* Z3 や GLPK を使用する場合は、各パッケージを追加インストールします:
89
-
90
- ```bash
91
- npm install z3-solver # SMT・矛盾診断を利用する場合
92
- npm install glpk.js # GLPK ソルバーを利用する場合 (GPL-3.0)
93
- ```
94
-
95
- *(任意)* AI コーディングエージェント(Claude Code, Antigravity, Cursor, Codex 等)向けに、[AIエージェント向けクイックリファレンス](docs/ja/getting-started/ai-agents.md)とあわせてポータブルな [`skills/washi/SKILL.md`](skills/washi/SKILL.md) を同梱しています:
96
-
97
- ```bash
98
- mkdir -p .agents/skills/washi
99
- cp node_modules/@ohtaman/washi/skills/washi/SKILL.md .agents/skills/washi/SKILL.md
100
- ```
85
+ プラグインを import した上で、`new Model(...)`・`m.solve(...)`・`m.check(...)` に `{ solver: "z3" }` または `{ solver: "glpk" }` を渡して切り替えます。
101
86
 
102
87
  ---
103
88
 
104
- ## 🚀 使い方ガイド
89
+ ## 🚀 基本的な使い方
105
90
 
106
- ### 1. 多次元変数・条件付き制約 (`m.indicator`)・解の検証 (`m.validateSolution`)
91
+ ### 1. 総和・内積(`sum` / `dot`)と条件付き制約
107
92
 
108
- 1次元辞書や2次元マトリクス変数を1行で宣言し、`m.indicator()` による条件付き Big-M 制約、進捗イベント(`onProgress`)とキャンセル(`AbortSignal`)、および `m.validateSolution()` による独立解検証を行えます:
93
+ `dot` / `sum` による線形式の記述と、`m.indicator()` による条件付き制約:
109
94
 
110
95
  ```ts
111
- import { Model, expr } from "@ohtaman/washi";
112
-
113
- const m = new Model("FacilityPlanning");
114
-
115
- // 1次元辞書形式のバイナリ変数群
116
- const openCity = m.binary(["Tokyo", "Osaka", "Nagoya"]);
117
-
118
- // 2次元輸送量行列: [工場] x [店舗]
119
- const flow = m.continuous(["F1", "F2"], ["StoreA", "StoreB"], { lb: 0, ub: 1000 });
120
-
121
- // 2次元グリッド (例: 8x8 チェス盤)
122
- const board = m.binary(8, 8, { prefix: "queen" });
123
-
124
- // 条件付き Big-M 制約: 東京拠点が閉鎖 (openCity['Tokyo'] == 0) なら flow <= 0
125
- // (M を省略すると、変数の有限な上下限から安全な最小の Big-M が自動導出されます)
126
- m.indicator(openCity["Tokyo"], expr`${flow["F1"]["StoreA"]} <= 0`, {
127
- activeValue: 0,
128
- name: "tokyo_closed_no_flow",
129
- });
130
-
131
- // 進捗コールバック (onProgress) と AbortSignal によるキャンセル制御
132
- const controller = new AbortController();
133
- await m.solve({
134
- signal: controller.signal,
135
- onProgress: (ev) => {
136
- // 分枝限定法のライブ指標: ev.elapsedTime, ev.objectiveValue, ev.objectiveBound, ev.mipGap
137
- },
138
- });
139
-
140
- // 求解結果が境界・整数性・線形/論理制約を満たすか独立検証
141
- const report = m.validateSolution();
142
- console.log("解の検証結果:", report.valid);
143
- ```
144
-
145
- ---
96
+ import { Model, expr, minimize } from "@ohtaman/washi";
146
97
 
147
- ### 2. ポートフォリオのリスク最小化 (凸二次計画: QP)
98
+ const m = new Model("TransportPlanning");
99
+ const factories = ["Tokyo", "Osaka"];
100
+ const stores = ["StoreA", "StoreB"];
101
+ const costs = {
102
+ Tokyo: { StoreA: 4, StoreB: 7 },
103
+ Osaka: { StoreA: 8, StoreB: 3 },
104
+ };
148
105
 
149
- 期待リターンと予算制約を満たしつつ、共分散行列に基づく投資リスクを最小化:
106
+ const open = m.binary(factories);
107
+ const ship = m.continuous(factories, stores, { lb: 0, ub: 500 });
150
108
 
151
- ```ts
152
- import { Model, QuadExpr, sum, dot, minimize, expr } from "@ohtaman/washi";
153
-
154
- const m = new Model("MarkowitzPortfolio");
155
- const assets = ["Tech", "Bonds", "RealEstate"];
156
- const returns = [0.14, 0.04, 0.08];
157
-
158
- // 決定変数: 投資比率 (0.0 〜 1.0)
159
- const w = m.continuous(assets, { lb: 0, ub: 1 });
160
-
161
- // 1. 予算制約: 合計 100%
162
- m.constraint(expr`${sum(assets, (a) => w[a])} == 1.0`, "budget");
163
-
164
- // 2. 目標リターン: 最低 8.5%
165
- const retMap = Object.fromEntries(assets.map((a, i) => [a, returns[i]]));
166
- m.constraint(expr`${dot(retMap, w)} >= 0.085`, "min_return");
167
-
168
- // 3. 共分散行列 (リスク & 相関)
169
- const cov = [
170
- [0.040, 0.002, 0.015],
171
- [0.002, 0.005, 0.002],
172
- [0.015, 0.002, 0.025],
173
- ];
174
-
175
- // 二次目的関数: w^T * Cov * w
176
- let risk = new QuadExpr();
177
- for (let i = 0; i < assets.length; i++) {
178
- for (let j = 0; j < assets.length; j++) {
179
- risk = risk.add(w[assets[i]].mul(w[assets[j]]).mul(cov[i][j]));
180
- }
181
- }
182
- m.objective(minimize(risk));
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");
183
112
 
113
+ m.objective(minimize(expr`dot(${costs}, ${ship})`));
184
114
  await m.solve();
185
- console.log(`最小分散: ${m.objectiveValue?.toFixed(6)}`);
186
- assets.forEach((name) => {
187
- console.log(` ${name}: ${((w[name].value || 0) * 100).toFixed(2)}%`);
188
- });
189
- ```
190
115
 
191
- ---
116
+ console.log("Tokyo -> StoreA:", ship["Tokyo"]["StoreA"].value);
117
+ ```
192
118
 
193
- ### 3. SMT 論理制約 & ルールエンジン (Z3 連携)
119
+ ### 2. 凸二次計画 (QP)
194
120
 
195
- 命題変数(`BoolVar`)と論理結合子(`and`, `or`, `implies`, `not`, `xor`)、数値比較制約を混在させたルール定義:
121
+ 線形制約のもとで二次の目的関数を最小化:
196
122
 
197
123
  ```ts
198
- import { Model, not, expr } from "@ohtaman/washi";
199
- import "@ohtaman/washi/solvers/z3";
200
-
201
- const m = new Model({ name: "SmartSecurityRules" });
202
-
203
- const isNight = m.bool("isNight");
204
- const motion = m.bool("motion");
205
- const alarm = m.bool("alarm");
206
- const siren = m.bool("siren");
207
- const lux = m.integer("lux", { lb: 0 });
208
-
209
- // 論理ルール
210
- m.constraint(lux.le(50).implies(isNight), "dark_implies_night");
211
- m.constraint(motion.and(isNight).and(alarm).implies(siren), "alarm_rule");
124
+ import { Model, expr, minimize } from "@ohtaman/washi";
212
125
 
213
- // 観測されたセンサー値
214
- m.constraint(expr`${lux} <= 10`, "sensor_dark");
215
- m.constraint(motion, "sensor_motion");
216
- m.constraint(alarm, "alarm_on");
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 });
217
129
 
218
- // 目的関数なしで制約充足可能性(SAT)を判定
219
- const res = await m.check({ solver: "z3" });
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`));
220
133
 
221
- console.log(`充足可能? ${res.status === "Sat"}`); // true
222
- console.log(`サイレン作動? ${m.values.get("siren")}`); // true
134
+ await m.solve();
135
+ console.log(`Tech: ${x.value?.toFixed(2)}, Bonds: ${y.value?.toFixed(2)}`);
223
136
  ```
224
137
 
225
- ---
226
-
227
- ### 4. 矛盾原因の自動特定 (`conflicts` / `unsatCore`)
138
+ ### 3. SMT 論理ルール & 矛盾診断 (`m.check`)
228
139
 
229
- 業務ルールや制約群が互いに矛盾している場合、**矛盾を引き起こしている制約の部分集合**(Unsat Core / Conflicts。最小性は保証しません)を特定してデバッグ(Z3 が必要):
140
+ 論理条件(`m.bool`, `implies`)を含むモデルの充足可能性を判定し、矛盾時の原因制約を特定します:
141
+ - **HiGHS(標準)**: 緩和すれば実行可能になる**修復集合**(`res.conflicts`)を特定します。
142
+ - **Z3**: 相互に矛盾している**充足不能コア**(`res.unsatCore` / `res.conflicts`)を抽出します。
230
143
 
231
144
  ```ts
232
- import { Model, expr } from "@ohtaman/washi";
233
- import "@ohtaman/washi/solvers/z3";
145
+ import { Model, implies, expr } from "@ohtaman/washi";
146
+ // import "@ohtaman/washi/solvers/z3"; // 厳密な SMT unsatCore を抽出する場合
234
147
 
235
- const m = new Model({ name: "ConflictDiagnosis", solver: "z3" });
148
+ const m = new Model("StaffingRules");
236
149
  const engineers = m.integer("engineers", { lb: 0, ub: 20 });
237
150
  const budget = m.continuous("budget", { lb: 0, ub: 100000 });
238
- const rushDelivery = m.bool("rushDelivery");
151
+ const rush = m.bool("rush");
239
152
 
240
- // ルール 1: エンジニア1人あたり $8,000
241
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"); // 無関係な制約
242
158
 
243
- // ルール 2: 特急納品が必須
244
- m.constraint(rushDelivery, "rush_required");
245
-
246
- // ルール 3: 特急納品には最低 8 人のエンジニアが必要
247
- m.constraint(rushDelivery.implies(engineers.ge(8)), "rush_staffing_rule");
248
-
249
- // ルール 4: 役員会の予算上限 $50,000 (矛盾: 8人 * $8000 = $64,000 > $50,000!)
250
- m.constraint(expr`${budget} <= 50000`, "strict_board_budget_cap");
251
-
252
- // ルール 5: 最低 1 人雇用の労働基準(無関係なルール)
253
- m.constraint(expr`${engineers} >= 1`, "minimum_one_employee");
254
-
255
- const res = await m.check({ solver: "z3" });
256
-
257
- console.log(`ステータス: ${res.status}`); // "Unsat"
258
- console.log("矛盾している制約:", res.conflicts);
259
- // 出力: ["budget_limit", "rush_required", "rush_staffing_rule", "strict_board_budget_cap"]
260
- // ※ 無関係な "minimum_one_employee" は的確に除外されます
261
- ```
262
-
263
- ---
264
-
265
- ### 5. GLPK ソルバーの利用 (GPL-3.0)
266
-
267
- GNU Linear Programming Kit (GLPK) ソルバープラグインを利用する場合:
268
-
269
- ```ts
270
- import { Model, expr, maximize } from "@ohtaman/washi";
271
- import "@ohtaman/washi/solvers/glpk";
272
-
273
- const m = new Model({ solver: "glpk" });
274
- const x = m.integer("x", { lb: 0 });
275
- const y = m.integer("y", { lb: 0 });
276
-
277
- m.objective(maximize(expr`30 * ${x} + 50 * ${y}`));
278
- m.constraint(expr`${x} + 2 * ${y} <= 40`, "wood_limit");
279
- m.constraint(expr`2 * ${x} + ${y} <= 50`, "labor_limit");
280
-
281
- const status = await m.solve();
282
- console.log(`ステータス: ${status}`); // "Optimal"
283
- console.log(`目的関数値: ${m.objectiveValue}`); // 1100
284
- ```
285
-
286
- ---
287
-
288
- ### 6. ベクトル演算と高速内積 (`dot`)
289
-
290
- ネストしたループを書くことなく、1次元・2次元の線形結合を1行で記述:
291
-
292
- ```ts
293
- import { Model, dot, minimize } from "@ohtaman/washi";
294
-
295
- const m = new Model();
296
- const factories = ["Tokyo", "Osaka"];
297
- const stores = ["StoreA", "StoreB"];
298
-
299
- const costs = {
300
- Tokyo: { StoreA: 4, StoreB: 7 },
301
- Osaka: { StoreA: 8, StoreB: 3 },
302
- };
303
-
304
- const ship = m.continuous(factories, stores);
305
-
306
- // 総輸送コストを1行で最小化:
307
- m.objective(minimize(dot(costs, ship)));
308
- await m.solve();
309
-
310
- // 最適解の全変数値を取得
311
- const solution = m.getValues(ship);
312
- console.log(solution);
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"]
313
162
  ```
314
163
 
315
164
  ---
316
165
 
317
166
  ## 🌐 ブラウザ & Web Worker での利用方法
318
167
 
319
- HiGHS はデフォルトでパッケージ同梱 WASM を使います。**CDN への自動フォールバックはありません。** Node.js はインストールされた HiGHS を使い、Vite / webpack 5 はパッケージ内の WASM・Worker 参照から配布ファイルを生成します。
320
-
321
- ### npm とバンドラー
322
-
323
- ```typescript
324
- import { Model } from "@ohtaman/washi";
325
- const model = new Model();
326
- // 変数・目的関数・制約を定義
327
- await model.solve();
328
- ```
329
-
330
- 検証対象の Vite / webpack ビルドでは WASM の手動コピー・URL 指定は不要です。その他のバンドラーや SSR は個別に確認し、ブラウザの求解はクライアントで実行してください。ブラウザでは Worker をデフォルトで使用します。簡単なデモは `model.solve({ useWorker: false })` でも動きますが、長い計算中は UI が止まります。
331
-
332
- ### ブラウザ標準 ESM(利用者側のビルド不要)
333
-
334
- `dist/browser` 一式(JS の分割ファイル・`highs.wasm`・Worker を含む)を HTTP 配信します。Import Maps は不要です。
168
+ - **バンドラー (Vite / webpack 5)**: `import { Model } from "@ohtaman/washi"` でそのまま動作します。ブラウザでは標準で Web Worker 上で実行されます(メインスレッドで実行する場合は `{ useWorker: false }` を指定)。
169
+ - **単体 ESM / script タグ / CDN**: `dist/browser/` 一式(`highs.wasm` や Worker を含む)を配信するか、CDN の URL を指定して読み込みます。
335
170
 
336
171
  ```html
172
+ <!-- ブラウザ ESM -->
337
173
  <script type="module">
338
174
  import { Model } from "./washi/washi.js";
339
- const model = new Model();
340
- // 変数・目的関数・制約を定義
341
- await model.solve({ useWorker: false });
342
- </script>
343
- ```
344
-
345
- ### 通常の script / CodePen
346
-
347
- `dist/browser/washi.min.js` はグローバル API `Washi` を公開します。CodePen の External Scripts にその URL を追加するか、次のように読み込みます。
348
-
349
- ```html
350
- <script src="./washi/washi.min.js"></script>
351
- <script>
352
- const model = new Washi.Model();
353
- // 変数・目的関数・制約を定義
354
- model.solve({ useWorker: false }).then(status => console.log(status));
355
- </script>
356
- ```
357
-
358
- CDN から直接読み込む場合は、URL を `https://cdn.jsdelivr.net/npm/@ohtaman/washi@<version>/dist/browser/washi.min.js`(対応版リリースが公開された後にそのバージョンを指定)に指定できます。ESM は同じ版の `dist/browser/washi.js` を指定します。CDN の URL を選ぶことが明示的な CDN 利用になり、ローカル配信が勝手に CDN へ切り替わることはありません。
359
-
360
- ### ブラウザ環境でのソルバープラグイン(GLPK & Z3)
361
-
362
- ブラウザ配布物には、`dist/browser/solvers/` 配下に事前バンドルされたスタンドアロンソルバープラグインが含まれています:
363
- - **GLPK**: `dist/browser/solvers/glpk.js` (ESM) および `dist/browser/solvers/glpk.min.js` (IIFE、グローバル `WashiGLPK` を登録)
364
- - **Z3**: `dist/browser/solvers/z3.js` (ESM) および `dist/browser/solvers/z3.min.js` (IIFE、グローバル `WashiZ3` を登録)、ならびに `z3-built.js` / `z3-built.wasm`
365
-
366
- #### ブラウザ ESM での GLPK 利用
367
- ```html
368
- <script type="module">
369
- import { Model, maximize } from "./washi/washi.js";
370
- import "./washi/solvers/glpk.js";
371
-
372
- const model = new Model({ solver: "glpk" });
373
- const x = model.continuous("x", { lb: 0, ub: 10 });
374
- model.objective(maximize(x));
375
- await model.solve();
376
- console.log("GLPK ステータス:", model.status);
175
+ // オプションプラグイン: import "./washi/solvers/glpk.js" または "./washi/solvers/z3.js"
176
+ const m = new Model();
177
+ await m.solve();
377
178
  </script>
378
- ```
379
179
 
380
- #### スクリプトタグでの GLPK 利用
381
- ```html
382
- <script src="./washi/washi.min.js"></script>
383
- <script src="./washi/solvers/glpk.min.js"></script>
384
- <script>
385
- const model = new Washi.Model({ solver: "glpk" });
386
- const x = model.continuous("x", { lb: 0, ub: 10 });
387
- model.objective(Washi.maximize(x));
388
- model.solve().then(status => console.log("GLPK ステータス:", status));
389
- </script>
180
+ <!-- script タグ / CodePen (グローバル Washi を公開) -->
181
+ <script src="https://cdn.jsdelivr.net/npm/@ohtaman/washi/dist/browser/washi.min.js"></script>
390
182
  ```
391
183
 
392
184
  > [!NOTE]
393
- > **ブラウザ環境での Z3 利用と Cross-Origin Isolation**:
394
- > Z3 の WebAssembly エンジンはマルチスレッド(`SharedArrayBuffer`)を必要とするため、`Cross-Origin-Opener-Policy: same-origin` および `Cross-Origin-Embedder-Policy: require-corp` ヘッダーによる Cross-Origin Isolation が必要です。静的ホスティング(`coi-serviceworker.js`)、イントラネット・オフライン配置、CSP(`worker-src blob:`)、カスタム WASM URL(`setHighsWasmUrl`)の詳細は [Cross-Origin Isolation 設定](docs/ja/getting-started/cross-origin.md) および [ランタイム環境とデプロイ構成](docs/ja/getting-started/runtimes.md) を参照してください。
395
-
396
- 完全なスタンドアロンサンプル(ESM、スクリプトタグ、CodePen)は [`examples/distribution/`](examples/distribution/README.md) に用意されています。
397
-
398
- ---
399
-
400
- ## 🛠️ カスタムソルバー開発と拡張性
401
-
402
- WaSHI は疎結合なプラグイン方式のソルバーアーキテクチャを採用しています。独自の最適化エンジン(クラウド REST ソルバー、WebAssembly エンジン、商用ソルバーアダプターなど)を容易に構築・登録できます:
403
-
404
- - 詳細な開発手順、API コントラクト仕様(`Solver`, `SolveModelData`, `CheckModelData`, `SolverResult`)、およびテスト手法については [カスタムソルバー開発ガイド](docs/ja/solvers/custom-solver.md) をご覧ください。
185
+ > **ブラウザでの Z3 利用**: Z3 の WebAssembly は `SharedArrayBuffer` を使用するため、Cross-Origin Isolation(`COOP: same-origin` / `COEP: require-corp`)が必要です。詳細は [Cross-Origin Isolation 設定](docs/ja/getting-started/cross-origin.md) および [`examples/distribution/`](examples/distribution/README.md) を参照してください。
405
186
 
406
187
  ---
407
188
 
408
- ## 📚 ドキュメント
189
+ ## 🤝 コントリビューション・開発
409
190
 
410
- 完全なドキュメントは **[ohtaman.github.io/washi/ja/](https://ohtaman.github.io/washi/ja/)** およびリポジトリの [`docs/ja/`](docs/ja/)([英語版 `docs/`](docs/))で公開されています:
411
-
412
- - **はじめに**: [クイックスタート](docs/ja/getting-started/index.md) · [AIエージェント向けクイックリファレンス](docs/ja/getting-started/ai-agents.md) · [ランタイム環境とデプロイ構成](docs/ja/getting-started/runtimes.md) · [Cross-Origin Isolation (Z3)](docs/ja/getting-started/cross-origin.md)
413
- - **モデリングガイド**: [決定変数 (`Var`, `BoolVar`)](docs/ja/guide/variables.md) · [数式と集計 (`expr`, `sum`, `dot`)](docs/ja/guide/expressions.md) · [制約と論理条件 (`indicator`, SMT)](docs/ja/guide/constraints.md) · [目的関数と求解 (`solve`, `validateSolution`)](docs/ja/guide/objectives.md) · [充足可能性と Unsat Core (`check`)](docs/ja/guide/unsat-core.md)
414
- - **ソルバー**: [ソルバー概要](docs/ja/solvers/index.md) · [HiGHS](docs/ja/solvers/highs.md) · [Z3](docs/ja/solvers/z3.md) · [GLPK](docs/ja/solvers/glpk.md) · [カスタムソルバー](docs/ja/solvers/custom-solver.md)
191
+ ローカル開発、テスト・ベンチマークの実行、WebAssembly アセットの再ビルド、およびリリース手順については [CONTRIBUTING.md](./CONTRIBUTING.md) を参照してください。
415
192
 
416
193
  ---
417
194
 
418
- ## 💻 サンプルとブラウザデモ
419
-
420
- [サンプル一覧](https://github.com/ohtaman/washi/blob/main/examples/README.md)および[オンライン実践レシピ集・API逆引き索引](https://ohtaman.github.io/washi/ja/examples/)では、目的別・WaSHI の API 機能別にサンプルを探せます。
195
+ ## 🙏 謝辞
421
196
 
422
- | カテゴリ | サンプル | 確認できること | ソルバー |
423
- | :--- | :--- | :--- | :--- |
424
- | **基本モデル** | [生産計画](https://github.com/ohtaman/washi/blob/main/examples/node/01-production-planning.ts) | 整数変数、利益の最大化、資源制約 (`expr`) | HiGHS |
425
- | **基本モデル** | [輸送・物流ネットワーク](https://github.com/ohtaman/washi/blob/main/examples/node/09-transportation-problem.ts) | 2次元マトリクス変数 (`continuous(rows, cols)`) と供給・需要バランス | HiGHS |
426
- | **基本モデル** | [栄養問題と感度分析](https://github.com/ohtaman/washi/blob/main/examples/node/10-diet-sensitivity.ts) | 潜在価格 (`constr.dual`)、余剰 (`constr.slack`)、被約費用 (`var.reducedCost`) | HiGHS |
427
- | **実践応用** | [スタッフのシフト作成](https://github.com/ohtaman/washi/blob/main/examples/node/11-shift-scheduling.ts) | 週間シフト最適化と、土曜日の希望休が衝突した際の原因特定 | HiGHS + Z3 |
428
- | **実践応用** | [ECカートのクーポン最適適用](https://github.com/ohtaman/washi/blob/main/examples/node/12-ecommerce-coupon-optimizer.ts) | 条件付き購入金額閾値 (`indicator`)、併用不可ルール、追加購入提案 | HiGHS |
429
- | **実践応用** | [ポートフォリオ配分](https://github.com/ohtaman/washi/blob/main/examples/node/03-portfolio-qp.ts) | 凸二次目的関数 (`QuadExpr`) と配分の制約 | HiGHS |
430
- | **論理 / SMT** | [業務ルールの検証](https://github.com/ohtaman/washi/blob/main/examples/node/04-smt-security-rules.ts) | 数値・論理制約 (`bool`, `implies`) の充足可能性の確認 | Z3 |
431
- | **論理 / SMT** | [矛盾する制約の診断](https://github.com/ohtaman/washi/blob/main/examples/node/05-unsat-core-diagnosis.ts) | 名前付き制約と Unsat Core (`unsatCore`) | Z3 |
432
-
433
- [公開ブラウザデモ](https://ohtaman.github.io/washi/demo/)では、モデルを編集して実行できます。ブラウザ標準 ESM、script タグ、CodePen での使い方は[配布形式のサンプル](https://github.com/ohtaman/washi/blob/main/examples/distribution/README.md)を参照してください。Z3 は Cross-Origin Isolation が必要です。詳細は上記のブラウザ要件に記載しています。
434
-
435
- ローカルで実行する場合は、リポジトリを取得して開発用依存をインストールします。
436
-
437
- ```bash
438
- git clone https://github.com/ohtaman/washi.git
439
- cd washi
440
- npm ci
441
- npx tsx examples/node/01-production-planning.ts
442
- npx tsx examples/node/09-transportation-problem.ts
443
- npx tsx examples/node/10-diet-sensitivity.ts
444
- npx tsx examples/node/11-shift-scheduling.ts
445
- npx tsx examples/node/12-ecommerce-coupon-optimizer.ts
446
-
447
- # ローカルのブラウザデモ: http://localhost:5173/demo/
448
- npm run dev
449
- ```
450
-
451
- サンプルはリポジトリの `src/` モジュールを import しています。公開パッケージを使うアプリでは、`@ohtaman/washi` と必要なソルバープラグインから import してください。
452
-
453
- ---
454
-
455
- ## 🧪 テスト & 再現可能なベンチマーク
456
-
457
- リポジトリのユニット・統合テストを実行し、配布物をビルドできます:
458
-
459
- ```bash
460
- # すべてのユニット・統合テストを実行
461
- npm test
462
-
463
- # プロダクション用バンドルと型定義を生成
464
- npm run build
465
- ```
466
-
467
- ### オプションの再現可能なベンチマーク
468
-
469
- 正しさのテストの合否閾値に実行時間を含めることなく、決定論的な `small-lp`(24変数・18制約)および `scheduling-mip`(315変数・231制約、再構築モデルの `initialValue` ウォームスタートを含む)の各フェーズを計測できます:
470
-
471
- ```bash
472
- # Node.js インプロセス WASM ベンチマークを実行(HiGHS・GLPK、デフォルト5回反復)
473
- npm run bench
474
-
475
- # 反復回数の指定や JSON 出力
476
- node scripts/run-benchmarks.mjs --iterations=10 --json
477
-
478
- # ヘッドレス Chromium の Web Worker 実行も計測(Playwright Chromium が必要)
479
- node scripts/run-benchmarks.mjs --browser
480
- ```
197
+ WaSHI は、数理最適化および自動推論分野の素晴らしいオープンソースソフトウェアの上に成り立っています:
481
198
 
482
- - **明示的な計測境界**: コールド初期化(`coldRuntimeInitMs`, `coldFirstSolveMs`)と再利用ランタイムでの反復計測(`modelBuildMs`, `validationMs`, LP文字列アダプタ向けの `lpSerializationMs` または構造化アダプタ向けの `symbolMapMs`, `MockSolver` による `resultMappingMs`, `adapterSolveMs`, `endToEndSolveMs`)を分離して直接計測します(無関係なフェーズ時間を差し引いて「ネイティブソルバー時間」とみなすことはしません)。
483
- - **実行環境の区別**: Node.js のインプロセス WASM(`usesBrowserWorker: false`)とブラウザ Web Worker 実行(`usesBrowserWorker: true`、Worker ライフサイクルや `postMessage` 転送を含む)は異なる実行環境として区別してレポートされます。
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 により開発された SMT ソルバーであり、オプションの論理充足判定および `unsatCore` 矛盾診断プラグインを支えています。
201
+ - **[GLPK](https://www.gnu.org/software/glpk/) & [`glpk.js`](https://github.com/jvail/glpk.js)** — オプションの GPL-3.0 LP / MIP ソルバープラグインを支えています。
202
+ - **[PuLP](https://github.com/coin-or/pulp)** — WaSHI の直感的な代数モデリング API 設計に大きな着想を与えました。
484
203
 
485
204
  ---
486
205
 
487
206
  ## 📄 ライセンス
488
207
 
489
208
  - **`@ohtaman/washi`**: [MIT ライセンス](./LICENSE)
490
- - **HiGHS**(標準エンジン): MIT ライセンス
491
- - **Z3**(オプション): MIT ライセンス
492
- - **GLPK**(オプション): GPL-3.0 ライセンス
209
+ - **同梱・外部ソルバー**: HiGHS (MIT)、Z3 (MIT)、GLPK (GPL-3.0)。詳細は [THIRD_PARTY_LICENSES.md](./THIRD_PARTY_LICENSES.md) を参照してください。