@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.
Files changed (130) hide show
  1. package/README.ja.md +149 -121
  2. package/README.md +149 -121
  3. package/README.zh-CN.md +150 -122
  4. package/THIRD_PARTY_LICENSES.md +3 -4
  5. package/dist/browser/_washi-node-only-BvRk9kiK.js +0 -0
  6. package/dist/browser/browser-runtime-TLCY0hkc.js +1793 -0
  7. package/dist/browser/highs-worker.js +21 -3
  8. package/dist/browser/highs.wasm +0 -0
  9. package/dist/browser/highs.wasm.LICENSE +1 -2
  10. package/dist/browser/loader-DewlSho8.js +643 -0
  11. package/dist/browser/solvers/glpk.js +433 -286
  12. package/dist/browser/solvers/glpk.min.js +1 -1
  13. package/dist/browser/solvers/z3.js +1008 -981
  14. package/dist/browser/solvers/z3.min.js +2 -2
  15. package/dist/browser/washi.js +2778 -673
  16. package/dist/browser/washi.min.js +3 -4
  17. package/dist/lib/_washi-node-only-BvRk9kiK.js +0 -0
  18. package/dist/lib/highs-browser-runtime.js +2120 -4124
  19. package/dist/lib/highs-node-runtime.js +24 -1
  20. package/dist/lib/highs-runtime.js +2 -0
  21. package/dist/lib/highs-worker.js +21 -3
  22. package/dist/lib/highs.wasm +0 -0
  23. package/dist/lib/highs.wasm.LICENSE +1 -2
  24. package/dist/lib/loader-BZUQNvh4.js +649 -0
  25. package/dist/lib/registry-C20sxTwm.js +964 -0
  26. package/dist/lib/solvers/glpk.js +201 -90
  27. package/dist/lib/solvers/z3.js +399 -259
  28. package/dist/lib/washi.js +2363 -1056
  29. package/dist/types/decomposition/benders.d.ts +32 -0
  30. package/dist/types/decomposition/benders.d.ts.map +1 -0
  31. package/dist/types/decomposition/column-generation.d.ts +34 -0
  32. package/dist/types/decomposition/column-generation.d.ts.map +1 -0
  33. package/dist/types/decomposition/index.d.ts +4 -0
  34. package/dist/types/decomposition/index.d.ts.map +1 -0
  35. package/dist/types/decomposition/types.d.ts +230 -0
  36. package/dist/types/decomposition/types.d.ts.map +1 -0
  37. package/dist/types/index.d.ts +5 -4
  38. package/dist/types/index.d.ts.map +1 -1
  39. package/dist/types/modeler/big-m.d.ts +75 -0
  40. package/dist/types/modeler/big-m.d.ts.map +1 -0
  41. package/dist/types/modeler/boolean-expr.d.ts +103 -14
  42. package/dist/types/modeler/boolean-expr.d.ts.map +1 -1
  43. package/dist/types/modeler/constraint.d.ts +47 -9
  44. package/dist/types/modeler/constraint.d.ts.map +1 -1
  45. package/dist/types/modeler/expression.d.ts +123 -28
  46. package/dist/types/modeler/expression.d.ts.map +1 -1
  47. package/dist/types/modeler/index.d.ts +11 -6
  48. package/dist/types/modeler/index.d.ts.map +1 -1
  49. package/dist/types/modeler/linearizer.d.ts +15 -0
  50. package/dist/types/modeler/linearizer.d.ts.map +1 -0
  51. package/dist/types/modeler/lp-writer.d.ts +30 -3
  52. package/dist/types/modeler/lp-writer.d.ts.map +1 -1
  53. package/dist/types/modeler/model.d.ts +623 -131
  54. package/dist/types/modeler/model.d.ts.map +1 -1
  55. package/dist/types/modeler/objective.d.ts +59 -0
  56. package/dist/types/modeler/objective.d.ts.map +1 -0
  57. package/dist/types/modeler/parser.d.ts +34 -10
  58. package/dist/types/modeler/parser.d.ts.map +1 -1
  59. package/dist/types/modeler/quad-expr.d.ts +26 -7
  60. package/dist/types/modeler/quad-expr.d.ts.map +1 -1
  61. package/dist/types/modeler/solution-validator.d.ts +93 -0
  62. package/dist/types/modeler/solution-validator.d.ts.map +1 -0
  63. package/dist/types/modeler/solvers/glpk/solver.d.ts +26 -2
  64. package/dist/types/modeler/solvers/glpk/solver.d.ts.map +1 -1
  65. package/dist/types/modeler/solvers/highs/browser-runtime.d.ts +2 -1
  66. package/dist/types/modeler/solvers/highs/browser-runtime.d.ts.map +1 -1
  67. package/dist/types/modeler/solvers/highs/driver.d.ts +232 -0
  68. package/dist/types/modeler/solvers/highs/driver.d.ts.map +1 -0
  69. package/dist/types/modeler/solvers/highs/index.d.ts +1 -0
  70. package/dist/types/modeler/solvers/highs/index.d.ts.map +1 -1
  71. package/dist/types/modeler/solvers/highs/loader.d.ts +38 -13
  72. package/dist/types/modeler/solvers/highs/loader.d.ts.map +1 -1
  73. package/dist/types/modeler/solvers/highs/node-runtime.d.ts +2 -1
  74. package/dist/types/modeler/solvers/highs/node-runtime.d.ts.map +1 -1
  75. package/dist/types/modeler/solvers/highs/solver.d.ts +12 -5
  76. package/dist/types/modeler/solvers/highs/solver.d.ts.map +1 -1
  77. package/dist/types/modeler/solvers/highs/worker-client.d.ts.map +1 -1
  78. package/dist/types/modeler/solvers/mock.d.ts +14 -5
  79. package/dist/types/modeler/solvers/mock.d.ts.map +1 -1
  80. package/dist/types/modeler/solvers/types.d.ts +73 -11
  81. package/dist/types/modeler/solvers/types.d.ts.map +1 -1
  82. package/dist/types/modeler/solvers/z3/loader.d.ts +2 -3
  83. package/dist/types/modeler/solvers/z3/loader.d.ts.map +1 -1
  84. package/dist/types/modeler/solvers/z3/solver.d.ts +15 -5
  85. package/dist/types/modeler/solvers/z3/solver.d.ts.map +1 -1
  86. package/dist/types/modeler/types.d.ts +86 -1
  87. package/dist/types/modeler/types.d.ts.map +1 -1
  88. package/dist/types/modeler/validation.d.ts +56 -0
  89. package/dist/types/modeler/validation.d.ts.map +1 -0
  90. package/dist/types/modeler/variable.d.ts +48 -14
  91. package/dist/types/modeler/variable.d.ts.map +1 -1
  92. package/docs/examples/diet-sensitivity.md +90 -0
  93. package/docs/examples/ecommerce-coupons.md +106 -0
  94. package/docs/examples/index.md +57 -0
  95. package/docs/examples/knapsack.md +60 -0
  96. package/docs/examples/portfolio-qp.md +83 -0
  97. package/docs/examples/production.md +51 -0
  98. package/docs/examples/shift-scheduling.md +175 -0
  99. package/docs/examples/smt-security.md +74 -0
  100. package/docs/examples/transportation.md +90 -0
  101. package/docs/examples/traveling-salesperson.md +173 -0
  102. package/docs/examples/unsat-core.md +64 -0
  103. package/docs/examples/vehicle-routing.md +206 -0
  104. package/docs/getting-started/ai-agents.md +271 -0
  105. package/docs/getting-started/cross-origin.md +87 -0
  106. package/docs/getting-started/index.md +116 -0
  107. package/docs/getting-started/runtimes.md +227 -0
  108. package/docs/guide/constraints.md +177 -0
  109. package/docs/guide/decomposition.md +399 -0
  110. package/docs/guide/expressions.md +204 -0
  111. package/docs/guide/objectives.md +170 -0
  112. package/docs/guide/unsat-core.md +154 -0
  113. package/docs/guide/variables.md +188 -0
  114. package/docs/ja/getting-started/ai-agents.md +270 -0
  115. package/docs/solvers/custom-solver.md +525 -0
  116. package/docs/solvers/glpk.md +66 -0
  117. package/docs/solvers/highs.md +115 -0
  118. package/docs/solvers/index.md +42 -0
  119. package/docs/solvers/z3.md +78 -0
  120. package/docs/zh/getting-started/ai-agents.md +270 -0
  121. package/llms-full.txt +4065 -0
  122. package/llms.txt +201 -0
  123. package/package.json +32 -16
  124. package/skills/washi/SKILL.md +197 -0
  125. package/dist/browser/browser-runtime-D13gHOT5.js +0 -4189
  126. package/dist/browser/loader-CVt4CloI.js +0 -58
  127. package/dist/lib/async-mutex-Duo4jwzn.js +0 -195
  128. package/dist/lib/constraint-BRuB3ooC.js +0 -90
  129. package/dist/lib/loader-Dti0v9yC.js +0 -50
  130. package/dist/lib/registry-DksqCSjI.js +0 -32
