From e25a4234253d7a9bc3b72f76dafb195afdf577ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Fuglede=20J=C3=B8rgensen?= Date: Tue, 10 Oct 2023 15:22:21 +0200 Subject: [PATCH] Update HiGHS to version 1.6.0 (#35) * Update HiGHS to version 1.6.0 * Use HiGHS interface to check if model is linear or quadratic * Use HighsModel.isMip to check if model is an LP or MILP This fixes an issue in the earlier commit; the property "isLinear" means "MILP but not LP". * Remove unused parameter * Remove "IsLinear" and "IsQuadratic" from solution object The information is rather superfluous, as, on one hand, the user will likely be aware which model they are solving, and on the other, since we can include the types of all variables now, the information on whether a model has integer variables can be determined from that. Indeed, we update all tests to contain the type information as well. * Update a test showcasing an error as the test now actually works * Update a few tests that contain now-invalid formatting * Remove information on linearity from a test * Remove a few unused methods/types * Destroy highs object as early as possible * Add an example of an invalid input in tests --- HiGHS | 2 +- README.md | 6 ++-- src/post.js | 8 ------ tests/test.js | 77 +++++++++++++++++++++++++++++++++++---------------- types.d.ts | 1 - 5 files changed, 58 insertions(+), 36 deletions(-) diff --git a/HiGHS b/HiGHS index 8194724..21da9b9 160000 --- a/HiGHS +++ b/HiGHS @@ -1 +1 @@ -Subproject commit 81947249d6277525efc1690f60597b562670f28b +Subproject commit 21da9b90e0dceeb22ef9e35e5ff2c3ab17dc5232 diff --git a/README.md b/README.md index bbd0d0a..5177050 100644 --- a/README.md +++ b/README.md @@ -34,8 +34,6 @@ Bounds End`; const EXPECTED_SOLUTION = { - IsLinear: true, - IsQuadratic: false, Status: 'Optimal', ObjectiveValue: 87.5, Columns: { @@ -44,6 +42,7 @@ const EXPECTED_SOLUTION = { Status: 'BS', Lower: 0, Upper: 40, + Type: 'Continuous', Primal: 17.5, Dual: -0, Name: 'x1' @@ -53,6 +52,7 @@ const EXPECTED_SOLUTION = { Status: 'BS', Lower: 0, Upper: Infinity, + Type: 'Continuous', Primal: 1, Dual: -0, Name: 'x2' @@ -62,6 +62,7 @@ const EXPECTED_SOLUTION = { Status: 'BS', Lower: 0, Upper: Infinity, + Type: 'Continuous', Primal: 16.5, Dual: -0, Name: 'x3' @@ -71,6 +72,7 @@ const EXPECTED_SOLUTION = { Status: 'LB', Lower: 2, Upper: 3, + Type: 'Continuous', Primal: 2, Dual: -8.75, Name: 'x4' diff --git a/src/post.js b/src/post.js index 932bb9a..623acef 100755 --- a/src/post.js +++ b/src/post.js @@ -165,18 +165,10 @@ function parseResult(lines, status) { let headers = headersForNonEmptyColumns(lines[1], lines[2]); - // We identity whether the problem is a QP by the available headers: For infeasible - // problems, "Status", "Dual", and "Primal" are missing, for integer linear programs, - // "Status" and "Dual" are missing, and for QPs, only "Status" is missing - const isQuadratic = !headers.includes("Status") && headers.includes("Dual"); - const isLinear = !headers.includes("Type") && !isQuadratic; - var result = { "Status": /** @type {"Infeasible"} */(status), "Columns": {}, "Rows": [], - "IsLinear": isLinear, - "IsQuadratic": isQuadratic, "ObjectiveValue": NaN }; diff --git a/tests/test.js b/tests/test.js index 147b36f..5380cbf 100644 --- a/tests/test.js +++ b/tests/test.js @@ -15,8 +15,6 @@ Bounds End`; const SOLUTION = { - IsLinear: true, - IsQuadratic: false, Status: 'Optimal', ObjectiveValue: 87.5, Columns: { @@ -24,6 +22,7 @@ const SOLUTION = { Index: 0, Status: 'BS', Lower: 0, + Type: 'Continuous', Upper: 40, Primal: 17.5, Dual: -0, @@ -33,6 +32,7 @@ const SOLUTION = { Index: 1, Status: 'BS', Lower: 0, + Type: 'Continuous', Upper: Infinity, Primal: 1, Dual: -0, @@ -42,6 +42,7 @@ const SOLUTION = { Index: 2, Status: 'BS', Lower: 0, + Type: 'Continuous', Upper: Infinity, Primal: 16.5, Dual: -0, @@ -51,6 +52,7 @@ const SOLUTION = { Index: 3, Status: 'LB', Lower: 2, + Type: 'Continuous', Upper: 3, Primal: 2, Dual: -8.75, @@ -110,13 +112,31 @@ function test_options(Module) { assert.deepStrictEqual(sol, SOLUTION); } +/** + * @param {import("../types").Highs} Module + */ +function test_empty_model(Module) { + // Arguably, this example should not be considered valid at all, but + // HiGHS parses it as an empty model; see + // https://github.com/ERGO-Code/HiGHS/issues/1451 + const sol = Module.solve("blah blah not a good file"); + assert.deepStrictEqual(sol, { + Columns: {}, + ObjectiveValue: 0, + Rows: [], + Status: 'Empty' + }); +} + /** * @param {import("../types").Highs} Module */ function test_invalid_model(Module) { assert.throws( - (_) => Module.solve("blah blah not a good file"), - /Unable to read LP model/ + (_) => Module.solve(`Minimize + ] 2 [ + End`), + /Unable to read LP model/ ); } @@ -132,8 +152,6 @@ function test_integer_problem(Module) { a End`); assert.deepStrictEqual(sol, { - IsLinear: false, - IsQuadratic: false, Status: 'Optimal', ObjectiveValue: 3.5, Columns: { @@ -168,8 +186,6 @@ function test_case_with_no_constraints(Module) { 2 <= x2 <= 3 End`); assert.deepStrictEqual(sol, { - "IsLinear": true, - "IsQuadratic": false, "Status": "Optimal", "ObjectiveValue": 46, "Columns": { @@ -178,6 +194,7 @@ function test_case_with_no_constraints(Module) { "Status": "UB", "Lower": 0, "Upper": 40, + "Type": "Continuous", "Primal": 40, "Dual": 1, "Name": "x1" @@ -186,6 +203,7 @@ function test_case_with_no_constraints(Module) { "Index": 1, "Status": "UB", "Lower": 2, + "Type": "Continuous", "Upper": 3, "Primal": 3, "Dual": 2, @@ -208,14 +226,14 @@ Subject To c1: a + b >= 10 End`); assert.deepStrictEqual(sol, { - IsLinear: false, - IsQuadratic: true, Status: 'Optimal', ObjectiveValue: 60, Columns: { a: { Index: 0, Lower: 0, + Status: "BS", + Type: 'Continuous', Upper: Infinity, Primal: 10, Dual: 0, @@ -224,13 +242,15 @@ End`); b: { Index: 1, Lower: 0, + Status: "LB", + Type: 'Continuous', Upper: Infinity, Primal: 0, Dual: 10, Name: 'b' } }, - Rows: [{ Index: 0, Lower: 10, Upper: Infinity, Primal: 10, Dual: 11, Name: 'c1' }] + Rows: [{ Index: 0, Lower: 10, Upper: Infinity, Primal: 10, Dual: 11, Status: "LB", Name: 'c1' }] }); } @@ -253,10 +273,14 @@ function test_quadratic_program_not_positive_semidefinite(Module) { * @param {import("../types").Highs} Module */ function test_infeasible(Module) { - const sol = Module.solve(`Maximize a subject to a >= 1 bounds a <= 0`); + const sol = Module.solve(`Maximize + a + subject to + a >= 1 + bounds + a <= 0 + End`); assert.deepStrictEqual(sol, { - IsLinear: true, - IsQuadratic: false, Status: 'Infeasible', ObjectiveValue: 0, Columns: { @@ -264,6 +288,7 @@ function test_infeasible(Module) { Index: 0, Lower: 0, Upper: 0, + Type: 'Continuous', Name: 'a' } }, @@ -288,8 +313,6 @@ General a end`); assert.deepStrictEqual(sol, { - IsLinear: false, - IsQuadratic: false, Status: 'Infeasible', ObjectiveValue: Infinity, Columns: { @@ -312,16 +335,18 @@ end`); * @param {import("../types").Highs} Module */ function test_unbounded(Module) { - const sol = Module.solve(`Maximize a subject to a >= 1`); + const sol = Module.solve(`Maximize a + subject to + a >= 1 + end`); assert.deepStrictEqual(sol, { - IsLinear: true, - IsQuadratic: false, Status: 'Unbounded', ObjectiveValue: 1, Columns: { a: { Index: 0, Lower: 0, + Type: 'Continuous', Upper: Infinity, Primal: 1, Dual: -0, @@ -349,8 +374,6 @@ Bounds 1.1 <= x2 <= 1 End`); assert.deepStrictEqual(sol, { - IsLinear: true, - IsQuadratic: false, Status: 'Infeasible', ObjectiveValue: 0, Columns: { @@ -358,23 +381,24 @@ End`); Index: 1, Lower: 0, Name: 'x0', + Type: 'Continuous', Upper: Infinity }, x1: { Index: 0, Lower: 0, Name: 'x1', + Type: 'Continuous', Upper: 1 }, x2: { Index: 2, Lower: 1.1, Name: 'x2', + Type: 'Continuous', Upper: 1 } }, - IsLinear: true, - IsQuadratic: false, Rows: [ { Index: 0, @@ -398,13 +422,18 @@ function test_big(Module) { function test_many_solves(Module) { // See https://github.com/lovasoa/highs-js/issues/10 for (let i = 0; i < 5000; i++) { - Module.solve(`Maximize a subject to a <= 1`); + Module.solve(`Maximize + a + subject to + a <= 1 + end`); } } async function test() { const Module = await highs(); test_optimal(Module); + test_empty_model(Module); test_invalid_model(Module); test_options(Module); test_integer_problem(Module); diff --git a/types.d.ts b/types.d.ts index d7495e6..603df68 100644 --- a/types.d.ts +++ b/types.d.ts @@ -291,7 +291,6 @@ type HighsSolution = >; type GenericHighsSolution = { - IsLinear: IsLinear, Status: Status; ObjectiveValue: number; Columns: Record;