├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .github └── workflows │ ├── CI.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── build.sh ├── demo ├── demo.js ├── index.html └── worker.js ├── example.js ├── exported_functions.json ├── package-lock.json ├── package.json ├── src ├── .prettierrc ├── post.js └── pre.js ├── tests ├── exceeds_stack.lp ├── life_goe.mod.lp └── test.js ├── tsconfig.json └── types.d.ts /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.205.2/containers/javascript-node/.devcontainer/base.Dockerfile 2 | 3 | # [Choice] Node.js version (use -bullseye variants on local arm64/Apple Silicon): 16, 14, 12, 16-bullseye, 14-bullseye, 12-bullseye, 16-buster, 14-buster, 12-buster 4 | ARG VARIANT="20-bookworm" 5 | FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:1-${VARIANT} 6 | 7 | # [Optional] Uncomment this section to install additional OS packages. 8 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 9 | && apt-get -y install cmake 10 | 11 | RUN git clone https://github.com/emscripten-core/emsdk.git /emsdk && \ 12 | sudo /emsdk/emsdk install 3.1.71 && \ 13 | sudo /emsdk/emsdk activate 3.1.71 && \ 14 | sudo ln -s /emsdk/upstream/emscripten /usr/share/emscripten 15 | 16 | ENV PATH="$PATH:/emsdk:/emsdk/upstream/emscripten:/emsdk/node/20.18.0_64bit/bin" 17 | 18 | RUN cd /emsdk/upstream/emscripten/ && sudo npm install acorn google-closure-compiler 19 | 20 | # [Optional] Uncomment if you want to install an additional version of node using nvm 21 | # ARG EXTRA_NODE_VERSION=10 22 | # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" 23 | 24 | # [Optional] Uncomment if you want to install more global node modules 25 | # RUN su node -c "npm install -g " 26 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.205.2/containers/javascript-node 3 | { 4 | "name": "Node.js", 5 | "build": { 6 | "dockerfile": "Dockerfile", 7 | // Update 'VARIANT' to pick a Node version: 16, 14, 12. 8 | // Append -bullseye or -buster to pin to an OS version. 9 | // Use -bullseye variants on local arm64/Apple Silicon. 10 | "args": { 11 | "VARIANT": "20-bookworm" 12 | } 13 | }, 14 | "customizations": { 15 | "vscode": { 16 | // Set *default* container specific settings.json values on container create. 17 | "settings": { 18 | "eslint.format.enable": true 19 | }, 20 | // Add the IDs of extensions you want installed when the container is created. 21 | "extensions": [ 22 | "esbenp.prettier-vscode" 23 | ] 24 | } 25 | }, 26 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 27 | // "forwardPorts": [], 28 | // Use 'postCreateCommand' to run commands after the container is created. 29 | "postCreateCommand": "npm install", 30 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 31 | "remoteUser": "node" 32 | } -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: Continuous Integration 4 | 5 | jobs: 6 | build: 7 | name: Continuous Integration 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | with: 12 | submodules: "recursive" 13 | - uses: mymindstorm/setup-emsdk@v14 14 | with: { version: "3.1.71" } 15 | - run: npm ci 16 | - name: build 17 | run: npm run build 18 | - name: test 19 | run: npm test 20 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create a release 2 | 3 | on: 4 | push: 5 | # Sequence of patterns matched against refs/tags 6 | tags: 7 | - "v*" # Push events to matching v*, i.e. v1.0, v20.15.10 8 | 9 | permissions: 10 | contents: write 11 | pages: write 12 | 13 | jobs: 14 | build: 15 | name: Create a release 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | submodules: "recursive" 21 | - name: Cache CMake build 22 | uses: actions/cache@v4 23 | with: 24 | path: | 25 | HiGHS/src/CMakeFiles 26 | HiGHS/build 27 | key: ${{ runner.os }}-cmake-${{ hashFiles('HiGHS/**/*.cmake', 'HiGHS/**/CMakeLists.txt') }} 28 | restore-keys: | 29 | ${{ runner.os }}-cmake- 30 | - uses: mymindstorm/setup-emsdk@v14 31 | with: { version: "3.1.71" } 32 | - run: npm ci 33 | - name: build 34 | run: npm run build 35 | - name: test 36 | run: npm test 37 | - run: cp build/highs.* demo/ 38 | - name: Deploy demo 🚀 39 | uses: JamesIves/github-pages-deploy-action@v4 40 | with: 41 | branch: gh-pages 42 | folder: demo 43 | - name: Create Release 44 | uses: softprops/action-gh-release@v2 45 | with: 46 | files: | 47 | build/highs.wasm 48 | build/highs.js 49 | fail_on_unmatched_files: true 50 | draft: false 51 | prerelease: false 52 | - name: publish the package to NPM 53 | run: | 54 | npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}" 55 | npm publish 56 | env: 57 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 58 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/* 2 | !build/build.sh 3 | !build/*json 4 | cbuild/ 5 | node_modules/ 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "HiGHS"] 2 | path = HiGHS 3 | url = https://github.com/ERGO-Code/HiGHS.git 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.sourceDirectory": "${workspaceFolder}/HiGHS" 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 highs-js 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # highs-js 2 | 3 | [![npm version](https://badge.fury.io/js/highs.svg)](https://www.npmjs.com/package/highs) 4 | [![CI status](https://github.com/lovasoa/highs-js/actions/workflows/CI.yml/badge.svg)](https://github.com/lovasoa/highs-js/actions/workflows/CI.yml) 5 | [![package size](https://badgen.net/bundlephobia/minzip/highs)](https://bundlephobia.com/result?p=highs) 6 | 7 | This is a javascript mixed integer linear programming library. 8 | It is built by compiling a high-performance C++ solver developed by the University of Edinburgh, ([HiGHS](https://highs.dev)), to WebAssembly using emscripten. 9 | 10 | ## Demo 11 | 12 | See the online demo at: https://lovasoa.github.io/highs-js/ 13 | 14 | ## Usage 15 | 16 | ```js 17 | const highs_settings = { 18 | // In node, locateFile is not needed 19 | // In the browser, point locateFile to the URL of the wasm file (see below) 20 | locateFile: (file) => "https://lovasoa.github.io/highs-js/" + file 21 | }; 22 | const highs_promise = require("highs")(highs_settings); 23 | 24 | const PROBLEM = `Maximize 25 | obj: 26 | x1 + 2 x2 + 4 x3 + x4 27 | Subject To 28 | c1: - x1 + x2 + x3 + 10 x4 <= 20 29 | c2: x1 - 4 x2 + x3 <= 30 30 | c3: x2 - 0.5 x4 = 0 31 | Bounds 32 | 0 <= x1 <= 40 33 | 2 <= x4 <= 3 34 | End`; 35 | 36 | const EXPECTED_SOLUTION = { 37 | Status: 'Optimal', 38 | ObjectiveValue: 87.5, 39 | Columns: { 40 | x1: { 41 | Index: 0, 42 | Status: 'BS', 43 | Lower: 0, 44 | Upper: 40, 45 | Type: 'Continuous', 46 | Primal: 17.5, 47 | Dual: -0, 48 | Name: 'x1' 49 | }, 50 | x2: { 51 | Index: 1, 52 | Status: 'BS', 53 | Lower: 0, 54 | Upper: Infinity, 55 | Type: 'Continuous', 56 | Primal: 1, 57 | Dual: -0, 58 | Name: 'x2' 59 | }, 60 | x3: { 61 | Index: 2, 62 | Status: 'BS', 63 | Lower: 0, 64 | Upper: Infinity, 65 | Type: 'Continuous', 66 | Primal: 16.5, 67 | Dual: -0, 68 | Name: 'x3' 69 | }, 70 | x4: { 71 | Index: 3, 72 | Status: 'LB', 73 | Lower: 2, 74 | Upper: 3, 75 | Type: 'Continuous', 76 | Primal: 2, 77 | Dual: -8.75, 78 | Name: 'x4' 79 | } 80 | }, 81 | Rows: [ 82 | { 83 | Index: 0, 84 | Name: 'c1', 85 | Status: 'UB', 86 | Lower: -Infinity, 87 | Upper: 20, 88 | Primal: 20, 89 | Dual: 1.5 90 | }, 91 | { 92 | Index: 1, 93 | Name: 'c2', 94 | Status: 'UB', 95 | Lower: -Infinity, 96 | Upper: 30, 97 | Primal: 30, 98 | Dual: 2.5 99 | }, 100 | { 101 | Index: 2, 102 | Name: 'c3', 103 | Status: 'UB', 104 | Lower: 0, 105 | Upper: 0, 106 | Primal: 0, 107 | Dual: 10.5 108 | } 109 | ] 110 | }; 111 | 112 | async function test() { 113 | const highs = await highs_promise; 114 | const sol = highs.solve(PROBLEM); 115 | require("assert").deepEqual(sol, EXPECTED_SOLUTION); 116 | } 117 | ``` 118 | 119 | The problem has to be passed in the [CPLEX .lp file format](http://web.mit.edu/lpsolve/doc/CPLEX-format.htm). 120 | 121 | For a more complete example, see the [`demo`](./demo/) folder. 122 | 123 | ### Loading the wasm file 124 | 125 | This package requires a wasm file. 126 | You can find it in `node_modules/highs/build/highs.wasm` inside the NPM package, 127 | or download it from the [release page](https://github.com/lovasoa/highs-js/releases). 128 | By default, it will be loaded from the same path as the javascript file, 129 | which means you have to add the wasm file to your assets. 130 | 131 | Alternatively, if you don't want to bother with that, 132 | if you are running highs-js in a web browser (and not in node), 133 | you can load the file directly from github: 134 | 135 | ```js 136 | const highs_loader = require("highs"); 137 | 138 | const highs = await highs_loader({ 139 | // In a browser, one can load the wasm file from github 140 | locateFile: (file) => "https://lovasoa.github.io/highs-js/" + file 141 | }); 142 | ``` 143 | ## Passing custom options 144 | 145 | HiGHS is configurable through [a large number of options](https://ergo-code.github.io/HiGHS/dev/options/definitions/). 146 | 147 | You can pass options as the second parameter to `solve` : 148 | 149 | ```js 150 | const highs_promise = require("highs")(highs_settings); 151 | const highs = await highs_promise; 152 | const sol = highs.solve(PROBLEM, { 153 | "allowed_cost_scale_factor": 2, 154 | "run_crossover": true, 155 | "presolve": "on", 156 | }); 157 | ``` 158 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | root="$(dirname $(realpath "$0"))" 5 | mkdir -p build 6 | cd build 7 | 8 | # Run emconfigure with the normal configure command as an argument. 9 | emcmake cmake ../HiGHS -DZLIB=OFF -DFAST_BUILD=OFF -DBUILD_SHARED_LIBS=OFF 10 | 11 | # Run emmake with the normal make to generate wasm object files. 12 | emmake make -j8 libhighs 13 | 14 | # Compile the linked code generated by make to JavaScript + WebAssembly. 15 | # 'project.o' should be replaced with the make output for your project, and 16 | # you may need to rename it if it isn't something emcc recognizes 17 | # (for example, it might have a different suffix like 'project.so' or 18 | # 'project.so.1', or no suffix like just 'project' for an executable). 19 | # If the project output is a library, you may need to add your 'main.c' file 20 | # here as well. 21 | # [-Ox] represents build optimisations (discussed in the next section). 22 | export EMCC_CLOSURE_ARGS="--jscomp_off=checkTypes" 23 | emcc -O3 \ 24 | -s EXPORTED_FUNCTIONS="@$root/exported_functions.json" \ 25 | -s EXPORTED_RUNTIME_METHODS="['cwrap']" \ 26 | -s MODULARIZE=1 \ 27 | -s ALLOW_MEMORY_GROWTH=1 \ 28 | -s STACK_SIZE=4194304 \ 29 | -flto \ 30 | --closure 1 \ 31 | --pre-js "$root/src/pre.js" \ 32 | --post-js "$root/src/post.js" \ 33 | lib/*.a -o highs.js 34 | -------------------------------------------------------------------------------- /demo/demo.js: -------------------------------------------------------------------------------- 1 | const lp_problem_el = document.getElementById("lp_problem"); 2 | const solution_el = document.getElementById("solution"); 3 | 4 | var worker = new Worker("worker.js"); 5 | 6 | function solve() { 7 | const lp = lp_problem_el.value; 8 | solution_el.innerText = "Loading..."; 9 | worker.postMessage(lp); 10 | } 11 | 12 | worker.onmessage = function ({ data: { solution, error } }) { 13 | if (solution) solution_el.innerText = JSON.stringify(solution, null, " "); 14 | else worker.onerror(error); 15 | }; 16 | 17 | worker.onerror = function (err) { 18 | solution_el.innerText = `Error: ${err.message || err}`; 19 | }; 20 | 21 | lp_problem_el.oninput = solve; 22 | solve(); 23 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | HiGHS-js linear programming 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 26 |

HiGHS online linear programming solver

27 |

A linear programming solver you can use directly from your browser

28 |
29 |
30 |
31 |
32 |
33 |

Demo

34 |
35 | 51 | 55 |
56 |
57 |
58 |

Try the API

59 |
60 | var highs = await require("highs")(); 61 | 62 | highs.solve(`Maximize 63 | obj: x + 2 y 64 | Subject To 65 | c1: x + y <= 20 66 | c2: x - y >= -30 67 | Bounds 68 | 0 <= x 69 | 0 <= y 70 | End`); 71 |
72 |
73 |
74 |
75 |
76 | "Linear programming is viewed as a revolutionary development giving man the ability to state general objectives and to find, by means of the simplex method, optimal policy decisions for a broad class of practical decision problems of great complexity. In the real world, planning tends to be ad hoc because of the many special-interest groups with their multiple objectives. " 77 |
- George Dantzig
78 |
79 |
80 |
81 |
82 |

83 | Contact info 84 |