@@ -1,6 +1,7 @@
1
- import type { Solver, SolverCapabilities, SolverOptions, SolverResult, SolverCheckResult } from "../types.js";
2
- import { resetZ3LoaderCache, killZ3Threads, unlockAllZ3Semaphores, notifyZ3WorkerError } from "./loader.js";
3
- export { resetZ3LoaderCache, killZ3Threads, unlockAllZ3Semaphores, notifyZ3WorkerError };
1
+ import type { CheckModelData, SolveModelData, Solver, SolverCapabilities, SolverOptions, SolverResult, SolverCheckResult } from "../types.js";
2
+ import { type LpExportResult, type LpModelData } from "../../lp-writer.js";
3
+ import { resetZ3LoaderCache, killZ3Threads, notifyZ3WorkerError } from "./loader.js";
4
+ export { resetZ3LoaderCache, killZ3Threads, notifyZ3WorkerError };
4
5
  /**
5
6
  * Z3 SMT / SAT / MIP Solver Adapter
6
7
  *
@@ -9,6 +10,12 @@ export { resetZ3LoaderCache, killZ3Threads, unlockAllZ3Semaphores, notifyZ3Worke
9
10
  * - Feasibility checking via check()
10
11
  * - Unsatisfiable core extraction (unsatCore) for conflict diagnosis
11
12
  * - Mixed-Integer Programming (MIP) optimization via Z3 Optimize
13
+ *
14
+ * Solution metrics provided by Z3:
15
+ * - `status` and `terminationStatus`: `"Optimal" | "Infeasible" | "Error"`
16
+ * - `hasPrimalSolution`: `true` when Z3 returns `"sat"` (`status === "Optimal"`), `false` otherwise.
17
+ * - `objectiveValue`: Primal objective value when `hasPrimalSolution` is `true`, otherwise `null`.
18
+ * - `objectiveBound`, `relGap` (`mipGap`), `absGap`: Z3 Optimize is an SMT optimization engine and does not expose branch-and-bound MIP dual bounds or relative/absolute MIP gaps, so these fields are intentionally left `undefined` rather than returning invented defaults.
12
19
  */
