@ohtaman/washi 0.1.2 → 0.2.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 +76 -2
- package/README.md +76 -2
- package/README.zh-CN.md +76 -2
- package/dist/browser/highs-worker.js +2 -2
- package/dist/browser/{highs-loader-T47YOyos.js → loader-CVt4CloI.js} +2 -2
- package/dist/browser/solvers/glpk.js +1057 -0
- package/dist/browser/solvers/glpk.min.js +1 -0
- package/dist/browser/solvers/z3-built.js +8245 -0
- package/dist/browser/solvers/z3-built.wasm +4 -0
- package/dist/browser/solvers/z3.js +7528 -0
- package/dist/browser/solvers/z3.min.js +5 -0
- package/dist/browser/washi.js +142 -476
- package/dist/browser/washi.min.js +3 -3
- package/dist/lib/async-mutex-Duo4jwzn.js +195 -0
- package/dist/lib/constraint-XWdn0ID9.js +93 -0
- package/dist/lib/highs-worker.js +2 -2
- package/dist/lib/{highs-loader-Blb99785.js → loader-Dti0v9yC.js} +1 -1
- package/dist/lib/registry-DksqCSjI.js +32 -0
- package/dist/lib/solvers/glpk.js +153 -2
- package/dist/lib/solvers/z3-assets.js +1 -0
- package/dist/lib/solvers/z3-built.js +8245 -0
- package/dist/lib/solvers/z3-built.wasm +4 -0
- package/dist/lib/solvers/z3.js +451 -2
- package/dist/lib/washi.js +400 -91
- package/dist/types/index.d.ts +2 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modeler/index.d.ts +1 -1
- package/dist/types/modeler/index.d.ts.map +1 -1
- package/dist/types/modeler/model.d.ts +1 -1
- package/dist/types/modeler/model.d.ts.map +1 -1
- package/dist/types/modeler/solvers/glpk/index.d.ts +3 -0
- package/dist/types/modeler/solvers/glpk/index.d.ts.map +1 -0
- package/dist/types/modeler/solvers/glpk/loader.d.ts +16 -0
- package/dist/types/modeler/solvers/glpk/loader.d.ts.map +1 -0
- package/dist/types/modeler/solvers/glpk/solver.d.ts +26 -0
- package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -0
- package/dist/types/modeler/solvers/glpk.d.ts +1 -21
- package/dist/types/modeler/solvers/glpk.d.ts.map +1 -1
- package/dist/types/{highs-assets.d.ts → modeler/solvers/highs/assets.d.ts} +1 -1
- package/dist/types/modeler/solvers/highs/assets.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs/browser-runtime.d.ts +2 -0
- package/dist/types/modeler/solvers/highs/browser-runtime.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs/index.d.ts +6 -0
- package/dist/types/modeler/solvers/highs/index.d.ts.map +1 -0
- package/dist/types/{highs-loader.d.ts → modeler/solvers/highs/loader.d.ts} +2 -2
- package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -0
- package/dist/types/{highs-node-runtime.d.ts → modeler/solvers/highs/node-runtime.d.ts} +1 -1
- package/dist/types/modeler/solvers/highs/node-runtime.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs/solver.d.ts +33 -0
- package/dist/types/modeler/solvers/highs/solver.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs/worker-client.d.ts +13 -0
- package/dist/types/modeler/solvers/highs/worker-client.d.ts.map +1 -0
- package/dist/types/{highs-worker-factory.d.ts → modeler/solvers/highs/worker-factory.d.ts} +1 -1
- package/dist/types/modeler/solvers/highs/worker-factory.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs/worker.d.ts +2 -0
- package/dist/types/modeler/solvers/highs/worker.d.ts.map +1 -0
- package/dist/types/modeler/solvers/highs.d.ts +1 -31
- package/dist/types/modeler/solvers/highs.d.ts.map +1 -1
- package/dist/types/modeler/solvers/index.d.ts +0 -2
- package/dist/types/modeler/solvers/index.d.ts.map +1 -1
- package/dist/types/modeler/solvers/mock.d.ts +1 -0
- package/dist/types/modeler/solvers/mock.d.ts.map +1 -1
- package/dist/types/modeler/solvers/registry.d.ts +1 -2
- package/dist/types/modeler/solvers/registry.d.ts.map +1 -1
- package/dist/types/modeler/solvers/z3/assets.d.ts +11 -0
- package/dist/types/modeler/solvers/z3/assets.d.ts.map +1 -0
- package/dist/types/modeler/solvers/z3/index.d.ts +3 -0
- package/dist/types/modeler/solvers/z3/index.d.ts.map +1 -0
- package/dist/types/modeler/solvers/z3/loader.d.ts +44 -0
- package/dist/types/modeler/solvers/z3/loader.d.ts.map +1 -0
- package/dist/types/modeler/solvers/z3/solver.d.ts +34 -0
- package/dist/types/modeler/solvers/z3/solver.d.ts.map +1 -0
- package/dist/types/modeler/solvers/z3.d.ts +1 -35
- package/dist/types/modeler/solvers/z3.d.ts.map +1 -1
- package/package.json +19 -5
- package/dist/browser/_washi-optional-engine-282Ug7Gw.js +0 -7
- package/dist/lib/glpk-5cUpjyb9.js +0 -135
- package/dist/lib/z3-C6GeIicJ.js +0 -509
- package/dist/types/glpk-loader.d.ts +0 -8
- package/dist/types/glpk-loader.d.ts.map +0 -1
- package/dist/types/highs-assets.d.ts.map +0 -1
- package/dist/types/highs-browser-runtime.d.ts +0 -2
- package/dist/types/highs-browser-runtime.d.ts.map +0 -1
- package/dist/types/highs-loader.d.ts.map +0 -1
- package/dist/types/highs-node-runtime.d.ts.map +0 -1
- package/dist/types/highs-worker-client.d.ts +0 -12
- package/dist/types/highs-worker-client.d.ts.map +0 -1
- package/dist/types/highs-worker-factory.d.ts.map +0 -1
- package/dist/types/highs-worker.d.ts +0 -2
- package/dist/types/highs-worker.d.ts.map +0 -1
- /package/dist/browser/{highs-browser-runtime-D13gHOT5.js → browser-runtime-D13gHOT5.js} +0 -0
package/README.ja.md
CHANGED
|
@@ -200,6 +200,7 @@ assets.forEach((name, i) => {
|
|
|
200
200
|
|
|
201
201
|
```ts
|
|
202
202
|
import { Model, not } from "@ohtaman/washi";
|
|
203
|
+
import "@ohtaman/washi/solvers/z3";
|
|
203
204
|
|
|
204
205
|
const m = new Model({ name: "SmartSecurityRules" });
|
|
205
206
|
|
|
@@ -265,7 +266,30 @@ console.log("矛盾している制約:", res.unsatCore);
|
|
|
265
266
|
|
|
266
267
|
---
|
|
267
268
|
|
|
268
|
-
### 5.
|
|
269
|
+
### 5. GLPK ソルバーの利用 (GPL-3.0)
|
|
270
|
+
|
|
271
|
+
GNU Linear Programming Kit (GLPK) ソルバープラグインを利用する場合:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
import { Model, expr, c } from "@ohtaman/washi";
|
|
275
|
+
import "@ohtaman/washi/solvers/glpk";
|
|
276
|
+
|
|
277
|
+
const m = new Model({ sense: "Maximize", solver: "glpk" });
|
|
278
|
+
const x = m.addVar({ type: "Integer", lb: 0 });
|
|
279
|
+
const y = m.addVar({ type: "Integer", lb: 0 });
|
|
280
|
+
|
|
281
|
+
m.maximize(expr`30 * ${x} + 50 * ${y}`);
|
|
282
|
+
m.addConstraint(c`${x} + 2 * ${y} <= 40`, "wood_limit");
|
|
283
|
+
m.addConstraint(c`2 * ${x} + ${y} <= 50`, "labor_limit");
|
|
284
|
+
|
|
285
|
+
const status = await m.solve();
|
|
286
|
+
console.log(`ステータス: ${status}`); // "Optimal"
|
|
287
|
+
console.log(`目的関数値: ${m.objectiveValue}`); // 1100
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### 6. Python PuLP 互換レイヤー
|
|
269
293
|
|
|
270
294
|
既存の Python PuLP 最適化スクリプトをスムーズに移植:
|
|
271
295
|
|
|
@@ -341,7 +365,48 @@ await model.solve();
|
|
|
341
365
|
|
|
342
366
|
CDN から直接読み込む場合は、URL を `https://cdn.jsdelivr.net/npm/@ohtaman/washi@0.1.2/dist/browser/washi.min.js`(`0.1.2` 以降のバージョンを固定)に指定できます。ESM は同じ版の `dist/browser/washi.js` を指定します。CDN の URL を選ぶことが明示的な CDN 利用になり、ローカル配信が勝手に CDN へ切り替わることはありません。
|
|
343
367
|
|
|
344
|
-
|
|
368
|
+
### ブラウザ環境でのソルバープラグイン(GLPK & Z3)
|
|
369
|
+
|
|
370
|
+
ブラウザ配布物には、`dist/browser/solvers/` 配下に事前バンドルされたスタンドアロンソルバープラグインが含まれています(CDN 利用時は `>= 0.2.0` または `@latest` で利用可能):
|
|
371
|
+
- **GLPK**: `dist/browser/solvers/glpk.js` (ESM) および `dist/browser/solvers/glpk.min.js` (IIFE、グローバル `WashiGLPK` を登録)
|
|
372
|
+
- **Z3**: `dist/browser/solvers/z3.js` (ESM) および `dist/browser/solvers/z3.min.js` (IIFE、グローバル `WashiZ3` を登録)、ならびに `z3-built.js` / `z3-built.wasm`
|
|
373
|
+
|
|
374
|
+
#### ブラウザ ESM での GLPK 利用
|
|
375
|
+
```html
|
|
376
|
+
<script type="module">
|
|
377
|
+
import { Model } from "./washi/washi.js";
|
|
378
|
+
import "./washi/solvers/glpk.js";
|
|
379
|
+
|
|
380
|
+
const model = new Model({ solver: "glpk" });
|
|
381
|
+
const x = model.addVar({ lb: 0, ub: 10 });
|
|
382
|
+
model.maximize(x);
|
|
383
|
+
await model.solve();
|
|
384
|
+
console.log("GLPK ステータス:", model.status);
|
|
385
|
+
</script>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### スクリプトタグでの GLPK 利用
|
|
389
|
+
```html
|
|
390
|
+
<script src="./washi/washi.min.js"></script>
|
|
391
|
+
<script src="./washi/solvers/glpk.min.js"></script>
|
|
392
|
+
<script>
|
|
393
|
+
const model = new Washi.Model({ solver: "glpk" });
|
|
394
|
+
const x = model.addVar({ lb: 0, ub: 10 });
|
|
395
|
+
model.maximize(x);
|
|
396
|
+
model.solve().then(status => console.log("GLPK ステータス:", status));
|
|
397
|
+
</script>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
> [!NOTE]
|
|
401
|
+
> **ブラウザ環境での Z3 利用について**:
|
|
402
|
+
> Z3 の WebAssembly エンジンはマルチスレッド(`SharedArrayBuffer`)を必要とするため、配信 Web サーバーがドキュメントレスポンスに以下の Cross-Origin-Isolation ヘッダーを送信する必要があります:
|
|
403
|
+
> ```http
|
|
404
|
+
> Cross-Origin-Opener-Policy: same-origin
|
|
405
|
+
> Cross-Origin-Embedder-Policy: require-corp
|
|
406
|
+
> ```
|
|
407
|
+
> また、別オリジン(CDN など)からアセットを読み込む場合は `Cross-Origin-Resource-Policy: cross-origin` の返却が必要です。
|
|
408
|
+
|
|
409
|
+
完全なスタンドアロンサンプル(ESM、スクリプトタグ、CodePen)は `examples/distribution/` に用意されています。
|
|
345
410
|
|
|
346
411
|
### 工場内・オフライン配布、Worker、自前配信
|
|
347
412
|
|
|
@@ -364,6 +429,14 @@ setHighsWasmUrl(OFFICIAL_HIGHS_CDN_WASM_URL);
|
|
|
364
429
|
|
|
365
430
|
---
|
|
366
431
|
|
|
432
|
+
## 🛠️ カスタムソルバー開発と拡張性
|
|
433
|
+
|
|
434
|
+
WaSHI は疎結合なプラグイン方式のソルバーアーキテクチャを採用しています。独自の最適化エンジン(クラウド REST ソルバー、WebAssembly エンジン、商用ソルバーアダプターなど)を容易に構築・登録できます:
|
|
435
|
+
|
|
436
|
+
- 詳細な開発手順、API コントラクト仕様(`Solver`, `LpModelData`, `SolverResult`)、およびテスト手法については [Custom Solver Developer Guide](docs/custom-solver-guide.md) をご覧ください。
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
367
440
|
## 💻 サンプルスクリプト & インタラクティブ Web デモ
|
|
368
441
|
|
|
369
442
|
`examples/node/` 配下に実行可能なスタンドアロンスクリプトを用意しています:
|
|
@@ -375,6 +448,7 @@ npx tsx examples/node/03-portfolio-qp.ts
|
|
|
375
448
|
npx tsx examples/node/04-smt-security-rules.ts
|
|
376
449
|
npx tsx examples/node/05-unsat-core-diagnosis.ts
|
|
377
450
|
npx tsx examples/node/06-pulp-compatibility.ts
|
|
451
|
+
npx tsx examples/node/08-glpk-solver-plugin.ts
|
|
378
452
|
```
|
|
379
453
|
|
|
380
454
|
ブラウザで動く Web デモ (`examples/web-demo`) を起動するには:
|
package/README.md
CHANGED
|
@@ -200,6 +200,7 @@ Express boolean variables, propositional connectives (`and`, `or`, `implies`, `n
|
|
|
200
200
|
|
|
201
201
|
```ts
|
|
202
202
|
import { Model, not } from "@ohtaman/washi";
|
|
203
|
+
import "@ohtaman/washi/solvers/z3";
|
|
203
204
|
|
|
204
205
|
const m = new Model({ name: "SmartSecurityRules" });
|
|
205
206
|
|
|
@@ -265,7 +266,30 @@ console.log("Conflicting constraints:", res.unsatCore);
|
|
|
265
266
|
|
|
266
267
|
---
|
|
267
268
|
|
|
268
|
-
### 5.
|
|
269
|
+
### 5. Solving with GLPK (GPL-3.0)
|
|
270
|
+
|
|
271
|
+
To use the GNU Linear Programming Kit (GLPK) solver plugin:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
import { Model, expr, c } from "@ohtaman/washi";
|
|
275
|
+
import "@ohtaman/washi/solvers/glpk";
|
|
276
|
+
|
|
277
|
+
const m = new Model({ sense: "Maximize", solver: "glpk" });
|
|
278
|
+
const x = m.addVar({ type: "Integer", lb: 0 });
|
|
279
|
+
const y = m.addVar({ type: "Integer", lb: 0 });
|
|
280
|
+
|
|
281
|
+
m.maximize(expr`30 * ${x} + 50 * ${y}`);
|
|
282
|
+
m.addConstraint(c`${x} + 2 * ${y} <= 40`, "wood_limit");
|
|
283
|
+
m.addConstraint(c`2 * ${x} + ${y} <= 50`, "labor_limit");
|
|
284
|
+
|
|
285
|
+
const status = await m.solve();
|
|
286
|
+
console.log(`Status: ${status}`); // "Optimal"
|
|
287
|
+
console.log(`Objective: ${m.objectiveValue}`); // 1100
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### 6. Python PuLP Compatibility Layer
|
|
269
293
|
|
|
270
294
|
If you have existing Python PuLP code, port it with near zero friction:
|
|
271
295
|
|
|
@@ -341,7 +365,48 @@ The package also includes `dist/browser/washi.min.js`, which exports the `Washi`
|
|
|
341
365
|
|
|
342
366
|
For CDN usage, replace the local URL with `https://cdn.jsdelivr.net/npm/@ohtaman/washi@0.1.2/dist/browser/washi.min.js` (or pin your desired release version `>= 0.1.2`). For ESM use the corresponding `dist/browser/washi.js` URL. Selecting the CDN URL is an explicit choice; local copies never switch to a CDN.
|
|
343
367
|
|
|
344
|
-
|
|
368
|
+
### Solver Plugins in the Browser (GLPK & Z3)
|
|
369
|
+
|
|
370
|
+
The browser distribution includes pre-bundled, standalone solver plugins under `dist/browser/solvers/` (available from `>= 0.2.0` or `@latest` on CDN):
|
|
371
|
+
- **GLPK**: `dist/browser/solvers/glpk.js` (ESM) and `dist/browser/solvers/glpk.min.js` (IIFE, registers global `WashiGLPK`)
|
|
372
|
+
- **Z3**: `dist/browser/solvers/z3.js` (ESM) and `dist/browser/solvers/z3.min.js` (IIFE, registers global `WashiZ3`), accompanied by `z3-built.js` and `z3-built.wasm`
|
|
373
|
+
|
|
374
|
+
#### Browser ESM with GLPK
|
|
375
|
+
```html
|
|
376
|
+
<script type="module">
|
|
377
|
+
import { Model } from "./washi/washi.js";
|
|
378
|
+
import "./washi/solvers/glpk.js";
|
|
379
|
+
|
|
380
|
+
const model = new Model({ solver: "glpk" });
|
|
381
|
+
const x = model.addVar({ lb: 0, ub: 10 });
|
|
382
|
+
model.maximize(x);
|
|
383
|
+
await model.solve();
|
|
384
|
+
console.log("GLPK status:", model.status);
|
|
385
|
+
</script>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### Plain Script with GLPK
|
|
389
|
+
```html
|
|
390
|
+
<script src="./washi/washi.min.js"></script>
|
|
391
|
+
<script src="./washi/solvers/glpk.min.js"></script>
|
|
392
|
+
<script>
|
|
393
|
+
const model = new Washi.Model({ solver: "glpk" });
|
|
394
|
+
const x = model.addVar({ lb: 0, ub: 10 });
|
|
395
|
+
model.maximize(x);
|
|
396
|
+
model.solve().then(status => console.log("GLPK status:", status));
|
|
397
|
+
</script>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
> [!NOTE]
|
|
401
|
+
> **Z3 in Browser Environments**:
|
|
402
|
+
> Because the Z3 WebAssembly engine uses multithreading (`SharedArrayBuffer`), the hosting web server must send Cross-Origin-Isolation delivery headers on the document response:
|
|
403
|
+
> ```http
|
|
404
|
+
> Cross-Origin-Opener-Policy: same-origin
|
|
405
|
+
> Cross-Origin-Embedder-Policy: require-corp
|
|
406
|
+
> ```
|
|
407
|
+
> And any cross-origin assets (e.g. from a CDN) must serve `Cross-Origin-Resource-Policy: cross-origin`.
|
|
408
|
+
|
|
409
|
+
Complete standalone examples for ESM, script tags, and CodePen are available in `examples/distribution/`.
|
|
345
410
|
|
|
346
411
|
### Offline distribution, Workers and custom hosting
|
|
347
412
|
|
|
@@ -364,6 +429,14 @@ Failed initialization reports the attempted URL and does not try a different hos
|
|
|
364
429
|
|
|
365
430
|
---
|
|
366
431
|
|
|
432
|
+
## 🛠️ Custom Solvers & Extensibility
|
|
433
|
+
|
|
434
|
+
WaSHI features a decoupled, pluggable solver architecture. You can easily build and register your own custom solver adapter (e.g., for cloud REST optimizers, WebAssembly engines, or proprietary solvers):
|
|
435
|
+
|
|
436
|
+
- See the complete [Custom Solver Developer Guide](docs/custom-solver-guide.md) for step-by-step tutorials, complete API contracts (`Solver`, `LpModelData`, `SolverResult`), and testing best practices.
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
367
440
|
## 💻 CLI & Interactive Demos
|
|
368
441
|
|
|
369
442
|
Ready-to-run standalone examples are available in `examples/node/`:
|
|
@@ -375,6 +448,7 @@ npx tsx examples/node/03-portfolio-qp.ts
|
|
|
375
448
|
npx tsx examples/node/04-smt-security-rules.ts
|
|
376
449
|
npx tsx examples/node/05-unsat-core-diagnosis.ts
|
|
377
450
|
npx tsx examples/node/06-pulp-compatibility.ts
|
|
451
|
+
npx tsx examples/node/08-glpk-solver-plugin.ts
|
|
378
452
|
```
|
|
379
453
|
|
|
380
454
|
To run the interactive browser showcase (`examples/web-demo`):
|
package/README.zh-CN.md
CHANGED
|
@@ -200,6 +200,7 @@ assets.forEach((name, i) => {
|
|
|
200
200
|
|
|
201
201
|
```ts
|
|
202
202
|
import { Model, not } from "@ohtaman/washi";
|
|
203
|
+
import "@ohtaman/washi/solvers/z3";
|
|
203
204
|
|
|
204
205
|
const m = new Model({ name: "SmartSecurityRules" });
|
|
205
206
|
|
|
@@ -265,7 +266,30 @@ console.log("冲突约束子集:", res.unsatCore);
|
|
|
265
266
|
|
|
266
267
|
---
|
|
267
268
|
|
|
268
|
-
### 5.
|
|
269
|
+
### 5. 使用 GLPK 求解器 (GPL-3.0)
|
|
270
|
+
|
|
271
|
+
使用 GNU Linear Programming Kit (GLPK) 求解器插件:
|
|
272
|
+
|
|
273
|
+
```ts
|
|
274
|
+
import { Model, expr, c } from "@ohtaman/washi";
|
|
275
|
+
import "@ohtaman/washi/solvers/glpk";
|
|
276
|
+
|
|
277
|
+
const m = new Model({ sense: "Maximize", solver: "glpk" });
|
|
278
|
+
const x = m.addVar({ type: "Integer", lb: 0 });
|
|
279
|
+
const y = m.addVar({ type: "Integer", lb: 0 });
|
|
280
|
+
|
|
281
|
+
m.maximize(expr`30 * ${x} + 50 * ${y}`);
|
|
282
|
+
m.addConstraint(c`${x} + 2 * ${y} <= 40`, "wood_limit");
|
|
283
|
+
m.addConstraint(c`2 * ${x} + ${y} <= 50`, "labor_limit");
|
|
284
|
+
|
|
285
|
+
const status = await m.solve();
|
|
286
|
+
console.log(`求解状态: ${status}`); // "Optimal"
|
|
287
|
+
console.log(`目标函数值: ${m.objectiveValue}`); // 1100
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### 6. Python PuLP 兼容层
|
|
269
293
|
|
|
270
294
|
若你已有 Python PuLP 代码资产,可零摩擦迁移:
|
|
271
295
|
|
|
@@ -341,7 +365,48 @@ await model.solve();
|
|
|
341
365
|
|
|
342
366
|
若通过 CDN 加载,可使用 `https://cdn.jsdelivr.net/npm/@ohtaman/washi@0.1.2/dist/browser/washi.min.js`(请固定 `0.1.2` 及以上版本号)。ESM 使用同版本的 `dist/browser/washi.js`。选择 CDN URL 就是显式使用 CDN;本地部署不会自动改用外部 CDN。
|
|
343
367
|
|
|
344
|
-
|
|
368
|
+
### 浏览器环境中的求解器插件(GLPK & Z3)
|
|
369
|
+
|
|
370
|
+
浏览器发布包在 `dist/browser/solvers/` 下提供了开箱即用的独立求解器插件(通过 CDN 引入时适用于 `>= 0.2.0` 或 `@latest`):
|
|
371
|
+
- **GLPK**: `dist/browser/solvers/glpk.js` (ESM) 与 `dist/browser/solvers/glpk.min.js` (IIFE,挂载全局 `WashiGLPK`)
|
|
372
|
+
- **Z3**: `dist/browser/solvers/z3.js` (ESM) 与 `dist/browser/solvers/z3.min.js` (IIFE,挂载全局 `WashiZ3`),附带 `z3-built.js` 和 `z3-built.wasm`
|
|
373
|
+
|
|
374
|
+
#### 浏览器 ESM 使用 GLPK
|
|
375
|
+
```html
|
|
376
|
+
<script type="module">
|
|
377
|
+
import { Model } from "./washi/washi.js";
|
|
378
|
+
import "./washi/solvers/glpk.js";
|
|
379
|
+
|
|
380
|
+
const model = new Model({ solver: "glpk" });
|
|
381
|
+
const x = model.addVar({ lb: 0, ub: 10 });
|
|
382
|
+
model.maximize(x);
|
|
383
|
+
await model.solve();
|
|
384
|
+
console.log("GLPK 求解状态:", model.status);
|
|
385
|
+
</script>
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### 原生脚本标签使用 GLPK
|
|
389
|
+
```html
|
|
390
|
+
<script src="./washi/washi.min.js"></script>
|
|
391
|
+
<script src="./washi/solvers/glpk.min.js"></script>
|
|
392
|
+
<script>
|
|
393
|
+
const model = new Washi.Model({ solver: "glpk" });
|
|
394
|
+
const x = model.addVar({ lb: 0, ub: 10 });
|
|
395
|
+
model.maximize(x);
|
|
396
|
+
model.solve().then(status => console.log("GLPK 求解状态:", status));
|
|
397
|
+
</script>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
> [!NOTE]
|
|
401
|
+
> **浏览器环境中使用 Z3 的配置要求**:
|
|
402
|
+
> 由于 Z3 的 WebAssembly 引擎依托多线程 (`SharedArrayBuffer`),承载页面的 Web 服务器必须在文档响应头中附带以下 Cross-Origin-Isolation 标头:
|
|
403
|
+
> ```http
|
|
404
|
+
> Cross-Origin-Opener-Policy: same-origin
|
|
405
|
+
> Cross-Origin-Embedder-Policy: require-corp
|
|
406
|
+
> ```
|
|
407
|
+
> 此外,任何跨源静态资源(如来自 CDN)都必须返回 `Cross-Origin-Resource-Policy: cross-origin` 响应头。
|
|
408
|
+
|
|
409
|
+
完整独立的 ESM、Script 标签与 CodePen 示例请参阅 `examples/distribution/`。
|
|
345
410
|
|
|
346
411
|
### 工厂内网、离线部署、Worker 与自定义 URL
|
|
347
412
|
|
|
@@ -364,6 +429,14 @@ setHighsWasmUrl(OFFICIAL_HIGHS_CDN_WASM_URL);
|
|
|
364
429
|
|
|
365
430
|
---
|
|
366
431
|
|
|
432
|
+
## 🛠️ 自定义求解器开发与架构扩展
|
|
433
|
+
|
|
434
|
+
WaSHI 采用完全解耦的插件式求解器架构。你可以轻松编写并注册自定义求解器适配器(如云端 REST 求解服务、定制 WebAssembly 引擎或商业求解器):
|
|
435
|
+
|
|
436
|
+
- 完整开发指南、接口契约(`Solver`, `LpModelData`, `SolverResult`)与测试实践详见 [Custom Solver Developer Guide](docs/custom-solver-guide.md)。
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
367
440
|
## 💻 本地脚本与交互式 Web 演示
|
|
368
441
|
|
|
369
442
|
在 `examples/node/` 中提供了即开即用的独立脚本:
|
|
@@ -375,6 +448,7 @@ npx tsx examples/node/03-portfolio-qp.ts
|
|
|
375
448
|
npx tsx examples/node/04-smt-security-rules.ts
|
|
376
449
|
npx tsx examples/node/05-unsat-core-diagnosis.ts
|
|
377
450
|
npx tsx examples/node/06-pulp-compatibility.ts
|
|
451
|
+
npx tsx examples/node/08-glpk-solver-plugin.ts
|
|
378
452
|
```
|
|
379
453
|
|
|
380
454
|
启动浏览器端交互式可视化演示 (`examples/web-demo`):
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { c as e } from "./
|
|
2
|
-
//#region src/highs
|
|
1
|
+
import { c as e } from "./loader-CVt4CloI.js";
|
|
2
|
+
//#region src/modeler/solvers/highs/worker.ts
|
|
3
3
|
self.onmessage = async (t) => {
|
|
4
4
|
let { type: n, id: r, lpString: i, options: a } = t.data;
|
|
5
5
|
if (n === "SOLVE") try {
|
|
@@ -8,7 +8,7 @@ function n() {
|
|
|
8
8
|
return t("highs.wasm");
|
|
9
9
|
}
|
|
10
10
|
//#endregion
|
|
11
|
-
//#region src/highs
|
|
11
|
+
//#region src/modeler/solvers/highs/loader.ts
|
|
12
12
|
var r = "https://cdn.jsdelivr.net/npm/highs@1.15.3/build/highs.wasm", i = null, a = null, o = null;
|
|
13
13
|
function s(e) {
|
|
14
14
|
o = e, i = null, a = null;
|
|
@@ -38,7 +38,7 @@ async function f(e = {}) {
|
|
|
38
38
|
if (i && a === n) return i;
|
|
39
39
|
a = n;
|
|
40
40
|
let r = (async () => {
|
|
41
|
-
let e = (await import("./
|
|
41
|
+
let e = (await import("./browser-runtime-D13gHOT5.js")).default;
|
|
42
42
|
return await e({ locateFile: (e) => e.endsWith(".wasm") ? t : e });
|
|
43
43
|
})().catch((e) => {
|
|
44
44
|
i === r && (i = null, a = null);
|