85 |
86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /demo/worker.js: -------------------------------------------------------------------------------- 1 | importScripts("highs.js"); 2 | 3 | onmessage = async function ({ data }) { 4 | const highs = await Module(); 5 | try { 6 | postMessage({ solution: highs.solve(data) }); 7 | } catch (error) { 8 | postMessage({ error: error.toString() }); 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | var highs = await require("highs")(); 2 | 3 | highs.solve(`Maximize 4 | obj: x + 2 y 5 | Subject To 6 | c1: x + y <= 20 7 | c2: x - y >= -30 8 | Bounds 9 | 0 <= x 10 | 0 <= y 11 | End`) -------------------------------------------------------------------------------- /exported_functions.json: -------------------------------------------------------------------------------- 1 | [ 2 | "_Highs_call", 3 | "_Highs_readModel", 4 | "_Highs_writeSolution", 5 | "_Highs_writeSolutionPretty", 6 | "_Highs_create", 7 | "_Highs_run", 8 | "_Highs_destroy", 9 | "_Highs_getModelStatus", 10 | "_Highs_setStringOptionValue", 11 | "_Highs_setIntOptionValue", 12 | "_Highs_setDoubleOptionValue", 13 | "_Highs_setBoolOptionValue" 14 | ] 15 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highs", 3 | "version": "1.8.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "highs", 9 | "version": "1.8.0", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@tsconfig/recommended": "^1.0.1", 13 | "typescript": "^5.6.3" 14 | } 15 | }, 16 | "node_modules/@tsconfig/recommended": { 17 | "version": "1.0.8", 18 | "resolved": "https://registry.npmjs.org/@tsconfig/recommended/-/recommended-1.0.8.tgz", 19 | "integrity": "sha512-TotjFaaXveVUdsrXCdalyF6E5RyG6+7hHHQVZonQtdlk1rJZ1myDIvPUUKPhoYv+JAzThb2lQJh9+9ZfF46hsA==", 20 | "dev": true, 21 | "license": "MIT" 22 | }, 23 | "node_modules/typescript": { 24 | "version": "5.6.3", 25 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", 26 | "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", 27 | "dev": true, 28 | "license": "Apache-2.0", 29 | "bin": { 30 | "tsc": "bin/tsc", 31 | "tsserver": "bin/tsserver" 32 | }, 33 | "engines": { 34 | "node": ">=14.17" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "highs", 3 | "version": "1.8.0", 4 | "description": "Mixed integer linear programming library, built by compiling a high-performance C++ solver developed by the University of Edinburgh (HiGHS) to WebAssembly.", 5 | "main": "build/highs.js", 6 | "type": "commonjs", 7 | "exports": { 8 | ".": { 9 | "types": "./types.d.ts", 10 | "default": "./build/highs.js" 11 | }, 12 | "./runtime": "./build/highs.wasm" 13 | }, 14 | "types": "types.d.ts", 15 | "directories": { 16 | "test": "test" 17 | }, 18 | "scripts": { 19 | "test": "tsc && node tests/test.js", 20 | "build": "./build.sh" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/lovasoa/highs-js.git" 25 | }, 26 | "keywords": [ 27 | "linear programming", 28 | "LP", 29 | "MILP", 30 | "solver", 31 | "maths", 32 | "or", 33 | "optimization" 34 | ], 35 | "author": "Ophir LOJKINE", 36 | "license": "MIT", 37 | "bugs": { 38 | "url": "https://github.com/lovasoa/highs-js/issues" 39 | }, 40 | "homepage": "https://lovasoa.github.io/highs-js/", 41 | "runkitExampleFilename": "example.js", 42 | "devDependencies": { 43 | "@tsconfig/recommended": "^1.0.1", 44 | "typescript": "^5.6.3" 45 | }, 46 | "files": [ 47 | "build/highs.js", 48 | "build/highs.wasm", 49 | "package.json", 50 | "types.d.ts", 51 | "README.md" 52 | ] 53 | } 54 | -------------------------------------------------------------------------------- /src/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | "quoteProps": "preserve" 5 | } 6 | -------------------------------------------------------------------------------- /src/post.js: -------------------------------------------------------------------------------- 1 | const MODEL_FILENAME = "m.lp"; 2 | 3 | Module.Highs_readModel = Module["cwrap"]("Highs_readModel", "number", [ 4 | "number", 5 | "string", 6 | ]); 7 | const Highs_setIntOptionValue = Module["cwrap"]( 8 | "Highs_setIntOptionValue", 9 | "number", 10 | ["number", "string", "number"] 11 | ); 12 | const Highs_setDoubleOptionValue = Module["cwrap"]( 13 | "Highs_setDoubleOptionValue", 14 | "number", 15 | ["number", "string", "number"] 16 | ); 17 | const Highs_setStringOptionValue = Module["cwrap"]( 18 | "Highs_setStringOptionValue", 19 | "number", 20 | ["number", "string", "string"] 21 | ); 22 | const Highs_setBoolOptionValue = Module["cwrap"]( 23 | "Highs_setBoolOptionValue", 24 | "number", 25 | ["number", "string", "number"] 26 | ); 27 | Module.Highs_writeSolutionPretty = Module["cwrap"]( 28 | "Highs_writeSolutionPretty", 29 | "number", 30 | ["number", "string"] 31 | ); 32 | 33 | const MODEL_STATUS_CODES = /** @type {const} */ ({ 34 | 0: "Not Set", 35 | 1: "Load error", 36 | 2: "Model error", 37 | 3: "Presolve error", 38 | 4: "Solve error", 39 | 5: "Postsolve error", 40 | 6: "Empty", 41 | 7: "Optimal", 42 | 8: "Infeasible", 43 | 9: "Primal infeasible or unbounded", 44 | 10: "Unbounded", 45 | 11: "Bound on objective reached", 46 | 12: "Target for objective reached", 47 | 13: "Time limit reached", 48 | 14: "Iteration limit reached", 49 | 15: "Unknown", 50 | }); 51 | 52 | /** @typedef {Object} Highs */ 53 | 54 | var /** @type {()=>Highs} */ _Highs_create, 55 | /** @type {(arg0:Highs)=>void} */ _Highs_run, 56 | /** @type {(arg0:Highs)=>void} */ _Highs_destroy, 57 | /** @type {(arg0:Highs, arg1:number)=>(keyof (typeof MODEL_STATUS_CODES))} */ _Highs_getModelStatus, 58 | /** @type {any}*/ FS; 59 | 60 | /** 61 | * Solve a model in the CPLEX LP file format. 62 | * @param {string} model_str The problem to solve in the .lp format 63 | * @param {undefined | import("../types").HighsOptions} highs_options Options to pass the solver. See https://github.com/ERGO-Code/HiGHS/blob/v1.8.0/src/lp_data/HighsOptions.h 64 | * @returns {import("../types").HighsSolution} The solution 65 | */ 66 | Module["solve"] = function (model_str, highs_options) { 67 | FS.writeFile(MODEL_FILENAME, model_str); 68 | const highs = _Highs_create(); 69 | assert_ok( 70 | () => Module.Highs_readModel(highs, MODEL_FILENAME), 71 | "read LP model (see http://web.mit.edu/lpsolve/doc/CPLEX-format.htm)" 72 | ); 73 | const options = highs_options || {}; 74 | for (const option_name in options) { 75 | const option_value = options[option_name]; 76 | const type = typeof option_value; 77 | let setoption; 78 | if (type === "number") setoption = setNumericOption; 79 | else if (type === "boolean") setoption = Highs_setBoolOptionValue; 80 | else if (type === "string") setoption = Highs_setStringOptionValue; 81 | else 82 | throw new Error( 83 | `Unsupported option value type ${option_value} for '${option_name}'` 84 | ); 85 | assert_ok( 86 | () => setoption(highs, option_name, option_value), 87 | `set option '${option_name}'` 88 | ); 89 | } 90 | assert_ok(() => _Highs_run(highs), "solve the problem"); 91 | const status = 92 | MODEL_STATUS_CODES[_Highs_getModelStatus(highs, 0)] || "Unknown"; 93 | // Flush the content of stdout in order to have a clean stream before writing the solution in it 94 | stdout_lines.length = 0; 95 | assert_ok( 96 | () => Module.Highs_writeSolutionPretty(highs, ""), 97 | "write and extract solution" 98 | ); 99 | _Highs_destroy(highs); 100 | const output = parseResult(stdout_lines, status); 101 | // Flush the content of stdout and stderr because these streams are not used anymore 102 | stdout_lines.length = 0; 103 | stderr_lines.length = 0; 104 | return output; 105 | }; 106 | 107 | function setNumericOption(highs, option_name, option_value) { 108 | let result = Highs_setDoubleOptionValue(highs, option_name, option_value); 109 | if (result === -1 && option_value === (option_value | 0)) 110 | result = Highs_setIntOptionValue(highs, option_name, option_value); 111 | return result; 112 | } 113 | 114 | function parseNum(s) { 115 | if (s === "inf") return 1 / 0; 116 | else if (s === "-inf") return -1 / 0; 117 | else return +s; 118 | } 119 | 120 | const known_columns = { 121 | "Index": (s) => parseInt(s), 122 | "Lower": parseNum, 123 | "Upper": parseNum, 124 | "Primal": parseNum, 125 | "Dual": parseNum, 126 | }; 127 | 128 | /** 129 | * @param {string} s 130 | * @returns {string[]} The values (words) of a line 131 | */ 132 | function lineValues(s) { 133 | return s.match(/[^\s]+/g) || []; 134 | } 135 | 136 | /** 137 | * 138 | * @param {string[]} headers 139 | * @param {string} line 140 | * @returns {Record} 141 | */ 142 | function lineToObj(headers, line) { 143 | const values = lineValues(line); 144 | /** @type {Record} */ 145 | const result = {}; 146 | for (let idx = 0; idx < values.length; idx++) { 147 | if (idx >= headers.length) 148 | throw new Error("Unable to parse solution line: " + line); 149 | const value = values[idx]; 150 | const header = headers[idx]; 151 | const parser = known_columns[header]; 152 | const parsed = parser ? parser(value) : value; 153 | result[header] = parsed; 154 | } 155 | return result; 156 | } 157 | 158 | /** 159 | * Parse HiGHS output lines 160 | * @param {string[]} lines stdout from highs 161 | * @param {import("../types").HighsModelStatus} status status 162 | * @returns {import("../types").HighsSolution} The solution 163 | */ 164 | function parseResult(lines, status) { 165 | if (lines.length < 3) 166 | throw new Error("Unable to parse solution. Too few lines."); 167 | 168 | let headers = headersForNonEmptyColumns(lines[1], lines[2]); 169 | 170 | var result = { 171 | "Status": /** @type {"Infeasible"} */ (status), 172 | "Columns": {}, 173 | "Rows": [], 174 | "ObjectiveValue": NaN, 175 | }; 176 | 177 | // Parse columns 178 | for (var i = 2; lines[i] != "Rows"; i++) { 179 | const obj = lineToObj(headers, lines[i]); 180 | if (!obj["Type"]) obj["Type"] = "Continuous"; 181 | result["Columns"][obj["Name"]] = obj; 182 | } 183 | 184 | // Parse rows 185 | headers = headersForNonEmptyColumns(lines[i + 1], lines[i + 2]); 186 | for (var j = i + 2; lines[j] != ""; j++) { 187 | result["Rows"].push(lineToObj(headers, lines[j])); 188 | } 189 | 190 | // Parse objective value 191 | result["ObjectiveValue"] = parseNum( 192 | lines[j + 3].match(/Objective value: (.+)/)[1] 193 | ); 194 | return result; 195 | } 196 | 197 | /** 198 | * Finds the non headers for non-empty columns in a HiGHS output 199 | * @param {string} headerLine The line containing the header names 200 | * @param {string} firstDataLine The line immediately below the header line 201 | * @returns {string[]} The headers for which there is data available 202 | */ 203 | function headersForNonEmptyColumns(headerLine, firstDataLine) { 204 | // Headers can correspond to empty columns. The contents of a column can be left or right 205 | // aligned, so we determine if a given header should be included by looking at whether 206 | // the row immediately below the header has any contents. 207 | return [...headerLine.matchAll(/[^\s]+/g)] 208 | .filter( 209 | (match) => 210 | firstDataLine[match.index] !== " " || 211 | firstDataLine[match.index + match[0].length - 1] !== " " 212 | ) 213 | .map((match) => match[0]); 214 | } 215 | 216 | function assert_ok(fn, action) { 217 | let err; 218 | try { 219 | err = fn(); 220 | } catch (e) { 221 | err = e; 222 | } 223 | // Allow HighsStatus::kOk (0) and HighsStatus::kWarning (1) but 224 | // disallow other values, such as e.g. HighsStatus::kError (-1). 225 | if (err !== 0 && err !== 1) 226 | throw new Error("Unable to " + action + ". HiGHS error " + err); 227 | } 228 | -------------------------------------------------------------------------------- /src/pre.js: -------------------------------------------------------------------------------- 1 | const stdout_lines = []; 2 | const stderr_lines = []; 3 | 4 | Module["print"] = (s) => stdout_lines.push(s); 5 | Module["printErr"] = (s) => stderr_lines.push(s); -------------------------------------------------------------------------------- /tests/life_goe.mod.lp: -------------------------------------------------------------------------------- 1 | \* Problem: life_goe *\ 2 | 3 | Minimize 4 | obj: 0 x(1,3) 5 | 6 | Subject To 7 | maincons(1,2): + 2 x(1,3) + 2 x(1,1) + 2 x(2,2) + 2 x(0,2) + 2 x(2,3) 8 | + 2 x(0,3) + 2 x(2,1) + 2 x(0,1) + x(1,2) - dpos(1,2) + dneg(1,2) = 6 9 | maincons(1,4): + 2 x(1,3) + 2 x(2,3) + 2 x(0,3) + 2 x(1,5) + 2 x(2,4) 10 | + 2 x(0,4) + 2 x(2,5) + 2 x(0,5) + x(1,4) - dpos(1,4) + dneg(1,4) = 6 11 | maincons(1,5): + x(1,5) + 2 x(2,4) + 2 x(0,4) + 2 x(2,5) + 2 x(0,5) 12 | + 2 x(1,4) + 2 x(1,6) + 2 x(2,6) + 2 x(0,6) - dpos(1,5) + dneg(1,5) = 6 13 | maincons(1,6): + 2 x(1,5) + 2 x(2,5) + 2 x(0,5) + x(1,6) + 2 x(2,6) 14 | + 2 x(0,6) + 2 x(1,7) + 2 x(2,7) + 2 x(0,7) - dpos(1,6) + dneg(1,6) = 6 15 | maincons(1,8): + 2 x(1,7) + 2 x(2,7) + 2 x(0,7) + 2 x(1,9) + 2 x(2,8) 16 | + 2 x(0,8) + 2 x(2,9) + 2 x(0,9) + x(1,8) - dpos(1,8) + dneg(1,8) = 6 17 | maincons(2,3): + 2 x(1,3) + 2 x(2,2) + x(2,3) + 2 x(1,2) + 2 x(2,4) 18 | + 2 x(1,4) + 2 x(3,3) + 2 x(3,4) + 2 x(3,2) - dpos(2,3) + dneg(2,3) = 6 19 | maincons(2,5): + 2 x(1,5) + 2 x(2,4) + x(2,5) + 2 x(1,4) + 2 x(1,6) 20 | + 2 x(2,6) + 2 x(3,4) + 2 x(3,5) + 2 x(3,6) - dpos(2,5) + dneg(2,5) = 6 21 | maincons(2,7): + 2 x(1,6) + 2 x(2,6) + 2 x(1,7) + x(2,7) + 2 x(2,8) 22 | + 2 x(1,8) + 2 x(3,6) + 2 x(3,7) + 2 x(3,8) - dpos(2,7) + dneg(2,7) = 6 23 | maincons(2,10): + 2 x(1,9) + 2 x(2,9) + 2 x(2,11) + 2 x(3,10) 24 | + 2 x(1,10) + 2 x(3,11) + 2 x(1,11) + 2 x(3,9) + x(2,10) - dpos(2,10) 25 | + dneg(2,10) = 6 26 | maincons(3,1): + 2 x(2,2) + 2 x(2,1) + 2 x(3,2) + 2 x(3,0) + 2 x(4,1) 27 | + 2 x(4,2) + 2 x(4,0) + 2 x(2,0) + x(3,1) - dpos(3,1) + dneg(3,1) = 6 28 | maincons(3,3): + 2 x(2,2) + 2 x(2,3) + 2 x(2,4) + x(3,3) + 2 x(3,4) 29 | + 2 x(3,2) + 2 x(4,2) + 2 x(4,3) + 2 x(4,4) - dpos(3,3) + dneg(3,3) = 6 30 | maincons(3,4): + 2 x(2,3) + 2 x(2,4) + 2 x(2,5) + 2 x(3,3) + x(3,4) 31 | + 2 x(3,5) + 2 x(4,3) + 2 x(4,4) + 2 x(4,5) - dpos(3,4) + dneg(3,4) = 6 32 | maincons(3,5): + 2 x(2,4) + 2 x(2,5) + 2 x(2,6) + 2 x(3,4) + x(3,5) 33 | + 2 x(3,6) + 2 x(4,4) + 2 x(4,5) + 2 x(4,6) - dpos(3,5) + dneg(3,5) = 6 34 | maincons(3,8): + 2 x(2,7) + 2 x(2,8) + 2 x(2,9) + 2 x(3,7) + x(3,8) 35 | + 2 x(3,9) + 2 x(4,8) + 2 x(4,9) + 2 x(4,7) - dpos(3,8) + dneg(3,8) = 6 36 | maincons(3,9): + 2 x(2,8) + 2 x(2,9) + 2 x(3,8) + 2 x(3,10) + x(3,9) 37 | + 2 x(2,10) + 2 x(4,8) + 2 x(4,9) + 2 x(4,10) - dpos(3,9) + dneg(3,9) 38 | = 6 39 | maincons(4,2): + 2 x(3,3) + 2 x(3,2) + 2 x(4,1) + x(4,2) + 2 x(3,1) 40 | + 2 x(4,3) + 2 x(5,2) + 2 x(5,3) + 2 x(5,1) - dpos(4,2) + dneg(4,2) = 6 41 | maincons(4,4): + 2 x(3,3) + 2 x(3,4) + 2 x(3,5) + 2 x(4,3) + x(4,4) 42 | + 2 x(4,5) + 2 x(5,3) + 2 x(5,4) + 2 x(5,5) - dpos(4,4) + dneg(4,4) = 6 43 | maincons(4,5): + 2 x(3,4) + 2 x(3,5) + 2 x(3,6) + 2 x(4,4) + x(4,5) 44 | + 2 x(4,6) + 2 x(5,4) + 2 x(5,5) + 2 x(5,6) - dpos(4,5) + dneg(4,5) = 6 45 | maincons(4,6): + 2 x(3,5) + 2 x(3,6) + 2 x(3,7) + 2 x(4,5) + x(4,6) 46 | + 2 x(4,7) + 2 x(5,5) + 2 x(5,6) + 2 x(5,7) - dpos(4,6) + dneg(4,6) = 6 47 | maincons(4,7): + 2 x(3,6) + 2 x(3,7) + 2 x(3,8) + 2 x(4,6) + 2 x(4,8) 48 | + x(4,7) + 2 x(5,6) + 2 x(5,7) + 2 x(5,8) - dpos(4,7) + dneg(4,7) = 6 49 | maincons(4,8): + 2 x(3,7) + 2 x(3,8) + 2 x(3,9) + x(4,8) + 2 x(4,9) 50 | + 2 x(4,7) + 2 x(5,7) + 2 x(5,8) + 2 x(5,9) - dpos(4,8) + dneg(4,8) = 6 51 | maincons(4,10): + 2 x(3,10) + 2 x(3,11) + 2 x(3,9) + 2 x(4,9) + x(4,10) 52 | + 2 x(5,9) + 2 x(4,11) + 2 x(5,10) + 2 x(5,11) - dpos(4,10) 53 | + dneg(4,10) = 6 54 | maincons(5,1): + 2 x(4,1) + 2 x(4,2) + 2 x(4,0) + 2 x(5,2) + x(5,1) 55 | + 2 x(5,0) + 2 x(6,1) + 2 x(6,2) + 2 x(6,0) - dpos(5,1) + dneg(5,1) = 6 56 | maincons(5,4): + 2 x(4,3) + 2 x(4,4) + 2 x(4,5) + 2 x(5,3) + x(5,4) 57 | + 2 x(5,5) + 2 x(6,4) + 2 x(6,5) + 2 x(6,3) - dpos(5,4) + dneg(5,4) = 6 58 | maincons(5,7): + 2 x(4,6) + 2 x(4,8) + 2 x(4,7) + 2 x(5,6) + x(5,7) 59 | + 2 x(5,8) + 2 x(6,7) + 2 x(6,8) + 2 x(6,6) - dpos(5,7) + dneg(5,7) = 6 60 | maincons(5,8): + 2 x(4,8) + 2 x(4,9) + 2 x(4,7) + 2 x(5,7) + x(5,8) 61 | + 2 x(5,9) + 2 x(6,7) + 2 x(6,8) + 2 x(6,9) - dpos(5,8) + dneg(5,8) = 6 62 | maincons(5,9): + 2 x(4,8) + 2 x(4,9) + 2 x(4,10) + 2 x(5,8) + x(5,9) 63 | + 2 x(5,10) + 2 x(6,8) + 2 x(6,9) + 2 x(6,10) - dpos(5,9) + dneg(5,9) 64 | = 6 65 | maincons(5,10): + 2 x(4,9) + 2 x(4,10) + 2 x(5,9) + 2 x(4,11) + x(5,10) 66 | + 2 x(5,11) + 2 x(6,9) + 2 x(6,10) + 2 x(6,11) - dpos(5,10) 67 | + dneg(5,10) = 6 68 | maincons(6,1): + 2 x(5,2) + 2 x(5,1) + 2 x(5,0) + x(6,1) + 2 x(6,2) 69 | + 2 x(6,0) + 2 x(7,1) + 2 x(7,2) + 2 x(7,0) - dpos(6,1) + dneg(6,1) = 6 70 | maincons(6,2): + 2 x(5,2) + 2 x(5,3) + 2 x(5,1) + 2 x(6,1) + x(6,2) 71 | + 2 x(6,3) + 2 x(7,1) + 2 x(7,2) + 2 x(7,3) - dpos(6,2) + dneg(6,2) = 6 72 | maincons(6,3): + 2 x(5,2) + 2 x(5,3) + 2 x(5,4) + 2 x(6,2) + 2 x(6,4) 73 | + x(6,3) + 2 x(7,2) + 2 x(7,3) + 2 x(7,4) - dpos(6,3) + dneg(6,3) = 6 74 | maincons(6,4): + 2 x(5,3) + 2 x(5,4) + 2 x(5,5) + x(6,4) + 2 x(6,5) 75 | + 2 x(6,3) + 2 x(7,3) + 2 x(7,4) + 2 x(7,5) - dpos(6,4) + dneg(6,4) = 6 76 | maincons(6,7): + 2 x(5,6) + 2 x(5,7) + 2 x(5,8) + x(6,7) + 2 x(6,8) 77 | + 2 x(6,6) + 2 x(7,7) + 2 x(7,8) + 2 x(7,6) - dpos(6,7) + dneg(6,7) = 6 78 | maincons(6,10): + 2 x(5,9) + 2 x(5,10) + 2 x(5,11) + 2 x(6,9) + x(6,10) 79 | + 2 x(6,11) + 2 x(7,10) + 2 x(7,11) + 2 x(7,9) - dpos(6,10) 80 | + dneg(6,10) = 6 81 | maincons(7,1): + 2 x(6,1) + 2 x(6,2) + 2 x(6,0) + x(7,1) + 2 x(7,2) 82 | + 2 x(7,0) + 2 x(8,1) + 2 x(8,2) + 2 x(8,0) - dpos(7,1) + dneg(7,1) = 6 83 | maincons(7,3): + 2 x(6,2) + 2 x(6,4) + 2 x(6,3) + 2 x(7,2) + x(7,3) 84 | + 2 x(7,4) + 2 x(8,2) + 2 x(8,3) + 2 x(8,4) - dpos(7,3) + dneg(7,3) = 6 85 | maincons(7,4): + 2 x(6,4) + 2 x(6,5) + 2 x(6,3) + 2 x(7,3) + x(7,4) 86 | + 2 x(7,5) + 2 x(8,3) + 2 x(8,4) + 2 x(8,5) - dpos(7,4) + dneg(7,4) = 6 87 | maincons(7,5): + 2 x(6,4) + 2 x(6,5) + 2 x(6,6) + 2 x(7,4) + x(7,5) 88 | + 2 x(7,6) + 2 x(8,4) + 2 x(8,5) + 2 x(8,6) - dpos(7,5) + dneg(7,5) = 6 89 | maincons(7,6): + 2 x(6,5) + 2 x(6,7) + 2 x(6,6) + 2 x(7,5) + 2 x(7,7) 90 | + x(7,6) + 2 x(8,5) + 2 x(8,6) + 2 x(8,7) - dpos(7,6) + dneg(7,6) = 6 91 | maincons(7,7): + 2 x(6,7) + 2 x(6,8) + 2 x(6,6) + x(7,7) + 2 x(7,8) 92 | + 2 x(7,6) + 2 x(8,6) + 2 x(8,7) + 2 x(8,8) - dpos(7,7) + dneg(7,7) = 6 93 | maincons(7,9): + 2 x(6,8) + 2 x(6,9) + 2 x(6,10) + 2 x(7,8) + 2 x(7,10) 94 | + x(7,9) + 2 x(8,8) + 2 x(8,9) + 2 x(8,10) - dpos(7,9) + dneg(7,9) = 6 95 | maincons(1,1): + x(1,1) + 2 x(2,2) + 2 x(0,2) + 2 x(2,1) + 2 x(0,1) 96 | + 2 x(1,2) + 2 x(2,0) + 2 x(1,0) + 2 x(0,0) - dpos(1,1) + dneg(1,1) = 6 97 | maincons(1,3): + x(1,3) + 2 x(2,2) + 2 x(0,2) + 2 x(2,3) + 2 x(0,3) 98 | + 2 x(1,2) + 2 x(2,4) + 2 x(0,4) + 2 x(1,4) - dpos(1,3) + dneg(1,3) = 6 99 | maincons(1,7): + 2 x(1,6) + 2 x(2,6) + 2 x(0,6) + x(1,7) + 2 x(2,7) 100 | + 2 x(0,7) + 2 x(2,8) + 2 x(0,8) + 2 x(1,8) - dpos(1,7) + dneg(1,7) = 6 101 | maincons(1,9): + x(1,9) + 2 x(2,8) + 2 x(0,8) + 2 x(2,9) + 2 x(0,9) 102 | + 2 x(1,8) + 2 x(1,10) + 2 x(2,10) + 2 x(0,10) - dpos(1,9) + dneg(1,9) 103 | = 6 104 | maincons(1,10): + 2 x(1,9) + 2 x(2,9) + 2 x(0,9) + 2 x(2,11) + x(1,10) 105 | + 2 x(1,11) + 2 x(2,10) + 2 x(0,10) + 2 x(0,11) - dpos(1,10) 106 | + dneg(1,10) = 6 107 | maincons(2,1): + 2 x(1,1) + 2 x(2,2) + x(2,1) + 2 x(1,2) + 2 x(3,2) 108 | + 2 x(3,0) + 2 x(2,0) + 2 x(3,1) + 2 x(1,0) - dpos(2,1) + dneg(2,1) = 6 109 | maincons(2,2): + 2 x(1,3) + 2 x(1,1) + x(2,2) + 2 x(2,3) + 2 x(2,1) 110 | + 2 x(1,2) + 2 x(3,3) + 2 x(3,2) + 2 x(3,1) - dpos(2,2) + dneg(2,2) = 6 111 | maincons(2,4): + 2 x(1,3) + 2 x(2,3) + 2 x(1,5) + x(2,4) + 2 x(2,5) 112 | + 2 x(1,4) + 2 x(3,3) + 2 x(3,4) + 2 x(3,5) - dpos(2,4) + dneg(2,4) = 6 113 | maincons(2,6): + 2 x(1,5) + 2 x(2,5) + 2 x(1,6) + x(2,6) + 2 x(1,7) 114 | + 2 x(2,7) + 2 x(3,5) + 2 x(3,6) + 2 x(3,7) - dpos(2,6) + dneg(2,6) = 6 115 | maincons(2,8): + 2 x(1,7) + 2 x(2,7) + 2 x(1,9) + x(2,8) + 2 x(2,9) 116 | + 2 x(1,8) + 2 x(3,7) + 2 x(3,8) + 2 x(3,9) - dpos(2,8) + dneg(2,8) = 6 117 | maincons(2,9): + 2 x(1,9) + 2 x(2,8) + x(2,9) + 2 x(1,8) + 2 x(3,8) 118 | + 2 x(3,10) + 2 x(1,10) + 2 x(3,9) + 2 x(2,10) - dpos(2,9) + dneg(2,9) 119 | = 6 120 | maincons(3,2): + 2 x(2,2) + 2 x(2,3) + 2 x(2,1) + 2 x(3,3) + x(3,2) 121 | + 2 x(4,1) + 2 x(4,2) + 2 x(3,1) + 2 x(4,3) - dpos(3,2) + dneg(3,2) = 6 122 | maincons(3,6): + 2 x(2,5) + 2 x(2,6) + 2 x(2,7) + 2 x(3,5) + x(3,6) 123 | + 2 x(3,7) + 2 x(4,5) + 2 x(4,6) + 2 x(4,7) - dpos(3,6) + dneg(3,6) = 6 124 | maincons(3,7): + 2 x(2,6) + 2 x(2,7) + 2 x(2,8) + 2 x(3,6) + x(3,7) 125 | + 2 x(3,8) + 2 x(4,6) + 2 x(4,8) + 2 x(4,7) - dpos(3,7) + dneg(3,7) = 6 126 | maincons(3,10): + 2 x(2,9) + 2 x(2,11) + x(3,10) + 2 x(3,11) + 2 x(3,9) 127 | + 2 x(2,10) + 2 x(4,9) + 2 x(4,10) + 2 x(4,11) - dpos(3,10) 128 | + dneg(3,10) = 6 129 | maincons(4,1): + 2 x(3,2) + 2 x(3,0) + x(4,1) + 2 x(4,2) + 2 x(4,0) 130 | + 2 x(3,1) + 2 x(5,2) + 2 x(5,1) + 2 x(5,0) - dpos(4,1) + dneg(4,1) = 6 131 | maincons(4,3): + 2 x(3,3) + 2 x(3,4) + 2 x(3,2) + 2 x(4,2) + x(4,3) 132 | + 2 x(4,4) + 2 x(5,2) + 2 x(5,3) + 2 x(5,4) - dpos(4,3) + dneg(4,3) = 6 133 | maincons(4,9): + 2 x(3,8) + 2 x(3,10) + 2 x(3,9) + 2 x(4,8) + x(4,9) 134 | + 2 x(4,10) + 2 x(5,8) + 2 x(5,9) + 2 x(5,10) - dpos(4,9) + dneg(4,9) 135 | = 6 136 | maincons(5,2): + 2 x(4,1) + 2 x(4,2) + 2 x(4,3) + x(5,2) + 2 x(5,3) 137 | + 2 x(5,1) + 2 x(6,1) + 2 x(6,2) + 2 x(6,3) - dpos(5,2) + dneg(5,2) = 6 138 | maincons(5,3): + 2 x(4,2) + 2 x(4,3) + 2 x(4,4) + 2 x(5,2) + x(5,3) 139 | + 2 x(5,4) + 2 x(6,2) + 2 x(6,4) + 2 x(6,3) - dpos(5,3) + dneg(5,3) = 6 140 | maincons(5,5): + 2 x(4,4) + 2 x(4,5) + 2 x(4,6) + 2 x(5,4) + x(5,5) 141 | + 2 x(5,6) + 2 x(6,4) + 2 x(6,5) + 2 x(6,6) - dpos(5,5) + dneg(5,5) = 6 142 | maincons(5,6): + 2 x(4,5) + 2 x(4,6) + 2 x(4,7) + 2 x(5,5) + x(5,6) 143 | + 2 x(5,7) + 2 x(6,5) + 2 x(6,7) + 2 x(6,6) - dpos(5,6) + dneg(5,6) = 6 144 | maincons(6,5): + 2 x(5,4) + 2 x(5,5) + 2 x(5,6) + 2 x(6,4) + x(6,5) 145 | + 2 x(6,6) + 2 x(7,4) + 2 x(7,5) + 2 x(7,6) - dpos(6,5) + dneg(6,5) = 6 146 | maincons(6,6): + 2 x(5,5) + 2 x(5,6) + 2 x(5,7) + 2 x(6,5) + 2 x(6,7) 147 | + x(6,6) + 2 x(7,5) + 2 x(7,7) + 2 x(7,6) - dpos(6,6) + dneg(6,6) = 6 148 | maincons(6,8): + 2 x(5,7) + 2 x(5,8) + 2 x(5,9) + 2 x(6,7) + x(6,8) 149 | + 2 x(6,9) + 2 x(7,7) + 2 x(7,8) + 2 x(7,9) - dpos(6,8) + dneg(6,8) = 6 150 | maincons(6,9): + 2 x(5,8) + 2 x(5,9) + 2 x(5,10) + 2 x(6,8) + x(6,9) 151 | + 2 x(6,10) + 2 x(7,8) + 2 x(7,10) + 2 x(7,9) - dpos(6,9) + dneg(6,9) 152 | = 6 153 | maincons(7,2): + 2 x(6,1) + 2 x(6,2) + 2 x(6,3) + 2 x(7,1) + x(7,2) 154 | + 2 x(7,3) + 2 x(8,1) + 2 x(8,2) + 2 x(8,3) - dpos(7,2) + dneg(7,2) = 6 155 | maincons(7,8): + 2 x(6,7) + 2 x(6,8) + 2 x(6,9) + 2 x(7,7) + x(7,8) 156 | + 2 x(7,9) + 2 x(8,7) + 2 x(8,8) + 2 x(8,9) - dpos(7,8) + dneg(7,8) = 6 157 | maincons(7,10): + 2 x(6,9) + 2 x(6,10) + 2 x(6,11) + x(7,10) 158 | + 2 x(7,11) + 2 x(7,9) + 2 x(8,9) + 2 x(8,10) + 2 x(8,11) - dpos(7,10) 159 | + dneg(7,10) = 6 160 | posbound(1,2): + dpos(1,2) - 11 dposup(1,2) <= -0 161 | posbound(1,4): + dpos(1,4) - 11 dposup(1,4) <= -0 162 | posbound(1,5): + dpos(1,5) - 11 dposup(1,5) <= -0 163 | posbound(1,6): + dpos(1,6) - 11 dposup(1,6) <= -0 164 | posbound(1,8): + dpos(1,8) - 11 dposup(1,8) <= -0 165 | posbound(2,3): + dpos(2,3) - 11 dposup(2,3) <= -0 166 | posbound(2,5): + dpos(2,5) - 11 dposup(2,5) <= -0 167 | posbound(2,7): + dpos(2,7) - 11 dposup(2,7) <= -0 168 | posbound(2,10): + dpos(2,10) - 11 dposup(2,10) <= -0 169 | posbound(3,1): + dpos(3,1) - 11 dposup(3,1) <= -0 170 | posbound(3,3): + dpos(3,3) - 11 dposup(3,3) <= -0 171 | posbound(3,4): + dpos(3,4) - 11 dposup(3,4) <= -0 172 | posbound(3,5): + dpos(3,5) - 11 dposup(3,5) <= -0 173 | posbound(3,8): + dpos(3,8) - 11 dposup(3,8) <= -0 174 | posbound(3,9): + dpos(3,9) - 11 dposup(3,9) <= -0 175 | posbound(4,2): + dpos(4,2) - 11 dposup(4,2) <= -0 176 | posbound(4,4): + dpos(4,4) - 11 dposup(4,4) <= -0 177 | posbound(4,5): + dpos(4,5) - 11 dposup(4,5) <= -0 178 | posbound(4,6): + dpos(4,6) - 11 dposup(4,6) <= -0 179 | posbound(4,7): + dpos(4,7) - 11 dposup(4,7) <= -0 180 | posbound(4,8): + dpos(4,8) - 11 dposup(4,8) <= -0 181 | posbound(4,10): + dpos(4,10) - 11 dposup(4,10) <= -0 182 | posbound(5,1): + dpos(5,1) - 11 dposup(5,1) <= -0 183 | posbound(5,4): + dpos(5,4) - 11 dposup(5,4) <= -0 184 | posbound(5,7): + dpos(5,7) - 11 dposup(5,7) <= -0 185 | posbound(5,8): + dpos(5,8) - 11 dposup(5,8) <= -0 186 | posbound(5,9): + dpos(5,9) - 11 dposup(5,9) <= -0 187 | posbound(5,10): + dpos(5,10) - 11 dposup(5,10) <= -0 188 | posbound(6,1): + dpos(6,1) - 11 dposup(6,1) <= -0 189 | posbound(6,2): + dpos(6,2) - 11 dposup(6,2) <= -0 190 | posbound(6,3): + dpos(6,3) - 11 dposup(6,3) <= -0 191 | posbound(6,4): + dpos(6,4) - 11 dposup(6,4) <= -0 192 | posbound(6,7): + dpos(6,7) - 11 dposup(6,7) <= -0 193 | posbound(6,10): + dpos(6,10) - 11 dposup(6,10) <= -0 194 | posbound(7,1): + dpos(7,1) - 11 dposup(7,1) <= -0 195 | posbound(7,3): + dpos(7,3) - 11 dposup(7,3) <= -0 196 | posbound(7,4): + dpos(7,4) - 11 dposup(7,4) <= -0 197 | posbound(7,5): + dpos(7,5) - 11 dposup(7,5) <= -0 198 | posbound(7,6): + dpos(7,6) - 11 dposup(7,6) <= -0 199 | posbound(7,7): + dpos(7,7) - 11 dposup(7,7) <= -0 200 | posbound(7,9): + dpos(7,9) - 11 dposup(7,9) <= -0 201 | posbound(1,1): + dpos(1,1) - 11 dposup(1,1) <= -0 202 | posbound(1,3): + dpos(1,3) - 11 dposup(1,3) <= -0 203 | posbound(1,7): + dpos(1,7) - 11 dposup(1,7) <= -0 204 | posbound(1,9): + dpos(1,9) - 11 dposup(1,9) <= -0 205 | posbound(1,10): + dpos(1,10) - 11 dposup(1,10) <= -0 206 | posbound(2,1): + dpos(2,1) - 11 dposup(2,1) <= -0 207 | posbound(2,2): + dpos(2,2) - 11 dposup(2,2) <= -0 208 | posbound(2,4): + dpos(2,4) - 11 dposup(2,4) <= -0 209 | posbound(2,6): + dpos(2,6) - 11 dposup(2,6) <= -0 210 | posbound(2,8): + dpos(2,8) - 11 dposup(2,8) <= -0 211 | posbound(2,9): + dpos(2,9) - 11 dposup(2,9) <= -0 212 | posbound(3,2): + dpos(3,2) - 11 dposup(3,2) <= -0 213 | posbound(3,6): + dpos(3,6) - 11 dposup(3,6) <= -0 214 | posbound(3,7): + dpos(3,7) - 11 dposup(3,7) <= -0 215 | posbound(3,10): + dpos(3,10) - 11 dposup(3,10) <= -0 216 | posbound(4,1): + dpos(4,1) - 11 dposup(4,1) <= -0 217 | posbound(4,3): + dpos(4,3) - 11 dposup(4,3) <= -0 218 | posbound(4,9): + dpos(4,9) - 11 dposup(4,9) <= -0 219 | posbound(5,2): + dpos(5,2) - 11 dposup(5,2) <= -0 220 | posbound(5,3): + dpos(5,3) - 11 dposup(5,3) <= -0 221 | posbound(5,5): + dpos(5,5) - 11 dposup(5,5) <= -0 222 | posbound(5,6): + dpos(5,6) - 11 dposup(5,6) <= -0 223 | posbound(6,5): + dpos(6,5) - 11 dposup(6,5) <= -0 224 | posbound(6,6): + dpos(6,6) - 11 dposup(6,6) <= -0 225 | posbound(6,8): + dpos(6,8) - 11 dposup(6,8) <= -0 226 | posbound(6,9): + dpos(6,9) - 11 dposup(6,9) <= -0 227 | posbound(7,2): + dpos(7,2) - 11 dposup(7,2) <= -0 228 | posbound(7,8): + dpos(7,8) - 11 dposup(7,8) <= -0 229 | posbound(7,10): + dpos(7,10) - 11 dposup(7,10) <= -0 230 | negbound(1,2): + dneg(1,2) - 6 dnegup(1,2) <= -0 231 | negbound(1,4): + dneg(1,4) - 6 dnegup(1,4) <= -0 232 | negbound(1,5): + dneg(1,5) - 6 dnegup(1,5) <= -0 233 | negbound(1,6): + dneg(1,6) - 6 dnegup(1,6) <= -0 234 | negbound(1,8): + dneg(1,8) - 6 dnegup(1,8) <= -0 235 | negbound(2,3): + dneg(2,3) - 6 dnegup(2,3) <= -0 236 | negbound(2,5): + dneg(2,5) - 6 dnegup(2,5) <= -0 237 | negbound(2,7): + dneg(2,7) - 6 dnegup(2,7) <= -0 238 | negbound(2,10): + dneg(2,10) - 6 dnegup(2,10) <= -0 239 | negbound(3,1): + dneg(3,1) - 6 dnegup(3,1) <= -0 240 | negbound(3,3): + dneg(3,3) - 6 dnegup(3,3) <= -0 241 | negbound(3,4): + dneg(3,4) - 6 dnegup(3,4) <= -0 242 | negbound(3,5): + dneg(3,5) - 6 dnegup(3,5) <= -0 243 | negbound(3,8): + dneg(3,8) - 6 dnegup(3,8) <= -0 244 | negbound(3,9): + dneg(3,9) - 6 dnegup(3,9) <= -0 245 | negbound(4,2): + dneg(4,2) - 6 dnegup(4,2) <= -0 246 | negbound(4,4): + dneg(4,4) - 6 dnegup(4,4) <= -0 247 | negbound(4,5): + dneg(4,5) - 6 dnegup(4,5) <= -0 248 | negbound(4,6): + dneg(4,6) - 6 dnegup(4,6) <= -0 249 | negbound(4,7): + dneg(4,7) - 6 dnegup(4,7) <= -0 250 | negbound(4,8): + dneg(4,8) - 6 dnegup(4,8) <= -0 251 | negbound(4,10): + dneg(4,10) - 6 dnegup(4,10) <= -0 252 | negbound(5,1): + dneg(5,1) - 6 dnegup(5,1) <= -0 253 | negbound(5,4): + dneg(5,4) - 6 dnegup(5,4) <= -0 254 | negbound(5,7): + dneg(5,7) - 6 dnegup(5,7) <= -0 255 | negbound(5,8): + dneg(5,8) - 6 dnegup(5,8) <= -0 256 | negbound(5,9): + dneg(5,9) - 6 dnegup(5,9) <= -0 257 | negbound(5,10): + dneg(5,10) - 6 dnegup(5,10) <= -0 258 | negbound(6,1): + dneg(6,1) - 6 dnegup(6,1) <= -0 259 | negbound(6,2): + dneg(6,2) - 6 dnegup(6,2) <= -0 260 | negbound(6,3): + dneg(6,3) - 6 dnegup(6,3) <= -0 261 | negbound(6,4): + dneg(6,4) - 6 dnegup(6,4) <= -0 262 | negbound(6,7): + dneg(6,7) - 6 dnegup(6,7) <= -0 263 | negbound(6,10): + dneg(6,10) - 6 dnegup(6,10) <= -0 264 | negbound(7,1): + dneg(7,1) - 6 dnegup(7,1) <= -0 265 | negbound(7,3): + dneg(7,3) - 6 dnegup(7,3) <= -0 266 | negbound(7,4): + dneg(7,4) - 6 dnegup(7,4) <= -0 267 | negbound(7,5): + dneg(7,5) - 6 dnegup(7,5) <= -0 268 | negbound(7,6): + dneg(7,6) - 6 dnegup(7,6) <= -0 269 | negbound(7,7): + dneg(7,7) - 6 dnegup(7,7) <= -0 270 | negbound(7,9): + dneg(7,9) - 6 dnegup(7,9) <= -0 271 | negbound(1,1): + dneg(1,1) - 6 dnegup(1,1) <= -0 272 | negbound(1,3): + dneg(1,3) - 6 dnegup(1,3) <= -0 273 | negbound(1,7): + dneg(1,7) - 6 dnegup(1,7) <= -0 274 | negbound(1,9): + dneg(1,9) - 6 dnegup(1,9) <= -0 275 | negbound(1,10): + dneg(1,10) - 6 dnegup(1,10) <= -0 276 | negbound(2,1): + dneg(2,1) - 6 dnegup(2,1) <= -0 277 | negbound(2,2): + dneg(2,2) - 6 dnegup(2,2) <= -0 278 | negbound(2,4): + dneg(2,4) - 6 dnegup(2,4) <= -0 279 | negbound(2,6): + dneg(2,6) - 6 dnegup(2,6) <= -0 280 | negbound(2,8): + dneg(2,8) - 6 dnegup(2,8) <= -0 281 | negbound(2,9): + dneg(2,9) - 6 dnegup(2,9) <= -0 282 | negbound(3,2): + dneg(3,2) - 6 dnegup(3,2) <= -0 283 | negbound(3,6): + dneg(3,6) - 6 dnegup(3,6) <= -0 284 | negbound(3,7): + dneg(3,7) - 6 dnegup(3,7) <= -0 285 | negbound(3,10): + dneg(3,10) - 6 dnegup(3,10) <= -0 286 | negbound(4,1): + dneg(4,1) - 6 dnegup(4,1) <= -0 287 | negbound(4,3): + dneg(4,3) - 6 dnegup(4,3) <= -0 288 | negbound(4,9): + dneg(4,9) - 6 dnegup(4,9) <= -0 289 | negbound(5,2): + dneg(5,2) - 6 dnegup(5,2) <= -0 290 | negbound(5,3): + dneg(5,3) - 6 dnegup(5,3) <= -0 291 | negbound(5,5): + dneg(5,5) - 6 dnegup(5,5) <= -0 292 | negbound(5,6): + dneg(5,6) - 6 dnegup(5,6) <= -0 293 | negbound(6,5): + dneg(6,5) - 6 dnegup(6,5) <= -0 294 | negbound(6,6): + dneg(6,6) - 6 dnegup(6,6) <= -0 295 | negbound(6,8): + dneg(6,8) - 6 dnegup(6,8) <= -0 296 | negbound(6,9): + dneg(6,9) - 6 dnegup(6,9) <= -0 297 | negbound(7,2): + dneg(7,2) - 6 dnegup(7,2) <= -0 298 | negbound(7,8): + dneg(7,8) - 6 dnegup(7,8) <= -0 299 | negbound(7,10): + dneg(7,10) - 6 dnegup(7,10) <= -0 300 | mutex(1,2): + dposup(1,2) + dnegup(1,2) = 1 301 | mutex(1,4): + dposup(1,4) + dnegup(1,4) = 1 302 | mutex(1,5): + dposup(1,5) + dnegup(1,5) = 1 303 | mutex(1,6): + dposup(1,6) + dnegup(1,6) = 1 304 | mutex(1,8): + dposup(1,8) + dnegup(1,8) = 1 305 | mutex(2,3): + dposup(2,3) + dnegup(2,3) = 1 306 | mutex(2,5): + dposup(2,5) + dnegup(2,5) = 1 307 | mutex(2,7): + dposup(2,7) + dnegup(2,7) = 1 308 | mutex(2,10): + dposup(2,10) + dnegup(2,10) = 1 309 | mutex(3,1): + dposup(3,1) + dnegup(3,1) = 1 310 | mutex(3,3): + dposup(3,3) + dnegup(3,3) = 1 311 | mutex(3,4): + dposup(3,4) + dnegup(3,4) = 1 312 | mutex(3,5): + dposup(3,5) + dnegup(3,5) = 1 313 | mutex(3,8): + dposup(3,8) + dnegup(3,8) = 1 314 | mutex(3,9): + dposup(3,9) + dnegup(3,9) = 1 315 | mutex(4,2): + dposup(4,2) + dnegup(4,2) = 1 316 | mutex(4,4): + dposup(4,4) + dnegup(4,4) = 1 317 | mutex(4,5): + dposup(4,5) + dnegup(4,5) = 1 318 | mutex(4,6): + dposup(4,6) + dnegup(4,6) = 1 319 | mutex(4,7): + dposup(4,7) + dnegup(4,7) = 1 320 | mutex(4,8): + dposup(4,8) + dnegup(4,8) = 1 321 | mutex(4,10): + dposup(4,10) + dnegup(4,10) = 1 322 | mutex(5,1): + dposup(5,1) + dnegup(5,1) = 1 323 | mutex(5,4): + dposup(5,4) + dnegup(5,4) = 1 324 | mutex(5,7): + dposup(5,7) + dnegup(5,7) = 1 325 | mutex(5,8): + dposup(5,8) + dnegup(5,8) = 1 326 | mutex(5,9): + dposup(5,9) + dnegup(5,9) = 1 327 | mutex(5,10): + dposup(5,10) + dnegup(5,10) = 1 328 | mutex(6,1): + dposup(6,1) + dnegup(6,1) = 1 329 | mutex(6,2): + dposup(6,2) + dnegup(6,2) = 1 330 | mutex(6,3): + dposup(6,3) + dnegup(6,3) = 1 331 | mutex(6,4): + dposup(6,4) + dnegup(6,4) = 1 332 | mutex(6,7): + dposup(6,7) + dnegup(6,7) = 1 333 | mutex(6,10): + dposup(6,10) + dnegup(6,10) = 1 334 | mutex(7,1): + dposup(7,1) + dnegup(7,1) = 1 335 | mutex(7,3): + dposup(7,3) + dnegup(7,3) = 1 336 | mutex(7,4): + dposup(7,4) + dnegup(7,4) = 1 337 | mutex(7,5): + dposup(7,5) + dnegup(7,5) = 1 338 | mutex(7,6): + dposup(7,6) + dnegup(7,6) = 1 339 | mutex(7,7): + dposup(7,7) + dnegup(7,7) = 1 340 | mutex(7,9): + dposup(7,9) + dnegup(7,9) = 1 341 | mutex(1,1): + dposup(1,1) + dnegup(1,1) = 1 342 | mutex(1,3): + dposup(1,3) + dnegup(1,3) = 1 343 | mutex(1,7): + dposup(1,7) + dnegup(1,7) = 1 344 | mutex(1,9): + dposup(1,9) + dnegup(1,9) = 1 345 | mutex(1,10): + dposup(1,10) + dnegup(1,10) = 1 346 | mutex(2,1): + dposup(2,1) + dnegup(2,1) = 1 347 | mutex(2,2): + dposup(2,2) + dnegup(2,2) = 1 348 | mutex(2,4): + dposup(2,4) + dnegup(2,4) = 1 349 | mutex(2,6): + dposup(2,6) + dnegup(2,6) = 1 350 | mutex(2,8): + dposup(2,8) + dnegup(2,8) = 1 351 | mutex(2,9): + dposup(2,9) + dnegup(2,9) = 1 352 | mutex(3,2): + dposup(3,2) + dnegup(3,2) = 1 353 | mutex(3,6): + dposup(3,6) + dnegup(3,6) = 1 354 | mutex(3,7): + dposup(3,7) + dnegup(3,7) = 1 355 | mutex(3,10): + dposup(3,10) + dnegup(3,10) = 1 356 | mutex(4,1): + dposup(4,1) + dnegup(4,1) = 1 357 | mutex(4,3): + dposup(4,3) + dnegup(4,3) = 1 358 | mutex(4,9): + dposup(4,9) + dnegup(4,9) = 1 359 | mutex(5,2): + dposup(5,2) + dnegup(5,2) = 1 360 | mutex(5,3): + dposup(5,3) + dnegup(5,3) = 1 361 | mutex(5,5): + dposup(5,5) + dnegup(5,5) = 1 362 | mutex(5,6): + dposup(5,6) + dnegup(5,6) = 1 363 | mutex(6,5): + dposup(6,5) + dnegup(6,5) = 1 364 | mutex(6,6): + dposup(6,6) + dnegup(6,6) = 1 365 | mutex(6,8): + dposup(6,8) + dnegup(6,8) = 1 366 | mutex(6,9): + dposup(6,9) + dnegup(6,9) = 1 367 | mutex(7,2): + dposup(7,2) + dnegup(7,2) = 1 368 | mutex(7,8): + dposup(7,8) + dnegup(7,8) = 1 369 | mutex(7,10): + dposup(7,10) + dnegup(7,10) = 1 370 | alive(1,2): + dpos(1,2) + dneg(1,2) <= 1 371 | alive(1,4): + dpos(1,4) + dneg(1,4) <= 1 372 | alive(1,5): + dpos(1,5) + dneg(1,5) <= 1 373 | alive(1,6): + dpos(1,6) + dneg(1,6) <= 1 374 | alive(1,8): + dpos(1,8) + dneg(1,8) <= 1 375 | alive(2,3): + dpos(2,3) + dneg(2,3) <= 1 376 | alive(2,5): + dpos(2,5) + dneg(2,5) <= 1 377 | alive(2,7): + dpos(2,7) + dneg(2,7) <= 1 378 | alive(2,10): + dpos(2,10) + dneg(2,10) <= 1 379 | alive(3,1): + dpos(3,1) + dneg(3,1) <= 1 380 | alive(3,3): + dpos(3,3) + dneg(3,3) <= 1 381 | alive(3,4): + dpos(3,4) + dneg(3,4) <= 1 382 | alive(3,5): + dpos(3,5) + dneg(3,5) <= 1 383 | alive(3,8): + dpos(3,8) + dneg(3,8) <= 1 384 | alive(3,9): + dpos(3,9) + dneg(3,9) <= 1 385 | alive(4,2): + dpos(4,2) + dneg(4,2) <= 1 386 | alive(4,4): + dpos(4,4) + dneg(4,4) <= 1 387 | alive(4,5): + dpos(4,5) + dneg(4,5) <= 1 388 | alive(4,6): + dpos(4,6) + dneg(4,6) <= 1 389 | alive(4,7): + dpos(4,7) + dneg(4,7) <= 1 390 | alive(4,8): + dpos(4,8) + dneg(4,8) <= 1 391 | alive(4,10): + dpos(4,10) + dneg(4,10) <= 1 392 | alive(5,1): + dpos(5,1) + dneg(5,1) <= 1 393 | alive(5,4): + dpos(5,4) + dneg(5,4) <= 1 394 | alive(5,7): + dpos(5,7) + dneg(5,7) <= 1 395 | alive(5,8): + dpos(5,8) + dneg(5,8) <= 1 396 | alive(5,9): + dpos(5,9) + dneg(5,9) <= 1 397 | alive(5,10): + dpos(5,10) + dneg(5,10) <= 1 398 | alive(6,1): + dpos(6,1) + dneg(6,1) <= 1 399 | alive(6,2): + dpos(6,2) + dneg(6,2) <= 1 400 | alive(6,3): + dpos(6,3) + dneg(6,3) <= 1 401 | alive(6,4): + dpos(6,4) + dneg(6,4) <= 1 402 | alive(6,7): + dpos(6,7) + dneg(6,7) <= 1 403 | alive(6,10): + dpos(6,10) + dneg(6,10) <= 1 404 | alive(7,1): + dpos(7,1) + dneg(7,1) <= 1 405 | alive(7,3): + dpos(7,3) + dneg(7,3) <= 1 406 | alive(7,4): + dpos(7,4) + dneg(7,4) <= 1 407 | alive(7,5): + dpos(7,5) + dneg(7,5) <= 1 408 | alive(7,6): + dpos(7,6) + dneg(7,6) <= 1 409 | alive(7,7): + dpos(7,7) + dneg(7,7) <= 1 410 | alive(7,9): + dpos(7,9) + dneg(7,9) <= 1 411 | dead(1,1): + dpos(1,1) + dneg(1,1) >= 2 412 | dead(1,3): + dpos(1,3) + dneg(1,3) >= 2 413 | dead(1,7): + dpos(1,7) + dneg(1,7) >= 2 414 | dead(1,9): + dpos(1,9) + dneg(1,9) >= 2 415 | dead(1,10): + dpos(1,10) + dneg(1,10) >= 2 416 | dead(2,1): + dpos(2,1) + dneg(2,1) >= 2 417 | dead(2,2): + dpos(2,2) + dneg(2,2) >= 2 418 | dead(2,4): + dpos(2,4) + dneg(2,4) >= 2 419 | dead(2,6): + dpos(2,6) + dneg(2,6) >= 2 420 | dead(2,8): + dpos(2,8) + dneg(2,8) >= 2 421 | dead(2,9): + dpos(2,9) + dneg(2,9) >= 2 422 | dead(3,2): + dpos(3,2) + dneg(3,2) >= 2 423 | dead(3,6): + dpos(3,6) + dneg(3,6) >= 2 424 | dead(3,7): + dpos(3,7) + dneg(3,7) >= 2 425 | dead(3,10): + dpos(3,10) + dneg(3,10) >= 2 426 | dead(4,1): + dpos(4,1) + dneg(4,1) >= 2 427 | dead(4,3): + dpos(4,3) + dneg(4,3) >= 2 428 | dead(4,9): + dpos(4,9) + dneg(4,9) >= 2 429 | dead(5,2): + dpos(5,2) + dneg(5,2) >= 2 430 | dead(5,3): + dpos(5,3) + dneg(5,3) >= 2 431 | dead(5,5): + dpos(5,5) + dneg(5,5) >= 2 432 | dead(5,6): + dpos(5,6) + dneg(5,6) >= 2 433 | dead(6,5): + dpos(6,5) + dneg(6,5) >= 2 434 | dead(6,6): + dpos(6,6) + dneg(6,6) >= 2 435 | dead(6,8): + dpos(6,8) + dneg(6,8) >= 2 436 | dead(6,9): + dpos(6,9) + dneg(6,9) >= 2 437 | dead(7,2): + dpos(7,2) + dneg(7,2) >= 2 438 | dead(7,8): + dpos(7,8) + dneg(7,8) >= 2 439 | dead(7,10): + dpos(7,10) + dneg(7,10) >= 2 440 | 441 | Bounds 442 | 0 <= x(1,3) <= 1 443 | 0 <= x(1,1) <= 1 444 | 0 <= x(2,2) <= 1 445 | 0 <= x(0,2) <= 1 446 | 0 <= x(2,3) <= 1 447 | 0 <= x(0,3) <= 1 448 | 0 <= x(2,1) <= 1 449 | 0 <= x(0,1) <= 1 450 | 0 <= x(1,2) <= 1 451 | 0 <= x(1,5) <= 1 452 | 0 <= x(2,4) <= 1 453 | 0 <= x(0,4) <= 1 454 | 0 <= x(2,5) <= 1 455 | 0 <= x(0,5) <= 1 456 | 0 <= x(1,4) <= 1 457 | 0 <= x(1,6) <= 1 458 | 0 <= x(2,6) <= 1 459 | 0 <= x(0,6) <= 1 460 | 0 <= x(1,7) <= 1 461 | 0 <= x(2,7) <= 1 462 | 0 <= x(0,7) <= 1 463 | 0 <= x(1,9) <= 1 464 | 0 <= x(2,8) <= 1 465 | 0 <= x(0,8) <= 1 466 | 0 <= x(2,9) <= 1 467 | 0 <= x(0,9) <= 1 468 | 0 <= x(1,8) <= 1 469 | 0 <= x(3,3) <= 1 470 | 0 <= x(3,4) <= 1 471 | 0 <= x(3,2) <= 1 472 | 0 <= x(3,5) <= 1 473 | 0 <= x(3,6) <= 1 474 | 0 <= x(3,7) <= 1 475 | 0 <= x(3,8) <= 1 476 | 0 <= x(2,11) <= 1 477 | 0 <= x(3,10) <= 1 478 | 0 <= x(1,10) <= 1 479 | 0 <= x(3,11) <= 1 480 | 0 <= x(1,11) <= 1 481 | 0 <= x(3,9) <= 1 482 | 0 <= x(2,10) <= 1 483 | 0 <= x(3,0) <= 1 484 | 0 <= x(4,1) <= 1 485 | 0 <= x(4,2) <= 1 486 | 0 <= x(4,0) <= 1 487 | 0 <= x(2,0) <= 1 488 | 0 <= x(3,1) <= 1 489 | 0 <= x(4,3) <= 1 490 | 0 <= x(4,4) <= 1 491 | 0 <= x(4,5) <= 1 492 | 0 <= x(4,6) <= 1 493 | 0 <= x(4,8) <= 1 494 | 0 <= x(4,9) <= 1 495 | 0 <= x(4,7) <= 1 496 | 0 <= x(4,10) <= 1 497 | 0 <= x(5,2) <= 1 498 | 0 <= x(5,3) <= 1 499 | 0 <= x(5,1) <= 1 500 | 0 <= x(5,4) <= 1 501 | 0 <= x(5,5) <= 1 502 | 0 <= x(5,6) <= 1 503 | 0 <= x(5,7) <= 1 504 | 0 <= x(5,8) <= 1 505 | 0 <= x(5,9) <= 1 506 | 0 <= x(4,11) <= 1 507 | 0 <= x(5,10) <= 1 508 | 0 <= x(5,11) <= 1 509 | 0 <= x(5,0) <= 1 510 | 0 <= x(6,1) <= 1 511 | 0 <= x(6,2) <= 1 512 | 0 <= x(6,0) <= 1 513 | 0 <= x(6,4) <= 1 514 | 0 <= x(6,5) <= 1 515 | 0 <= x(6,3) <= 1 516 | 0 <= x(6,7) <= 1 517 | 0 <= x(6,8) <= 1 518 | 0 <= x(6,6) <= 1 519 | 0 <= x(6,9) <= 1 520 | 0 <= x(6,10) <= 1 521 | 0 <= x(6,11) <= 1 522 | 0 <= x(7,1) <= 1 523 | 0 <= x(7,2) <= 1 524 | 0 <= x(7,0) <= 1 525 | 0 <= x(7,3) <= 1 526 | 0 <= x(7,4) <= 1 527 | 0 <= x(7,5) <= 1 528 | 0 <= x(7,7) <= 1 529 | 0 <= x(7,8) <= 1 530 | 0 <= x(7,6) <= 1 531 | 0 <= x(7,10) <= 1 532 | 0 <= x(7,11) <= 1 533 | 0 <= x(7,9) <= 1 534 | 0 <= x(8,1) <= 1 535 | 0 <= x(8,2) <= 1 536 | 0 <= x(8,0) <= 1 537 | 0 <= x(8,3) <= 1 538 | 0 <= x(8,4) <= 1 539 | 0 <= x(8,5) <= 1 540 | 0 <= x(8,6) <= 1 541 | 0 <= x(8,7) <= 1 542 | 0 <= x(8,8) <= 1 543 | 0 <= x(8,9) <= 1 544 | 0 <= x(8,10) <= 1 545 | 0 <= x(1,0) <= 1 546 | 0 <= x(0,0) <= 1 547 | 0 <= x(0,10) <= 1 548 | 0 <= x(0,11) <= 1 549 | 0 <= x(8,11) <= 1 550 | 0 <= dposup(1,2) <= 1 551 | 0 <= dposup(1,4) <= 1 552 | 0 <= dposup(1,5) <= 1 553 | 0 <= dposup(1,6) <= 1 554 | 0 <= dposup(1,8) <= 1 555 | 0 <= dposup(2,3) <= 1 556 | 0 <= dposup(2,5) <= 1 557 | 0 <= dposup(2,7) <= 1 558 | 0 <= dposup(2,10) <= 1 559 | 0 <= dposup(3,1) <= 1 560 | 0 <= dposup(3,3) <= 1 561 | 0 <= dposup(3,4) <= 1 562 | 0 <= dposup(3,5) <= 1 563 | 0 <= dposup(3,8) <= 1 564 | 0 <= dposup(3,9) <= 1 565 | 0 <= dposup(4,2) <= 1 566 | 0 <= dposup(4,4) <= 1 567 | 0 <= dposup(4,5) <= 1 568 | 0 <= dposup(4,6) <= 1 569 | 0 <= dposup(4,7) <= 1 570 | 0 <= dposup(4,8) <= 1 571 | 0 <= dposup(4,10) <= 1 572 | 0 <= dposup(5,1) <= 1 573 | 0 <= dposup(5,4) <= 1 574 | 0 <= dposup(5,7) <= 1 575 | 0 <= dposup(5,8) <= 1 576 | 0 <= dposup(5,9) <= 1 577 | 0 <= dposup(5,10) <= 1 578 | 0 <= dposup(6,1) <= 1 579 | 0 <= dposup(6,2) <= 1 580 | 0 <= dposup(6,3) <= 1 581 | 0 <= dposup(6,4) <= 1 582 | 0 <= dposup(6,7) <= 1 583 | 0 <= dposup(6,10) <= 1 584 | 0 <= dposup(7,1) <= 1 585 | 0 <= dposup(7,3) <= 1 586 | 0 <= dposup(7,4) <= 1 587 | 0 <= dposup(7,5) <= 1 588 | 0 <= dposup(7,6) <= 1 589 | 0 <= dposup(7,7) <= 1 590 | 0 <= dposup(7,9) <= 1 591 | 0 <= dposup(1,1) <= 1 592 | 0 <= dposup(1,3) <= 1 593 | 0 <= dposup(1,7) <= 1 594 | 0 <= dposup(1,9) <= 1 595 | 0 <= dposup(1,10) <= 1 596 | 0 <= dposup(2,1) <= 1 597 | 0 <= dposup(2,2) <= 1 598 | 0 <= dposup(2,4) <= 1 599 | 0 <= dposup(2,6) <= 1 600 | 0 <= dposup(2,8) <= 1 601 | 0 <= dposup(2,9) <= 1 602 | 0 <= dposup(3,2) <= 1 603 | 0 <= dposup(3,6) <= 1 604 | 0 <= dposup(3,7) <= 1 605 | 0 <= dposup(3,10) <= 1 606 | 0 <= dposup(4,1) <= 1 607 | 0 <= dposup(4,3) <= 1 608 | 0 <= dposup(4,9) <= 1 609 | 0 <= dposup(5,2) <= 1 610 | 0 <= dposup(5,3) <= 1 611 | 0 <= dposup(5,5) <= 1 612 | 0 <= dposup(5,6) <= 1 613 | 0 <= dposup(6,5) <= 1 614 | 0 <= dposup(6,6) <= 1 615 | 0 <= dposup(6,8) <= 1 616 | 0 <= dposup(6,9) <= 1 617 | 0 <= dposup(7,2) <= 1 618 | 0 <= dposup(7,8) <= 1 619 | 0 <= dposup(7,10) <= 1 620 | 0 <= dnegup(1,2) <= 1 621 | 0 <= dnegup(1,4) <= 1 622 | 0 <= dnegup(1,5) <= 1 623 | 0 <= dnegup(1,6) <= 1 624 | 0 <= dnegup(1,8) <= 1 625 | 0 <= dnegup(2,3) <= 1 626 | 0 <= dnegup(2,5) <= 1 627 | 0 <= dnegup(2,7) <= 1 628 | 0 <= dnegup(2,10) <= 1 629 | 0 <= dnegup(3,1) <= 1 630 | 0 <= dnegup(3,3) <= 1 631 | 0 <= dnegup(3,4) <= 1 632 | 0 <= dnegup(3,5) <= 1 633 | 0 <= dnegup(3,8) <= 1 634 | 0 <= dnegup(3,9) <= 1 635 | 0 <= dnegup(4,2) <= 1 636 | 0 <= dnegup(4,4) <= 1 637 | 0 <= dnegup(4,5) <= 1 638 | 0 <= dnegup(4,6) <= 1 639 | 0 <= dnegup(4,7) <= 1 640 | 0 <= dnegup(4,8) <= 1 641 | 0 <= dnegup(4,10) <= 1 642 | 0 <= dnegup(5,1) <= 1 643 | 0 <= dnegup(5,4) <= 1 644 | 0 <= dnegup(5,7) <= 1 645 | 0 <= dnegup(5,8) <= 1 646 | 0 <= dnegup(5,9) <= 1 647 | 0 <= dnegup(5,10) <= 1 648 | 0 <= dnegup(6,1) <= 1 649 | 0 <= dnegup(6,2) <= 1 650 | 0 <= dnegup(6,3) <= 1 651 | 0 <= dnegup(6,4) <= 1 652 | 0 <= dnegup(6,7) <= 1 653 | 0 <= dnegup(6,10) <= 1 654 | 0 <= dnegup(7,1) <= 1 655 | 0 <= dnegup(7,3) <= 1 656 | 0 <= dnegup(7,4) <= 1 657 | 0 <= dnegup(7,5) <= 1 658 | 0 <= dnegup(7,6) <= 1 659 | 0 <= dnegup(7,7) <= 1 660 | 0 <= dnegup(7,9) <= 1 661 | 0 <= dnegup(1,1) <= 1 662 | 0 <= dnegup(1,3) <= 1 663 | 0 <= dnegup(1,7) <= 1 664 | 0 <= dnegup(1,9) <= 1 665 | 0 <= dnegup(1,10) <= 1 666 | 0 <= dnegup(2,1) <= 1 667 | 0 <= dnegup(2,2) <= 1 668 | 0 <= dnegup(2,4) <= 1 669 | 0 <= dnegup(2,6) <= 1 670 | 0 <= dnegup(2,8) <= 1 671 | 0 <= dnegup(2,9) <= 1 672 | 0 <= dnegup(3,2) <= 1 673 | 0 <= dnegup(3,6) <= 1 674 | 0 <= dnegup(3,7) <= 1 675 | 0 <= dnegup(3,10) <= 1 676 | 0 <= dnegup(4,1) <= 1 677 | 0 <= dnegup(4,3) <= 1 678 | 0 <= dnegup(4,9) <= 1 679 | 0 <= dnegup(5,2) <= 1 680 | 0 <= dnegup(5,3) <= 1 681 | 0 <= dnegup(5,5) <= 1 682 | 0 <= dnegup(5,6) <= 1 683 | 0 <= dnegup(6,5) <= 1 684 | 0 <= dnegup(6,6) <= 1 685 | 0 <= dnegup(6,8) <= 1 686 | 0 <= dnegup(6,9) <= 1 687 | 0 <= dnegup(7,2) <= 1 688 | 0 <= dnegup(7,8) <= 1 689 | 0 <= dnegup(7,10) <= 1 690 | 691 | Generals 692 | x(1,3) 693 | x(1,1) 694 | x(2,2) 695 | x(0,2) 696 | x(2,3) 697 | x(0,3) 698 | x(2,1) 699 | x(0,1) 700 | x(1,2) 701 | x(1,5) 702 | x(2,4) 703 | x(0,4) 704 | x(2,5) 705 | x(0,5) 706 | x(1,4) 707 | x(1,6) 708 | x(2,6) 709 | x(0,6) 710 | x(1,7) 711 | x(2,7) 712 | x(0,7) 713 | x(1,9) 714 | x(2,8) 715 | x(0,8) 716 | x(2,9) 717 | x(0,9) 718 | x(1,8) 719 | x(3,3) 720 | x(3,4) 721 | x(3,2) 722 | x(3,5) 723 | x(3,6) 724 | x(3,7) 725 | x(3,8) 726 | x(2,11) 727 | x(3,10) 728 | x(1,10) 729 | x(3,11) 730 | x(1,11) 731 | x(3,9) 732 | x(2,10) 733 | x(3,0) 734 | x(4,1) 735 | x(4,2) 736 | x(4,0) 737 | x(2,0) 738 | x(3,1) 739 | x(4,3) 740 | x(4,4) 741 | x(4,5) 742 | x(4,6) 743 | x(4,8) 744 | x(4,9) 745 | x(4,7) 746 | x(4,10) 747 | x(5,2) 748 | x(5,3) 749 | x(5,1) 750 | x(5,4) 751 | x(5,5) 752 | x(5,6) 753 | x(5,7) 754 | x(5,8) 755 | x(5,9) 756 | x(4,11) 757 | x(5,10) 758 | x(5,11) 759 | x(5,0) 760 | x(6,1) 761 | x(6,2) 762 | x(6,0) 763 | x(6,4) 764 | x(6,5) 765 | x(6,3) 766 | x(6,7) 767 | x(6,8) 768 | x(6,6) 769 | x(6,9) 770 | x(6,10) 771 | x(6,11) 772 | x(7,1) 773 | x(7,2) 774 | x(7,0) 775 | x(7,3) 776 | x(7,4) 777 | x(7,5) 778 | x(7,7) 779 | x(7,8) 780 | x(7,6) 781 | x(7,10) 782 | x(7,11) 783 | x(7,9) 784 | x(8,1) 785 | x(8,2) 786 | x(8,0) 787 | x(8,3) 788 | x(8,4) 789 | x(8,5) 790 | x(8,6) 791 | x(8,7) 792 | x(8,8) 793 | x(8,9) 794 | x(8,10) 795 | x(1,0) 796 | x(0,0) 797 | x(0,10) 798 | x(0,11) 799 | x(8,11) 800 | dposup(1,2) 801 | dposup(1,4) 802 | dposup(1,5) 803 | dposup(1,6) 804 | dposup(1,8) 805 | dposup(2,3) 806 | dposup(2,5) 807 | dposup(2,7) 808 | dposup(2,10) 809 | dposup(3,1) 810 | dposup(3,3) 811 | dposup(3,4) 812 | dposup(3,5) 813 | dposup(3,8) 814 | dposup(3,9) 815 | dposup(4,2) 816 | dposup(4,4) 817 | dposup(4,5) 818 | dposup(4,6) 819 | dposup(4,7) 820 | dposup(4,8) 821 | dposup(4,10) 822 | dposup(5,1) 823 | dposup(5,4) 824 | dposup(5,7) 825 | dposup(5,8) 826 | dposup(5,9) 827 | dposup(5,10) 828 | dposup(6,1) 829 | dposup(6,2) 830 | dposup(6,3) 831 | dposup(6,4) 832 | dposup(6,7) 833 | dposup(6,10) 834 | dposup(7,1) 835 | dposup(7,3) 836 | dposup(7,4) 837 | dposup(7,5) 838 | dposup(7,6) 839 | dposup(7,7) 840 | dposup(7,9) 841 | dposup(1,1) 842 | dposup(1,3) 843 | dposup(1,7) 844 | dposup(1,9) 845 | dposup(1,10) 846 | dposup(2,1) 847 | dposup(2,2) 848 | dposup(2,4) 849 | dposup(2,6) 850 | dposup(2,8) 851 | dposup(2,9) 852 | dposup(3,2) 853 | dposup(3,6) 854 | dposup(3,7) 855 | dposup(3,10) 856 | dposup(4,1) 857 | dposup(4,3) 858 | dposup(4,9) 859 | dposup(5,2) 860 | dposup(5,3) 861 | dposup(5,5) 862 | dposup(5,6) 863 | dposup(6,5) 864 | dposup(6,6) 865 | dposup(6,8) 866 | dposup(6,9) 867 | dposup(7,2) 868 | dposup(7,8) 869 | dposup(7,10) 870 | dnegup(1,2) 871 | dnegup(1,4) 872 | dnegup(1,5) 873 | dnegup(1,6) 874 | dnegup(1,8) 875 | dnegup(2,3) 876 | dnegup(2,5) 877 | dnegup(2,7) 878 | dnegup(2,10) 879 | dnegup(3,1) 880 | dnegup(3,3) 881 | dnegup(3,4) 882 | dnegup(3,5) 883 | dnegup(3,8) 884 | dnegup(3,9) 885 | dnegup(4,2) 886 | dnegup(4,4) 887 | dnegup(4,5) 888 | dnegup(4,6) 889 | dnegup(4,7) 890 | dnegup(4,8) 891 | dnegup(4,10) 892 | dnegup(5,1) 893 | dnegup(5,4) 894 | dnegup(5,7) 895 | dnegup(5,8) 896 | dnegup(5,9) 897 | dnegup(5,10) 898 | dnegup(6,1) 899 | dnegup(6,2) 900 | dnegup(6,3) 901 | dnegup(6,4) 902 | dnegup(6,7) 903 | dnegup(6,10) 904 | dnegup(7,1) 905 | dnegup(7,3) 906 | dnegup(7,4) 907 | dnegup(7,5) 908 | dnegup(7,6) 909 | dnegup(7,7) 910 | dnegup(7,9) 911 | dnegup(1,1) 912 | dnegup(1,3) 913 | dnegup(1,7) 914 | dnegup(1,9) 915 | dnegup(1,10) 916 | dnegup(2,1) 917 | dnegup(2,2) 918 | dnegup(2,4) 919 | dnegup(2,6) 920 | dnegup(2,8) 921 | dnegup(2,9) 922 | dnegup(3,2) 923 | dnegup(3,6) 924 | dnegup(3,7) 925 | dnegup(3,10) 926 | dnegup(4,1) 927 | dnegup(4,3) 928 | dnegup(4,9) 929 | dnegup(5,2) 930 | dnegup(5,3) 931 | dnegup(5,5) 932 | dnegup(5,6) 933 | dnegup(6,5) 934 | dnegup(6,6) 935 | dnegup(6,8) 936 | dnegup(6,9) 937 | dnegup(7,2) 938 | dnegup(7,8) 939 | dnegup(7,10) 940 | 941 | End 942 | -------------------------------------------------------------------------------- /tests/test.js: -------------------------------------------------------------------------------- 1 | /** @type {import("../types").default} */ 2 | const highs = require('../build/highs.js'); 3 | const assert = require('assert').strict; 4 | const fs = require('fs'); 5 | 6 | const PROBLEM = `Maximize 7 | obj: x1 + 2 x2 + 4 x3 + x4 8 | Subject To 9 | c1: - x1 + x2 + x3 + 10 x4 <= 20 10 | c2: x1 - 4 x2 + x3 <= 30 11 | c3: x2 - 0.5 x4 = 0 12 | Bounds 13 | 0 <= x1 <= 40 14 | 2 <= x4 <= 3 15 | End`; 16 | 17 | const SOLUTION = { 18 | Status: 'Optimal', 19 | ObjectiveValue: 87.5, 20 | Columns: { 21 | x1: { 22 | Index: 0, 23 | Status: 'BS', 24 | Lower: 0, 25 | Type: 'Continuous', 26 | Upper: 40, 27 | Primal: 17.5, 28 | Dual: -0, 29 | Name: 'x1' 30 | }, 31 | x2: { 32 | Index: 1, 33 | Status: 'BS', 34 | Lower: 0, 35 | Type: 'Continuous', 36 | Upper: Infinity, 37 | Primal: 1, 38 | Dual: -0, 39 | Name: 'x2' 40 | }, 41 | x3: { 42 | Index: 2, 43 | Status: 'BS', 44 | Lower: 0, 45 | Type: 'Continuous', 46 | Upper: Infinity, 47 | Primal: 16.5, 48 | Dual: -0, 49 | Name: 'x3' 50 | }, 51 | x4: { 52 | Index: 3, 53 | Status: 'LB', 54 | Lower: 2, 55 | Type: 'Continuous', 56 | Upper: 3, 57 | Primal: 2, 58 | Dual: -8.75, 59 | Name: 'x4' 60 | } 61 | }, 62 | Rows: [ 63 | { 64 | Index: 0, 65 | Name: 'c1', 66 | Status: 'UB', 67 | Lower: -Infinity, 68 | Upper: 20, 69 | Primal: 20, 70 | Dual: 1.5 71 | }, 72 | { 73 | Index: 1, 74 | Name: 'c2', 75 | Status: 'UB', 76 | Lower: -Infinity, 77 | Upper: 30, 78 | Primal: 30, 79 | Dual: 2.5 80 | }, 81 | { 82 | Index: 2, 83 | Name: 'c3', 84 | Status: 'UB', 85 | Lower: 0, 86 | Upper: 0, 87 | Primal: 0, 88 | Dual: 10.5 89 | } 90 | ] 91 | }; 92 | 93 | /** 94 | * @param {import("../types").Highs} Module 95 | */ 96 | function test_optimal(Module) { 97 | const sol = Module.solve(PROBLEM); 98 | assert.deepStrictEqual(sol, SOLUTION); 99 | } 100 | 101 | /** 102 | * @param {import("../types").Highs} Module 103 | */ 104 | function test_options(Module) { 105 | const sol = Module.solve(PROBLEM, { 106 | primal_feasibility_tolerance: 1e-9, // option type: double 107 | time_limit: 1000, // option type: double 108 | allowed_cost_scale_factor: 2, // option type: integer 109 | use_implied_bounds_from_presolve: true, 110 | presolve: 'off' 111 | }); 112 | assert.deepStrictEqual(sol, SOLUTION); 113 | } 114 | 115 | /** 116 | * @param {import("../types").Highs} Module 117 | */ 118 | function test_empty_model(Module) { 119 | // Arguably, this example should not be considered valid at all, but 120 | // HiGHS parses it as an empty model; see 121 | // https://github.com/ERGO-Code/HiGHS/issues/1451 122 | const sol = Module.solve(`Minimize 123 | 42 124 | End`); 125 | assert.deepStrictEqual(sol, { 126 | Columns: {}, 127 | ObjectiveValue: 0, 128 | Rows: [], 129 | Status: 'Empty' 130 | }); 131 | } 132 | 133 | /** 134 | * @param {import("../types").Highs} Module 135 | */ 136 | function test_invalid_model(Module) { 137 | assert.throws( 138 | _ => 139 | Module.solve(`Minimize 140 | ] 2 [ 141 | End`), 142 | /Unable to read LP model/ 143 | ); 144 | } 145 | 146 | /** 147 | * @param {import("../types").Highs} Module 148 | */ 149 | function test_integer_problem(Module) { 150 | const sol = Module.solve(`Minimize 151 | obj: a + b 152 | Subject To 153 | c1: 2 a + b >= 6.5 154 | General 155 | a 156 | End`); 157 | assert.deepStrictEqual(sol, { 158 | Status: 'Optimal', 159 | ObjectiveValue: 3.5, 160 | Columns: { 161 | a: { 162 | Index: 0, 163 | Lower: 0, 164 | Upper: Infinity, 165 | Primal: 3, 166 | Type: 'Integer', 167 | Name: 'a' 168 | }, 169 | b: { 170 | Index: 1, 171 | Lower: 0, 172 | Upper: Infinity, 173 | Primal: 0.5, 174 | Type: 'Continuous', 175 | Name: 'b' 176 | } 177 | }, 178 | Rows: [{ Index: 0, Lower: 6.5, Upper: Infinity, Primal: 6.5, Name: 'c1' }] 179 | }); 180 | } 181 | 182 | function test_case_with_no_constraints(Module) { 183 | const sol = Module.solve(`Maximize 184 | obj: x1 + 2 x2 185 | Bounds 186 | 0 <= x1 <= 40 187 | 2 <= x2 <= 3 188 | End`); 189 | assert.deepStrictEqual(sol, { 190 | Status: 'Optimal', 191 | ObjectiveValue: 46, 192 | Columns: { 193 | x1: { 194 | Index: 0, 195 | Status: 'UB', 196 | Lower: 0, 197 | Upper: 40, 198 | Type: 'Continuous', 199 | Primal: 40, 200 | Dual: 1, 201 | Name: 'x1' 202 | }, 203 | x2: { 204 | Index: 1, 205 | Status: 'UB', 206 | Lower: 2, 207 | Type: 'Continuous', 208 | Upper: 3, 209 | Primal: 3, 210 | Dual: 2, 211 | Name: 'x2' 212 | } 213 | }, 214 | Rows: [] 215 | }); 216 | } 217 | 218 | /** 219 | * @param {import("../types").Highs} Module 220 | */ 221 | function test_quadratic_program(Module) { 222 | const sol = Module.solve(`Minimize 223 | obj: a + b + [ a^2 + 4 a * b + 7 b^2 ]/2 224 | Subject To 225 | c1: a + b >= 10 226 | End`); 227 | assert.deepStrictEqual(sol, { 228 | Status: 'Optimal', 229 | ObjectiveValue: 60, 230 | Columns: { 231 | a: { 232 | Index: 0, 233 | Lower: 0, 234 | Status: 'BS', 235 | Type: 'Continuous', 236 | Upper: Infinity, 237 | Primal: 10, 238 | Dual: 0, 239 | Name: 'a' 240 | }, 241 | b: { 242 | Index: 1, 243 | Lower: 0, 244 | Status: 'LB', 245 | Type: 'Continuous', 246 | Upper: Infinity, 247 | Primal: 0, 248 | Dual: 10, 249 | Name: 'b' 250 | } 251 | }, 252 | Rows: [{ Index: 0, Lower: 10, Upper: Infinity, Primal: 10, Dual: 11, Status: 'LB', Name: 'c1' }] 253 | }); 254 | } 255 | 256 | /** 257 | * @param {import("../types").Highs} Module 258 | */ 259 | function test_quadratic_program_not_positive_semidefinite(Module) { 260 | assert.throws(_ => 261 | Module.solve(`Maximize 262 | obj: [x1^2]/2 263 | Bounds 264 | 0 <= x1 <= 40 265 | End`) 266 | ); 267 | } 268 | 269 | /** 270 | * @param {import("../types").Highs} Module 271 | */ 272 | function test_infeasible(Module) { 273 | const sol = Module.solve(`Maximize 274 | a 275 | subject to 276 | a >= 1 277 | bounds 278 | a <= 0 279 | End`); 280 | assert.deepStrictEqual(sol, { 281 | Status: 'Infeasible', 282 | ObjectiveValue: 0, 283 | Columns: { 284 | a: { 285 | Index: 0, 286 | Lower: 0, 287 | Upper: 0, 288 | Type: 'Continuous', 289 | Name: 'a' 290 | } 291 | }, 292 | Rows: [{ Index: 0, Lower: 1, Upper: Infinity, Name: 'HiGHS_R0' }] 293 | }); 294 | } 295 | 296 | /** 297 | * @param {import("../types").Highs} Module 298 | */ 299 | function test_infeasible_ilp(Module) { 300 | const sol = Module.solve(`Maximize 301 | a 302 | subject to 303 | a >= 1 304 | bounds 305 | a <= 0 306 | General 307 | a 308 | end`); 309 | assert.deepStrictEqual(sol, { 310 | Status: 'Infeasible', 311 | ObjectiveValue: Infinity, 312 | Columns: { 313 | a: { 314 | Index: 0, 315 | Lower: 0, 316 | Upper: 0, 317 | Type: 'Integer', 318 | Name: 'a' 319 | } 320 | }, 321 | Rows: [{ Index: 0, Lower: 1, Upper: Infinity, Name: 'HiGHS_R0' }] 322 | }); 323 | } 324 | 325 | /** 326 | * @param {import("../types").Highs} Module 327 | */ 328 | function test_unbounded(Module) { 329 | const sol = Module.solve(`Maximize a 330 | subject to 331 | a >= 1 332 | end`); 333 | assert.deepStrictEqual(sol, { 334 | Status: 'Unbounded', 335 | ObjectiveValue: 1, 336 | Columns: { 337 | a: { 338 | Index: 0, 339 | Lower: 0, 340 | Type: 'Continuous', 341 | Upper: Infinity, 342 | Primal: 1, 343 | Dual: -0, 344 | Status: 'BS', 345 | Name: 'a' 346 | } 347 | }, 348 | Rows: [{ Index: 0, Status: 'LB', Lower: 1, Upper: Infinity, Primal: 1, Dual: 1, Name: 'HiGHS_R0' }] 349 | }); 350 | } 351 | 352 | /** 353 | * @param {import("../types").Highs} Module 354 | */ 355 | function test_read_model_warning(Module) { 356 | // See https://github.com/lovasoa/highs-js/issues/17 357 | const sol = Module.solve(`Minimize 358 | obj: x1 359 | Subject To 360 | c1: 1 x0 + 1 x1 = 1 361 | Bounds 362 | 0 <= x1 <= 1 363 | 1.1 <= x2 <= 1 364 | End`); 365 | assert.deepStrictEqual(sol, { 366 | Status: 'Infeasible', 367 | ObjectiveValue: 0, 368 | Columns: { 369 | x0: { 370 | Index: 1, 371 | Lower: 0, 372 | Name: 'x0', 373 | Type: 'Continuous', 374 | Upper: Infinity 375 | }, 376 | x1: { 377 | Index: 0, 378 | Lower: 0, 379 | Name: 'x1', 380 | Type: 'Continuous', 381 | Upper: 1 382 | }, 383 | x2: { 384 | Index: 2, 385 | Lower: 1.1, 386 | Name: 'x2', 387 | Type: 'Continuous', 388 | Upper: 1 389 | } 390 | }, 391 | Rows: [ 392 | { 393 | Index: 0, 394 | Lower: 1, 395 | Upper: 1, 396 | Name: 'c1' 397 | } 398 | ] 399 | }); 400 | } 401 | 402 | /** 403 | * @param {import("../types").Highs} Module 404 | */ 405 | function test_big(Module) { 406 | const pb = fs.readFileSync(__dirname + '/life_goe.mod.lp'); 407 | Module.solve(pb); 408 | } 409 | 410 | function test_many_solves(Module) { 411 | // See https://github.com/lovasoa/highs-js/issues/10 412 | for (let i = 0; i < 5000; i++) { 413 | Module.solve(`Maximize 414 | a 415 | subject to 416 | a <= 1 417 | end`); 418 | } 419 | } 420 | 421 | function test_exceeds_stack(Module) { 422 | // See https://github.com/lovasoa/highs-js/issues/41 423 | const pb = fs.readFileSync(__dirname + '/exceeds_stack.lp'); 424 | Module.solve(pb); 425 | } 426 | 427 | 428 | async function test() { 429 | const Module = await highs(); 430 | test_optimal(Module); 431 | test_empty_model(Module); 432 | test_invalid_model(Module); 433 | test_options(Module); 434 | test_integer_problem(Module); 435 | test_case_with_no_constraints(Module); 436 | test_quadratic_program(Module); 437 | test_quadratic_program_not_positive_semidefinite(Module); 438 | test_infeasible(Module); 439 | test_infeasible_ilp(Module); 440 | test_unbounded(Module); 441 | test_read_model_warning(Module); 442 | test_big(Module); 443 | test_many_solves(Module); 444 | test_exceeds_stack(Module); 445 | console.log('test succeeded'); 446 | } 447 | 448 | test(); 449 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/recommended/tsconfig.json", 3 | "compilerOptions": { 4 | "checkJs": true, 5 | "allowJs": true, 6 | "noEmit": true, 7 | "strict": false, 8 | "lib": ["es2020"] 9 | 10 | }, 11 | "include": [ 12 | "src/**/*" 13 | ], 14 | "exclude": [ 15 | "node_modules", 16 | "**/*.spec.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | type Highs = { 2 | solve(problem: string, options?: HighsOptions): HighsSolution; 3 | }; 4 | 5 | type HighsOptions = Readonly< 6 | Partial<{ 7 | /** 8 | * @default "choose" 9 | */ 10 | presolve: 'off' | 'choose' | 'on'; 11 | 12 | /** 13 | * Solver option: "simplex", "choose", "ipm" or "pdlp". If 14 | * "simplex"/"ipm"/"pdlp" is chosen then, for a MIP (QP) the 15 | * integrality 16 | * constraint (quadratic term) will be ignored 17 | * @default "choose" 18 | */ 19 | solver: 'simplex' | 'choose' | 'ipm' | 'pdlp'; 20 | 21 | /** 22 | * Parallel option: "off", "choose" or "on" 23 | * @default "choose" 24 | */ 25 | parallel: 'off' | 'choose' | 'on'; 26 | 27 | /** 28 | * Run IPM crossover: "off", "choose" or "on" 29 | * @default "on" 30 | */ 31 | run_crossover: 'off' | 'choose' | 'on'; 32 | 33 | /** 34 | * Time limit (seconds) 35 | * @default Number.POSITIVE_INFINITY 36 | */ 37 | time_limit: number; 38 | 39 | /** 40 | * Compute cost, bound, RHS and basic solution ranging: "off" or "on" 41 | * @default "off" 42 | */ 43 | ranging: 'off' | 'on'; 44 | 45 | /** 46 | * Limit on |cost coefficient|: values greater than or equal to 47 | * this will be treated as infinite 48 | * @min 1e+15 49 | * @default 1e+20 50 | */ 51 | infinite_cost: number; 52 | 53 | /** 54 | * Limit on |constraint bound|: values greater than or equal to 55 | * this will be treated as infinite 56 | * @min 1e+15 57 | * @default 1e+20 58 | */ 59 | infinite_bound: number; 60 | 61 | /** 62 | * Lower limit on |matrix entries|: values less than or equal to this 63 | * will be 64 | * treated as zero 65 | * @min 1e-12 66 | * @default 1e-09 67 | */ 68 | small_matrix_value: number; 69 | 70 | /** 71 | * Upper limit on |matrix entries|: values greater than or equal to 72 | * this will be treated as infinite 73 | * @min 1e+00 74 | * @default 1e+15 75 | */ 76 | large_matrix_value: number; 77 | 78 | /** 79 | * Primal feasibility tolerance 80 | * @min 1e-10 81 | * @default 1e-07 82 | */ 83 | primal_feasibility_tolerance: number; 84 | 85 | /** 86 | * Dual feasibility tolerance 87 | * @min 1e-10 88 | * @default 1e-07 89 | */ 90 | dual_feasibility_tolerance: number; 91 | 92 | /** 93 | * IPM optimality tolerance 94 | * @min 1e-12 95 | * @default 1e-08 96 | */ 97 | ipm_optimality_tolerance: number; 98 | 99 | /** 100 | * Objective bound for termination of the dual simplex solver 101 | * @default Number.POSITIVE_INFINITY 102 | */ 103 | objective_bound: number; 104 | 105 | /** 106 | * Objective target for termination of the MIP solver 107 | * @default Number.NEGATIVE_INFINITY 108 | */ 109 | objective_target: number; 110 | 111 | /** 112 | * random seed used in HiGHS 113 | * @min 0 114 | * @default 0 115 | */ 116 | random_seed: number; 117 | 118 | /** 119 | * number of threads used by HiGHS (0: automatic) 120 | * @min 0 121 | * @default 0 122 | */ 123 | threads: number; 124 | 125 | /** 126 | * Exponent of power-of-two bound scaling for model 127 | * @default 0 128 | */ 129 | user_bound_scale: number; 130 | 131 | /** 132 | * Exponent of power-of-two cost scaling for model 133 | * @default 0 134 | */ 135 | user_cost_scale: number; 136 | 137 | /** 138 | * Debugging level in HiGHS 139 | * @default 0 140 | */ 141 | highs_debug_level: HighsDebugLevel; 142 | 143 | /** 144 | * Analysis level in HiGHS 145 | * @default 0 146 | */ 147 | highs_analysis_level: HighsAnalysisLevel; 148 | 149 | /** 150 | * Strategy for simplex solver 0 => Choose; 1 => Dual (serial); 2 => 151 | * Dual (PAMI); 3 => Dual (SIP); 4 => Primal 152 | * @default 1 153 | */ 154 | simplex_strategy: SimplexStrategy; 155 | 156 | /** 157 | * Simplex scaling strategy: off / choose / equilibration / forced equilibration / max value 0 / max value 1 (0/1/2/3/4/5) 158 | * @default 1 159 | */ 160 | simplex_scale_strategy: SimplexScaleStrategy; 161 | 162 | /** 163 | * Strategy for simplex crash: off / LTSSF / Bixby (0/1/2) 164 | * @default 0 165 | */ 166 | simplex_crash_strategy: SimplexCrashStrategy; 167 | 168 | /** 169 | * Strategy for simplex dual edge weights: Choose / Dantzig / Devex / Steepest Edge (-1/0/1/2) 170 | * @default -1 171 | */ 172 | simplex_dual_edge_weight_strategy: SimplexEdgeWeightStrategy; 173 | 174 | /** 175 | * Strategy for simplex primal edge weights: Choose / Dantzig / Devex (-1/0/1) 176 | * @default -1 177 | */ 178 | simplex_primal_edge_weight_strategy: SimplexEdgeWeightStrategy; 179 | 180 | /** 181 | * Iteration limit for simplex solver when solving LPs, but not 182 | * subproblems in the MIP solver 183 | * @min 0 184 | * @default Number.MAX_SAFE_INTEGER 185 | */ 186 | simplex_iteration_limit: number; 187 | 188 | /** 189 | * Limit on the number of simplex UPDATE operations 190 | * @min 0 191 | * @default 5000 192 | */ 193 | simplex_update_limit: number; 194 | 195 | /** 196 | * Minimum level of concurrency in parallel simplex 197 | * @min 0 198 | * @default 1 199 | * @max 8 200 | */ 201 | simplex_min_concurrency: number; 202 | 203 | /** 204 | * Maximum level of concurrency in parallel simplex 205 | * @min 1 206 | * @default 8 207 | * @max 8 208 | */ 209 | simplex_max_concurrency: number; 210 | 211 | /** 212 | * Enables or disables solver output 213 | * @default true 214 | */ 215 | output_flag: boolean; 216 | 217 | /** 218 | * Enables or disables console logging 219 | * @default true 220 | */ 221 | log_to_console: boolean; 222 | 223 | /** 224 | * Solution file 225 | * @default "" 226 | */ 227 | solution_file: string; 228 | 229 | /** 230 | * Log file 231 | * @default "" 232 | */ 233 | log_file: string; 234 | 235 | /** 236 | * Write the primal and dual solution to a file 237 | * @default false 238 | */ 239 | write_solution_to_file: boolean; 240 | 241 | /** 242 | * Style of solution file (raw = computer-readable, 243 | * pretty = human-readable): 244 | * -1 => HiGHS old raw (deprecated); 0 => HiGHS raw; 245 | * 1 => HiGHS pretty; 2 => Glpsol raw; 3 => Glpsol pretty; 246 | * 4 => HiGHS sparse raw 247 | * @default 0 248 | */ 249 | write_solution_style: SolutionStyle; 250 | 251 | /** 252 | * Location of cost row for Glpsol file: 253 | * -2 => Last; -1 => None; 0 => None if empty, otherwise data file 254 | * location; 1 <= n <= num_row => Location n; n > 255 | * num_row => Last 256 | */ 257 | glpsol_cost_row_location: GlpsolCostRowLocation | number; 258 | 259 | /** 260 | * Run iCrash 261 | * @default false 262 | */ 263 | icrash: boolean; 264 | 265 | /** 266 | * Dualize strategy for iCrash 267 | * @default false 268 | */ 269 | icrash_dualize: boolean; 270 | 271 | /** 272 | * Strategy for iCrash 273 | * @default "ICA" 274 | */ 275 | icrash_strategy: string; 276 | 277 | /** 278 | * iCrash starting weight 279 | * @min 1e-10 280 | * @default 1e-03 281 | * @max 1e50 282 | */ 283 | icrash_starting_weight: number; 284 | 285 | /** 286 | * iCrash iterations 287 | * @min 0 288 | * @default 30 289 | * @max 200 290 | */ 291 | icrash_iterations: number; 292 | 293 | /** 294 | * iCrash approximate minimization iterations 295 | * @min 0 296 | * @default 50 297 | * @max 100 298 | */ 299 | icrash_approx_iter: number; 300 | 301 | /** 302 | * Exact subproblem solution for iCrash 303 | * @default false 304 | */ 305 | icrash_exact: boolean; 306 | 307 | /** 308 | * Exact subproblem solution for iCrash 309 | * @default false 310 | */ 311 | icrash_breakpoints: boolean; 312 | 313 | /** 314 | * Write model file 315 | * @default "" 316 | */ 317 | write_model_file: string; 318 | 319 | /** 320 | * Write the model to a file 321 | * @default false 322 | */ 323 | write_model_to_file: boolean; 324 | 325 | /** 326 | * Write presolved model file 327 | * @default "" 328 | */ 329 | write_presolved_model_file: string; 330 | 331 | /** 332 | * Write the presolved model to a file 333 | * @default false 334 | */ 335 | write_presolved_model_to_file: boolean; 336 | 337 | /** 338 | * Whether MIP symmetry should be detected 339 | * @default true 340 | */ 341 | mip_detect_symmetry: boolean; 342 | 343 | /** 344 | * Whether MIP restart is permitted 345 | * @default true 346 | */ 347 | mip_allow_restart: boolean; 348 | 349 | /** 350 | * MIP solver max number of nodes 351 | * @default Number.MAX_SAFE_INTEGER 352 | */ 353 | mip_max_nodes: number; 354 | 355 | /** 356 | * MIP solver max number of nodes where estimate is above cutoff bound 357 | * @min 0 358 | * @default Number.MAX_SAFE_INTEGER 359 | */ 360 | mip_max_stall_nodes: number; 361 | 362 | /** 363 | * MIP solver max number of nodes when completing a partial MIP start 364 | * @min 0 365 | * @default 500 366 | */ 367 | mip_max_start_nodes: number; 368 | 369 | // #ifdef HIGHS_DEBUGSOL 370 | // /** 371 | // * Solution file for debug solution of the MIP solver 372 | // * @default "" 373 | // */ 374 | // mip_debug_solution_file: string; 375 | // #endif 376 | 377 | /** 378 | * Whether improving MIP solutions should be saved 379 | * @default false 380 | */ 381 | mip_improving_solution_save: boolean; 382 | 383 | /** 384 | * Whether improving MIP solutions should be reported in sparse format 385 | * @default false 386 | */ 387 | mip_improving_solution_report_sparse: boolean; 388 | 389 | /** 390 | * File for reporting improving MIP solutions: not reported for an empty 391 | * string \"\" 392 | * @default "" 393 | */ 394 | mip_improving_solution_file: string; 395 | 396 | /** 397 | * MIP solver max number of leave nodes 398 | * @min 0 399 | * @default Number.MAX_SAFE_INTEGER 400 | */ 401 | mip_max_leaves: number; 402 | 403 | /** 404 | * Limit on the number of improving solutions found to stop the MIP 405 | * solver prematurely 406 | * @min 1 407 | * @default Number.MAX_SAFE_INTEGER 408 | */ 409 | mip_max_improving_sols: number; 410 | 411 | /** 412 | * maximal age of dynamic LP rows before they are removed from the LP relaxation in the MIP solver 413 | * @min 0 414 | * @default 10 415 | * @max 32767 416 | */ 417 | mip_lp_age_limit: number; 418 | 419 | /** 420 | * maximal age of rows in the MIP solver cutpool before they are deleted 421 | * @min 0 422 | * @default 30 423 | * @max 1000 424 | */ 425 | mip_pool_age_limit: number; 426 | 427 | /** 428 | * soft limit on the number of rows in the MIP solver cutpool for dynamic age adjustment 429 | * @min 1 430 | * @default 10000 431 | */ 432 | mip_pool_soft_limit: number; 433 | 434 | /** 435 | * minimal number of observations before MIP solver pseudo costs are considered reliable 436 | * @min 0 437 | * @default 8 438 | */ 439 | mip_pscost_minreliable: number; 440 | 441 | /** 442 | * Minimal number of entries in the MIP solver cliquetable before 443 | * neighbourhood 444 | * queries of the conflict graph use parallel processing 445 | * @min 0 446 | * @default 100000 447 | */ 448 | mip_min_cliquetable_entries_for_parallelism: number; 449 | 450 | /** 451 | * MIP solver reporting level 452 | * @min 0 453 | * @default 1 454 | * @max 2 455 | */ 456 | mip_report_level: number; 457 | 458 | /** 459 | * MIP feasibility tolerance 460 | * @min 1e-10 461 | * @default 1e-06 462 | */ 463 | mip_feasibility_tolerance: number; 464 | 465 | /** 466 | * Effort spent for MIP heuristics 467 | * @min 0 468 | * @default 0.05 469 | * @max 1 470 | */ 471 | mip_heuristic_effort: number; 472 | 473 | /** 474 | * Tolerance on relative gap, |ub-lb|/|ub|, to determine whether 475 | * optimality has been reached for a MIP instance 476 | * @min 0 477 | * @default 1e-04 478 | */ 479 | mip_rel_gap: number; 480 | 481 | /** 482 | * Tolerance on absolute gap of MIP, |ub-lb|, to determine whether 483 | * optimality has been reached for a MIP instance 484 | * @min 0 485 | * @default 1e-06 486 | */ 487 | mip_abs_gap: number; 488 | 489 | /** 490 | * MIP minimum logging interval 491 | * @min 0 492 | * @default 5 493 | */ 494 | mip_min_logging_interval: number; 495 | 496 | /** 497 | * Iteration limit for IPM solver 498 | * @default Number.MAX_SAFE_INTEGER 499 | */ 500 | ipm_iteration_limit: number; 501 | 502 | /** 503 | * Use native termination for PDLP solver: Default = false 504 | * @default false 505 | */ 506 | pdlp_native_termination: boolean; 507 | 508 | /** 509 | * Scaling option for PDLP solver: Default = true 510 | * @default true 511 | */ 512 | pdlp_scaling: boolean; 513 | 514 | /** 515 | * Iteration limit for PDLP solver 516 | * @min 0 517 | */ 518 | pdlp_iteration_limit: number; 519 | 520 | /** 521 | * Restart mode for PDLP solver: 0 => none; 522 | * 1 => GPU (default); 2 => CPU 523 | * @min 0 524 | * @default 1 525 | * @max 2 526 | */ 527 | pdlp_e_restart_method: number; 528 | 529 | /** 530 | * Duality gap tolerance for PDLP solver: Default = 1e-4 531 | * @min 1e-12 532 | * @default 1e-04 533 | */ 534 | pdlp_d_gap_tol: number; 535 | 536 | /** 537 | * Iteration limit for QP solver 538 | * @min 0 539 | * @default Number.MAX_SAFE_INTEGER 540 | */ 541 | qp_iteration_limit: number; 542 | 543 | /** 544 | * Nullspace limit for QP solver 545 | * @min 0 546 | * @default 4000 547 | */ 548 | qp_nullspace_limit: number; 549 | 550 | /** 551 | * Strategy for IIS calculation: 552 | * Prioritise rows (default) / 553 | * Prioritise columns 554 | * (0/1) 555 | * @default 0 556 | */ 557 | iis_strategy: IisStrategy; 558 | }> 559 | >; 560 | type HighsSolution = 561 | | GenericHighsSolution 562 | | GenericHighsSolution 563 | | GenericHighsSolution; 564 | 565 | type GenericHighsSolution = { 566 | Status: Status; 567 | ObjectiveValue: number; 568 | Columns: Record; 569 | Rows: RowType[]; 570 | }; 571 | 572 | type HighsModelStatus = 573 | | 'Not Set' 574 | | 'Load error' 575 | | 'Model error' 576 | | 'Presolve error' 577 | | 'Solve error' 578 | | 'Postsolve error' 579 | | 'Empty' 580 | | 'Optimal' 581 | | 'Infeasible' 582 | | 'Primal infeasible or unbounded' 583 | | 'Unbounded' 584 | | 'Bound on objective reached' 585 | | 'Target for objective reached' 586 | | 'Time limit reached' 587 | | 'Iteration limit reached' 588 | | 'Unknown'; 589 | 590 | interface HighsInfeasibleSolutionBase { 591 | Index: number; 592 | Lower: number | null; 593 | Upper: number | null; 594 | } 595 | 596 | interface HighsInfeasibleSolutionRow extends HighsInfeasibleSolutionBase {} 597 | interface HighsInfeasibleSolutionColumn extends HighsInfeasibleSolutionBase { 598 | Type: 'Integer' | 'Continuous'; 599 | } 600 | 601 | interface HighsSolutionBase extends HighsInfeasibleSolutionBase { 602 | Primal: number; 603 | } 604 | 605 | interface HighsLinearSolutionColumn extends HighsSolutionBase { 606 | Dual: number; 607 | Name: string; 608 | Status: HighsBasisStatus; 609 | } 610 | 611 | interface HighsMixedIntegerLinearSolutionColumn extends HighsSolutionBase { 612 | Type: 'Integer' | 'Continuous'; 613 | Name: string; 614 | } 615 | 616 | interface HighsLinearSolutionRow extends HighsSolutionBase { 617 | Dual: number; 618 | Status: HighsBasisStatus; 619 | Name: string; 620 | } 621 | 622 | interface HighsMixedIntegerLinearSolutionRow extends HighsSolutionBase {} 623 | 624 | type HighsBasisStatus = 625 | /** Fixed */ 626 | | 'FX' 627 | /** Lower Bound */ 628 | | 'LB' 629 | /** Basis */ 630 | | 'BS' 631 | /** Upper Bound */ 632 | | 'UB' 633 | /** Free */ 634 | | 'FR' 635 | /** Non-Bounded */ 636 | | 'NB'; 637 | 638 | type HighsLoaderOptions = Readonly< 639 | Partial<{ 640 | /** Should return the URL of an asset given its name. Useful for locating the wasm file */ 641 | locateFile(file: string): string; 642 | }> 643 | >; 644 | 645 | enum HighsAnalysisLevel { 646 | kHighsAnalysisLevelNone = 0, 647 | kHighsAnalysisLevelModelData = 1, 648 | kHighsAnalysisLevelSolverSummaryData = 2, 649 | kHighsAnalysisLevelSolverRuntimeData = 4, 650 | kHighsAnalysisLevelSolverTime = 8, 651 | kHighsAnalysisLevelNlaData = 16, 652 | kHighsAnalysisLevelNlaTime = 32, 653 | kHighsAnalysisLevelMin = kHighsAnalysisLevelNone, 654 | kHighsAnalysisLevelMax = kHighsAnalysisLevelModelData + 655 | kHighsAnalysisLevelSolverSummaryData + 656 | kHighsAnalysisLevelSolverRuntimeData + 657 | kHighsAnalysisLevelSolverTime + 658 | kHighsAnalysisLevelNlaData + 659 | kHighsAnalysisLevelNlaTime 660 | } 661 | 662 | enum HighsDebugLevel { 663 | kHighsDebugLevelNone = 0, 664 | kHighsDebugLevelCheap, 665 | kHighsDebugLevelCostly, 666 | kHighsDebugLevelExpensive, 667 | kHighsDebugLevelMin = kHighsDebugLevelNone, 668 | kHighsDebugLevelMax = kHighsDebugLevelExpensive 669 | } 670 | 671 | enum SimplexScaleStrategy { 672 | kSimplexScaleStrategyMin = 0, 673 | kSimplexScaleStrategyOff = kSimplexScaleStrategyMin, // 0 674 | kSimplexScaleStrategyChoose, // 1 675 | kSimplexScaleStrategyEquilibration, // 2 676 | kSimplexScaleStrategyForcedEquilibration, // 3 677 | kSimplexScaleStrategyMaxValue015, // 4 678 | kSimplexScaleStrategyMaxValue0157, // 5 679 | kSimplexScaleStrategyMax = kSimplexScaleStrategyMaxValue0157 680 | } 681 | 682 | enum SimplexStrategy { 683 | kSimplexStrategyMin = 0, 684 | kSimplexStrategyChoose = kSimplexStrategyMin, // 0 685 | kSimplexStrategyDual, // 1 686 | kSimplexStrategyDualPlain = kSimplexStrategyDual, // 1 687 | kSimplexStrategyDualTasks, // 2 688 | kSimplexStrategyDualMulti, // 3 689 | kSimplexStrategyPrimal, // 4 690 | kSimplexStrategyMax = kSimplexStrategyPrimal, 691 | kSimplexStrategyNum 692 | } 693 | 694 | enum SimplexCrashStrategy { 695 | kSimplexCrashStrategyMin = 0, 696 | kSimplexCrashStrategyOff = kSimplexCrashStrategyMin, 697 | kSimplexCrashStrategyLtssfK, 698 | kSimplexCrashStrategyLtssf = kSimplexCrashStrategyLtssfK, 699 | kSimplexCrashStrategyBixby, 700 | kSimplexCrashStrategyLtssfPri, 701 | kSimplexCrashStrategyLtsfK, 702 | kSimplexCrashStrategyLtsfPri, 703 | kSimplexCrashStrategyLtsf, 704 | kSimplexCrashStrategyBixbyNoNonzeroColCosts, 705 | kSimplexCrashStrategyBasic, 706 | kSimplexCrashStrategyTestSing, 707 | kSimplexCrashStrategyMax = kSimplexCrashStrategyTestSing 708 | } 709 | 710 | enum SimplexEdgeWeightStrategy { 711 | kSimplexEdgeWeightStrategyMin = -1, 712 | kSimplexEdgeWeightStrategyChoose = kSimplexEdgeWeightStrategyMin, 713 | kSimplexEdgeWeightStrategyDantzig, 714 | kSimplexEdgeWeightStrategyDevex, 715 | kSimplexEdgeWeightStrategySteepestEdge, 716 | kSimplexEdgeWeightStrategyMax = kSimplexEdgeWeightStrategySteepestEdge 717 | } 718 | 719 | enum SolutionStyle { 720 | kSolutionStyleOldRaw = -1, 721 | kSolutionStyleRaw = 0, 722 | kSolutionStylePretty, // 1; 723 | kSolutionStyleGlpsolRaw, // 2; 724 | kSolutionStyleGlpsolPretty, // 3; 725 | kSolutionStyleSparse, // 4; 726 | kSolutionStyleMin = kSolutionStyleOldRaw, 727 | kSolutionStyleMax = kSolutionStyleSparse 728 | } 729 | 730 | enum GlpsolCostRowLocation { 731 | kGlpsolCostRowLocationLast = -2, 732 | kGlpsolCostRowLocationNone, // -1 733 | kGlpsolCostRowLocationNoneIfEmpty, // 0 734 | kGlpsolCostRowLocationMin = kGlpsolCostRowLocationLast 735 | } 736 | 737 | enum IisStrategy { 738 | kIisStrategyMin = 0, 739 | kIisStrategyFromLpRowPriority = kIisStrategyMin, // 0 740 | kIisStrategyFromLpColPriority, // 1 741 | // kIisStrategyFromRayRowPriority, // 2 742 | // kIisStrategyFromRayColPriority, // 3 743 | kIisStrategyMax = kIisStrategyFromLpColPriority 744 | }; 745 | 746 | /** Loads HiGHS */ 747 | export default function highsLoader(options?: HighsLoaderOptions): Promise; 748 | 749 | // export const Model: unknown 750 | --------------------------------------------------------------------------------