From 0885d00b840aecf97b13e5a4a2b107c3db92dbcd Mon Sep 17 00:00:00 2001 From: Dominik Peters Date: Wed, 21 Feb 2024 12:36:45 +0100 Subject: [PATCH] readme and demo updates --- README.md | 106 ++++++++++++++++++++++++++++++++++++++++++++++++--- index.html | 7 +++- src/model.js | 5 +++ 3 files changed, 111 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3a7daa1..2ce57ad 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,12 @@ JavaScript package for modelling (Integer) Linear Programs -This is a lightweight JS package for specifying LPs and ILPs using a convenient syntax. The constructed model can be exported to the `.lp` [CPLEX LP format](https://web.mit.edu/lpsolve/doc/CPLEX-format.htm), and solved using the [highs-js](https://github.com/lovasoa/highs-js) and [glpk.js](https://github.com/jvail/glpk.js) solvers available as WebAssembly. This can be done both in the browser ([demo page](https://dominikpeters.github.io/lp-model/)) and in Node.js. +This is a lightweight JS package for specifying LPs and ILPs using a convenient syntax. The constructed model can be exported to the `.lp` [CPLEX LP format](https://web.mit.edu/lpsolve/doc/CPLEX-format.htm), and solved using +* [highs-js](https://github.com/lovasoa/highs-js) (WebAssembly wrapper for the [HiGHS solver](https://github.com/ERGO-Code/HiGHS), a high-performance LP/ILP solver), +* [glpk.js](https://github.com/jvail/glpk.js) (WebAssembly wrapper for the [GLPK solver](https://www.gnu.org/software/glpk/)), and +* [jsLPSolver](https://github.com/JWally/jsLPSolver) (a pure JS solver, not as fast as the others, but small bundle size). + +All solvers work both in the browser ([demo page](https://dominikpeters.github.io/lp-model/)) and in Node.js. ## Installation @@ -17,6 +22,7 @@ npm install lp-model # optionally install the solvers npm install highs npm install glpk.js +npm install javascript-lp-solver ``` In the browser: @@ -42,21 +48,28 @@ async function main() { // or const glpk = await require("glpk.js")(); model.solve(glpk); + // or + const jsLPSolver = require("javascript-lp-solver"); + model.solve(jsLPSolver); } main(); ``` -Setup in the browser for high-js: +Setup in the browser for high-js and jsLPSolver: ```html + @@ -110,17 +123,98 @@ const problem = { const itemNames = problem.items.map(item => item.name); +// make binary variables for each item const included = model.addVars(itemNames, { vtype: "BINARY" }); // included[A], included[B], included[C], included[D] are binary variables -model.addConstr(problem.items.map((item, i) => [item.weight, included[item.name]]), "<=", problem.capacity); // sum of weights of included items <= capacity +model.addConstr(problem.items.map((item, i) => [item.weight, included[item.name]]), "<=", problem.capacity); // equivalent to: 3*included[A] + 4*included[B] + 5*included[C] + 8*included[D] <= 15 -model.setObjective(problem.items.map((item, i) => [item.value, included[item.name]]), "MAXIMIZE"); // maximize sum of values of included items +model.setObjective( + problem.items.map((item, i) => [item.value, included[item.name]]), + "MAXIMIZE" + ); await model.solve(highs); -console.log(`Objective value: ${model.ObjVal}`); +console.log(`Objective value: ${model.ObjVal}`); // 17 console.log(`Included items: ${itemNames.filter(name => included[name].value > 0.5)}`); // A,B,D -``` \ No newline at end of file +``` + +## API + +### model.addVar(options) ⇒ Var +Adds a variable to the model. + +**Kind**: instance method of [Model](#module_lp-model.Model) +**Returns**: Var - The created variable instance. + + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| options | Object | | Options for creating the variable. | +| [options.lb] | number \| "-infinity" | 0 | The lower bound of the variable. | +| [options.ub] | number \| "+infinity" | "+infinity" | The upper bound of the variable. | +| [options.vtype] | "CONTINUOUS" \| "BINARY" \| "INTEGER" | "CONTINUOUS" | The type of the variable. | +| [options.name] | string | | The name of the variable. If not provided, a unique name is generated. | + + + +### model.addVars(varNames, options) ⇒ Object +Adds multiple variables to the model based on an array of names. +Each variable is created with the same provided options. + +**Returns**: Object - An object where keys are variable names and values are the created variable instances. + + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| varNames | Array.<string> | | Array of names for the variables to be added. | +| options | Object | | Common options for creating the variables. | +| [options.lb] | number \| "-infinity" | 0 | The lower bound for all variables. | +| [options.ub] | number \| "+infinity" | "+infinity" | The upper bound for all variables. | +| [options.vtype] | "CONTINUOUS" \| "BINARY" \| "INTEGER" | "CONTINUOUS" | The type for all variables. | + + + +### model.setObjective(expression, sense) +Sets the objective function of the model. + +| Param | Type | Description | +| --- | --- | --- | +| expression | Array | The linear expression representing the objective function. | +| sense | "MAXIMIZE" \| "MINIMIZE" | The sense of optimization, either "MAXIMIZE" or "MINIMIZE". | + + + +### model.addConstr(lhs, comparison, rhs) ⇒ Constr +Adds a constraint to the model. + +**Returns**: Constr - The created constraint instance. + +| Param | Type | Description | +| --- | --- | --- | +| lhs | Array | The left-hand side expression of the constraint. | +| comparison | string | The comparison operator, either "<=", "=", or ">=". | +| rhs | number \| Array | The right-hand side, which can be a number or a linear expression. | + + + +### model.toLPFormat() ⇒ string +Converts the model to CPLEX LP format string. + +**Returns**: string - The model represented in LP format. +**See**: [https://web.mit.edu/lpsolve/doc/CPLEX-format.htm](https://web.mit.edu/lpsolve/doc/CPLEX-format.htm) + + + +### model.solve(solver, [options]) +Solves the model using the provided solver. highs-js, glpk.js, or jsLPSolver can be used. +The solution can be accessed from the variables' `value` properties and the constraints' `primal` and `dual` properties. + +| Param | Type | Default | Description | +| --- | --- | --- | --- | +| solver | Object | | The solver instance to use for solving the model, either from highs-js, glpk.js, or jsLPSolver. | +| [options] | Object | {} | Options to pass to the solver's solve method (refer to their respective documentation: https://ergo-code.github.io/HiGHS/dev/options/definitions/, https://www.npmjs.com/package/glpk.js, https://github.com/JWally/jsLPSolver?tab=readme-ov-file#options). | + diff --git a/index.html b/index.html index b235495..c71e749 100644 --- a/index.html +++ b/index.html @@ -18,11 +18,12 @@

lp-model

convenient syntax, used together with the highs-js and glpk.js solvers using WebAssembly.

-

+        

         

If you see an ILP written in the CPLEX LP format, and both the HiGHS solution and the GLPK solution, it worked! HTML source code

+