From e482de87fde6ccad1af01501d407f9584d5a8d3d Mon Sep 17 00:00:00 2001 From: Chris Coey Date: Thu, 26 Oct 2023 16:43:11 -0700 Subject: [PATCH 1/2] support interval, handle range correctly, change an unnecessary range test to use interval --- src/json_to_moi.jl | 24 +++++++++++------------- test/all_tests.jl | 2 +- test/inputs/min_range.json | 1 - test/outputs/min_range.json | 1 - 4 files changed, 12 insertions(+), 16 deletions(-) delete mode 100644 test/inputs/min_range.json delete mode 100644 test/outputs/min_range.json diff --git a/src/json_to_moi.jl b/src/json_to_moi.jl index 220402c..50768d7 100644 --- a/src/json_to_moi.jl +++ b/src/json_to_moi.jl @@ -65,6 +65,16 @@ function add_cons!( MOI.add_constraint(model, v, MOI.Integer()) f = MOI.ScalarNonlinearFunction(:abs, Any[v]) MOI.add_constraint(model, f, MOI.EqualTo(1)) + elseif head == "interval" + if length(a) != 4 + throw(Error(InvalidModel, "The `interval` constraint expects 3 arguments.")) + end + v = json_to_snf(a[4], vars_map) + _check_v_type(v) + if !(a[2] isa Number && a[3] isa Number) + throw(Error(InvalidModel, "The `interval` constraint expects numerical bounds.")) + end + MOI.add_constraint(model, v, MOI.Interval{T}(T(a[2]), T(a[3]))) elseif head == "range" if length(a) != 5 throw(Error(InvalidModel, "The `range` constraint expects 4 arguments.")) @@ -159,19 +169,7 @@ function json_to_snf(a::JSON3.Array, vars_map::Dict) args = Any[json_to_snf(a[i], vars_map) for i in eachindex(a) if i != 1] head isa String || return args - if head == "range" - # TODO handle variables in different positions, etc - # TODO handle as interval constraint? - lb, ub, step, x = args - step == 1 || throw(Error(NotAllowed, "Step size $step is not supported.")) - return MOI.ScalarNonlinearFunction( - :∧, - Any[ - MOI.ScalarNonlinearFunction(:<=, Any[lb, x]), - MOI.ScalarNonlinearFunction(:<=, Any[x, ub]), - ], - ) - elseif head == "and" + if head == "and" head = "forall" args = Any[args] elseif head == "or" diff --git a/test/all_tests.jl b/test/all_tests.jl index d353efb..7f9b34e 100644 --- a/test/all_tests.jl +++ b/test/all_tests.jl @@ -63,7 +63,7 @@ end # names of JSON files in inputs/ and outputs/ folders json_names = [ "feas_range", - "min_range", + "min_interval", "tiny_min", "tiny_feas", "tiny_infeas", diff --git a/test/inputs/min_range.json b/test/inputs/min_range.json deleted file mode 100644 index 487c0dc..0000000 --- a/test/inputs/min_range.json +++ /dev/null @@ -1 +0,0 @@ -{"version":"0.1","sense":"min","variables":["x"],"constraints":[["range",0,9,1,"x"],["Int","x"]],"objectives":["x"],"options":{"time_limit_sec":60,"solver":"HiGHS","silent":0,"print_format":"MOI"}} diff --git a/test/outputs/min_range.json b/test/outputs/min_range.json deleted file mode 100644 index d6144f8..0000000 --- a/test/outputs/min_range.json +++ /dev/null @@ -1 +0,0 @@ -{"model_string":"Minimize: x\n\nSubject to:\n x ∈ [0, 9]\n x ∈ ℤ\n","termination_status":"OPTIMAL","results":[{"names":["\"x\""],"values":[0.0],"primal_status":"FEASIBLE_POINT","objective_value":0.0}],"version":"0.1"} From eaba2da8c48eb2014810b206118a3f3e28c589c9 Mon Sep 17 00:00:00 2001 From: Chris Coey Date: Thu, 26 Oct 2023 16:47:42 -0700 Subject: [PATCH 2/2] fixes --- CHANGELOG.md | 4 +++- src/json_to_moi.jl | 2 +- test/inputs/min_interval.json | 1 + test/outputs/min_interval.json | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 test/inputs/min_interval.json create mode 100644 test/outputs/min_interval.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 1073b42..67e3fe8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [0.2.0] + - Improve test coverage, error messages, and others [#1](https://github.com/RelationalAI/SolverAPI.jl/pull/1), [#7](https://github.com/RelationalAI/SolverAPI.jl/pull/7), [#8](https://github.com/RelationalAI/SolverAPI.jl/pull/8), [#10](https://github.com/RelationalAI/SolverAPI.jl/pull/10) - Fix `StackOverflowError` and improve performance [#6](https://github.com/RelationalAI/SolverAPI.jl/pull/6) - Return solve time and solver version [#5](https://github.com/RelationalAI/SolverAPI.jl/pull/5) - - Add default time limit [#2](https://github.com/RelationalAI/SolverAPI.jl/pull/2) + - Add default time limit [#2](https://github.com/RelationalAI/SolverAPI.jl/pull/2) ## [0.1.0] + - Initial release diff --git a/src/json_to_moi.jl b/src/json_to_moi.jl index 50768d7..7486caa 100644 --- a/src/json_to_moi.jl +++ b/src/json_to_moi.jl @@ -72,7 +72,7 @@ function add_cons!( v = json_to_snf(a[4], vars_map) _check_v_type(v) if !(a[2] isa Number && a[3] isa Number) - throw(Error(InvalidModel, "The `interval` constraint expects numerical bounds.")) + throw(Error(InvalidModel, "The `interval` constraint expects number bounds.")) end MOI.add_constraint(model, v, MOI.Interval{T}(T(a[2]), T(a[3]))) elseif head == "range" diff --git a/test/inputs/min_interval.json b/test/inputs/min_interval.json new file mode 100644 index 0000000..f2238aa --- /dev/null +++ b/test/inputs/min_interval.json @@ -0,0 +1 @@ +{"version":"0.1","sense":"min","variables":["x"],"constraints":[["interval",1,3.5,"x"],["Float","x"]],"objectives":["x"],"options":{"time_limit_sec":60,"solver":"HiGHS","silent":0,"print_format":"MOI"}} diff --git a/test/outputs/min_interval.json b/test/outputs/min_interval.json new file mode 100644 index 0000000..0330904 --- /dev/null +++ b/test/outputs/min_interval.json @@ -0,0 +1 @@ +{"model_string":"Minimize: x\n\nSubject to:\n x ∈ [1, 3.5]\n","termination_status":"OPTIMAL","results":[{"names":["\"x\""],"values":[1.0],"primal_status":"FEASIBLE_POINT","objective_value":1.0}],"version":"0.1"}