@ohtaman/washi 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.ja.md +341 -0
- package/README.md +340 -2
- package/README.zh-CN.md +341 -0
- package/THIRD_PARTY_LICENSES.md +83 -0
- package/dist/lib/assets/highs-worker-D57nd9KC.js +3 -0
- package/dist/lib/glpk-BC32ZaPG.js +126 -0
- package/dist/lib/highs.wasm +0 -0
- package/dist/lib/highs.wasm.LICENSE +22 -0
- package/dist/lib/solvers/glpk.js +2 -0
- package/dist/lib/solvers/z3.js +2 -0
- package/dist/lib/washi.js +908 -0
- package/dist/lib/z3-C5DfllfD.js +562 -0
- package/dist/types/glpk-loader.d.ts +8 -0
- package/dist/types/glpk-loader.d.ts.map +1 -0
- package/dist/types/highs-loader.d.ts +39 -0
- package/dist/types/highs-loader.d.ts.map +1 -0
- package/dist/types/highs-worker-client.d.ts +12 -0
- package/dist/types/highs-worker-client.d.ts.map +1 -0
- package/dist/types/highs-worker.d.ts +2 -0
- package/dist/types/highs-worker.d.ts.map +1 -0
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/modeler/boolean-expr.d.ts +38 -0
- package/dist/types/modeler/boolean-expr.d.ts.map +1 -0
- package/dist/types/modeler/constraint.d.ts +28 -0
- package/dist/types/modeler/constraint.d.ts.map +1 -0
- package/dist/types/modeler/expression.d.ts +79 -0
- package/dist/types/modeler/expression.d.ts.map +1 -0
- package/dist/types/modeler/index.d.ts +14 -0
- package/dist/types/modeler/index.d.ts.map +1 -0
- package/dist/types/modeler/lp-writer.d.ts +30 -0
- package/dist/types/modeler/lp-writer.d.ts.map +1 -0
- package/dist/types/modeler/mip-compat.d.ts +43 -0
- package/dist/types/modeler/mip-compat.d.ts.map +1 -0
- package/dist/types/modeler/model.d.ts +156 -0
- package/dist/types/modeler/model.d.ts.map +1 -0
- package/dist/types/modeler/parser.d.ts +27 -0
- package/dist/types/modeler/parser.d.ts.map +1 -0
- package/dist/types/modeler/pulp-compat.d.ts +67 -0
- package/dist/types/modeler/pulp-compat.d.ts.map +1 -0
- package/dist/types/modeler/quad-expr.d.ts +55 -0
- package/dist/types/modeler/quad-expr.d.ts.map +1 -0
- package/dist/types/modeler/solvers/glpk.d.ts +22 -0
- package/dist/types/modeler/solvers/glpk.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs.d.ts +26 -0
- package/dist/types/modeler/solvers/highs.d.ts.map +1 -0
- package/dist/types/modeler/solvers/index.d.ts +7 -0
- package/dist/types/modeler/solvers/index.d.ts.map +1 -0
- package/dist/types/modeler/solvers/mock.d.ts +25 -0
- package/dist/types/modeler/solvers/mock.d.ts.map +1 -0
- package/dist/types/modeler/solvers/registry.d.ts +20 -0
- package/dist/types/modeler/solvers/registry.d.ts.map +1 -0
- package/dist/types/modeler/solvers/types.d.ts +86 -0
- package/dist/types/modeler/solvers/types.d.ts.map +1 -0
- package/dist/types/modeler/solvers/z3.d.ts +37 -0
- package/dist/types/modeler/solvers/z3.d.ts.map +1 -0
- package/dist/types/modeler/types.d.ts +27 -0
- package/dist/types/modeler/types.d.ts.map +1 -0
- package/dist/types/modeler/variable.d.ts +52 -0
- package/dist/types/modeler/variable.d.ts.map +1 -0
- package/package.json +97 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ohtaman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="./assets/washi-header-dark.png">
|
|
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" />
|
|
6
|
+
</picture>
|
|
7
|
+
<p><strong>TypeScript / JavaScript のための直感的な数理最適化・代数モデラー</strong></p>
|
|
8
|
+
<p>
|
|
9
|
+
<em>線形計画 (LP) • 混合整数計画 (MIP) • 凸二次計画 (QP) • SMT論理制約 & 矛盾診断</em>
|
|
10
|
+
</p>
|
|
11
|
+
<p>
|
|
12
|
+
<a href="./README.md">English</a> •
|
|
13
|
+
<a href="./README.ja.md">日本語</a> •
|
|
14
|
+
<a href="./README.zh-CN.md">简体中文</a>
|
|
15
|
+
</p>
|
|
16
|
+
<p>
|
|
17
|
+
<a href="https://ohtaman.github.io/washi/"><img src="https://img.shields.io/badge/demo-online-brightgreen" alt="live demo" /></a>
|
|
18
|
+
<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>
|
|
19
|
+
<a href="https://bundlephobia.com/package/@ohtaman/washi"><img src="https://img.shields.io/badge/bundle%20size-7.2%20kB%20(gzip)-blue" alt="bundle size" /></a>
|
|
20
|
+
<a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="license" /></a>
|
|
21
|
+
<img src="https://img.shields.io/badge/types-TypeScript-blue" alt="TypeScript types" />
|
|
22
|
+
<img src="https://img.shields.io/badge/tests-120%2B%20passing-brightgreen" alt="tests" />
|
|
23
|
+
</p>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
**WaSHI** は、Python の **PuLP** や Julia の **JuMP** のような表現力豊かな代数モデリングの美しさを、モダンな TypeScript / JavaScript エコシステムにもたらす高水準モデラーライブラリです。数式そのままの自然な記法で数理最適化モデルを定式化し、Node.js、ブラウザ、Bun、Deno、Next.js 上でネイティブ C++ コンパイル不要で即座に求解できます(WebAssembly 版の **HiGHS**、**Z3**、**GLPK** ソルバーを統合サポート)。
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { Model, expr, c } from "@ohtaman/washi";
|
|
32
|
+
|
|
33
|
+
const m = new Model({ sense: "Maximize" });
|
|
34
|
+
const x = m.addVar({ type: "Integer", lb: 0 });
|
|
35
|
+
const y = m.addVar({ type: "Integer", lb: 0 });
|
|
36
|
+
|
|
37
|
+
m.maximize(expr`30 * ${x} + 50 * ${y}`);
|
|
38
|
+
m.addConstraint(c`${x} + 2 * ${y} <= 40`, "wood_limit");
|
|
39
|
+
m.addConstraint(c`2 * ${x} + ${y} <= 50`, "labor_limit");
|
|
40
|
+
|
|
41
|
+
await m.solve();
|
|
42
|
+
console.log(`生産量: x=${x.value}, y=${y.value} (最大利益: $${m.objectiveValue})`);
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 🎯 なぜ WaSHI を選ぶのか?
|
|
48
|
+
|
|
49
|
+
1. 🌐 **完全クライアントサイド実行 & サーバーコストゼロ**: ブラウザ、エッジワーカー、Electron アプリ内で本格的な数理最適化を完結。バックエンドサーバーの運用コストがゼロになり、オフライン環境でも動作可能。社外秘データ(シフト表や原価など)が外部に送信されないため強固なプライバシーを担保します。
|
|
50
|
+
2. 📦 **ゼロ依存・単一パッケージでの圧倒的な配布容易性**: Python のランタイム管理や仮想環境、OS 別の C/C++ ネイティブソルバーバイナリの同梱に悩まされることはありません。`npm install @ohtaman/washi` だけで WebAssembly ソルバーを含めて即座に動作します。
|
|
51
|
+
3. ✍️ **直感的な代数モデリング DX(PuLP / python-mip 互換)**: 泥臭い行列のインデックス操作は不要。テンプレートリテラル記法(`c`${x} + 2 * ${y} <= 40``)や、Python 最適化開発者におなじみの構文(`LpProblem`, `lpSum`)で、教科書そのままの数式を記述できます。
|
|
52
|
+
4. 🔄 **統一マルチソルバー API(HiGHS / Z3 / GLPK)**: 定式化したモデルコードはそのまま、産業用 MIP/QP に強い **HiGHS**、論理制約・SMT に強い **Z3**、学術用途の **GLPK** をオプション1つで柔軟に切り替え可能です。
|
|
53
|
+
5. 🔍 **実行不可能(Infeasible)時の矛盾原因自動診断**: ルール同士が矛盾して解なしになった場合、どの制約同士が衝突しているかの最小部分集合(Unsat Core)を Z3 エンジン経由で瞬時に特定・診断します。
|
|
54
|
+
6. ⚡ **WebAssembly 上での本格的な産業規模パフォーマンス**: 線形時間 $O(N)$ の高速式ビルダーにより、20,000 変数を超える大規模 MIP を約100msで定式化し、WebAssembly 版 HiGHS で約15秒で高速に求解します。
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ⚡ ソルバー対応マトリクス
|
|
59
|
+
|
|
60
|
+
| ソルバー | ライセンス | 解ける問題クラス | 最適な用途 | WaSHI での提供形態 |
|
|
61
|
+
| :--- | :--- | :--- | :--- | :--- |
|
|
62
|
+
| **HiGHS** | **MIT** | **LP, MIP, 凸QP** | 産業規模の計画最適化、生産スケジューリング、金融ポートフォリオ | **標準ビルトイン**(ゼロ設定) |
|
|
63
|
+
| **Z3** | **MIT** | **SMT, SAT, 命題論理, MIP** | 業務ルール検証、制約矛盾の診断 (`unsatCore`)、ルールエンジン | オプションプラグイン (`@ohtaman/washi/solvers/z3`) |
|
|
64
|
+
| **GLPK** | **GPL-3.0** | **LP, MIP** | 学術的ベンチマーク、既存 GLPK モデル資産との照合 | オプションプラグイン (`@ohtaman/washi/solvers/glpk`) |
|
|
65
|
+
| **Mock** | **MIT** | *任意* | WASM をロードしない CI/CD での高速単体テスト | 標準ビルトイン |
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## 📦 インストール
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# npm
|
|
73
|
+
npm install @ohtaman/washi
|
|
74
|
+
|
|
75
|
+
# pnpm
|
|
76
|
+
pnpm add @ohtaman/washi
|
|
77
|
+
|
|
78
|
+
# yarn
|
|
79
|
+
yarn add @ohtaman/washi
|
|
80
|
+
|
|
81
|
+
# bun
|
|
82
|
+
bun add @ohtaman/washi
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
*(任意)* Z3 や GLPK を使用する場合は、各パッケージを追加インストールします:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm install z3-solver # SMT・矛盾診断を利用する場合
|
|
89
|
+
npm install glpk.js # GLPK ソルバーを利用する場合 (GPL-3.0)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 🚀 使い方ガイド
|
|
95
|
+
|
|
96
|
+
### 1. 混合整数線形計画法 (MIP: 生産計画問題)
|
|
97
|
+
|
|
98
|
+
リソース制約の下で利益を最大化する生産計画:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { Model, c, expr } from "@ohtaman/washi";
|
|
102
|
+
|
|
103
|
+
const m = new Model({ name: "FactoryPlanning", sense: "Maximize" });
|
|
104
|
+
|
|
105
|
+
// 決定変数(整数・非負)
|
|
106
|
+
const chairs = m.addVar({ name: "chairs", type: "Integer", lb: 0 });
|
|
107
|
+
const tables = m.addVar({ name: "tables", type: "Integer", lb: 0 });
|
|
108
|
+
|
|
109
|
+
// テンプレートリテラル記法による自然な目的関数と制約
|
|
110
|
+
m.maximize(expr`30 * ${chairs} + 50 * ${tables}`);
|
|
111
|
+
m.addConstraint(c`${chairs} + 2 * ${tables} <= 40`, "wood_limit");
|
|
112
|
+
m.addConstraint(c`2 * ${chairs} + ${tables} <= 50`, "labor_limit");
|
|
113
|
+
|
|
114
|
+
// 標準の HiGHS WASM エンジンで求解
|
|
115
|
+
const status = await m.solve();
|
|
116
|
+
|
|
117
|
+
console.log(`ステータス: ${status}`); // "Optimal"
|
|
118
|
+
console.log(`最大利益: $${m.objectiveValue}`); // 1100
|
|
119
|
+
console.log(`生産数: 椅子=${chairs.value}, 机=${tables.value}`); // 椅子 20, 机 10
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### 🗂 多次元変数グリッド (`addVars`)
|
|
123
|
+
|
|
124
|
+
キー一覧や多次元インデックスから、1 行で変数群を定義(PuLP の `LpVariable.dicts` 相当):
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
// 1次元辞書形式のバイナリ変数群
|
|
128
|
+
const openCity = m.addVars(["Tokyo", "Osaka", "Nagoya"], { type: "Binary" });
|
|
129
|
+
|
|
130
|
+
// 2次元輸送量行列: [工場] x [店舗]
|
|
131
|
+
const flow = m.addVars(["F1", "F2"], ["StoreA", "StoreB"], { lb: 0 });
|
|
132
|
+
|
|
133
|
+
// 2次元グリッド (例: 8x8 チェス盤)
|
|
134
|
+
const board = m.addVars(8, 8, { type: "Binary", prefix: "queen" });
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
#### 🔀 Big-M インジケータ制約 (`addIndicator`)
|
|
138
|
+
|
|
139
|
+
条件分岐や固定費の発生ルールを、煩雑な手動 Big-M 計算なしに記述:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
// 「東京工場が稼働していない (openCity['Tokyo'] == 0) なら、生産量 flow は 0」
|
|
143
|
+
m.addIndicator(openCity["Tokyo"], flow["F1"]["StoreA"].le(0), {
|
|
144
|
+
activeValue: 0,
|
|
145
|
+
M: 1000,
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### 2. ポートフォリオのリスク最小化 (凸二次計画: QP)
|
|
152
|
+
|
|
153
|
+
期待リターンと予算制約を満たしつつ、共分散行列に基づく投資リスクを最小化:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { Model, QuadExpr, sum } from "@ohtaman/washi";
|
|
157
|
+
|
|
158
|
+
const m = new Model({ name: "MarkowitzPortfolio", sense: "Minimize" });
|
|
159
|
+
const assets = ["Tech", "Bonds", "RealEstate"];
|
|
160
|
+
const returns = [0.14, 0.04, 0.08];
|
|
161
|
+
|
|
162
|
+
// 決定変数: 投資比率 (0.0 〜 1.0)
|
|
163
|
+
const w = assets.map((a) => m.addVar({ name: `w_${a}`, lb: 0, ub: 1 }));
|
|
164
|
+
|
|
165
|
+
// 1. 予算制約: 合計 100%
|
|
166
|
+
m.addConstraint(sum(w).eq(1.0), "budget");
|
|
167
|
+
|
|
168
|
+
// 2. 目標リターン: 最低 8.5%
|
|
169
|
+
m.addConstraint(sum(w.map((v, i) => v.mul(returns[i]))).ge(0.085), "min_return");
|
|
170
|
+
|
|
171
|
+
// 3. 共分散行列 (リスク & 相関)
|
|
172
|
+
const cov = [
|
|
173
|
+
[0.040, 0.002, 0.015],
|
|
174
|
+
[0.002, 0.005, 0.002],
|
|
175
|
+
[0.015, 0.002, 0.025],
|
|
176
|
+
];
|
|
177
|
+
|
|
178
|
+
// 二次目的関数: w^T * Cov * w
|
|
179
|
+
let risk = new QuadExpr();
|
|
180
|
+
for (let i = 0; i < assets.length; i++) {
|
|
181
|
+
for (let j = 0; j < assets.length; j++) {
|
|
182
|
+
risk = risk.add(w[i].mul(w[j]).mul(cov[i][j]));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
m.minimize(risk);
|
|
186
|
+
|
|
187
|
+
await m.solve();
|
|
188
|
+
console.log(`最小分散: ${m.objectiveValue?.toFixed(6)}`);
|
|
189
|
+
assets.forEach((name, i) => {
|
|
190
|
+
console.log(` ${name}: ${((w[i].value || 0) * 100).toFixed(2)}%`);
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
### 3. SMT 論理制約 & ルールエンジン (Z3 連携)
|
|
197
|
+
|
|
198
|
+
命題変数(`BoolVar`)と論理結合子(`and`, `or`, `implies`, `not`, `xor`)、数値比較制約を混在させたルール定義:
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { Model, not } from "@ohtaman/washi";
|
|
202
|
+
|
|
203
|
+
const m = new Model({ name: "SmartSecurityRules" });
|
|
204
|
+
|
|
205
|
+
const isNight = m.addBoolVar("isNight");
|
|
206
|
+
const motion = m.addBoolVar("motion");
|
|
207
|
+
const alarm = m.addBoolVar("alarm");
|
|
208
|
+
const siren = m.addBoolVar("siren");
|
|
209
|
+
const lux = m.addVar({ name: "lux", type: "Integer", lb: 0 });
|
|
210
|
+
|
|
211
|
+
// 論理ルール
|
|
212
|
+
m.addConstraint(lux.le(50).implies(isNight), "dark_implies_night");
|
|
213
|
+
m.addConstraint(motion.and(isNight).and(alarm).implies(siren), "alarm_rule");
|
|
214
|
+
|
|
215
|
+
// 観測されたセンサー値
|
|
216
|
+
m.addConstraint(lux.le(10), "sensor_dark");
|
|
217
|
+
m.addConstraint(motion, "sensor_motion");
|
|
218
|
+
m.addConstraint(alarm, "alarm_on");
|
|
219
|
+
|
|
220
|
+
// 目的関数なしで制約充足可能性(SAT)を判定
|
|
221
|
+
const res = await m.check({ solver: "z3" });
|
|
222
|
+
|
|
223
|
+
console.log(`充足可能? ${res.status === "Sat"}`); // true
|
|
224
|
+
console.log(`サイレン作動? ${m.values.get("siren")}`); // true
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### 4. 矛盾原因の自動特定 (`unsatCore`)
|
|
230
|
+
|
|
231
|
+
業務ルールや制約群が互いに矛盾している場合、**矛盾を引き起こしている最小の制約サブセット**を特定してデバッグ(Z3 が必要):
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
import { Model } from "@ohtaman/washi";
|
|
235
|
+
import "@ohtaman/washi/solvers/z3";
|
|
236
|
+
|
|
237
|
+
const m = new Model({ name: "ConflictDiagnosis", solver: "z3" });
|
|
238
|
+
const engineers = m.addVar({ name: "engineers", type: "Integer", lb: 0, ub: 20 });
|
|
239
|
+
const budget = m.addVar({ name: "budget", type: "Continuous", lb: 0, ub: 100000 });
|
|
240
|
+
const rushDelivery = m.addBoolVar("rushDelivery");
|
|
241
|
+
|
|
242
|
+
// ルール 1: エンジニア1人あたり $8,000
|
|
243
|
+
m.addConstraint(engineers.mul(8000).le(budget), "budget_limit");
|
|
244
|
+
|
|
245
|
+
// ルール 2: 特急納品が必須
|
|
246
|
+
m.addConstraint(rushDelivery, "rush_required");
|
|
247
|
+
|
|
248
|
+
// ルール 3: 特急納品には最低 8 人のエンジニアが必要
|
|
249
|
+
m.addConstraint(rushDelivery.implies(engineers.ge(8)), "rush_staffing_rule");
|
|
250
|
+
|
|
251
|
+
// ルール 4: 役員会の予算上限 $50,000 (矛盾: 8人 * $8000 = $64,000 > $50,000!)
|
|
252
|
+
m.addConstraint(budget.le(50000), "strict_board_budget_cap");
|
|
253
|
+
|
|
254
|
+
// ルール 5: 最低 1 人雇用の労働基準(無関係なルール)
|
|
255
|
+
m.addConstraint(engineers.ge(1), "minimum_one_employee");
|
|
256
|
+
|
|
257
|
+
const res = await m.check({ solver: "z3" });
|
|
258
|
+
|
|
259
|
+
console.log(`ステータス: ${res.status}`); // "Unsat"
|
|
260
|
+
console.log("矛盾している制約:", res.unsatCore);
|
|
261
|
+
// 出力: ["budget_limit", "rush_required", "rush_staffing_rule", "strict_board_budget_cap"]
|
|
262
|
+
// ※ 無関係な "minimum_one_employee" は的確に除外されます
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
### 5. Python PuLP 互換レイヤー
|
|
268
|
+
|
|
269
|
+
既存の Python PuLP 最適化スクリプトをスムーズに移植:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import {
|
|
273
|
+
LpProblem,
|
|
274
|
+
LpVariable,
|
|
275
|
+
LpMaximize,
|
|
276
|
+
LpInteger,
|
|
277
|
+
HiGHS,
|
|
278
|
+
value,
|
|
279
|
+
} from "@ohtaman/washi";
|
|
280
|
+
|
|
281
|
+
const prob = new LpProblem("PuLPDemo", LpMaximize);
|
|
282
|
+
|
|
283
|
+
const x = new LpVariable("x", 0, undefined, LpInteger);
|
|
284
|
+
const y = new LpVariable("y", 0, undefined, LpInteger);
|
|
285
|
+
|
|
286
|
+
// PuLP の += 相当
|
|
287
|
+
prob.add(x.mul(30).add(y.mul(50)));
|
|
288
|
+
prob.add(x.add(y.mul(2)).le(40));
|
|
289
|
+
prob.add(x.mul(2).add(y).le(50));
|
|
290
|
+
|
|
291
|
+
await prob.solve(new HiGHS());
|
|
292
|
+
|
|
293
|
+
console.log(`ステータス: ${prob.status}`);
|
|
294
|
+
console.log(`目的関数値: ${value(prob.objective)}`);
|
|
295
|
+
console.log(`x = ${value(x)}, y = ${value(y)}`);
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## 💻 サンプルスクリプト & インタラクティブ Web デモ
|
|
301
|
+
|
|
302
|
+
`examples/node/` 配下に実行可能なスタンドアロンスクリプトを用意しています:
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
npx tsx examples/node/01-production-planning.ts
|
|
306
|
+
npx tsx examples/node/02-knapsack-problem.ts
|
|
307
|
+
npx tsx examples/node/03-portfolio-qp.ts
|
|
308
|
+
npx tsx examples/node/04-smt-security-rules.ts
|
|
309
|
+
npx tsx examples/node/05-unsat-core-diagnosis.ts
|
|
310
|
+
npx tsx examples/node/06-pulp-compatibility.ts
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
ブラウザで動く Web デモ (`examples/web-demo`) を起動するには:
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
npm run dev
|
|
317
|
+
# ブラウザで http://localhost:5173/ を開きます
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 🧪 テスト & 信頼性
|
|
323
|
+
|
|
324
|
+
厳格なテスト駆動開発 (TDD) により、120 以上の自動テストを実施しています:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# すべてのユニット・統合テストを実行
|
|
328
|
+
npm test
|
|
329
|
+
|
|
330
|
+
# プロダクション用バンドルと型定義を生成
|
|
331
|
+
npm run build
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
## 📄 ライセンス
|
|
337
|
+
|
|
338
|
+
- **`@ohtaman/washi`**: [MIT ライセンス](./LICENSE)
|
|
339
|
+
- **HiGHS**(標準エンジン): MIT ライセンス
|
|
340
|
+
- **Z3**(オプション): MIT ライセンス
|
|
341
|
+
- **GLPK**(オプション): GPL-3.0 ライセンス
|