13
20
  export declare class Z3Solver implements Solver {
14
21
  readonly name = "z3";
@@ -17,15 +24,18 @@ export declare class Z3Solver implements Solver {
17
24
  * Helper to build AST translations for a given Z3 Context
18
25
  */
19
26
  private createContextTranslator;
27
+ private addVariableBounds;
28
+ private runZ3CheckWithErrorGuard;
20
29
  /**
21
30
  * Check feasibility & propositional satisfaction without an objective function.
22
31
  * Tracks constraints to return an unsatCore if infeasible.
23
32
  */
24
- check(modelData: any, options?: SolverOptions): Promise<SolverCheckResult>;
33
+ check(modelData: CheckModelData, options?: SolverOptions): Promise<SolverCheckResult>;
25
34
  /**
26
35
  * Solve optimization problem (MIP) or feasibility problem
27
36
  */
28
- solve(modelData: any, _lpResult: any, options?: SolverOptions): Promise<SolverResult>;
37
+ solve(modelData: SolveModelData, options?: SolverOptions): Promise<SolverResult>;
38
+ solve(modelData: LpModelData, lpResult: LpExportResult, options?: SolverOptions): Promise<SolverResult>;
29
39
  }
30
40
  /**
31
41
  * Register Z3 solver into global solver registry
@@ -1 +1 @@
1
- {"version":3,"file":"solver.d.ts","sourceRoot":"","sources":["../../../../../src/modeler/solvers/z3/solver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,MAAM,EACN,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,iBAAiB,EAClB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAU,kBAAkB,EAAE,aAAa,EAA0B,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAE5I,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,CAAC;AAEzF;;;;;;;;GAQG;AACH,qBAAa,QAAS,YAAW,MAAM;IACrC,QAAQ,CAAC,IAAI,QAAQ;IACrB,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAKvC;IAEF;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAyM/B;;;OAGG;IACG,KAAK,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAgGnF;IAED;;OAEG;IACG,KAAK,CACT,SAAS,EAAE,GAAG,EACd,SAAS,EAAE,GAAG,EACd,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CA4HvB;CACF;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
1
+ {"version":3,"file":"solver.d.ts","sourceRoot":"","sources":["../../../../../src/modeler/solvers/z3/solver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,MAAM,EACN,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,iBAAiB,EAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,WAAW,EACjB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAU,kBAAkB,EAAE,aAAa,EAA0B,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAErH,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,mBAAmB,EAAE,CAAC;AAWlE;;;;;;;;;;;;;;GAcG;AACH,qBAAa,QAAS,YAAW,MAAM;IACrC,QAAQ,CAAC,IAAI,QAAQ;IACrB,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAMvC;IAEF;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgO/B,OAAO,CAAC,iBAAiB;YAqBX,wBAAwB;IAgBtC;;;OAGG;IACG,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA2G9F;IAED;;OAEG;IACG,KAAK,CAAC,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACjF,KAAK,CACT,SAAS,EAAE,WAAW,EACtB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,YAAY,CAAC,CAAC;CAkR1B;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -1,14 +1,41 @@
1
+ import type { Constraint } from "./constraint.js";
1
2
  /**
2
3
  * HiGHS & Model Types
3
4
  */
4
5
  export type VarType = "Continuous" | "Integer" | "Binary" | "continuous" | "integer" | "binary" | "cont" | "int" | "bin";
5
6
  export type OptimizationSense = "Minimize" | "Maximize" | "minimize" | "maximize";
6
7
  /**
7
- * Normalizes user-facing optimization sense to internal canonical form ("Maximize" | "Minimize")
8
+ * Normalizes user-facing optimization sense to internal canonical form ("Maximize" | "Minimize").
9
+ * Throws a descriptive error if an invalid sense string is provided at runtime.
8
10
  */
9
11
  export declare function normalizeSense(sense?: OptimizationSense): "Maximize" | "Minimize";
10
12
  export type ComparisonSense = "<=" | ">=" | "==";
11
13
  export type SolverStatus = "Optimal" | "Feasible" | "Infeasible" | "Unbounded" | "TimeLimit" | "IterationLimit" | "Error" | "NotSolved" | "Sat" | "Unsat" | "Unknown";
14
+ export type TerminationStatus = "Optimal" | "Feasible" | "Infeasible" | "Unbounded" | "InfeasibleOrUnbounded" | "TimeLimit" | "IterationLimit" | "SolutionLimit" | "MemoryLimit" | "ObjectiveBound" | "ObjectiveTarget" | "Interrupted" | "Error" | "NotSolved" | "Sat" | "Unsat" | "Unknown";
15
+ export interface SolveProgressEvent {
16
+ /** Elapsed solver time in seconds */
17
+ elapsedTime: number;
18
+ /** Alias for elapsedTime: elapsed solver time in seconds */
19
+ elapsedSeconds?: number;
20
+ /** Current solver phase when known */
21
+ phase?: "simplex" | "ipm" | "mip";
22
+ /** Best feasible incumbent objective value when available */
23
+ objectiveValue?: number;
24
+ /** Best proven dual / objective bound when available */
25
+ objectiveBound?: number;
26
+ /** Relative MIP optimality gap when available */
27
+ relGap?: number;
28
+ /** Alias for relGap: relative MIP optimality gap when available */
29
+ mipGap?: number;
30
+ /** Absolute MIP optimality gap |objectiveValue - objectiveBound| when available */
31
+ absGap?: number;
32
+ /** Explored MIP branch-and-bound node count when available */
33
+ nodes?: number;
34
+ /** Solver iteration count (simplex, IPM, or MIP LP iterations) when available */
35
+ iterations?: number;
36
+ /** Optional raw progress message from the solver */
37
+ message?: string;
38
+ }
12
39
  export interface SolveOptions {
13
40
  timeLimit?: number;
14
41
  outputFlag?: boolean;
@@ -17,11 +44,37 @@ export interface SolveOptions {
17
44
  relGap?: number;
18
45
  absGap?: number;
19
46
  wasmUrl?: string;
47
+ /**
48
+ * AbortSignal to cancel a solve:
49
+ * - Pre-solve cancellation (`signal.aborted` before execution starts) is supported by all solvers.
50
+ * - Preemptive mid-solve cancellation is supported in browser HiGHS via Web Worker termination
51
+ * (and cancels queued Worker requests before they are dispatched).
52
+ * - Main-thread (Node.js) HiGHS supports cooperative mid-solve cancellation when `abort()` is
53
+ * triggered synchronously inside an `onProgress` callback at a solver interrupt checkpoint.
54
+ * - Single-threaded WASM solvers without interrupt hooks (GLPK, Z3) check `signal` before execution starts.
55
+ */
56
+ signal?: AbortSignal;
57
+ /** Callback invoked with real solver progress metrics when available */
58
+ onProgress?: (progress: SolveProgressEvent) => void;
59
+ /** Solve the continuous (LP) relaxation of the model by relaxing integer and binary variables */
60
+ relax?: boolean;
20
61
  [key: string]: any;
21
62
  }
22
63
  export interface SolverSolution {
23
64
  status: SolverStatus;
65
+ /** Exact termination reason independent of whether a feasible incumbent is available */
66
+ terminationStatus: TerminationStatus;
67
+ /** Whether a feasible primal solution / incumbent is available */
68
+ hasPrimalSolution: boolean;
24
69
  objectiveValue: number | null;
70
+ /** Best proven dual/objective bound when provided by the solver */
71
+ objectiveBound?: number;
72
+ /** Relative MIP optimality gap when provided by the solver */
73
+ relGap?: number;
74
+ /** Alias for relGap: relative MIP optimality gap when provided by the solver */
75
+ mipGap?: number;
76
+ /** Absolute MIP optimality gap |objectiveValue - objectiveBound| when provided by the solver */
77
+ absGap?: number;
25
78
  values: Record<string, number>;
26
79
  duals: Record<string, number>;
27
80
  reducedCosts: Record<string, number>;
@@ -29,4 +82,36 @@ export interface SolverSolution {
29
82
  runTime: number;
30
83
  raw?: any;
31
84
  }
85
+ export interface CheckResult {
86
+ status: "Sat" | "Unsat" | "Unknown";
87
+ values: Record<string, number | boolean>;
88
+ unsatCore?: readonly string[];
89
+ /** Alias for unsatCore: subset of conflicting constraints causing infeasibility */
90
+ conflicts?: readonly string[];
91
+ runTime?: number;
92
+ }
93
+ /**
94
+ * Definition for dynamically adding a column (decision variable + constraint coefficients + objective cost).
95
+ * Core primitive for Column Generation and Dantzig-Wolfe decomposition.
96
+ */
97
+ export interface ColumnDefinition {
98
+ name?: string;
99
+ type?: VarType;
100
+ lb?: number;
101
+ ub?: number;
102
+ /** Objective cost coefficient */
103
+ cost?: number;
104
+ /**
105
+ * Constraint coefficients for this column.
106
+ * Accepts:
107
+ * - Record<string, number> (keyed by constraint name)
108
+ * - Map<Constraint | string, number>
109
+ * - Array<[Constraint | string, number]>
110
+ * - Array<{ constraint: Constraint | string; coeff: number }>
111
+ */
112
+ coefficients?: Record<string, number> | Map<Constraint | string, number> | Array<[Constraint | string, number]> | Array<{
113
+ constraint: Constraint | string;
114
+ coeff: number;
115
+ }>;
116
+ }
32
117
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modeler/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,OAAO,GACf,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,YAAY,GACZ,SAAS,GACT,QAAQ,GACR,MAAM,GACN,KAAK,GACL,KAAK,CAAC;AAEV,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,UAAU,GACV,UAAU,GACV,UAAU,CAAC;AAEf;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,iBAAiB,GAAG,UAAU,GAAG,UAAU,CAGjF;AAGD,MAAM,MAAM,eAAe,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEjD,MAAM,MAAM,YAAY,GACpB,SAAS,GACT,UAAU,GACV,YAAY,GACZ,WAAW,GACX,WAAW,GACX,gBAAgB,GAChB,OAAO,GACP,WAAW,GACX,KAAK,GACL,OAAO,GACP,SAAS,CAAC;AAEd,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,QAAQ,CAAC;IACnC,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,YAAY,CAAC;IACrB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,GAAG,CAAC;CACX"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/modeler/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import type { Model } from "./model.js";
2
+ import { Var } from "./variable.js";
3
+ import { BoolVar, type LogicElement } from "./boolean-expr.js";
4
+ import { Constraint } from "./constraint.js";
5
+ import { LinExpr } from "./expression.js";
6
+ import { QuadExpr } from "./quad-expr.js";
7
+ /**
8
+ * Recursively attaches ownerModel mutation tracking to any Constraint nodes embedded in a logical expression.
9
+ */
10
+ export declare function attachLogicElementOwnership(elem: LogicElement, model: Model, undoActions?: (() => void)[]): void;
11
+ /**
12
+ * Associates a variable instance with its owning model and rejects cross-model sharing.
13
+ */
14
+ export declare function claimVarOwnership(v: Var, model: Model): void;
15
+ /**
16
+ * Associates a constraint instance with its owning model and rejects reusing or cross-model sharing.
17
+ */
18
+ export declare function claimConstraintOwnership(c: Constraint, model: Model): Model | undefined;
19
+ /**
20
+ * Releases variable ownership when rolling back a failed batch operation.
21
+ */
22
+ export declare function releaseVarOwnership(v: Var, model: Model): void;
23
+ /**
24
+ * Releases constraint ownership when rolling back a failed batch operation.
25
+ */
26
+ export declare function releaseConstraintOwnership(c: Constraint, model: Model, previousOwner?: Model): void;
27
+ /**
28
+ * Numerical tolerance used when validating variable initial values against bounds and integrality.
29
+ */
30
+ export declare const INITIAL_VALUE_TOLERANCE = 0.000001;
31
+ /**
32
+ * Validates lower and upper bounds (and optional primal initialValue) of a single variable.
33
+ */
34
+ export declare function validateVarBounds(v: Var): void;
35
+ /**
36
+ * Validates and normalizes a variable's optional primal initialValue for solver consumption.
37
+ * Rounds near-integer values for Integer/Binary variables and clamps near-bound values for Continuous variables.
38
+ */
39
+ export declare function normalizeVarInitialValue(v: Var): number | undefined;
40
+ /**
41
+ * Validates objective expression constants, coefficients, and variable ownership.
42
+ */
43
+ export declare function validateObjectiveExpr(expr: LinExpr | QuadExpr, modelName: string, isOwnedVar: (v: Var) => boolean): void;
44
+ /**
45
+ * Validates a linear constraint's RHS, LHS constant, coefficients, and variable ownership.
46
+ */
47
+ export declare function validateLinearConstraint(c: Constraint, modelName: string, isOwnedVar: (v: Var) => boolean, constrName?: string): void;
48
+ /**
49
+ * Validates a logical constraint element recursively.
50
+ */
51
+ export declare function validateLogicElement(elem: LogicElement, lcName: string, modelName: string, isOwnedVar: (v: Var) => boolean, isOwnedBoolVar: (bv: BoolVar) => boolean, ownerModel?: Model): void;
52
+ /**
53
+ * Validates the structural and numerical integrity of an optimization model.
54
+ */
55
+ export declare function validateModelIntegrity(model: Model): void;
56
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../src/modeler/validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM1C;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,KAAK,EACZ,WAAW,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,GAC3B,IAAI,CAuBN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAQ5D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,KAAK,GAAG,SAAS,CAkBvF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,CAI9D;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,CAAC,EAAE,UAAU,EACb,KAAK,EAAE,KAAK,EACZ,aAAa,CAAC,EAAE,KAAK,GACpB,IAAI,CAWN;AAED;;GAEG;AACH,eAAO,MAAM,uBAAuB,WAAO,CAAC;AAE5C;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAwD9C;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAWnE;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,GAAG,QAAQ,EACxB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO,GAC9B,IAAI,CAuDN;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,CAAC,EAAE,UAAU,EACb,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO,EAC/B,UAAU,SAAS,GAClB,IAAI,CAuBN;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,OAAO,EAC/B,cAAc,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,OAAO,EACxC,UAAU,CAAC,EAAE,KAAK,GACjB,IAAI,CA2CN;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAiGzD"}
@@ -8,46 +8,80 @@ export interface VarOptions {
8
8
  type?: VarType;
9
9
  lb?: number;
10
10
  ub?: number;
11
+ /**
12
+ * Optional finite primal initial value (MIP start / warm-start hint), distinct from solved `Var.value`.
13
+ * Validated within tolerance `1e-6` against `[lb, ub]` and integer/binary domains.
14
+ * Supported by HiGHS (`supportsWarmStart: true`); throws on solvers without warm-start support (GLPK, Z3).
15
+ */
16
+ initialValue?: number;
11
17
  }
12
18
  /**
13
- * Represents a decision variable in an optimization problem.
19
+ * Represents a numeric decision variable (`"Continuous"`, `"Integer"`, or `"Binary"`) in an optimization model.
20
+ * Typically created and registered via `m.continuous(...)`, `m.integer(...)`, or `m.binary(...)`.
21
+ *
22
+ * @example
23
+ * ```ts
24
+ * const m = new Model("VarExample");
25
+ * const x = m.continuous("x", { lb: 0, ub: 100 });
26
+ * const y = m.integer("y", { lb: 0, ub: 10, initialValue: 5 });
27
+ * m.objective(maximize(x.mul(2).add(y.mul(5))));
28
+ * m.constraint(x.add(y).le(50));
29
+ * ```
14
30
  */
15
31
  export declare class Var {
16
32
  readonly id: number;
17
- readonly name: string;
18
- type: "Continuous" | "Integer" | "Binary";
19
- lb: number;
20
- ub: number;
33
+ private _name;
34
+ readonly prefix: string;
35
+ hasExplicitName: boolean;
36
+ ownerModel: {
37
+ notifyMutation?: () => void;
38
+ } | null;
39
+ private _type;
40
+ private _lb;
41
+ private _ub;
42
+ private _initialValue;
21
43
  /** Optimal primal value after solve */
22
44
  value: number | null;
23
45
  /** Reduced cost from dual solution */
24
46
  reducedCost: number | null;
25
47
  constructor(options?: VarOptions);
48
+ get name(): string;
49
+ get type(): "Continuous" | "Integer" | "Binary";
50
+ set type(val: VarType);
51
+ get lb(): number;
52
+ set lb(val: number);
53
+ get ub(): number;
54
+ set ub(val: number);
55
+ /**
56
+ * Optional finite primal initial value (MIP start / warm-start hint), distinct from solved `Var.value`.
57
+ * Supported by HiGHS (`supportsWarmStart: true`); throws on solvers without warm-start support (GLPK, Z3).
58
+ */
59
+ get initialValue(): number | undefined;
60
+ set initialValue(val: number | undefined);
61
+ /** @internal Assigns a model-scoped name when registering an unnamed Var via Model.add() */
62
+ _assignModelName(name: string): void;
26
63
  /** Multiply variable by a scalar coefficient or another variable/expression */
27
64
  mul(coeff: number): LinExpr;
28
65
  mul(other: Var): QuadExpr;
29
66
  mul(other: LinExpr): QuadExpr;
30
67
  mul(other: QuadExpr): QuadExpr;
31
- mul(other: number | Var | LinExpr | QuadExpr): LinExpr | QuadExpr;
68
+ mul(other: number | Var | LinExpr | QuadExpr | Constraint): LinExpr | QuadExpr;
32
69
  /** Add variable with another variable, linear/quadratic expression, or number */
33
70
  add(other: QuadExpr): QuadExpr;
34
71
  add(other: Var | LinExpr | number): LinExpr;
35
- add(other: Var | LinExpr | QuadExpr | number): LinExpr | QuadExpr;
72
+ add(other: Var | LinExpr | QuadExpr | number | Constraint): LinExpr | QuadExpr;
36
73
  /** Subtract another variable, linear/quadratic expression, or number from this variable */
37
74
  sub(other: QuadExpr): QuadExpr;
38
75
  sub(other: Var | LinExpr | number): LinExpr;
39
- sub(other: Var | LinExpr | QuadExpr | number): LinExpr | QuadExpr;
76
+ sub(other: Var | LinExpr | QuadExpr | number | Constraint): LinExpr | QuadExpr;
40
77
  /** Negate this variable: -x */
41
78
  neg(): LinExpr;
42
79
  /** Create a less-than-or-equal constraint: this <= rhs */
43
- le(rhs: number | Var | LinExpr, name?: string): Constraint;
44
- lessThanOrEqual(rhs: number | Var | LinExpr, name?: string): Constraint;
80
+ le(rhs: number | Var | LinExpr | QuadExpr | Constraint, name?: string): Constraint;
45
81
  /** Create a greater-than-or-equal constraint: this >= rhs */
46
- ge(rhs: number | Var | LinExpr, name?: string): Constraint;
47
- greaterThanOrEqual(rhs: number | Var | LinExpr, name?: string): Constraint;
82
+ ge(rhs: number | Var | LinExpr | QuadExpr | Constraint, name?: string): Constraint;
48
83
  /** Create an equality constraint: this == rhs */
49
- eq(rhs: number | Var | LinExpr, name?: string): Constraint;
50
- equalTo(rhs: number | Var | LinExpr, name?: string): Constraint;
84
+ eq(rhs: number | Var | LinExpr | QuadExpr | Constraint, name?: string): Constraint;
51
85
  toString(): string;
52
86
  }
53
87
  //# sourceMappingURL=variable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"variable.d.ts","sourceRoot":"","sources":["../../../src/modeler/variable.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"variable.d.ts","sourceRoot":"","sources":["../../../src/modeler/variable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ # Diet Problem & Sensitivity Analysis (LP Duals & Slacks)
2
+
3
+ | Problem Class | Solver | Key APIs | Links |
4
+ | :--- | :--- | :--- | :--- |
5
+ | Linear Programming (LP) | HiGHS (default) | `m.continuous()`, `m.constraint()`, `expr`, `minimize`, `dot` | <ul><li><a href="https://ohtaman.github.io/washi/demo/?preset=diet_sensitivity">Open in Playground</a></li><li><a href="https://github.com/ohtaman/washi/blob/main/examples/node/10-diet-sensitivity.ts">Source Code</a></li></ul> |
6
+
7
+ When solving a Linear Programming model, the optimal variable values (`var.value`) are only half the story. In practice, decision-makers need to know:
8
+
9
+ 1. **Bottlenecks (`constr.dual` — Shadow Price):** Which minimum requirements are actively driving up the total cost, and by how much per unit?
10
+ 2. **Surpluses (`constr.slack`):** Which constraints have room to spare?
11
+ 3. **Reduced Costs (`var.reducedCost`):** For items not selected in the optimal plan, how much cheaper would they need to become before entering the solution?
12
+
13
+ ## Problem Inputs
14
+
15
+ We choose daily servings ($0 \le x_i \le 4$) among 6 food items to meet 4 daily nutritional minimums (`Calories >= 2000 kcal`, `Protein >= 105 g`, `Calcium >= 1000 mg`, `Iron >= 18 mg`) at minimum cost:
16
+
17
+ | Food Item | Cost / Serving | Calories (kcal) | Protein (g) | Calcium (mg) | Iron (mg) | Max Servings |
18
+ | :--- | :---: | :---: | :---: | :---: | :---: | :---: |
19
+ | **Oats** | $0.60 | 150 | 5 | 20 | 1.8 | 4.0 |
20
+ | **Chicken** | $2.40 | 220 | 32 | 15 | 1.2 | 4.0 |
21
+ | **Eggs** | $0.80 | 140 | 12 | 50 | 1.7 | 4.0 |
22
+ | **Milk** | $0.90 | 120 | 8 | 280 | 0.1 | 4.0 |
23
+ | **Spinach** | $1.50 | 40 | 4 | 120 | 3.5 | 4.0 |
24
+ | **Salmon** | $3.60 | 200 | 25 | 20 | 0.8 | 4.0 |
25
+
26
+ ## Implementation in WaSHI
27
+
28
+ <CodeRunner preset="diet_sensitivity">
29
+
30
+ ```typescript
31
+ import { Model, minimize, dot, expr } from "@ohtaman/washi";
32
+
33
+ const foods = [
34
+ { name: "Oats", cost: 0.60, calories: 150, protein: 5, calcium: 20, iron: 1.8 },
35
+ { name: "Chicken", cost: 2.40, calories: 220, protein: 32, calcium: 15, iron: 1.2 },
36
+ { name: "Eggs", cost: 0.80, calories: 140, protein: 12, calcium: 50, iron: 1.7 },
37
+ { name: "Milk", cost: 0.90, calories: 120, protein: 8, calcium: 280, iron: 0.1 },
38
+ { name: "Spinach", cost: 1.50, calories: 40, protein: 4, calcium: 120, iron: 3.5 },
39
+ { name: "Salmon", cost: 3.60, calories: 200, protein: 25, calcium: 20, iron: 0.8 },
40
+ ];
41
+
42
+ async function runDietSensitivity() {
43
+ const m = new Model("DietSensitivity");
44
+
45
+ // Continuous servings per day (0 to 4 servings max per food)
46
+ const srv = m.continuous(foods.map((f) => f.name), { lb: 0, ub: 4 });
47
+
48
+ const costs = Object.fromEntries(foods.map((f) => [f.name, f.cost]));
49
+ const cals = Object.fromEntries(foods.map((f) => [f.name, f.calories]));
50
+ const prots = Object.fromEntries(foods.map((f) => [f.name, f.protein]));
51
+ const calcs = Object.fromEntries(foods.map((f) => [f.name, f.calcium]));
52
+ const irons = Object.fromEntries(foods.map((f) => [f.name, f.iron]));
53
+
54
+ // Objective: Minimize total daily cost via dot product
55
+ m.objective(minimize(dot(costs, srv)));
56
+
57
+ // Nutritional constraints defined declaratively with expr and constraint()
58
+ m.constraint(expr`${dot(cals, srv)} >= 2000`, "min_calories")
59
+ .constraint(expr`${dot(prots, srv)} >= 105`, "min_protein")
60
+ .constraint(expr`${dot(calcs, srv)} >= 1000`, "min_calcium")
61
+ .constraint(expr`${dot(irons, srv)} >= 18`, "min_iron");
62
+
63
+ const status = await m.solve();
64
+
65
+ console.log(`Status: ${status}, Minimum Daily Cost: $${m.objectiveValue?.toFixed(2)}`);
66
+ console.log("--- Food Servings & Reduced Costs ---");
67
+ for (const f of foods) {
68
+ const v = srv[f.name];
69
+ console.log(` ${f.name.padEnd(8)}: value=${v.value?.toFixed(2)}, reducedCost=${v.reducedCost?.toFixed(4)}`);
70
+ }
71
+ console.log("--- Nutritional Constraints (Dual & Slack) ---");
72
+ for (const name of ["min_calories", "min_protein", "min_calcium", "min_iron"]) {
73
+ const c = m.getConstraintByName(name);
74
+ if (c) {
75
+ console.log(` ${c.name.padEnd(13)}: dual=$${c.dual?.toFixed(4)}, slack=${Math.abs(c.slack ?? 0).toFixed(2)}`);
76
+ }
77
+ }
78
+ }
79
+
80
+ runDietSensitivity();
81
+ ```
82
+
83
+ </CodeRunner>
84
+
85
+ ## Interpretation of Results
86
+
87
+ - **Bottleneck constraints (`slack == 0`, `dual > 0`):** Calories (`2000 kcal`) and Iron (`18 mg`) are tight at their lower bounds. Increasing the daily Iron requirement by 1 mg increases the minimum daily diet cost by **$0.3241**.
88
+ - **Constraints with surplus (`slack > 0`, `dual == 0`):** Protein (`+46.46 g` surplus) and Calcium (`+483.02 mg` surplus) are already exceeded with room to spare, so their shadow prices are `$0`.
89
+ - **Reduced cost (`Salmon`):** Unselected `Salmon` (`0.00` servings) has a reduced cost of `+1.5125`, meaning its price per serving would need to drop by at least **$1.51** before it enters the optimal daily menu.
90
+
@@ -0,0 +1,106 @@
1
+ # E-Commerce Cart & Coupon Optimizer (Indicator MIP)
2
+
3
+ | Problem Class | Solver | Key APIs | Links |
4
+ | :--- | :--- | :--- | :--- |
5
+ | Mixed-Integer Programming (MIP) | HiGHS (default) | `m.binary()`, `m.constraint()`, `m.indicator()`, `expr`, `minimize` | <ul><li><a href="https://ohtaman.github.io/washi/demo/?preset=cart_coupon">Open in Playground</a></li><li><a href="https://github.com/ohtaman/washi/blob/main/examples/node/12-ecommerce-coupon-optimizer.ts">Source Code</a></li></ul> |
6
+
7
+ Modern e-commerce checkouts often feature complex promotional rules: minimum spend thresholds, category-specific discounts, stackable vs. mutually exclusive coupons, and maximum coupon limits per order. Running an optimizer directly in the browser (or an edge worker) lets the checkout UI automatically apply the best coupon combination—and even recommend a small "filler" item when crossing a spend threshold lowers the customer's net bill.
8
+
9
+ This example demonstrates **`m.indicator(binVar, constraint, { activeValue, M? })`**, which automatically linearizes conditional *"if coupon is selected, minimum spend must hold"* constraints using Big-M reformulation for MIP solvers like HiGHS. When `M` is omitted, WaSHI automatically derives safe, tight Big-M values from finite variable bounds.
10
+
11
+ <EcommerceCouponDemo />
12
+
13
+ ## Scenario & Promotion Rules
14
+
15
+ A customer's shopping cart currently contains **$242** of merchandise (**$210** in Tech items and **$32** in Apparel):
16
+ - **Optional Filler Add-on:** A **$10** Braided USB-C Cable (Tech) can be added to bring the cart total from `$242` to `$252`.
17
+ - **Available Coupons** (maximum **2 coupons** total per checkout; at most **1 Exclusive** coupon):
18
+
19
+ | Coupon Code | Discount | Condition | Stacking Rule |
20
+ | :--- | :---: | :--- | :--- |
21
+ | `WELCOME15` | **-$15** | Total cart spend $\ge \$100$ | **Stackable** |
22
+ | `TECH30` | **-$30** | Tech category spend $\ge \$200$ | **Exclusive** (cannot combine with `MEGA45_250`) |
23
+ | `MEGA45_250` | **-$45** | Total cart spend $\ge \$250$ | **Exclusive** (cannot combine with `TECH30`) |
24
+ | `MEMBER10` | **-$10** | Total cart spend $\ge \$150$ | **Stackable** |
25
+
26
+ Without adding the `$10` cable, the cart (`$242`) cannot use `MEGA45_250` and pays `$242 - $30 (TECH30) - $15 (WELCOME15) = $197`.
27
+ By adding the `$10` cable (`$252` gross), the customer unlocks `MEGA45_250` (`-$45`) + `WELCOME15` (`-$15`) for a net total of **$192**—saving an extra **$5** while getting an extra item!
28
+
29
+ ## Implementation in WaSHI
30
+
31
+ <CodeRunner preset="cart_coupon">
32
+
33
+ ```typescript
34
+ import { Model, sum, minimize, expr } from "@ohtaman/washi";
35
+
36
+ async function optimizeCheckoutCart() {
37
+ const m = new Model("CartCouponOptimizer");
38
+
39
+ const baseCartSubtotal = 242;
40
+ const baseTechSubtotal = 210;
41
+
42
+ // Binary decision: add optional $10 USB-C cable to unlock $250 tier?
43
+ const addUsbCable = m.binary("addon_USB_Cable");
44
+ const usbCablePrice = 10;
45
+
46
+ const coupons = [
47
+ { id: "WELCOME15", discount: 15, minCart: 100, minTech: 0, stackable: true },
48
+ { id: "TECH30", discount: 30, minCart: 0, minTech: 200, stackable: false },
49
+ { id: "MEGA45_250", discount: 45, minCart: 250, minTech: 0, stackable: false },
50
+ { id: "MEMBER10", discount: 10, minCart: 150, minTech: 0, stackable: true },
51
+ ];
52
+
53
+ // Binary decision variables for each coupon
54
+ const useCoupon = m.binary(coupons.map((c) => c.id));
55
+
56
+ const merchSpend = addUsbCable.mul(usbCablePrice).add(baseCartSubtotal);
57
+ const techSpend = addUsbCable.mul(usbCablePrice).add(baseTechSubtotal);
58
+
59
+ // 1. Indicator constraints: If useCoupon[id] == 1, minimum spend threshold must hold
60
+ for (const cpn of coupons) {
61
+ if (cpn.minCart > 0) {
62
+ m.indicator(useCoupon[cpn.id], merchSpend.ge(cpn.minCart), {
63
+ activeValue: 1,
64
+ M: 500,
65
+ name: `min_spend_${cpn.id}`,
66
+ });
67
+ }
68
+ if (cpn.minTech > 0) {
69
+ m.indicator(useCoupon[cpn.id], techSpend.ge(cpn.minTech), {
70
+ activeValue: 1,
71
+ M: 500,
72
+ name: `min_tech_${cpn.id}`,
73
+ });
74
+ }
75
+ }
76
+
77
+ // 2. Mutual exclusion among non-stackable ("Exclusive") coupons
78
+ const exclusiveCoupons = coupons.filter((c) => !c.stackable);
79
+ m.constraint(
80
+ expr`${sum(exclusiveCoupons, (c) => useCoupon[c.id])} <= 1`,
81
+ "at_most_one_exclusive"
82
+ );
83
+
84
+ // 3. Max 2 coupons per order
85
+ m.constraint(
86
+ expr`${sum(coupons, (c) => useCoupon[c.id])} <= 2`,
87
+ "max_two_coupons"
88
+ );
89
+
90
+ // Objective: Minimize final net payable amount (merchSpend - totalDiscounts)
91
+ const totalDiscount = sum(coupons, (c) => useCoupon[c.id].mul(c.discount));
92
+ m.objective(minimize(merchSpend.sub(totalDiscount)));
93
+
94
+ const status = await m.solve();
95
+ console.log(`Status: ${status}, Optimal Net Payable: $${m.objectiveValue}`);
96
+ console.log(`Recommended Add-on (+$10 USB-C Cable): ${(addUsbCable.value ?? 0) > 0.5 ? "YES" : "NO"}`);
97
+ for (const cpn of coupons) {
98
+ const applied = (useCoupon[cpn.id].value ?? 0) > 0.5;
99
+ console.log(` ${applied ? "✅ [APPLIED]" : " [skipped]"} ${cpn.id.padEnd(11)} (-$${cpn.discount})`);
100
+ }
101
+ }
102
+
103
+ optimizeCheckoutCart();
104
+ ```
105
+
106
+ </CodeRunner>
@@ -0,0 +1,57 @@
1
+ # Examples & API Finder
2
+
3
+ Explore runnable optimization and logic formulations built with WaSHI. Every example can be executed directly inside its documentation page, or edited in the [Playground](https://ohtaman.github.io/washi/demo/).
4
+
5
+ ## Examples
6
+
7
+ | Example | Problem Class | Solver | Key WaSHI APIs | Description | Code Editor |
8
+ | :--- | :--- | :--- | :--- | :--- | :--- |
9
+ | **[Production Planning](./production.md)** | LP / MIP | HiGHS | `m.integer()`, `m.constraint()`, `expr` | Basic variables, tagged template literal equations, and maximizing profit under resource limits. | [Playground](https://ohtaman.github.io/washi/demo/?preset=production) |
10
+ | **[0-1 Knapsack](./knapsack.md)** | Binary MIP | HiGHS | `m.binary(keys)`, `sum()`, `m.constraint()` | 1D dictionary of `Binary` variables and linear aggregation over item arrays. | [Playground](https://ohtaman.github.io/washi/demo/?preset=knapsack) |
11
+ | **[Transportation Network](./transportation.md)** | LP | HiGHS | `m.continuous(rows, cols)`, `dot()`, `m.constraint()` | 2D matrix indexing (`ship[factory][store]`) and row/column flow balance constraints. | [Playground](https://ohtaman.github.io/washi/demo/?preset=transportation) |
12
+ | **[Diet & Sensitivity Analysis](./diet-sensitivity.md)** | LP | HiGHS | `constr.dual`, `constr.slack`, `var.reducedCost` | Reading shadow prices (bottlenecks), constraint surpluses, and reduced costs after solving. | [Playground](https://ohtaman.github.io/washi/demo/?preset=diet_sensitivity) |
13
+ | **[Staff Shift Scheduling](./shift-scheduling.md)** | Binary MIP + Unsat Core | HiGHS + Z3 | `m.binary(staff, days)`, `check()`, `unsatCore` | 5×7 weekly roster planner (coverage, senior duty, max shifts, day-off requests) and diagnosing conflicting vacation requests with Z3 `unsatCore`. | [Playground](https://ohtaman.github.io/washi/demo/?preset=shift_scheduling) |
14
+ | **[E-Commerce Coupon Optimizer](./ecommerce-coupons.md)** | Indicator MIP | HiGHS | `m.indicator()`, `sum()`, `m.constraint()` | Checkout optimizer using `m.indicator()` for minimum spend thresholds, exclusive vs. stackable rules, and smart filler add-on suggestions. | [Playground](https://ohtaman.github.io/washi/demo/?preset=cart_coupon) |
15
+ | **[Portfolio Optimization](./portfolio-qp.md)** | Convex QP | HiGHS | `m.continuous()`, `m.constraint()`, `dot()`, `QuadExpr` | Markowitz mean-variance risk minimization ($w^T \Sigma w$) using `QuadExpr` subject to return targets. | [Playground](https://ohtaman.github.io/washi/demo/?preset=portfolio_qp) |
16
+ | **[SMT Security Policies](./smt-security.md)** | SMT Logic | Z3 | `m.bool()`, `m.constraint()`, `m.check()` | Propositional variables (`BoolVar`) and logical connectives (`implies`, `and`, `not`, `xor`) mixed with integer bounds. | [Playground](https://ohtaman.github.io/washi/demo/?preset=smt_sat_scheduling) |
17
+ | **[Conflict Diagnosis (`unsatCore`)](./unsat-core.md)** | Unsat Core | Z3 | `m.constraint()`, `m.check()`, `m.unsatCore` | Extracting a conflicting constraint subset (`unsatCore`) when staffing and budget rules contradict each other. | [Playground](https://ohtaman.github.io/washi/demo/?preset=conflict_diagnosis_unsat) |
18
+ | **[Vehicle Routing (CVRP)](./vehicle-routing.md)** | Combinatorial OR / Dantzig-Wolfe | HiGHS | `m.solveColumnGeneration()`, `pricing` | Dynamic route column generation from customer dual shadow prices to minimize total fleet vehicles. | [Decomposition Guide](../guide/decomposition.md) |
19
+ | **[Traveling Salesperson (TSP)](./traveling-salesperson.md)** | Combinatorial OR / Benders | HiGHS | `m.solveBenders()`, `subproblem` | Subtour elimination on degree-assignment relaxation using dynamic Benders feasibility cuts. | [Decomposition Guide](../guide/decomposition.md) |
20
+
21
+ ## Find by WaSHI API (Reverse Index)
22
+
23
+ Looking for a specific modeling method or solver capability? Jump straight to the example that demonstrates it:
24
+
25
+ | Feature / API | Description | Example Page | Node.js Source |
26
+ | :--- | :--- | :--- | :--- |
27
+ | ``m.constraint(expr`...`)`` | Tagged template literal constraints | [Production Planning](./production.md) | [`01-production-planning.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/01-production-planning.ts) |
28
+ | `m.binary(keys)` / `m.continuous(keys)` | 1D dictionary of indexed variables | [0-1 Knapsack](./knapsack.md) | [`02-knapsack-problem.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/02-knapsack-problem.ts) |
29
+ | `m.continuous(rows, cols)` / `m.binary(rows, cols)` | 2D matrix of indexed variables | [Transportation Network](./transportation.md), [Shift Scheduling](./shift-scheduling.md) | [`09-transportation-problem.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/09-transportation-problem.ts) |
30
+ | `dot(matrix, vars2d)` / `dot(vector, vars)` | Fast vector/matrix dot product | [Transportation Network](./transportation.md), [Portfolio Optimization](./portfolio-qp.md) | [`09-transportation-problem.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/09-transportation-problem.ts) |
31
+ | `constr.dual` & `constr.slack` | Shadow prices & constraint surpluses | [Diet & Sensitivity Analysis](./diet-sensitivity.md) | [`10-diet-sensitivity.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/10-diet-sensitivity.ts) |
32
+ | `var.reducedCost` | Variable reduced costs in LP | [Diet & Sensitivity Analysis](./diet-sensitivity.md) | [`10-diet-sensitivity.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/10-diet-sensitivity.ts) |
33
+ | `m.indicator()` | Big-M conditional constraints (`binVar => constr`) | [E-Commerce Coupon Optimizer](./ecommerce-coupons.md) | [`12-ecommerce-coupon-optimizer.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/12-ecommerce-coupon-optimizer.ts) |
34
+ | `new QuadExpr()` | Convex quadratic objectives ($x^T Q x$) | [Portfolio Optimization](./portfolio-qp.md) | [`03-portfolio-qp.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/03-portfolio-qp.ts) |
35
+ | `m.bool()` & `.implies()` | Propositional logic & SMT rules | [SMT Security Policies](./smt-security.md) | [`04-smt-security-rules.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/04-smt-security-rules.ts) |
36
+ | `m.check()` & `m.unsatCore` | Feasibility check & conflict diagnosis | [Conflict Diagnosis](./unsat-core.md), [Shift Scheduling](./shift-scheduling.md) | [`05-unsat-core-diagnosis.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/05-unsat-core-diagnosis.ts) |
37
+ | `m.solveColumnGeneration()` | Dantzig-Wolfe Column Generation | [Vehicle Routing](./vehicle-routing.md) | [`13-vehicle-routing-column-generation.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/13-vehicle-routing-column-generation.ts) |
38
+ | `m.solveBenders()` | Benders Decomposition & cut separation | [Traveling Salesperson](./traveling-salesperson.md) | [`14-traveling-salesperson-benders.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/14-traveling-salesperson-benders.ts) |
39
+ | `solver: "glpk"` | Solving LP/MIP with GLPK plugin | [GLPK Solver Guide](../solvers/glpk.md) | [`08-glpk-solver-plugin.ts`](https://github.com/ohtaman/washi/blob/main/examples/node/08-glpk-solver-plugin.ts) |
40
+
41
+ ## Running Examples Locally in Node.js
42
+
43
+ All standalone scripts are located in [`examples/node/`](https://github.com/ohtaman/washi/tree/main/examples/node):
44
+
45
+ ```bash
46
+ npx tsx examples/node/01-production-planning.ts
47
+ npx tsx examples/node/02-knapsack-problem.ts
48
+ npx tsx examples/node/03-portfolio-qp.ts
49
+ npx tsx examples/node/04-smt-security-rules.ts
50
+ npx tsx examples/node/05-unsat-core-diagnosis.ts
51
+ npx tsx examples/node/07-hybrid-smt-mip.ts
52
+ npx tsx examples/node/08-glpk-solver-plugin.ts
53
+ npx tsx examples/node/09-transportation-problem.ts
54
+ npx tsx examples/node/10-diet-sensitivity.ts
55
+ npx tsx examples/node/11-shift-scheduling.ts
56
+ npx tsx examples/node/12-ecommerce-coupon-optimizer.ts
57
+ ```