@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
|
@@ -1,131 +1,364 @@
|
|
|
1
|
-
import { type OptimizationSense, type SolverStatus, type SolveOptions, type SolverSolution } from "./types.js";
|
|
1
|
+
import { type OptimizationSense, type SolverStatus, type TerminationStatus, type SolveOptions, type SolverSolution, type CheckResult, type ColumnDefinition } from "./types.js";
|
|
2
|
+
import { type ObjectiveSpec } from "./objective.js";
|
|
2
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";
|
|
8
|
+
import { type ParsedExpr } from "./parser.js";
|
|
7
9
|
import { type Solver } from "./solvers/index.js";
|
|
10
|
+
import { type SolutionValidationOptions, type SolutionValidationReport } from "./solution-validator.js";
|
|
11
|
+
import { type BendersOptions, type BendersResult, type ColumnGenerationOptions, type ColumnGenerationResult } from "../decomposition/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Valid items that can be added as a constraint to a model.
|
|
14
|
+
* Raw mathematical expressions (LinExpr, QuadExpr) without comparisons are strictly prohibited.
|
|
15
|
+
*/
|
|
16
|
+
export type ConstraintItem = Constraint | BoolExpr | string;
|
|
8
17
|
export interface ModelOptions {
|
|
18
|
+
/** Optional model name (default: `"OptimizationModel"`). */
|
|
9
19
|
name?: string;
|
|
20
|
+
/** Default optimization direction (`"Minimize"` or `"Maximize"`, default: `"Minimize"`). */
|
|
10
21
|
sense?: OptimizationSense;
|
|
22
|
+
/** Solver instance or registered solver name (`"highs"`, `"glpk"`, `"z3"`, or custom solver). */
|
|
11
23
|
solver?: Solver | string;
|
|
12
24
|
}
|
|
13
25
|
export interface BoundsOptions {
|
|
26
|
+
/** Explicit name for a scalar variable, or fallback prefix for indexed variable containers. */
|
|
14
27
|
name?: string;
|
|
28
|
+
/** Name prefix when creating unnamed scalar variables or indexed variable containers (default: `"x"`). */
|
|
15
29
|
prefix?: string;
|
|
30
|
+
/** Lower bound (default: `0`; `-Infinity` allowed for free lower bound; `+Infinity` and `NaN` rejected). */
|
|
16
31
|
lb?: number;
|
|
32
|
+
/** Upper bound (default: `Infinity`; `-Infinity` and `NaN` rejected; must satisfy `lb <= ub`). */
|
|
17
33
|
ub?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Optional finite primal initial value (MIP start / warm-start hint), distinct from solved `Var.value`.
|
|
36
|
+
* Validated within tolerance `1e-6` against `[lb, ub]` and integer domain.
|
|
37
|
+
* Supported by HiGHS (`supportsWarmStart: true`); throws on solvers without warm-start support (GLPK, Z3).
|
|
38
|
+
*/
|
|
39
|
+
initialValue?: number;
|
|
40
|
+
[Symbol.iterator]?: never;
|
|
18
41
|
}
|
|
19
|
-
export interface
|
|
20
|
-
|
|
21
|
-
M?: number;
|
|
42
|
+
export interface BinaryOptions {
|
|
43
|
+
/** Explicit name for a scalar variable, or fallback prefix for indexed variable containers. */
|
|
22
44
|
name?: string;
|
|
45
|
+
/** Name prefix when creating unnamed scalar variables or indexed variable containers (default: `"x"`). */
|
|
46
|
+
prefix?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Optional finite primal initial value (`0` or `1` within tolerance `1e-6`), distinct from solved `Var.value`.
|
|
49
|
+
* Supported by HiGHS (`supportsWarmStart: true`); throws on solvers without warm-start support (GLPK, Z3).
|
|
50
|
+
*/
|
|
51
|
+
initialValue?: number;
|
|
52
|
+
[Symbol.iterator]?: never;
|
|
23
53
|
}
|
|
54
|
+
type VarNameOptions = {
|
|
55
|
+
prefix?: string;
|
|
56
|
+
name?: string;
|
|
57
|
+
[Symbol.iterator]?: never;
|
|
58
|
+
};
|
|
59
|
+
import { type IndicatorOptions } from "./big-m.js";
|
|
60
|
+
export type { IndicatorOptions };
|
|
24
61
|
/**
|
|
25
|
-
*
|
|
26
|
-
* running directly with WebAssembly solvers (HiGHS, Z3, GLPK) in browser and Node.js.
|
|
62
|
+
* Named propositional or SMT constraint registered on a `Model`.
|
|
27
63
|
*/
|
|
28
64
|
export interface LogicalConstraint {
|
|
29
65
|
name: string;
|
|
30
66
|
expr: BoolExpr | Constraint;
|
|
31
67
|
}
|
|
68
|
+
declare const UniqueStringTag: unique symbol;
|
|
69
|
+
declare global {
|
|
70
|
+
interface String {
|
|
71
|
+
readonly [UniqueStringTag]: false;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export type KeyCollection<K extends string | number> = ReadonlyArray<K> | (Iterable<K> & object & {
|
|
75
|
+
readonly [UniqueStringTag]?: true;
|
|
76
|
+
});
|
|
77
|
+
/**
|
|
78
|
+
* High-level mathematical programming and SMT model for LP, MIP, convex QP, and SAT/SMT,
|
|
79
|
+
* running with WebAssembly solvers (HiGHS, GLPK, Z3) in Node.js and browsers.
|
|
80
|
+
*
|
|
81
|
+
* **Solver capability notes**:
|
|
82
|
+
* - `"highs"` (default, built-in): Supports LP, MIP, convex QP objectives (`supportsQP: true`),
|
|
83
|
+
* and `initialValue` warm starts (`supportsWarmStart: true`). Also supports `m.check()` on purely
|
|
84
|
+
* linear models via a zero-objective feasibility fallback. Throws if `BoolVar`/logical constraints are present.
|
|
85
|
+
* - `"glpk"` (`import "@ohtaman/washi/solvers/glpk"`): Supports LP and MIP, and `m.check()` on purely
|
|
86
|
+
* linear models via LP feasibility fallback. Throws on quadratic objectives, `BoolVar`/logical constraints,
|
|
87
|
+
* or `initialValue` warm starts.
|
|
88
|
+
* - `"z3"` (`import "@ohtaman/washi/solvers/z3"`): Supports SMT satisfiability (`m.check()`), optimization (`m.solve()`),
|
|
89
|
+
* `BoolVar`/logical constraints (`and`, `or`, `not`, `implies`, `xor`), and unsatisfiable-core extraction
|
|
90
|
+
* (`conflicts` / `unsatCore`). Throws on quadratic objectives or `initialValue` warm starts.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { Model, expr, sum, dot, maximize } from "@ohtaman/washi";
|
|
95
|
+
*
|
|
96
|
+
* const m = new Model("ProductionPlan");
|
|
97
|
+
* const qty = m.integer(["desk", "chair"] as const, { lb: 0, ub: 100 });
|
|
98
|
+
* const setup = m.binary("setup", { initialValue: 1 });
|
|
99
|
+
*
|
|
100
|
+
* m.objective(maximize(expr`${dot({ desk: 30, chair: 50 }, qty)} - 20 * ${setup}`));
|
|
101
|
+
* m.constraint(expr`${dot({ desk: 1, chair: 2 }, qty)} <= 40`, "wood_cap");
|
|
102
|
+
* m.constraint(expr`${sum(Object.values(qty))} <= 30 * ${setup}`, "require_setup");
|
|
103
|
+
*
|
|
104
|
+
* const status = await m.solve();
|
|
105
|
+
* const report = m.validateSolution();
|
|
106
|
+
* const solvedQty = m.getValues(qty);
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
32
109
|
export declare class Model {
|
|
33
110
|
name: string;
|
|
34
|
-
|
|
35
|
-
|
|
111
|
+
private _sense;
|
|
112
|
+
private _objectiveExpr;
|
|
36
113
|
variables: Var[];
|
|
37
114
|
constraints: Constraint[];
|
|
38
115
|
boolVars: BoolVar[];
|
|
39
116
|
logicalConstraints: LogicalConstraint[];
|
|
40
|
-
unsatCore: string[];
|
|
117
|
+
unsatCore: readonly string[] | undefined;
|
|
118
|
+
private _conflicts;
|
|
41
119
|
values: Map<string, number | boolean>;
|
|
42
120
|
private varMapByName;
|
|
121
|
+
private varPrefixCounters;
|
|
43
122
|
private boolVarMapByName;
|
|
44
123
|
private boolVarPrefixCounters;
|
|
45
124
|
private constrMapByName;
|
|
125
|
+
private constrPrefixCounters;
|
|
126
|
+
private logicalConstrMapByName;
|
|
127
|
+
private logicalConstrCounter;
|
|
46
128
|
status: SolverStatus;
|
|
129
|
+
terminationStatus: TerminationStatus;
|
|
130
|
+
hasPrimalSolution: boolean;
|
|
47
131
|
objectiveValue: number | null;
|
|
132
|
+
objectiveBound: number | undefined;
|
|
133
|
+
relGap: number | undefined;
|
|
134
|
+
mipGap: number | undefined;
|
|
135
|
+
absGap: number | undefined;
|
|
48
136
|
runTime: number;
|
|
49
137
|
solution: SolverSolution | null;
|
|
50
138
|
solver: Solver | null;
|
|
139
|
+
/**
|
|
140
|
+
* Latest decomposition result if solved using Benders decomposition or Column Generation.
|
|
141
|
+
*/
|
|
142
|
+
decomposition?: BendersResult | ColumnGenerationResult;
|
|
143
|
+
private _linkingConstraints?;
|
|
144
|
+
private hasSolutionState;
|
|
145
|
+
private modelRevision;
|
|
146
|
+
private activeOperationId;
|
|
147
|
+
private batchDepth;
|
|
148
|
+
private batchMutated;
|
|
149
|
+
private batchUndoActions;
|
|
51
150
|
constructor(nameOrOptions?: string | ModelOptions, maybeOptions?: ModelOptions);
|
|
52
|
-
get
|
|
53
|
-
|
|
151
|
+
get sense(): OptimizationSense;
|
|
152
|
+
set sense(value: OptimizationSense);
|
|
153
|
+
get objectiveExpr(): LinExpr | QuadExpr;
|
|
154
|
+
set objectiveExpr(value: LinExpr | QuadExpr | Constraint);
|
|
155
|
+
/**
|
|
156
|
+
* User-friendly alias for unsatCore or MIP elastic conflict diagnosis.
|
|
157
|
+
* Returns a subset of conflicting constraint names causing infeasibility,
|
|
158
|
+
* or undefined if not diagnosed, not applicable, or satisfiable.
|
|
159
|
+
*/
|
|
160
|
+
get conflicts(): readonly string[] | undefined;
|
|
161
|
+
set conflicts(value: readonly string[] | undefined);
|
|
54
162
|
get numVars(): number;
|
|
55
163
|
get numConstrs(): number;
|
|
164
|
+
/**
|
|
165
|
+
* Clears stored solution and diagnostic fields on the model and its entities.
|
|
166
|
+
*/
|
|
167
|
+
private clearSolutionFields;
|
|
168
|
+
/**
|
|
169
|
+
* Records a model mutation, invalidating any stored solution state and in-flight solver executions.
|
|
170
|
+
*/
|
|
171
|
+
private recordModelMutation;
|
|
172
|
+
/**
|
|
173
|
+
* @internal Notifies the model that an owned entity (e.g., Var bounds/type or Constraint RHS/sense) was mutated.
|
|
174
|
+
*/
|
|
175
|
+
notifyMutation(): void;
|
|
176
|
+
/**
|
|
177
|
+
* Reset prior solution and diagnostic state to avoid stale data leakage across runs,
|
|
178
|
+
* and invalidate any in-flight solve() or check() execution.
|
|
179
|
+
*/
|
|
180
|
+
resetSolutionState(): void;
|
|
181
|
+
/**
|
|
182
|
+
* Executes a multi-item model mutation atomically so failed batch edits neither leave
|
|
183
|
+
* partial entities registered nor invalidate prior solved / in-flight state.
|
|
184
|
+
*/
|
|
185
|
+
private runTransactionalBatch;
|
|
56
186
|
/**
|
|
57
187
|
* Internal generator for domain-specific variables
|
|
58
188
|
*/
|
|
59
189
|
private createDomainVars;
|
|
60
190
|
/**
|
|
61
|
-
* Create 0-1 binary variable(s) (x in {0, 1}).
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* - m.binary(
|
|
65
|
-
* - m.binary(
|
|
66
|
-
* - m.binary(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
191
|
+
* Create 0-1 binary decision variable(s) ($x \in \{0, 1\}$).
|
|
192
|
+
*
|
|
193
|
+
* **Scalar & indexed container overloads**:
|
|
194
|
+
* - `m.binary("x", options?)` or `m.binary(options?)` -> `Var`
|
|
195
|
+
* - `m.binary(count, options?)` -> `Var[]`
|
|
196
|
+
* - `m.binary(keys, options?)` -> `Record<K, Var>`
|
|
197
|
+
* - `m.binary(rowsCount, colsCount, options?)` -> `Var[][]`
|
|
198
|
+
* - `m.binary(rowsCount, colKeys, options?)` -> `Array<Record<C, Var>>`
|
|
199
|
+
* - `m.binary(rowKeys, colsCount, options?)` -> `Record<R, Var[]>`
|
|
200
|
+
* - `m.binary(rowKeys, colKeys, options?)` -> `Record<R, Record<C, Var>>`
|
|
201
|
+
*
|
|
202
|
+
* **Warm-start (`initialValue`) semantics**:
|
|
203
|
+
* - `options.initialValue` supplies an optional finite primal hint (`0` or `1` within tolerance `1e-6`),
|
|
204
|
+
* kept distinct from solved `v.value`.
|
|
205
|
+
* - Supported by HiGHS (`supportsWarmStart: true`); throws on GLPK and Z3.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* ```ts
|
|
209
|
+
* const m = new Model("BinaryVars");
|
|
210
|
+
* const b = m.binary("b", { initialValue: 1 }); // Var
|
|
211
|
+
* const vec = m.binary(4, { prefix: "u" }); // Var[]
|
|
212
|
+
* const grid = m.binary(2, 3, { prefix: "g" }); // Var[][]
|
|
213
|
+
* const byShift = m.binary(["day", "night"] as const); // Record<"day" | "night", Var>
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
binary(name?: string, options?: BinaryOptions): Var;
|
|
217
|
+
binary(options: BinaryOptions): Var;
|
|
218
|
+
binary(count: number, options?: BinaryOptions): Var[];
|
|
219
|
+
binary<K extends string | number>(keys: KeyCollection<K>, options?: BinaryOptions): Record<K, Var>;
|
|
220
|
+
binary(rows: number, cols: number, options?: BinaryOptions): Var[][];
|
|
221
|
+
binary<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: BinaryOptions): Array<Record<C, Var>>;
|
|
222
|
+
binary<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: BinaryOptions): Record<R, Var[]>;
|
|
223
|
+
binary<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: BinaryOptions): Record<R, Record<C, Var>>;
|
|
224
|
+
/**
|
|
225
|
+
* Create integer decision variable(s) ($y \in \mathbb{Z}$, default bounds `lb: 0`, `ub: Infinity`).
|
|
226
|
+
*
|
|
227
|
+
* **Scalar & indexed container overloads**:
|
|
228
|
+
* - `m.integer("y", options?)` or `m.integer(options)` -> `Var`
|
|
229
|
+
* - `m.integer(count, options?)` -> `Var[]`
|
|
230
|
+
* - `m.integer(keys, options?)` -> `Record<K, Var>`
|
|
231
|
+
* - `m.integer(rowsCount, colsCount, options?)` -> `Var[][]`
|
|
232
|
+
* - `m.integer(rowsCount, colKeys, options?)` -> `Array<Record<C, Var>>`
|
|
233
|
+
* - `m.integer(rowKeys, colsCount, options?)` -> `Record<R, Var[]>`
|
|
234
|
+
* - `m.integer(rowKeys, colKeys, options?)` -> `Record<R, Record<C, Var>>`
|
|
235
|
+
*
|
|
236
|
+
* **Warm-start (`initialValue`) semantics**:
|
|
237
|
+
* - `options.initialValue` supplies an optional finite integer primal hint within tolerance `1e-6` of `[lb, ub]`,
|
|
238
|
+
* kept distinct from solved `v.value`.
|
|
239
|
+
* - Supported by HiGHS (`supportsWarmStart: true`); throws on GLPK and Z3.
|
|
240
|
+
*
|
|
241
|
+
* @example
|
|
242
|
+
* ```ts
|
|
243
|
+
* const m = new Model("IntegerVars");
|
|
244
|
+
* const n = m.integer("n", { lb: 0, ub: 10, initialValue: 4 }); // Var
|
|
245
|
+
* const counts = m.integer(3, { lb: 0, prefix: "k" }); // Var[]
|
|
246
|
+
* const matrix = m.integer(2, 2, { lb: 0, prefix: "m" }); // Var[][]
|
|
247
|
+
* const byItem = m.integer(["desk", "chair"] as const, { lb: 0, ub: 50 }); // Record<"desk" | "chair", Var>
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
integer(name?: string, options?: BoundsOptions): Var;
|
|
251
|
+
integer(options: BoundsOptions): Var;
|
|
90
252
|
integer(count: number, options?: BoundsOptions): Var[];
|
|
91
|
-
integer<K extends string | number>(keys:
|
|
92
|
-
integer
|
|
253
|
+
integer<K extends string | number>(keys: KeyCollection<K>, options?: BoundsOptions): Record<K, Var>;
|
|
254
|
+
integer(rows: number, cols: number, options?: BoundsOptions): Var[][];
|
|
255
|
+
integer<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: BoundsOptions): Array<Record<C, Var>>;
|
|
256
|
+
integer<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: BoundsOptions): Record<R, Var[]>;
|
|
257
|
+
integer<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: BoundsOptions): Record<R, Record<C, Var>>;
|
|
93
258
|
/**
|
|
94
|
-
* Create continuous (real) variable(s) (z in R).
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* - m.continuous(
|
|
98
|
-
* - m.continuous(
|
|
99
|
-
* - m.continuous(
|
|
259
|
+
* Create continuous (real) decision variable(s) ($z \in \mathbb{R}$, default bounds `lb: 0`, `ub: Infinity`).
|
|
260
|
+
*
|
|
261
|
+
* **Scalar & indexed container overloads**:
|
|
262
|
+
* - `m.continuous("z", options?)` or `m.continuous(options)` -> `Var`
|
|
263
|
+
* - `m.continuous(count, options?)` -> `Var[]`
|
|
264
|
+
* - `m.continuous(keys, options?)` -> `Record<K, Var>`
|
|
265
|
+
* - `m.continuous(rowsCount, colsCount, options?)` -> `Var[][]`
|
|
266
|
+
* - `m.continuous(rowsCount, colKeys, options?)` -> `Array<Record<C, Var>>`
|
|
267
|
+
* - `m.continuous(rowKeys, colsCount, options?)` -> `Record<R, Var[]>`
|
|
268
|
+
* - `m.continuous(rowKeys, colKeys, options?)` -> `Record<R, Record<C, Var>>`
|
|
269
|
+
*
|
|
270
|
+
* **Warm-start (`initialValue`) semantics**:
|
|
271
|
+
* - `options.initialValue` supplies an optional finite primal hint within tolerance `1e-6` of `[lb, ub]`,
|
|
272
|
+
* kept distinct from solved `v.value`.
|
|
273
|
+
* - Supported by HiGHS (`supportsWarmStart: true`); throws on GLPK and Z3.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* const m = new Model("ContinuousVars");
|
|
278
|
+
* const x = m.continuous("x", { lb: 0, ub: 100, initialValue: 25 }); // Var
|
|
279
|
+
* const vec = m.continuous(4, { lb: 0, prefix: "v" }); // Var[]
|
|
280
|
+
* const flow = m.continuous(2, 3, { lb: 0, prefix: "f" }); // Var[][]
|
|
281
|
+
* const alloc = m.continuous(["A", "B"] as const, { lb: 0 }); // Record<"A" | "B", Var>
|
|
282
|
+
* ```
|
|
100
283
|
*/
|
|
101
|
-
continuous(name
|
|
284
|
+
continuous(name?: string, options?: BoundsOptions): Var;
|
|
285
|
+
continuous(options: BoundsOptions): Var;
|
|
102
286
|
continuous(count: number, options?: BoundsOptions): Var[];
|
|
103
|
-
continuous<K extends string | number>(keys:
|
|
104
|
-
continuous
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
*
|
|
110
|
-
* -
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
287
|
+
continuous<K extends string | number>(keys: KeyCollection<K>, options?: BoundsOptions): Record<K, Var>;
|
|
288
|
+
continuous(rows: number, cols: number, options?: BoundsOptions): Var[][];
|
|
289
|
+
continuous<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: BoundsOptions): Array<Record<C, Var>>;
|
|
290
|
+
continuous<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: BoundsOptions): Record<R, Var[]>;
|
|
291
|
+
continuous<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: BoundsOptions): Record<R, Record<C, Var>>;
|
|
292
|
+
/**
|
|
293
|
+
* Dynamically add a column (decision variable + constraint coefficients + objective cost) to the model.
|
|
294
|
+
* This is the core primitive for Column Generation and Dantzig-Wolfe decomposition.
|
|
295
|
+
*
|
|
296
|
+
* @param options Column definition including variable type/bounds, objective cost, and constraint coefficients
|
|
297
|
+
* @returns The newly created decision variable `Var`
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* const m = new Model("ColumnExample");
|
|
302
|
+
* m.constraint(expr`0 <= 10`, "demand_itemA");
|
|
303
|
+
* m.constraint(expr`0 <= 10`, "demand_itemB");
|
|
304
|
+
* const colVar = m.addColumn({
|
|
305
|
+
* name: "pattern_1",
|
|
306
|
+
* type: "Continuous",
|
|
307
|
+
* lb: 0,
|
|
308
|
+
* cost: 1,
|
|
309
|
+
* coefficients: {
|
|
310
|
+
* demand_itemA: 2,
|
|
311
|
+
* demand_itemB: 1,
|
|
312
|
+
* },
|
|
313
|
+
* });
|
|
314
|
+
* ```
|
|
315
|
+
*/
|
|
316
|
+
addColumn(options: ColumnDefinition): Var;
|
|
317
|
+
/**
|
|
318
|
+
* Create propositional Boolean variable(s) (`BoolVar`: `true` / `false`) for SMT / SAT logical modeling.
|
|
319
|
+
*
|
|
320
|
+
* **Scalar & indexed container overloads**:
|
|
321
|
+
* - `m.bool("flag", options?)` or `m.bool(options?)` -> `BoolVar`
|
|
322
|
+
* - `m.bool(count, options?)` -> `BoolVar[]`
|
|
323
|
+
* - `m.bool(keys, options?)` -> `Record<K, BoolVar>`
|
|
324
|
+
* - `m.bool(rowsCount, colsCount, options?)` -> `BoolVar[][]`
|
|
325
|
+
* - `m.bool(rowsCount, colKeys, options?)` -> `Array<Record<C, BoolVar>>`
|
|
326
|
+
* - `m.bool(rowKeys, colsCount, options?)` -> `Record<R, BoolVar[]>`
|
|
327
|
+
* - `m.bool(rowKeys, colKeys, options?)` -> `Record<R, Record<C, BoolVar>>`
|
|
328
|
+
*
|
|
329
|
+
* **Solver capability note**:
|
|
330
|
+
* - Logical constraints over `BoolVar` (`and`, `or`, `not`, `implies`, `xor`) require an SMT-capable solver
|
|
331
|
+
* such as Z3 (`new Model("...", { solver: "z3" })` after `import "@ohtaman/washi/solvers/z3"`).
|
|
332
|
+
* - LP/MIP solvers (HiGHS, GLPK) throw if logical constraints are present. For 0-1 arithmetic variables
|
|
333
|
+
* in LP/MIP (or Big-M `m.indicator()`), use `m.binary()` instead.
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```ts
|
|
337
|
+
* import "@ohtaman/washi/solvers/z3";
|
|
338
|
+
*
|
|
339
|
+
* const m = new Model("BoolVars", { solver: "z3" });
|
|
340
|
+
* const vip = m.bool("vip"); // BoolVar
|
|
341
|
+
* const flags = m.bool(3, { prefix: "f" }); // BoolVar[]
|
|
342
|
+
* const grid = m.bool(2, 2, { prefix: "g" }); // BoolVar[][]
|
|
343
|
+
* const byRole = m.bool(["admin", "guest"] as const); // Record<"admin" | "guest", BoolVar>
|
|
344
|
+
* m.constraint(implies(vip, flags[0]), "vip_flag");
|
|
345
|
+
* ```
|
|
346
|
+
*/
|
|
347
|
+
bool(name?: string, options?: VarNameOptions): BoolVar;
|
|
348
|
+
bool(options: VarNameOptions): BoolVar;
|
|
349
|
+
bool(count: number, options?: VarNameOptions): BoolVar[];
|
|
350
|
+
bool<K extends string | number>(keys: KeyCollection<K>, options?: VarNameOptions): Record<K, BoolVar>;
|
|
351
|
+
bool(rows: number, cols: number, options?: VarNameOptions): BoolVar[][];
|
|
352
|
+
bool<C extends string | number>(rows: number, cols: KeyCollection<C>, options?: VarNameOptions): Array<Record<C, BoolVar>>;
|
|
353
|
+
bool<R extends string | number>(rows: KeyCollection<R>, cols: number, options?: VarNameOptions): Record<R, BoolVar[]>;
|
|
354
|
+
bool<R extends string | number, C extends string | number>(rows: KeyCollection<R>, cols: KeyCollection<C>, options?: VarNameOptions): Record<R, Record<C, BoolVar>>;
|
|
127
355
|
private hasVarName;
|
|
356
|
+
private getNextVarName;
|
|
128
357
|
private getNextBoolVarName;
|
|
358
|
+
private hasConstraintName;
|
|
359
|
+
private hasBoolVarName;
|
|
360
|
+
private getNextConstrName;
|
|
361
|
+
private getNextLogicalConstrName;
|
|
129
362
|
private createBoolVar;
|
|
130
363
|
/**
|
|
131
364
|
* Internal variable creator
|
|
@@ -144,39 +377,86 @@ export declare class Model {
|
|
|
144
377
|
*/
|
|
145
378
|
getConstraintByName(name: string): Constraint | undefined;
|
|
146
379
|
/**
|
|
147
|
-
*
|
|
380
|
+
* Find a logical constraint by its name
|
|
148
381
|
*/
|
|
149
|
-
|
|
382
|
+
getLogicalConstraintByName(name: string): LogicalConstraint | undefined;
|
|
150
383
|
/**
|
|
151
|
-
*
|
|
384
|
+
* Get the current objective expression, or set the objective function and direction (`maximize(...)` / `minimize(...)`).
|
|
385
|
+
* Calling `objective(spec)` replaces any previously defined objective and returns `this` for chaining.
|
|
386
|
+
*
|
|
387
|
+
* **Formulation & solver capability notes**:
|
|
388
|
+
* - Supports linear (`LinExpr`, `Var`, `number`, formula string) and quadratic (`QuadExpr`: `^2`, `${x} * ${y}`) expressions.
|
|
389
|
+
* - Quadratic terms are supported in **objectives only** (requires a QP-capable solver such as HiGHS; throws on GLPK and Z3).
|
|
390
|
+
* - Passing a comparison `Constraint` (`<=`, `>=`, `==`) throws an Error.
|
|
391
|
+
*
|
|
392
|
+
* @example
|
|
393
|
+
* ```ts
|
|
394
|
+
* const m = new Model("ObjectiveExample");
|
|
395
|
+
* const chairs = m.integer("chairs", { lb: 0 });
|
|
396
|
+
* const tables = m.integer("tables", { lb: 0 });
|
|
397
|
+
*
|
|
398
|
+
* m.objective(maximize(expr`30 * ${chairs} + 50 * ${tables}`));
|
|
399
|
+
* const currentExpr = m.objective();
|
|
400
|
+
* ```
|
|
152
401
|
*/
|
|
153
|
-
|
|
402
|
+
objective(): LinExpr | QuadExpr;
|
|
403
|
+
objective(spec: ObjectiveSpec): this;
|
|
154
404
|
/**
|
|
155
|
-
*
|
|
405
|
+
* Internal objective setter.
|
|
156
406
|
*/
|
|
157
|
-
|
|
407
|
+
private applyObjective;
|
|
158
408
|
/**
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* -
|
|
409
|
+
* Register linear comparison constraint(s) (`<=`, `>=`, `==`), SMT logical constraint(s) (`BoolVar`, `BoolExpr`),
|
|
410
|
+
* or constraint formula string(s) on the model. Chainable: returns `this`.
|
|
411
|
+
*
|
|
412
|
+
* **Formulation & solver capability notes**:
|
|
413
|
+
* - Rejects raw arithmetic expressions (`LinExpr`, `QuadExpr`) without a comparison operator and quadratic constraints.
|
|
414
|
+
* - Logical constraints (`BoolVar`, `and`, `or`, `not`, `implies`, `xor`) require an SMT-capable solver (`{ solver: "z3" }`);
|
|
415
|
+
* LP/MIP solvers (HiGHS, GLPK) throw if logical constraints are present.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* ```ts
|
|
419
|
+
* const m = new Model("ConstraintExample");
|
|
420
|
+
* const desks = m.integer("desks", { lb: 0 });
|
|
421
|
+
* const chairs = m.integer("chairs", { lb: 0 });
|
|
422
|
+
* const x = m.continuous(3, { lb: 0, prefix: "x" });
|
|
423
|
+
*
|
|
424
|
+
* m.constraint(expr`${desks} + 2 * ${chairs} <= 40`, "wood");
|
|
425
|
+
* m.constraint(x.map((v) => expr`${v} <= 10`));
|
|
426
|
+
* m.constraint(desks.ge(2)).constraint(chairs.ge(4));
|
|
427
|
+
* ```
|
|
164
428
|
*/
|
|
165
|
-
|
|
166
|
-
|
|
429
|
+
constraint(constraint: ConstraintItem | LinExpr | QuadExpr, name?: string): this;
|
|
430
|
+
constraint(constraints: ReadonlyArray<ConstraintItem | LinExpr | QuadExpr>): this;
|
|
167
431
|
/**
|
|
168
|
-
* Extract primal solution values directly into plain primitives:
|
|
169
|
-
* - m.getValues(x) -> number | null
|
|
170
|
-
* - m.getValues(p) -> boolean | null
|
|
171
|
-
* - m.getValues([x, y]) -> (number | null)[]
|
|
172
|
-
* - m.getValues([
|
|
173
|
-
* - m.getValues(record) -> Record<
|
|
174
|
-
* - m.getValues(matrix) -> Record<
|
|
432
|
+
* Extract primal solution values directly into plain primitives, preserving container shapes:
|
|
433
|
+
* - `m.getValues(x)` -> `number | null`
|
|
434
|
+
* - `m.getValues(p)` -> `boolean | null`
|
|
435
|
+
* - `m.getValues([x, y])` -> `(number | null)[]`
|
|
436
|
+
* - `m.getValues([[x11, x12], [x21, x22]])` -> `(number | null)[][]`
|
|
437
|
+
* - `m.getValues(record)` -> `Record<K, number | boolean | null>`
|
|
438
|
+
* - `m.getValues(matrix)` -> `Record<R, Record<C, number | boolean | null>>`
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```ts
|
|
442
|
+
* const m = new Model("GetValuesExample");
|
|
443
|
+
* const qty = m.integer(["desk", "chair"] as const, { lb: 0, ub: 10 });
|
|
444
|
+
* m.objective(maximize(expr`30 * ${qty.desk} + 50 * ${qty.chair}`));
|
|
445
|
+
* m.constraint(expr`${qty.desk} + ${qty.chair} <= 10`);
|
|
446
|
+
* await m.solve();
|
|
447
|
+
* const values = m.getValues(qty); // Record<"desk" | "chair", number | null>
|
|
448
|
+
* ```
|
|
175
449
|
*/
|
|
176
450
|
getValues(item: Var): number | null;
|
|
177
451
|
getValues(item: BoolVar): boolean | null;
|
|
178
|
-
getValues(items: Var
|
|
179
|
-
getValues(items: BoolVar
|
|
452
|
+
getValues(items: ReadonlyArray<Var>): (number | null)[];
|
|
453
|
+
getValues(items: ReadonlyArray<BoolVar>): (boolean | null)[];
|
|
454
|
+
getValues(items: ReadonlyArray<ReadonlyArray<Var>>): (number | null)[][];
|
|
455
|
+
getValues(items: ReadonlyArray<ReadonlyArray<BoolVar>>): (boolean | null)[][];
|
|
456
|
+
getValues<C extends string | number>(items: ReadonlyArray<Record<C, Var>>): Array<Record<C, number | null>>;
|
|
457
|
+
getValues<C extends string | number>(items: ReadonlyArray<Record<C, BoolVar>>): Array<Record<C, boolean | null>>;
|
|
458
|
+
getValues<R extends string | number>(items: Record<R, ReadonlyArray<Var>>): Record<R, (number | null)[]>;
|
|
459
|
+
getValues<R extends string | number>(items: Record<R, ReadonlyArray<BoolVar>>): Record<R, (boolean | null)[]>;
|
|
180
460
|
getValues<K extends string | number>(items: Record<K, Var>): Record<K, number | null>;
|
|
181
461
|
getValues<K extends string | number>(items: Record<K, BoolVar>): Record<K, boolean | null>;
|
|
182
462
|
getValues<R extends string | number, C extends string | number>(items: Record<R, Record<C, Var>>): Record<R, Record<C, number | null>>;
|
|
@@ -186,54 +466,266 @@ export declare class Model {
|
|
|
186
466
|
*/
|
|
187
467
|
private addConstraint;
|
|
188
468
|
/**
|
|
189
|
-
*
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
* -
|
|
194
|
-
* -
|
|
195
|
-
* -
|
|
196
|
-
*
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
add(expr: BoolExpr, name?: string): this;
|
|
200
|
-
add(strConstraint: string, name?: string): this;
|
|
201
|
-
add(variable: Var): this;
|
|
202
|
-
add(items: (Constraint | BoolExpr | string | Var)[]): this;
|
|
203
|
-
/**
|
|
204
|
-
* Add an indicator constraint via Big-M auto-linearization:
|
|
205
|
-
* "If binVar == activeValue, then constraint holds"
|
|
469
|
+
* Add an indicator constraint via floating-point Big-M auto-linearization:
|
|
470
|
+
* `"If binVar === activeValue, then constraint holds"` (`activeValue` defaults to `1`).
|
|
471
|
+
*
|
|
472
|
+
* **Formulation & solver capability notes**:
|
|
473
|
+
* - Automatically linearizes `<=`, `>=`, and `==` constraints for LP/MIP solvers (HiGHS, GLPK)
|
|
474
|
+
* under standard floating-point feasibility tolerances (`==` generates `_le` and `_ge` rows).
|
|
475
|
+
* - Variables appearing in `constraint` must have finite bounds (`lb`/`ub`) to derive a safe tight Big-M
|
|
476
|
+
* automatically, unless an explicit `{ M }` override is supplied in `options`.
|
|
477
|
+
* - Because Big-M rows are floating-point linear relaxations, they do not guarantee exact rational
|
|
478
|
+
* equivalence in SMT solvers (Z3); use `implies(...)` with `m.bool(...)` when exact SMT diagnosis is required.
|
|
206
479
|
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
480
|
+
* @example
|
|
481
|
+
* ```ts
|
|
482
|
+
* const m = new Model("IndicatorExample");
|
|
483
|
+
* const b = m.binary("b");
|
|
484
|
+
* const x = m.continuous("x", { lb: 0, ub: 100 });
|
|
485
|
+
* // Enforces x <= 50 when b === 1 (relaxed to x <= 100 when b === 0)
|
|
486
|
+
* m.indicator(b, expr`${x} <= 50`, { activeValue: 1, name: "cap_when_b" });
|
|
487
|
+
* ```
|
|
209
488
|
*/
|
|
210
489
|
indicator(binVar: Var, constraint: Constraint | LinExpr | QuadExpr, options?: IndicatorOptions): Constraint[];
|
|
211
490
|
/**
|
|
212
|
-
*
|
|
491
|
+
* Validate model integrity (`validateIntegrity()`) and serialize the model's linear/quadratic objective,
|
|
492
|
+
* linear constraints, and numeric variable bounds/domains (`Continuous`, `Integer`, `Binary`) to a
|
|
493
|
+
* standard CPLEX LP format string with collision-free sanitized identifiers.
|
|
494
|
+
*
|
|
495
|
+
* **Note**: Propositional `BoolVar`s and SMT `logicalConstraints` are not part of the CPLEX LP format.
|
|
496
|
+
*
|
|
497
|
+
* @example
|
|
498
|
+
* ```ts
|
|
499
|
+
* const m = new Model("LpExportExample");
|
|
500
|
+
* const x = m.integer("x", { lb: 0, ub: 10 });
|
|
501
|
+
* m.objective(maximize(expr`5 * ${x}`));
|
|
502
|
+
* m.constraint(expr`${x} <= 8`, "cap");
|
|
503
|
+
* const lpText = m.toLpString();
|
|
504
|
+
* ```
|
|
213
505
|
*/
|
|
214
506
|
toLpString(): string;
|
|
215
507
|
/**
|
|
216
|
-
*
|
|
217
|
-
*
|
|
508
|
+
* Validates model integrity: variable bounds, ownership, numeric sanity, and unique constraint names.
|
|
509
|
+
* Throws an Error with actionable explanation if any validation rule is violated.
|
|
510
|
+
*/
|
|
511
|
+
validateIntegrity(): void;
|
|
512
|
+
private ensureExecutionValid;
|
|
513
|
+
private wrapSolveOptions;
|
|
514
|
+
private hasPrimalFromResult;
|
|
515
|
+
/**
|
|
516
|
+
* Resolves the target solver and execution options without mutating caller-owned objects,
|
|
517
|
+
* stripping the routing `solver` field from the returned `SolverOptions`.
|
|
518
|
+
*/
|
|
519
|
+
private resolveSolverAndOptions;
|
|
520
|
+
/**
|
|
521
|
+
* Solve the continuous (LP) relaxation of the model.
|
|
522
|
+
* Treats all integer and binary decision variables as continuous variables within their bounds.
|
|
523
|
+
* This computes theoretical lower/upper dual bounds and extracts constraint shadow prices (duals),
|
|
524
|
+
* which is the foundational building block for Column Generation, Dantzig-Wolfe, and Benders decomposition.
|
|
525
|
+
*
|
|
526
|
+
* @param solverOrOptions Optional solver instance, name, or solve options
|
|
527
|
+
* @param options Solve options
|
|
528
|
+
* @returns Solver status ("Optimal", "Infeasible", etc.)
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* ```ts
|
|
532
|
+
* const m = new Model("RelaxExample");
|
|
533
|
+
* const x = m.integer("x", { lb: 0, ub: 10 });
|
|
534
|
+
* m.objective(maximize(x));
|
|
535
|
+
* m.constraint(expr`${x} <= 5.5`, "cap");
|
|
536
|
+
* const status = await m.relax();
|
|
537
|
+
* if (status === "Optimal") {
|
|
538
|
+
* const bound = m.objectiveValue;
|
|
539
|
+
* const shadow = m.solution?.duals?.cap;
|
|
540
|
+
* }
|
|
541
|
+
* ```
|
|
218
542
|
*/
|
|
219
|
-
|
|
543
|
+
relax(solverOrOptions?: Solver | string | SolveOptions, options?: SolveOptions): Promise<SolverStatus>;
|
|
220
544
|
/**
|
|
221
|
-
*
|
|
222
|
-
* await
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
545
|
+
* Solve the optimization model using the configured solver (defaults to HiGHS WASM)
|
|
546
|
+
* or a solver passed dynamically (e.g., `await m.solve("glpk")` or `await m.solve({ timeLimit: 10 })`).
|
|
547
|
+
*
|
|
548
|
+
* **Return status (`SolverStatus`)**:
|
|
549
|
+
* - Built-in optimization solvers return `"Optimal"`, `"Feasible"`, `"Infeasible"`, `"Unbounded"`,
|
|
550
|
+
* `"TimeLimit"`, `"IterationLimit"`, `"Error"`, `"Unknown"`, or `"NotSolved"` (`"Sat"` / `"Unsat"`
|
|
551
|
+
* are included in `SolverStatus` for custom/satisfiability adapters).
|
|
552
|
+
* - When a time-, iteration-, or solution-limited run (or an interrupted solve) has found a valid
|
|
553
|
+
* primal incumbent, `solve()` returns `"Feasible"` (`m.hasPrimalSolution === true`, with the exact
|
|
554
|
+
* stopping reason in `m.terminationStatus`).
|
|
555
|
+
* - After solving, read primal/dual values via `x.value`, `m.getValues(...)`, `m.objectiveValue`,
|
|
556
|
+
* `constr.dual`, `constr.slack`, and `x.reducedCost`, and verify primal feasibility with `m.validateSolution()`.
|
|
557
|
+
*
|
|
558
|
+
* **Solver capability preconditions**:
|
|
559
|
+
* - Quadratic objectives (`QuadExpr`) require `supportsQP` (supported by HiGHS; throws on GLPK and Z3).
|
|
560
|
+
* - Logical constraints (`BoolVar`, `and`, `or`, `not`, `implies`, `xor`) require `supportsSMT`
|
|
561
|
+
* (supported by Z3; throws on HiGHS and GLPK).
|
|
562
|
+
* - Primal `initialValue` warm starts require `supportsWarmStart` (supported by HiGHS; throws on GLPK and Z3).
|
|
563
|
+
* - Mutating the model or starting a newer `solve()` / `check()` while in flight discards the stale
|
|
564
|
+
* result and rejects the pending promise.
|
|
565
|
+
*
|
|
566
|
+
* @example
|
|
567
|
+
* ```ts
|
|
568
|
+
* const m = new Model("SolveExample");
|
|
569
|
+
* const x = m.integer("x", { lb: 0, ub: 50, initialValue: 10 });
|
|
570
|
+
* const y = m.integer("y", { lb: 0, ub: 50 });
|
|
571
|
+
* m.objective(maximize(expr`30 * ${x} + 50 * ${y}`));
|
|
572
|
+
* m.constraint(expr`${x} + 2 * ${y} <= 40`, "resource_limit");
|
|
573
|
+
*
|
|
574
|
+
* const status = await m.solve();
|
|
575
|
+
* const report = m.validateSolution();
|
|
576
|
+
* const obj = m.objectiveValue;
|
|
577
|
+
* ```
|
|
226
578
|
*/
|
|
227
579
|
solve(solverOrOptions?: Solver | string | SolveOptions, options?: SolveOptions): Promise<SolverStatus>;
|
|
228
580
|
/**
|
|
229
|
-
* Check satisfiability of the model without requiring an objective function.
|
|
230
|
-
*
|
|
581
|
+
* Check satisfiability / feasibility of the model without requiring an objective function.
|
|
582
|
+
*
|
|
583
|
+
* Returns `CheckResult` (`{ status: "Sat" | "Unsat" | "Unknown", values, conflicts?, unsatCore?, runTime? }`).
|
|
584
|
+
*
|
|
585
|
+
* **LP feasibility fallback vs. Z3 requirement**:
|
|
586
|
+
* - **Linear models (`m.check()` fallback)**: For models containing only linear arithmetic constraints,
|
|
587
|
+
* `m.check()` works with any solver (including the default HiGHS and GLPK) by falling back to a
|
|
588
|
+
* zero-objective feasibility `solve()` without mutating `m.objectiveExpr` or `m.sense`.
|
|
589
|
+
* - **Logical constraints & `unsatCore` (requires Z3)**: Models containing `BoolVar` or logical
|
|
590
|
+
* constraints (`and`, `or`, `not`, `implies`, `xor`) require an SMT-capable solver (`{ solver: "z3" }`
|
|
591
|
+
* after `import "@ohtaman/washi/solvers/z3"`). Unsatisfiable-core extraction (`result.conflicts` /
|
|
592
|
+
* `result.unsatCore` and `m.conflicts` / `m.unsatCore`) is populated only when an unsat-core-capable
|
|
593
|
+
* solver such as Z3 returns `"Unsat"`, reporting a subset of registered constraint names that conflicts
|
|
594
|
+
* together with the model's fixed variable bounds/domains.
|
|
595
|
+
* - Mutating the model or starting a newer `solve()` / `check()` while in flight discards the stale
|
|
596
|
+
* result and rejects the pending promise.
|
|
597
|
+
*
|
|
598
|
+
* @example
|
|
599
|
+
* ```ts
|
|
600
|
+
* import "@ohtaman/washi/solvers/z3";
|
|
601
|
+
*
|
|
602
|
+
* // 1. Linear feasibility check (works with default HiGHS via LP fallback)
|
|
603
|
+
* const mLin = new Model("LinearCheck");
|
|
604
|
+
* const x = mLin.continuous("x", { lb: 0, ub: 10 });
|
|
605
|
+
* mLin.constraint(expr`${x} >= 4`, "min_x");
|
|
606
|
+
* const linRes = await mLin.check(); // { status: "Sat", values: { x: ... } }
|
|
607
|
+
*
|
|
608
|
+
* // 2. SMT satisfiability & unsatCore diagnosis (requires Z3)
|
|
609
|
+
* const mSmt = new Model("PolicyCheck", { solver: "z3" });
|
|
610
|
+
* const vip = mSmt.bool("vip");
|
|
611
|
+
* const discount = mSmt.integer("discount", { lb: 0, ub: 50 });
|
|
612
|
+
* mSmt.constraint(vip, "is_vip");
|
|
613
|
+
* mSmt.constraint(implies(vip, expr`${discount} >= 20`), "vip_min");
|
|
614
|
+
* mSmt.constraint(expr`${discount} <= 10`, "cap");
|
|
615
|
+
* const smtRes = await mSmt.check(); // { status: "Unsat", conflicts: [...], unsatCore: [...] }
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
check(solverOrOptions?: Solver | string | SolveOptions, options?: SolveOptions): Promise<CheckResult>;
|
|
619
|
+
/**
|
|
620
|
+
* Independently evaluate and verify variable finiteness, variable bounds (`lb`/`ub`),
|
|
621
|
+
* integer/binary/boolean domains, linear constraint residuals, and logical (SMT/propositional)
|
|
622
|
+
* constraints against the model's current solved values (or an explicit `options.values` map).
|
|
623
|
+
*
|
|
624
|
+
* Returns a `SolutionValidationReport` (`{ valid, complete, maxViolation, violations, violationsByName, uncheckedConstraints, missingVariables, summary }`).
|
|
625
|
+
*
|
|
626
|
+
* **Verification notes**:
|
|
627
|
+
* - Runs purely in JavaScript/TypeScript without requiring any WASM solver runtime.
|
|
628
|
+
* - Verifies primal feasibility of variables and constraints; does not recompute or compare `m.objectiveValue`.
|
|
629
|
+
*
|
|
630
|
+
* @example
|
|
631
|
+
* ```ts
|
|
632
|
+
* const m = new Model("ValidateExample");
|
|
633
|
+
* const x = m.integer("x", { lb: 0, ub: 10 });
|
|
634
|
+
* m.objective(maximize(expr`3 * ${x}`));
|
|
635
|
+
* m.constraint(expr`${x} <= 7`, "cap");
|
|
636
|
+
*
|
|
637
|
+
* await m.solve();
|
|
638
|
+
* const report = m.validateSolution();
|
|
639
|
+
* const isFeasible = report.valid && report.maxViolation <= 1e-6;
|
|
640
|
+
* ```
|
|
641
|
+
*/
|
|
642
|
+
validateSolution(options?: SolutionValidationOptions): SolutionValidationReport;
|
|
643
|
+
/**
|
|
644
|
+
* Register a linking constraint (row) that connects this subproblem model's variables
|
|
645
|
+
* with decision variables in the master problem for Benders decomposition.
|
|
646
|
+
*
|
|
647
|
+
* @param constraint The linear constraint connecting subproblem variables with master variables
|
|
648
|
+
* @returns The registered linking constraint
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* ```ts
|
|
652
|
+
* const master = new Model("Master");
|
|
653
|
+
* const y = master.binary("y");
|
|
654
|
+
*
|
|
655
|
+
* const sub = new Model("Subproblem");
|
|
656
|
+
* const x = sub.continuous("x", { lb: 0 });
|
|
657
|
+
* sub.link(expr`${x} <= 50 * ${y}`);
|
|
658
|
+
* ```
|
|
659
|
+
*/
|
|
660
|
+
link(constraint: Constraint | ParsedExpr): Constraint;
|
|
661
|
+
/**
|
|
662
|
+
* Linking constraints registered on this model for Benders decomposition.
|
|
663
|
+
*/
|
|
664
|
+
get linkingConstraints(): ReadonlyArray<Constraint>;
|
|
665
|
+
/**
|
|
666
|
+
* Solve this model as a Master Problem using Benders Decomposition.
|
|
667
|
+
*
|
|
668
|
+
* Partitions the problem into a master problem (this model) and a subproblem.
|
|
669
|
+
* On each iteration, the subproblem is evaluated: either automatically (generating Benders cuts
|
|
670
|
+
* from a returned subproblem model and its linking constraints) or manually via a cut callback.
|
|
671
|
+
*
|
|
672
|
+
* @param options Benders options including subproblem callback
|
|
673
|
+
* @returns BendersResult containing status, objective, bounds, gap, iterations, cuts, and decision values
|
|
674
|
+
*
|
|
675
|
+
* @example
|
|
676
|
+
* ```ts
|
|
677
|
+
* const master = new Model("FacilityMaster");
|
|
678
|
+
* const y = master.binary("open");
|
|
679
|
+
* master.constraint(expr`${y} >= 1`);
|
|
680
|
+
* master.objective(minimize(expr`100 * ${y}`));
|
|
681
|
+
*
|
|
682
|
+
* const result = await master.solveBenders({
|
|
683
|
+
* subproblem: () => {
|
|
684
|
+
* const sub = new Model("Transport");
|
|
685
|
+
* const x = sub.continuous("x", { lb: 0 });
|
|
686
|
+
* sub.objective(minimize(expr`2 * ${x}`));
|
|
687
|
+
* sub.constraint(expr`${x} >= 30`, "demand");
|
|
688
|
+
* sub.link(expr`${x} <= 50 * ${y}`);
|
|
689
|
+
* return sub;
|
|
690
|
+
* },
|
|
691
|
+
* });
|
|
692
|
+
* ```
|
|
693
|
+
*/
|
|
694
|
+
solveBenders(options: Omit<BendersOptions, "master">): Promise<BendersResult>;
|
|
695
|
+
/**
|
|
696
|
+
* Solve this model as a Restricted Master Problem using Column Generation (Dantzig-Wolfe decomposition).
|
|
697
|
+
*
|
|
698
|
+
* Solves the continuous LP relaxation to obtain dual shadow prices, evaluates the pricing subproblem
|
|
699
|
+
* to dynamically generate columns with negative reduced costs, and optionally finalizes as a MIP.
|
|
700
|
+
*
|
|
701
|
+
* @param options Column generation options including custom pricing callback
|
|
702
|
+
* @returns ColumnGenerationResult containing status, objective, iterations, columns, and values
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```ts
|
|
706
|
+
* const master = new Model("CuttingStock");
|
|
707
|
+
* master.objective(minimize(0));
|
|
708
|
+
* master.constraint(expr`0 >= 10`, "demand");
|
|
709
|
+
* const [demand] = master.constraints;
|
|
710
|
+
* master.addColumn({ cost: 1, type: "Integer", coefficients: { demand: 2 } });
|
|
711
|
+
*
|
|
712
|
+
* const result = await master.solveColumnGeneration({
|
|
713
|
+
* finalizeAsMIP: true,
|
|
714
|
+
* pricing: async () => {
|
|
715
|
+
* const sub = new Model("Pricing");
|
|
716
|
+
* const a = sub.integer("a", { lb: 0, ub: 5 });
|
|
717
|
+
* sub.objective(maximize(expr`${(demand.dual ?? 0)} * ${a}`));
|
|
718
|
+
* sub.constraint(expr`${a} <= 5`);
|
|
719
|
+
* await sub.solve();
|
|
720
|
+
* return {
|
|
721
|
+
* cost: 1,
|
|
722
|
+
* type: "Integer",
|
|
723
|
+
* coefficients: { demand: a.value ?? 0 },
|
|
724
|
+
* };
|
|
725
|
+
* },
|
|
726
|
+
* });
|
|
727
|
+
* ```
|
|
231
728
|
*/
|
|
232
|
-
|
|
233
|
-
status: "Sat" | "Unsat" | "Unknown";
|
|
234
|
-
values: Record<string, number | boolean>;
|
|
235
|
-
unsatCore?: string[];
|
|
236
|
-
runTime?: number;
|
|
237
|
-
}>;
|
|
729
|
+
solveColumnGeneration<TColumnMeta = unknown>(options: Omit<ColumnGenerationOptions<TColumnMeta>, "master">): Promise<ColumnGenerationResult<TColumnMeta>>;
|
|
238
730
|
}
|
|
239
731
|
//# sourceMappingURL=model.d.ts.map
|