@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.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
|
|
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/ja/"><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)は、Python の **PuLP** や Julia の **JuMP**
|
|
27
|
+
**WaSHI**(WebAssembly-backed, Solver-independent, High-level modeling Interface)は、Python の **PuLP** や Julia の **JuMP** に着想を得た、数理最適化と制約プログラミングのための TypeScript / JavaScript 向け代数モデラーです。アプリケーションのコードで変数・目的関数・数値制約や論理制約を記述できます。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/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)
|
|
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`, "木材上限");
|
|
42
|
+
m.constraint(expr`2 * ${x} + ${y} <= 50`, "労働力上限");
|
|
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.objective
|
|
|
49
49
|
|
|
50
50
|
## 🎯 WaSHI が提供するもの
|
|
51
51
|
|
|
52
|
-
1. **代数的なモデル記述**:
|
|
53
|
-
2. **ソルバーアダプター**: 共通のモデリング API から HiGHS・Z3・GLPK を利用でき、[独自アダプターも登録できます](https://github.com/ohtaman/washi/blob/main/docs/custom-solver
|
|
54
|
-
3. **ローカル実行と WebAssembly の配布**: ローカルソルバーのアダプターでは、別途 Python サービスや C/C++
|
|
55
|
-
4.
|
|
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. **名前付き制約と矛盾原因の特定**: 充足可能性チェック(`m.check()`)により、矛盾した制約(`conflicts` / `unsatCore`)を調査して実行不能の原因を特定できます。組み込み HiGHS では**エラスティック修復集合**(実行可能性の回復のために緩和が必要な制約集合 `conflicts`)を検出し、Z3 では **SMT 充足不能コア**(相互に矛盾する制約部分集合 `unsatCore` / `conflicts`、最小性は保証されません)を抽出します。
|
|
56
|
+
5. **高度な分解法オーケストレーション**: 素朴な一体型 MIP では探索木が爆発するボトルネック構造(カッティングストック、配送計画/VRP、巡回セールスマン/TSP、施設配置計画など)を、ファーストクラスの分解法(`master.solveColumnGeneration`, `master.solveBenders`)で克服します。価格付け(Pricing)や連結制約(`sub.link(...)`)を活用したクリーンなコールバック設計により、双対価格付け・カット生成・整数解の復元をきれいに調整します。
|
|
56
57
|
|
|
57
58
|
モデルの構築と変換は WaSHI が担当します。扱える問題クラス、数値計算の挙動、求解時間は、選択したソルバー・設定・問題に依存します。モデル構築のオーバーヘッドとソルバーの実行時間は分けて計測する必要があり、特定のモデルでの結果は一般的な性能保証ではありません。
|
|
58
59
|
|
|
@@ -62,9 +63,9 @@ console.log(`生産量: x=${x.value}, y=${y.value} (最大利益: $${m.objective
|
|
|
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
|
+
1次元辞書や2次元マトリクス変数を1行で宣言し、`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
|
-
キー一覧や多次元インデックスから、1 行で変数群を定義:
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
120
|
// 1次元辞書形式のバイナリ変数群
|
|
131
121
|
const openCity = m.binary(["Tokyo", "Osaka", "Nagoya"]);
|
|
132
122
|
|
|
133
123
|
// 2次元輸送量行列: [工場] 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
|
// 2次元グリッド (例: 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 を省略すると、変数の有限な上下限から安全な最小の 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()` が単一 solve の弾性スラック緩和($\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: エンジニア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人 * $8000 = $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 を緩和すれば実行可能となるため修復対象として特定されます)
|
|
268
|
+
|
|
269
|
+
// 2. または Z3 による厳密な SMT 充足不能コア抽出(import "@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
|
ネストしたループを書くことなく、1次元・2次元の線形結合を1行で記述:
|
|
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
|
// 総輸送コストを1行で最小化:
|
|
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 から直接読み込む場合は、URL を `https://cdn.jsdelivr.net/npm/@ohtaman/washi
|
|
370
|
+
CDN から直接読み込む場合は、URL を `https://cdn.jsdelivr.net/npm/@ohtaman/washi@<version>/dist/browser/washi.min.js`(対応版リリースが公開された後にそのバージョンを指定)に指定できます。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 @@ CDN から直接読み込む場合は、URL を `https://cdn.jsdelivr.net/npm/@o
|
|
|
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 利用と Cross-Origin Isolation**:
|
|
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 で公開している公式 Web デモでは、`/washi/` スコープ限定の独立した `coi-serviceworker.js` を同オリジンに配置・登録し、初回アクセス時に1回だけ安全に再読み込みを行って `window.crossOriginIsolated === true` を確立してから Z3 を実行します。Service Worker が利用できない環境や隔離の確立に失敗した環境では、原因を明示して安全に実行を中断します。
|
|
411
|
-
|
|
412
|
-
完全なスタンドアロンサンプル(ESM、スクリプトタグ、CodePen)は `examples/distribution/` に用意されています。
|
|
413
|
-
|
|
414
|
-
### 工場内・オフライン配布、Worker、自前配信
|
|
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` ヘッダーによる 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) を参照してください。
|
|
417
407
|
|
|
418
|
-
ESM
|
|
408
|
+
完全なスタンドアロンサンプル(ESM、スクリプトタグ、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
|
+
- 詳細な開発手順、API コントラクト仕様(`Solver`, `SolveModelData`, `CheckModelData`, `SolverResult`)、およびテスト手法については [カスタムソルバー開発ガイド](docs/ja/solvers/custom-solver.md) をご覧ください。
|
|
432
417
|
|
|
433
418
|
---
|
|
434
419
|
|
|
435
|
-
##
|
|
420
|
+
## 📚 ドキュメント
|
|
436
421
|
|
|
437
|
-
|
|
422
|
+
完全なドキュメントは **[ohtaman.github.io/washi/ja/](https://ohtaman.github.io/washi/ja/)** およびリポジトリの [`docs/ja/`](docs/ja/)([英語版 `docs/`](docs/))で公開されています:
|
|
438
423
|
|
|
439
|
-
-
|
|
424
|
+
- **はじめに**: [クイックスタート](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)
|
|
425
|
+
- **モデリングガイド**: [決定変数 (`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) · [分解法 (`solveColumnGeneration`, `solveBenders`)](docs/ja/guide/decomposition.md)
|
|
426
|
+
- **ソルバー**: [ソルバー概要](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)
|
|
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) | 2次元マトリクス変数 (`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
|
| **実践応用** | [ECカートのクーポン最適適用](https://github.com/ohtaman/washi/blob/main/examples/node/12-ecommerce-coupon-optimizer.ts) | 条件付き購入金額閾値 (`indicator`)、併用不可ルール、追加購入提案 | HiGHS |
|
|
441
|
+
| **分解法 (OR)** | [配送計画 (CVRP)](https://github.com/ohtaman/washi/blob/main/examples/node/13-vehicle-routing-column-generation.ts) | 列生成法 (Dantzig-Wolfe): 双対変数を用いた実行可能車両ルートの動的プライシング | HiGHS |
|
|
442
|
+
| **分解法 (OR)** | [巡回セールスマン (TSP)](https://github.com/ohtaman/washi/blob/main/examples/node/14-traveling-salesperson-benders.ts) | ベンダーズ分解 (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 マージ後、オンデマンド取得(scripts/ensure-highs-wasm.mjs)のハッシュと一致するよう
|
|
509
|
+
# 対応する highs-<version> GitHub Release タグのアセットを上書きアップロード:
|
|
510
|
+
gh release upload highs-v1.15.1 public/highs.wasm src/modeler/solvers/highs/runtime.js --clobber
|
|
511
|
+
```
|
|
512
|
+
(GitHub Actions の **Build HiGHS WebAssembly** ワークフロー `.github/workflows/build-wasm.yml` を `create_release: true` で手動実行することも可能です。その場合は生成された `highs-wasm-assets` アーティファクト(`public/highs.wasm`、`src/modeler/solvers/highs/runtime.js`、`highs.config.json`)を取得してリポジトリへコミットし、Release アセットと SHA-256 ハッシュを同期してください。)
|
|
513
|
+
|
|
514
|
+
2. **`@ohtaman/washi` の npm パッケージリリース**:
|
|
515
|
+
- `main` ブランチへのマージにより、ドキュメントと Web デモは GitHub Pages(`.github/workflows/deploy-demo.yml`)へ自動デプロイされますが、npm への公開は自動では行われません。
|
|
516
|
+
- npm に新バージョンを公開する場合は、`package.json` の `"version"` を更新して `main` にマージした上で、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) をご覧ください。
|