@ohtaman/washi 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +111 -118
- package/README.md +109 -116
- package/README.zh-CN.md +112 -119
- package/dist/browser/highs-worker.js +21 -3
- package/dist/browser/loader-CtaDHef_.js +273 -0
- package/dist/browser/solvers/glpk.js +433 -286
- package/dist/browser/solvers/glpk.min.js +1 -1
- package/dist/browser/solvers/z3.js +1002 -981
- package/dist/browser/solvers/z3.min.js +2 -2
- package/dist/browser/washi.js +2178 -622
- package/dist/browser/washi.min.js +4 -4
- package/dist/lib/highs-worker.js +21 -3
- package/dist/lib/loader-DmNC_UNk.js +279 -0
- package/dist/lib/registry-BEfvpZW3.js +951 -0
- package/dist/lib/solvers/glpk.js +201 -90
- package/dist/lib/solvers/z3.js +399 -259
- package/dist/lib/washi.js +1674 -932
- package/dist/types/index.d.ts +4 -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 +36 -9
- package/dist/types/modeler/constraint.d.ts.map +1 -1
- package/dist/types/modeler/expression.d.ts +117 -27
- package/dist/types/modeler/expression.d.ts.map +1 -1
- package/dist/types/modeler/index.d.ts +10 -6
- package/dist/types/modeler/index.d.ts.map +1 -1
- package/dist/types/modeler/lp-writer.d.ts +27 -2
- package/dist/types/modeler/lp-writer.d.ts.map +1 -1
- package/dist/types/modeler/model.d.ts +491 -140
- 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 +39 -14
- package/dist/types/modeler/parser.d.ts.map +1 -1
- package/dist/types/modeler/quad-expr.d.ts +28 -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/loader.d.ts +36 -11
- package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -1
- package/dist/types/modeler/solvers/highs/solver.d.ts +11 -4
- 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 +71 -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 +60 -2
- 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 +53 -13
- 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 +53 -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/unsat-core.md +64 -0
- package/docs/getting-started/ai-agents.md +267 -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/expressions.md +204 -0
- package/docs/guide/objectives.md +170 -0
- package/docs/guide/unsat-core.md +147 -0
- package/docs/guide/variables.md +188 -0
- package/docs/ja/getting-started/ai-agents.md +266 -0
- package/docs/solvers/custom-solver.md +525 -0
- package/docs/solvers/glpk.md +66 -0
- package/docs/solvers/highs.md +93 -0
- package/docs/solvers/index.md +42 -0
- package/docs/solvers/z3.md +78 -0
- package/docs/zh/getting-started/ai-agents.md +266 -0
- package/llms-full.txt +3249 -0
- package/llms.txt +197 -0
- package/package.json +19 -6
- package/skills/washi/SKILL.md +197 -0
- 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
|
@@ -1,235 +1,586 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import {
|
|
1
|
+
import { type OptimizationSense, type SolverStatus, type TerminationStatus, type SolveOptions, type SolverSolution, type CheckResult } from "./types.js";
|
|
2
|
+
import { type ObjectiveSpec } from "./objective.js";
|
|
3
|
+
import { Var } from "./variable.js";
|
|
3
4
|
import { LinExpr } from "./expression.js";
|
|
4
5
|
import { QuadExpr } from "./quad-expr.js";
|
|
5
6
|
import { Constraint } from "./constraint.js";
|
|
6
7
|
import { BoolVar, BoolExpr } from "./boolean-expr.js";
|
|
7
8
|
import { type Solver } from "./solvers/index.js";
|
|
9
|
+
import { type SolutionValidationOptions, type SolutionValidationReport } from "./solution-validator.js";
|
|
10
|
+
/**
|
|
11
|
+
* Valid items that can be added as a constraint to a model.
|
|
12
|
+
* Raw mathematical expressions (LinExpr, QuadExpr) without comparisons are strictly prohibited.
|
|
13
|
+
*/
|
|
14
|
+
export type ConstraintItem = Constraint | BoolExpr | string;
|
|
8
15
|
export interface ModelOptions {
|
|
16
|
+
/** Optional model name (default: `"OptimizationModel"`). */
|
|
9
17
|
name?: string;
|
|
18
|
+
/** Default optimization direction (`"Minimize"` or `"Maximize"`, default: `"Minimize"`). */
|
|
10
19
|
sense?: OptimizationSense;
|
|
20
|
+
/** Solver instance or registered solver name (`"highs"`, `"glpk"`, `"z3"`, or custom solver). */
|
|
11
21
|
solver?: Solver | string;
|
|
12
22
|
}
|
|
13
23
|
export interface BoundsOptions {
|
|
24
|
+
/** Explicit name for a scalar variable, or fallback prefix for indexed variable containers. */
|
|
14
25
|
name?: string;
|
|
26
|
+
/** Name prefix when creating unnamed scalar variables or indexed variable containers (default: `"x"`). */
|
|
15
27
|
prefix?: string;
|
|
28
|
+
/** Lower bound (default: `0`; `-Infinity` allowed for free lower bound; `+Infinity` and `NaN` rejected). */
|
|
16
29
|
lb?: number;
|
|
30
|
+
/** Upper bound (default: `Infinity`; `-Infinity` and `NaN` rejected; must satisfy `lb <= ub`). */
|
|
17
31
|
ub?: number;
|
|
32
|
+
/**
|
|
33
|
+
* Optional finite primal initial value (MIP start / warm-start hint), distinct from solved `Var.value`.
|
|
34
|
+
* Validated within tolerance `1e-6` against `[lb, ub]` and integer domain.
|
|
35
|
+
* Supported by HiGHS (`supportsWarmStart: true`); throws on solvers without warm-start support (GLPK, Z3).
|
|
36
|
+
*/
|
|
37
|
+
initialValue?: number;
|
|
38
|
+
[Symbol.iterator]?: never;
|
|
18
39
|
}
|
|
19
|
-
export interface
|
|
20
|
-
|
|
21
|
-
M?: number;
|
|
40
|
+
export interface BinaryOptions {
|
|
41
|
+
/** Explicit name for a scalar variable, or fallback prefix for indexed variable containers. */
|
|
22
42
|
name?: string;
|
|
43
|
+
/** Name prefix when creating unnamed scalar variables or indexed variable containers (default: `"x"`). */
|
|
44
|
+
prefix?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Optional finite primal initial value (`0` or `1` within tolerance `1e-6`), distinct from solved `Var.value`.
|
|
47
|
+
* Supported by HiGHS (`supportsWarmStart: true`); throws on solvers without warm-start support (GLPK, Z3).
|
|
48
|
+
*/
|
|
49
|
+
initialValue?: number;
|
|
50
|
+
[Symbol.iterator]?: never;
|
|
23
51
|
}
|
|
52
|
+
type VarNameOptions = {
|
|
53
|
+
prefix?: string;
|
|
54
|
+
name?: string;
|
|
55
|
+
[Symbol.iterator]?: never;
|
|
56
|
+
};
|
|
57
|
+
import { type IndicatorOptions } from "./big-m.js";
|
|
58
|
+
export type { IndicatorOptions };
|
|
24
59
|
/**
|
|
25
|
-
*
|
|
26
|
-
* running directly with WebAssembly solvers (HiGHS, Z3, GLPK) in browser and Node.js.
|
|
60
|
+
* Named propositional or SMT constraint registered on a `Model`.
|
|
27
61
|
*/
|
|
28
62
|
export interface LogicalConstraint {
|
|
29
63
|
name: string;
|
|
30
64
|
expr: BoolExpr | Constraint;
|
|
31
65
|
}
|
|
66
|
+
declare const UniqueStringTag: unique symbol;
|
|
67
|
+
declare global {
|
|
68
|
+
interface String {
|
|
69
|
+
readonly [UniqueStringTag]: false;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export type KeyCollection<K extends string | number> = ReadonlyArray<K> | (Iterable<K> & object & {
|
|
73
|
+
readonly [UniqueStringTag]?: true;
|
|
74
|
+
});
|
|
75
|
+
/**
|
|
76
|
+
* High-level mathematical programming and SMT model for LP, MIP, convex QP, and SAT/SMT,
|
|
77
|
+
* running with WebAssembly solvers (HiGHS, GLPK, Z3) in Node.js and browsers.
|
|
78
|
+
*
|
|
79
|
+
* **Solver capability notes**:
|
|
80
|
+
* - `"highs"` (default, built-in): Supports LP, MIP, convex QP objectives (`supportsQP: true`),
|
|
81
|
+
* and `initialValue` warm starts (`supportsWarmStart: true`). Also supports `m.check()` on purely
|
|
82
|
+
* linear models via a zero-objective feasibility fallback. Throws if `BoolVar`/logical constraints are present.
|
|
83
|
+
* - `"glpk"` (`import "@ohtaman/washi/solvers/glpk"`): Supports LP and MIP, and `m.check()` on purely
|
|
84
|
+
* linear models via LP feasibility fallback. Throws on quadratic objectives, `BoolVar`/logical constraints,
|
|
85
|
+
* or `initialValue` warm starts.
|
|
86
|
+
* - `"z3"` (`import "@ohtaman/washi/solvers/z3"`): Supports SMT satisfiability (`m.check()`), optimization (`m.solve()`),
|
|
87
|
+
* `BoolVar`/logical constraints (`and`, `or`, `not`, `implies`, `xor`), and unsatisfiable-core extraction
|
|
88
|
+
* (`conflicts` / `unsatCore`). Throws on quadratic objectives or `initialValue` warm starts.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { Model, expr, sum, dot, maximize } from "@ohtaman/washi";
|
|
93
|
+
*
|
|
94
|
+
* const m = new Model("ProductionPlan");
|
|
95
|
+
* const qty = m.integer(["desk", "chair"] as const, { lb: 0, ub: 100 });
|
|
96
|
+
* const setup = m.binary("setup", { initialValue: 1 });
|
|
97
|
+
*
|
|
98
|
+
* m.objective(maximize(expr`${dot({ desk: 30, chair: 50 }, qty)} - 20 * ${setup}`));
|
|
99
|
+
* m.constraint(expr`${dot({ desk: 1, chair: 2 }, qty)} <= 40`, "wood_cap");
|
|
100
|
+
* m.constraint(expr`${sum(Object.values(qty))} <= 30 * ${setup}`, "require_setup");
|
|
101
|
+
*
|
|
102
|
+
* const status = await m.solve();
|
|
103
|
+
* const report = m.validateSolution();
|
|
104
|
+
* const solvedQty = m.getValues(qty);
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
32
107
|
export declare class Model {
|
|
33
108
|
name: string;
|
|
34
|
-
|
|
35
|
-
|
|
109
|
+
private _sense;
|
|
110
|
+
private _objectiveExpr;
|
|
36
111
|
variables: Var[];
|
|
37
112
|
constraints: Constraint[];
|
|
38
113
|
boolVars: BoolVar[];
|
|
39
114
|
logicalConstraints: LogicalConstraint[];
|
|
40
|
-
unsatCore: string[];
|
|
115
|
+
unsatCore: readonly string[] | undefined;
|
|
41
116
|
values: Map<string, number | boolean>;
|
|
42
117
|
private varMapByName;
|
|
118
|
+
private varPrefixCounters;
|
|
119
|
+
private boolVarMapByName;
|
|
120
|
+
private boolVarPrefixCounters;
|
|
43
121
|
private constrMapByName;
|
|
122
|
+
private constrPrefixCounters;
|
|
123
|
+
private logicalConstrMapByName;
|
|
124
|
+
private logicalConstrCounter;
|
|
44
125
|
status: SolverStatus;
|
|
126
|
+
terminationStatus: TerminationStatus;
|
|
127
|
+
hasPrimalSolution: boolean;
|
|
45
128
|
objectiveValue: number | null;
|
|
129
|
+
objectiveBound: number | undefined;
|
|
130
|
+
relGap: number | undefined;
|
|
131
|
+
mipGap: number | undefined;
|
|
132
|
+
absGap: number | undefined;
|
|
46
133
|
runTime: number;
|
|
47
134
|
solution: SolverSolution | null;
|
|
48
135
|
solver: Solver | null;
|
|
136
|
+
private hasSolutionState;
|
|
137
|
+
private modelRevision;
|
|
138
|
+
private activeOperationId;
|
|
139
|
+
private batchDepth;
|
|
140
|
+
private batchMutated;
|
|
141
|
+
private batchUndoActions;
|
|
49
142
|
constructor(nameOrOptions?: string | ModelOptions, maybeOptions?: ModelOptions);
|
|
50
|
-
get
|
|
51
|
-
|
|
143
|
+
get sense(): OptimizationSense;
|
|
144
|
+
set sense(value: OptimizationSense);
|
|
145
|
+
get objectiveExpr(): LinExpr | QuadExpr;
|
|
146
|
+
set objectiveExpr(value: LinExpr | QuadExpr | Constraint);
|
|
147
|
+
/**
|
|
148
|
+
* User-friendly alias for unsatCore.
|
|
149
|
+
* Returns a subset of conflicting constraint names causing infeasibility,
|
|
150
|
+
* or undefined if not diagnosed, not applicable, or satisfiable.
|
|
151
|
+
*/
|
|
152
|
+
get conflicts(): readonly string[] | undefined;
|
|
52
153
|
get numVars(): number;
|
|
53
154
|
get numConstrs(): number;
|
|
155
|
+
/**
|
|
156
|
+
* Clears stored solution and diagnostic fields on the model and its entities.
|
|
157
|
+
*/
|
|
158
|
+
private clearSolutionFields;
|
|
159
|
+
/**
|
|
160
|
+
* Records a model mutation, invalidating any stored solution state and in-flight solver executions.
|
|
161
|
+
*/
|
|
162
|
+
private recordModelMutation;
|
|
163
|
+
/**
|
|
164
|
+
* @internal Notifies the model that an owned entity (e.g., Var bounds/type or Constraint RHS/sense) was mutated.
|
|
165
|
+
*/
|
|
166
|
+
notifyMutation(): void;
|
|
167
|
+
/**
|
|
168
|
+
* Reset prior solution and diagnostic state to avoid stale data leakage across runs,
|
|
169
|
+
* and invalidate any in-flight solve() or check() execution.
|
|
170
|
+
*/
|
|
171
|
+
resetSolutionState(): void;
|
|
172
|
+
/**
|
|
173
|
+
* Executes a multi-item model mutation atomically so failed batch edits neither leave
|
|
174
|
+
* partial entities registered nor invalidate prior solved / in-flight state.
|
|
175
|
+
*/
|
|
176
|
+
private runTransactionalBatch;
|
|
54
177
|
/**
|
|
55
178
|
* Internal generator for domain-specific variables
|
|
56
179
|
*/
|
|
57
180
|
private createDomainVars;
|
|
58
181
|
/**
|
|
59
|
-
* Create 0-1 binary variable(s) (x in {0, 1}).
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* - m.binary(
|
|
63
|
-
* - m.binary(
|
|
64
|
-
* - m.binary(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
182
|
+
* Create 0-1 binary decision variable(s) ($x \in \{0, 1\}$).
|
|
183
|
+
*
|
|
184
|
+
* **Scalar & indexed container overloads**:
|
|
185
|
+
* - `m.binary("x", options?)` or `m.binary(options?)` -> `Var`
|
|
186
|
+
* - `m.binary(count, options?)` -> `Var[]`
|
|
187
|
+
* - `m.binary(keys, options?)` -> `Record<K, Var>`
|
|
188
|
+
* - `m.binary(rowsCount, colsCount, options?)` -> `Var[][]`
|
|
189
|
+
* - `m.binary(rowsCount, colKeys, options?)` -> `Array<Record<C, Var>>`
|
|
190
|
+
* - `m.binary(rowKeys, colsCount, options?)` -> `Record<R, Var[]>`
|
|
191
|
+
* - `m.binary(rowKeys, colKeys, options?)` -> `Record<R, Record<C, Var>>`
|
|
192
|
+
*
|
|
193
|
+
* **Warm-start (`initialValue`) semantics**:
|
|
194
|
+
* - `options.initialValue` supplies an optional finite primal hint (`0` or `1` within tolerance `1e-6`),
|
|
195
|
+
* kept distinct from solved `v.value`.
|
|
196
|
+
* - Supported by HiGHS (`supportsWarmStart: true`); throws on GLPK and Z3.
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* const m = new Model("BinaryVars");
|
|
201
|
+
* const b = m.binary("b", { initialValue: 1 }); // Var
|
|
202
|
+
* const vec = m.binary(4, { prefix: "u" }); // Var[]
|
|
203
|
+
* const grid = m.binary(2, 3, { prefix: "g" }); // Var[][]
|
|
204
|
+
* const byShift = m.binary(["day", "night"] as const); // Record<"day" | "night", Var>
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
binary(name?: string, options?: BinaryOptions): Var;
|
|
208
|
+
binary(options: BinaryOptions): Var;
|
|
209
|
+
binary(count: number, options?: BinaryOptions): Var[];
|
|
210
|
+
binary<K extends string | number>(keys: KeyCollection<K>, options?: BinaryOptions): Record<K, Var>;
|
|
211
|
+
binary(rows: number, cols: number, options?: BinaryOptions): Var[][];
|
|
212
|
+
binary<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: BinaryOptions): Array<Record<C, Var>>;
|
|
213
|
+
binary<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: BinaryOptions): Record<R, Var[]>;
|
|
214
|
+
binary<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: BinaryOptions): Record<R, Record<C, Var>>;
|
|
91
215
|
/**
|
|
92
|
-
* Create
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* - m.
|
|
96
|
-
* - m.
|
|
97
|
-
* - m.
|
|
216
|
+
* Create integer decision variable(s) ($y \in \mathbb{Z}$, default bounds `lb: 0`, `ub: Infinity`).
|
|
217
|
+
*
|
|
218
|
+
* **Scalar & indexed container overloads**:
|
|
219
|
+
* - `m.integer("y", options?)` or `m.integer(options)` -> `Var`
|
|
220
|
+
* - `m.integer(count, options?)` -> `Var[]`
|
|
221
|
+
* - `m.integer(keys, options?)` -> `Record<K, Var>`
|
|
222
|
+
* - `m.integer(rowsCount, colsCount, options?)` -> `Var[][]`
|
|
223
|
+
* - `m.integer(rowsCount, colKeys, options?)` -> `Array<Record<C, Var>>`
|
|
224
|
+
* - `m.integer(rowKeys, colsCount, options?)` -> `Record<R, Var[]>`
|
|
225
|
+
* - `m.integer(rowKeys, colKeys, options?)` -> `Record<R, Record<C, Var>>`
|
|
226
|
+
*
|
|
227
|
+
* **Warm-start (`initialValue`) semantics**:
|
|
228
|
+
* - `options.initialValue` supplies an optional finite integer primal hint within tolerance `1e-6` of `[lb, ub]`,
|
|
229
|
+
* kept distinct from solved `v.value`.
|
|
230
|
+
* - Supported by HiGHS (`supportsWarmStart: true`); throws on GLPK and Z3.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```ts
|
|
234
|
+
* const m = new Model("IntegerVars");
|
|
235
|
+
* const n = m.integer("n", { lb: 0, ub: 10, initialValue: 4 }); // Var
|
|
236
|
+
* const counts = m.integer(3, { lb: 0, prefix: "k" }); // Var[]
|
|
237
|
+
* const matrix = m.integer(2, 2, { lb: 0, prefix: "m" }); // Var[][]
|
|
238
|
+
* const byItem = m.integer(["desk", "chair"] as const, { lb: 0, ub: 50 }); // Record<"desk" | "chair", Var>
|
|
239
|
+
* ```
|
|
98
240
|
*/
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
241
|
+
integer(name?: string, options?: BoundsOptions): Var;
|
|
242
|
+
integer(options: BoundsOptions): Var;
|
|
243
|
+
integer(count: number, options?: BoundsOptions): Var[];
|
|
244
|
+
integer<K extends string | number>(keys: KeyCollection<K>, options?: BoundsOptions): Record<K, Var>;
|
|
245
|
+
integer(rows: number, cols: number, options?: BoundsOptions): Var[][];
|
|
246
|
+
integer<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: BoundsOptions): Array<Record<C, Var>>;
|
|
247
|
+
integer<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: BoundsOptions): Record<R, Var[]>;
|
|
248
|
+
integer<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: BoundsOptions): Record<R, Record<C, Var>>;
|
|
103
249
|
/**
|
|
104
|
-
*
|
|
250
|
+
* Create continuous (real) decision variable(s) ($z \in \mathbb{R}$, default bounds `lb: 0`, `ub: Infinity`).
|
|
251
|
+
*
|
|
252
|
+
* **Scalar & indexed container overloads**:
|
|
253
|
+
* - `m.continuous("z", options?)` or `m.continuous(options)` -> `Var`
|
|
254
|
+
* - `m.continuous(count, options?)` -> `Var[]`
|
|
255
|
+
* - `m.continuous(keys, options?)` -> `Record<K, Var>`
|
|
256
|
+
* - `m.continuous(rowsCount, colsCount, options?)` -> `Var[][]`
|
|
257
|
+
* - `m.continuous(rowsCount, colKeys, options?)` -> `Array<Record<C, Var>>`
|
|
258
|
+
* - `m.continuous(rowKeys, colsCount, options?)` -> `Record<R, Var[]>`
|
|
259
|
+
* - `m.continuous(rowKeys, colKeys, options?)` -> `Record<R, Record<C, Var>>`
|
|
260
|
+
*
|
|
261
|
+
* **Warm-start (`initialValue`) semantics**:
|
|
262
|
+
* - `options.initialValue` supplies an optional finite primal hint within tolerance `1e-6` of `[lb, ub]`,
|
|
263
|
+
* kept distinct from solved `v.value`.
|
|
264
|
+
* - Supported by HiGHS (`supportsWarmStart: true`); throws on GLPK and Z3.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```ts
|
|
268
|
+
* const m = new Model("ContinuousVars");
|
|
269
|
+
* const x = m.continuous("x", { lb: 0, ub: 100, initialValue: 25 }); // Var
|
|
270
|
+
* const vec = m.continuous(4, { lb: 0, prefix: "v" }); // Var[]
|
|
271
|
+
* const flow = m.continuous(2, 3, { lb: 0, prefix: "f" }); // Var[][]
|
|
272
|
+
* const alloc = m.continuous(["A", "B"] as const, { lb: 0 }); // Record<"A" | "B", Var>
|
|
273
|
+
* ```
|
|
105
274
|
*/
|
|
106
|
-
|
|
107
|
-
|
|
275
|
+
continuous(name?: string, options?: BoundsOptions): Var;
|
|
276
|
+
continuous(options: BoundsOptions): Var;
|
|
277
|
+
continuous(count: number, options?: BoundsOptions): Var[];
|
|
278
|
+
continuous<K extends string | number>(keys: KeyCollection<K>, options?: BoundsOptions): Record<K, Var>;
|
|
279
|
+
continuous(rows: number, cols: number, options?: BoundsOptions): Var[][];
|
|
280
|
+
continuous<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: BoundsOptions): Array<Record<C, Var>>;
|
|
281
|
+
continuous<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: BoundsOptions): Record<R, Var[]>;
|
|
282
|
+
continuous<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: BoundsOptions): Record<R, Record<C, Var>>;
|
|
108
283
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* -
|
|
113
|
-
* -
|
|
284
|
+
* Create propositional Boolean variable(s) (`BoolVar`: `true` / `false`) for SMT / SAT logical modeling.
|
|
285
|
+
*
|
|
286
|
+
* **Scalar & indexed container overloads**:
|
|
287
|
+
* - `m.bool("flag", options?)` or `m.bool(options?)` -> `BoolVar`
|
|
288
|
+
* - `m.bool(count, options?)` -> `BoolVar[]`
|
|
289
|
+
* - `m.bool(keys, options?)` -> `Record<K, BoolVar>`
|
|
290
|
+
* - `m.bool(rowsCount, colsCount, options?)` -> `BoolVar[][]`
|
|
291
|
+
* - `m.bool(rowsCount, colKeys, options?)` -> `Array<Record<C, BoolVar>>`
|
|
292
|
+
* - `m.bool(rowKeys, colsCount, options?)` -> `Record<R, BoolVar[]>`
|
|
293
|
+
* - `m.bool(rowKeys, colKeys, options?)` -> `Record<R, Record<C, BoolVar>>`
|
|
294
|
+
*
|
|
295
|
+
* **Solver capability note**:
|
|
296
|
+
* - Logical constraints over `BoolVar` (`and`, `or`, `not`, `implies`, `xor`) require an SMT-capable solver
|
|
297
|
+
* such as Z3 (`new Model("...", { solver: "z3" })` after `import "@ohtaman/washi/solvers/z3"`).
|
|
298
|
+
* - LP/MIP solvers (HiGHS, GLPK) throw if logical constraints are present. For 0-1 arithmetic variables
|
|
299
|
+
* in LP/MIP (or Big-M `m.indicator()`), use `m.binary()` instead.
|
|
300
|
+
*
|
|
301
|
+
* @example
|
|
302
|
+
* ```ts
|
|
303
|
+
* import "@ohtaman/washi/solvers/z3";
|
|
304
|
+
*
|
|
305
|
+
* const m = new Model("BoolVars", { solver: "z3" });
|
|
306
|
+
* const vip = m.bool("vip"); // BoolVar
|
|
307
|
+
* const flags = m.bool(3, { prefix: "f" }); // BoolVar[]
|
|
308
|
+
* const grid = m.bool(2, 2, { prefix: "g" }); // BoolVar[][]
|
|
309
|
+
* const byRole = m.bool(["admin", "guest"] as const); // Record<"admin" | "guest", BoolVar>
|
|
310
|
+
* m.constraint(implies(vip, flags[0]), "vip_flag");
|
|
311
|
+
* ```
|
|
114
312
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
313
|
+
bool(name?: string, options?: VarNameOptions): BoolVar;
|
|
314
|
+
bool(options: VarNameOptions): BoolVar;
|
|
315
|
+
bool(count: number, options?: VarNameOptions): BoolVar[];
|
|
316
|
+
bool<K extends string | number>(keys: KeyCollection<K>, options?: VarNameOptions): Record<K, BoolVar>;
|
|
317
|
+
bool(rows: number, cols: number, options?: VarNameOptions): BoolVar[][];
|
|
318
|
+
bool<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: VarNameOptions): Array<Record<C, BoolVar>>;
|
|
319
|
+
bool<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: VarNameOptions): Record<R, BoolVar[]>;
|
|
320
|
+
bool<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: VarNameOptions): Record<R, Record<C, BoolVar>>;
|
|
321
|
+
private hasVarName;
|
|
322
|
+
private getNextVarName;
|
|
323
|
+
private getNextBoolVarName;
|
|
324
|
+
private hasConstraintName;
|
|
325
|
+
private hasBoolVarName;
|
|
326
|
+
private getNextConstrName;
|
|
327
|
+
private getNextLogicalConstrName;
|
|
328
|
+
private createBoolVar;
|
|
118
329
|
/**
|
|
119
|
-
*
|
|
330
|
+
* Internal variable creator
|
|
120
331
|
*/
|
|
121
|
-
|
|
332
|
+
private addVar;
|
|
122
333
|
/**
|
|
123
334
|
* Find variable by name
|
|
124
335
|
*/
|
|
125
336
|
getVarByName(name: string): Var | undefined;
|
|
337
|
+
/**
|
|
338
|
+
* Find boolean variable by name
|
|
339
|
+
*/
|
|
340
|
+
getBoolVarByName(name: string): BoolVar | undefined;
|
|
126
341
|
/**
|
|
127
342
|
* Find a constraint by its name
|
|
128
343
|
*/
|
|
129
344
|
getConstraintByName(name: string): Constraint | undefined;
|
|
130
345
|
/**
|
|
131
|
-
*
|
|
346
|
+
* Find a logical constraint by its name
|
|
132
347
|
*/
|
|
133
|
-
|
|
348
|
+
getLogicalConstraintByName(name: string): LogicalConstraint | undefined;
|
|
134
349
|
/**
|
|
135
|
-
*
|
|
350
|
+
* Get the current objective expression, or set the objective function and direction (`maximize(...)` / `minimize(...)`).
|
|
351
|
+
* Calling `objective(spec)` replaces any previously defined objective and returns `this` for chaining.
|
|
352
|
+
*
|
|
353
|
+
* **Formulation & solver capability notes**:
|
|
354
|
+
* - Supports linear (`LinExpr`, `Var`, `number`, formula string) and quadratic (`QuadExpr`: `^2`, `${x} * ${y}`) expressions.
|
|
355
|
+
* - Quadratic terms are supported in **objectives only** (requires a QP-capable solver such as HiGHS; throws on GLPK and Z3).
|
|
356
|
+
* - Passing a comparison `Constraint` (`<=`, `>=`, `==`) throws an Error.
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* ```ts
|
|
360
|
+
* const m = new Model("ObjectiveExample");
|
|
361
|
+
* const chairs = m.integer("chairs", { lb: 0 });
|
|
362
|
+
* const tables = m.integer("tables", { lb: 0 });
|
|
363
|
+
*
|
|
364
|
+
* m.objective(maximize(expr`30 * ${chairs} + 50 * ${tables}`));
|
|
365
|
+
* const currentExpr = m.objective();
|
|
366
|
+
* ```
|
|
136
367
|
*/
|
|
137
|
-
|
|
368
|
+
objective(): LinExpr | QuadExpr;
|
|
369
|
+
objective(spec: ObjectiveSpec): this;
|
|
138
370
|
/**
|
|
139
|
-
*
|
|
371
|
+
* Internal objective setter.
|
|
140
372
|
*/
|
|
141
|
-
|
|
373
|
+
private applyObjective;
|
|
142
374
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
* -
|
|
375
|
+
* Register linear comparison constraint(s) (`<=`, `>=`, `==`), SMT logical constraint(s) (`BoolVar`, `BoolExpr`),
|
|
376
|
+
* or constraint formula string(s) on the model. Chainable: returns `this`.
|
|
377
|
+
*
|
|
378
|
+
* **Formulation & solver capability notes**:
|
|
379
|
+
* - Rejects raw arithmetic expressions (`LinExpr`, `QuadExpr`) without a comparison operator and quadratic constraints.
|
|
380
|
+
* - Logical constraints (`BoolVar`, `and`, `or`, `not`, `implies`, `xor`) require an SMT-capable solver (`{ solver: "z3" }`);
|
|
381
|
+
* LP/MIP solvers (HiGHS, GLPK) throw if logical constraints are present.
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```ts
|
|
385
|
+
* const m = new Model("ConstraintExample");
|
|
386
|
+
* const desks = m.integer("desks", { lb: 0 });
|
|
387
|
+
* const chairs = m.integer("chairs", { lb: 0 });
|
|
388
|
+
* const x = m.continuous(3, { lb: 0, prefix: "x" });
|
|
389
|
+
*
|
|
390
|
+
* m.constraint(expr`${desks} + 2 * ${chairs} <= 40`, "wood");
|
|
391
|
+
* m.constraint(x.map((v) => expr`${v} <= 10`));
|
|
392
|
+
* m.constraint(desks.ge(2)).constraint(chairs.ge(4));
|
|
393
|
+
* ```
|
|
148
394
|
*/
|
|
149
|
-
|
|
150
|
-
|
|
395
|
+
constraint(constraint: ConstraintItem | LinExpr | QuadExpr, name?: string): this;
|
|
396
|
+
constraint(constraints: ReadonlyArray<ConstraintItem | LinExpr | QuadExpr>): this;
|
|
151
397
|
/**
|
|
152
|
-
* Extract primal solution values directly into plain primitives:
|
|
153
|
-
* - m.getValues(x) -> number | null
|
|
154
|
-
* - m.getValues(
|
|
155
|
-
* - m.getValues(
|
|
156
|
-
* - m.getValues(
|
|
398
|
+
* Extract primal solution values directly into plain primitives, preserving container shapes:
|
|
399
|
+
* - `m.getValues(x)` -> `number | null`
|
|
400
|
+
* - `m.getValues(p)` -> `boolean | null`
|
|
401
|
+
* - `m.getValues([x, y])` -> `(number | null)[]`
|
|
402
|
+
* - `m.getValues([[x11, x12], [x21, x22]])` -> `(number | null)[][]`
|
|
403
|
+
* - `m.getValues(record)` -> `Record<K, number | boolean | null>`
|
|
404
|
+
* - `m.getValues(matrix)` -> `Record<R, Record<C, number | boolean | null>>`
|
|
405
|
+
*
|
|
406
|
+
* @example
|
|
407
|
+
* ```ts
|
|
408
|
+
* const m = new Model("GetValuesExample");
|
|
409
|
+
* const qty = m.integer(["desk", "chair"] as const, { lb: 0, ub: 10 });
|
|
410
|
+
* m.objective(maximize(expr`30 * ${qty.desk} + 50 * ${qty.chair}`));
|
|
411
|
+
* m.constraint(expr`${qty.desk} + ${qty.chair} <= 10`);
|
|
412
|
+
* await m.solve();
|
|
413
|
+
* const values = m.getValues(qty); // Record<"desk" | "chair", number | null>
|
|
414
|
+
* ```
|
|
157
415
|
*/
|
|
158
416
|
getValues(item: Var): number | null;
|
|
159
|
-
getValues(
|
|
417
|
+
getValues(item: BoolVar): boolean | null;
|
|
418
|
+
getValues(items: ReadonlyArray<Var>): (number | null)[];
|
|
419
|
+
getValues(items: ReadonlyArray<BoolVar>): (boolean | null)[];
|
|
420
|
+
getValues(items: ReadonlyArray<ReadonlyArray<Var>>): (number | null)[][];
|
|
421
|
+
getValues(items: ReadonlyArray<ReadonlyArray<BoolVar>>): (boolean | null)[][];
|
|
422
|
+
getValues<C extends string | number>(items: ReadonlyArray<Record<C, Var>>): Array<Record<C, number | null>>;
|
|
423
|
+
getValues<C extends string | number>(items: ReadonlyArray<Record<C, BoolVar>>): Array<Record<C, boolean | null>>;
|
|
424
|
+
getValues<R extends string | number>(items: Record<R, ReadonlyArray<Var>>): Record<R, (number | null)[]>;
|
|
425
|
+
getValues<R extends string | number>(items: Record<R, ReadonlyArray<BoolVar>>): Record<R, (boolean | null)[]>;
|
|
160
426
|
getValues<K extends string | number>(items: Record<K, Var>): Record<K, number | null>;
|
|
427
|
+
getValues<K extends string | number>(items: Record<K, BoolVar>): Record<K, boolean | null>;
|
|
161
428
|
getValues<R extends string | number, C extends string | number>(items: Record<R, Record<C, Var>>): Record<R, Record<C, number | null>>;
|
|
429
|
+
getValues<R extends string | number, C extends string | number>(items: Record<R, Record<C, BoolVar>>): Record<R, Record<C, boolean | null>>;
|
|
162
430
|
/**
|
|
163
|
-
*
|
|
431
|
+
* Internal linear or logical constraint adder
|
|
164
432
|
*/
|
|
165
|
-
|
|
433
|
+
private addConstraint;
|
|
166
434
|
/**
|
|
167
|
-
* Add
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
*
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
*
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
186
|
-
* - m.add([c1, c2, c3])
|
|
187
|
-
* - m.add(new Var(...))
|
|
188
|
-
* - m.add(c1).add(c2) (fluent chaining)
|
|
435
|
+
* Add an indicator constraint via floating-point Big-M auto-linearization:
|
|
436
|
+
* `"If binVar === activeValue, then constraint holds"` (`activeValue` defaults to `1`).
|
|
437
|
+
*
|
|
438
|
+
* **Formulation & solver capability notes**:
|
|
439
|
+
* - Automatically linearizes `<=`, `>=`, and `==` constraints for LP/MIP solvers (HiGHS, GLPK)
|
|
440
|
+
* under standard floating-point feasibility tolerances (`==` generates `_le` and `_ge` rows).
|
|
441
|
+
* - Variables appearing in `constraint` must have finite bounds (`lb`/`ub`) to derive a safe tight Big-M
|
|
442
|
+
* automatically, unless an explicit `{ M }` override is supplied in `options`.
|
|
443
|
+
* - Because Big-M rows are floating-point linear relaxations, they do not guarantee exact rational
|
|
444
|
+
* equivalence in SMT solvers (Z3); use `implies(...)` with `m.bool(...)` when exact SMT diagnosis is required.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* const m = new Model("IndicatorExample");
|
|
449
|
+
* const b = m.binary("b");
|
|
450
|
+
* const x = m.continuous("x", { lb: 0, ub: 100 });
|
|
451
|
+
* // Enforces x <= 50 when b === 1 (relaxed to x <= 100 when b === 0)
|
|
452
|
+
* m.indicator(b, expr`${x} <= 50`, { activeValue: 1, name: "cap_when_b" });
|
|
453
|
+
* ```
|
|
189
454
|
*/
|
|
190
|
-
|
|
191
|
-
add(expr: BoolExpr, name?: string): this;
|
|
192
|
-
add(strConstraint: string, name?: string): this;
|
|
193
|
-
add(variable: Var): this;
|
|
194
|
-
add(items: (Constraint | BoolExpr | string | Var)[]): this;
|
|
455
|
+
indicator(binVar: Var, constraint: Constraint | LinExpr | QuadExpr, options?: IndicatorOptions): Constraint[];
|
|
195
456
|
/**
|
|
196
|
-
*
|
|
197
|
-
*
|
|
457
|
+
* Validate model integrity (`validateIntegrity()`) and serialize the model's linear/quadratic objective,
|
|
458
|
+
* linear constraints, and numeric variable bounds/domains (`Continuous`, `Integer`, `Binary`) to a
|
|
459
|
+
* standard CPLEX LP format string with collision-free sanitized identifiers.
|
|
460
|
+
*
|
|
461
|
+
* **Note**: Propositional `BoolVar`s and SMT `logicalConstraints` are not part of the CPLEX LP format.
|
|
198
462
|
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
463
|
+
* @example
|
|
464
|
+
* ```ts
|
|
465
|
+
* const m = new Model("LpExportExample");
|
|
466
|
+
* const x = m.integer("x", { lb: 0, ub: 10 });
|
|
467
|
+
* m.objective(maximize(expr`5 * ${x}`));
|
|
468
|
+
* m.constraint(expr`${x} <= 8`, "cap");
|
|
469
|
+
* const lpText = m.toLpString();
|
|
470
|
+
* ```
|
|
201
471
|
*/
|
|
202
|
-
|
|
472
|
+
toLpString(): string;
|
|
203
473
|
/**
|
|
204
|
-
*
|
|
474
|
+
* Validates model integrity: variable bounds, ownership, numeric sanity, and unique constraint names.
|
|
475
|
+
* Throws an Error with actionable explanation if any validation rule is violated.
|
|
205
476
|
*/
|
|
206
|
-
|
|
477
|
+
validateIntegrity(): void;
|
|
478
|
+
private ensureExecutionValid;
|
|
479
|
+
private wrapSolveOptions;
|
|
480
|
+
private hasPrimalFromResult;
|
|
207
481
|
/**
|
|
208
|
-
*
|
|
482
|
+
* Resolves the target solver and execution options without mutating caller-owned objects,
|
|
483
|
+
* stripping the routing `solver` field from the returned `SolverOptions`.
|
|
209
484
|
*/
|
|
210
|
-
|
|
485
|
+
private resolveSolverAndOptions;
|
|
211
486
|
/**
|
|
212
487
|
* Solve the optimization model using the configured solver (defaults to HiGHS WASM)
|
|
213
|
-
* or a solver passed dynamically (e.g., await
|
|
488
|
+
* or a solver passed dynamically (e.g., `await m.solve("glpk")` or `await m.solve({ timeLimit: 10 })`).
|
|
489
|
+
*
|
|
490
|
+
* **Return status (`SolverStatus`)**:
|
|
491
|
+
* - Built-in optimization solvers return `"Optimal"`, `"Feasible"`, `"Infeasible"`, `"Unbounded"`,
|
|
492
|
+
* `"TimeLimit"`, `"IterationLimit"`, `"Error"`, `"Unknown"`, or `"NotSolved"` (`"Sat"` / `"Unsat"`
|
|
493
|
+
* are included in `SolverStatus` for custom/satisfiability adapters).
|
|
494
|
+
* - When a time-, iteration-, or solution-limited run (or an interrupted solve) has found a valid
|
|
495
|
+
* primal incumbent, `solve()` returns `"Feasible"` (`m.hasPrimalSolution === true`, with the exact
|
|
496
|
+
* stopping reason in `m.terminationStatus`).
|
|
497
|
+
* - After solving, read primal/dual values via `x.value`, `m.getValues(...)`, `m.objectiveValue`,
|
|
498
|
+
* `constr.dual`, `constr.slack`, and `x.reducedCost`, and verify primal feasibility with `m.validateSolution()`.
|
|
499
|
+
*
|
|
500
|
+
* **Solver capability preconditions**:
|
|
501
|
+
* - Quadratic objectives (`QuadExpr`) require `supportsQP` (supported by HiGHS; throws on GLPK and Z3).
|
|
502
|
+
* - Logical constraints (`BoolVar`, `and`, `or`, `not`, `implies`, `xor`) require `supportsSMT`
|
|
503
|
+
* (supported by Z3; throws on HiGHS and GLPK).
|
|
504
|
+
* - Primal `initialValue` warm starts require `supportsWarmStart` (supported by HiGHS; throws on GLPK and Z3).
|
|
505
|
+
* - Mutating the model or starting a newer `solve()` / `check()` while in flight discards the stale
|
|
506
|
+
* result and rejects the pending promise.
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```ts
|
|
510
|
+
* const m = new Model("SolveExample");
|
|
511
|
+
* const x = m.integer("x", { lb: 0, ub: 50, initialValue: 10 });
|
|
512
|
+
* const y = m.integer("y", { lb: 0, ub: 50 });
|
|
513
|
+
* m.objective(maximize(expr`30 * ${x} + 50 * ${y}`));
|
|
514
|
+
* m.constraint(expr`${x} + 2 * ${y} <= 40`, "resource_limit");
|
|
515
|
+
*
|
|
516
|
+
* const status = await m.solve();
|
|
517
|
+
* const report = m.validateSolution();
|
|
518
|
+
* const obj = m.objectiveValue;
|
|
519
|
+
* ```
|
|
214
520
|
*/
|
|
215
|
-
|
|
521
|
+
solve(solverOrOptions?: Solver | string | SolveOptions, options?: SolveOptions): Promise<SolverStatus>;
|
|
216
522
|
/**
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
523
|
+
* Check satisfiability / feasibility of the model without requiring an objective function.
|
|
524
|
+
*
|
|
525
|
+
* Returns `CheckResult` (`{ status: "Sat" | "Unsat" | "Unknown", values, conflicts?, unsatCore?, runTime? }`).
|
|
526
|
+
*
|
|
527
|
+
* **LP feasibility fallback vs. Z3 requirement**:
|
|
528
|
+
* - **Linear models (`m.check()` fallback)**: For models containing only linear arithmetic constraints,
|
|
529
|
+
* `m.check()` works with any solver (including the default HiGHS and GLPK) by falling back to a
|
|
530
|
+
* zero-objective feasibility `solve()` without mutating `m.objectiveExpr` or `m.sense`.
|
|
531
|
+
* - **Logical constraints & `unsatCore` (requires Z3)**: Models containing `BoolVar` or logical
|
|
532
|
+
* constraints (`and`, `or`, `not`, `implies`, `xor`) require an SMT-capable solver (`{ solver: "z3" }`
|
|
533
|
+
* after `import "@ohtaman/washi/solvers/z3"`). Unsatisfiable-core extraction (`result.conflicts` /
|
|
534
|
+
* `result.unsatCore` and `m.conflicts` / `m.unsatCore`) is populated only when an unsat-core-capable
|
|
535
|
+
* solver such as Z3 returns `"Unsat"`, reporting a subset of registered constraint names that conflicts
|
|
536
|
+
* together with the model's fixed variable bounds/domains.
|
|
537
|
+
* - Mutating the model or starting a newer `solve()` / `check()` while in flight discards the stale
|
|
538
|
+
* result and rejects the pending promise.
|
|
539
|
+
*
|
|
540
|
+
* @example
|
|
541
|
+
* ```ts
|
|
542
|
+
* import "@ohtaman/washi/solvers/z3";
|
|
543
|
+
*
|
|
544
|
+
* // 1. Linear feasibility check (works with default HiGHS via LP fallback)
|
|
545
|
+
* const mLin = new Model("LinearCheck");
|
|
546
|
+
* const x = mLin.continuous("x", { lb: 0, ub: 10 });
|
|
547
|
+
* mLin.constraint(expr`${x} >= 4`, "min_x");
|
|
548
|
+
* const linRes = await mLin.check(); // { status: "Sat", values: { x: ... } }
|
|
549
|
+
*
|
|
550
|
+
* // 2. SMT satisfiability & unsatCore diagnosis (requires Z3)
|
|
551
|
+
* const mSmt = new Model("PolicyCheck", { solver: "z3" });
|
|
552
|
+
* const vip = mSmt.bool("vip");
|
|
553
|
+
* const discount = mSmt.integer("discount", { lb: 0, ub: 50 });
|
|
554
|
+
* mSmt.constraint(vip, "is_vip");
|
|
555
|
+
* mSmt.constraint(implies(vip, expr`${discount} >= 20`), "vip_min");
|
|
556
|
+
* mSmt.constraint(expr`${discount} <= 10`, "cap");
|
|
557
|
+
* const smtRes = await mSmt.check(); // { status: "Unsat", conflicts: [...], unsatCore: [...] }
|
|
558
|
+
* ```
|
|
222
559
|
*/
|
|
223
|
-
|
|
560
|
+
check(solverOrOptions?: Solver | string | SolveOptions, options?: SolveOptions): Promise<CheckResult>;
|
|
224
561
|
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
562
|
+
* Independently evaluate and verify variable finiteness, variable bounds (`lb`/`ub`),
|
|
563
|
+
* integer/binary/boolean domains, linear constraint residuals, and logical (SMT/propositional)
|
|
564
|
+
* constraints against the model's current solved values (or an explicit `options.values` map).
|
|
565
|
+
*
|
|
566
|
+
* Returns a `SolutionValidationReport` (`{ valid, complete, maxViolation, violations, violationsByName, uncheckedConstraints, missingVariables, summary }`).
|
|
567
|
+
*
|
|
568
|
+
* **Verification notes**:
|
|
569
|
+
* - Runs purely in JavaScript/TypeScript without requiring any WASM solver runtime.
|
|
570
|
+
* - Verifies primal feasibility of variables and constraints; does not recompute or compare `m.objectiveValue`.
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* ```ts
|
|
574
|
+
* const m = new Model("ValidateExample");
|
|
575
|
+
* const x = m.integer("x", { lb: 0, ub: 10 });
|
|
576
|
+
* m.objective(maximize(expr`3 * ${x}`));
|
|
577
|
+
* m.constraint(expr`${x} <= 7`, "cap");
|
|
578
|
+
*
|
|
579
|
+
* await m.solve();
|
|
580
|
+
* const report = m.validateSolution();
|
|
581
|
+
* const isFeasible = report.valid && report.maxViolation <= 1e-6;
|
|
582
|
+
* ```
|
|
227
583
|
*/
|
|
228
|
-
|
|
229
|
-
status: "Sat" | "Unsat" | "Unknown";
|
|
230
|
-
values: Record<string, number | boolean>;
|
|
231
|
-
unsatCore?: string[];
|
|
232
|
-
runTime?: number;
|
|
233
|
-
}>;
|
|
584
|
+
validateSolution(options?: SolutionValidationOptions): SolutionValidationReport;
|
|
234
585
|
}
|
|
235
586
|
//# sourceMappingURL=model.d.ts.map
|