diff --git a/Project.toml b/Project.toml index 04984a6..2964904 100644 --- a/Project.toml +++ b/Project.toml @@ -12,7 +12,7 @@ PrecompileTools = "aea7be01-6a6a-4083-8856-8a6e6704d82a" SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" [compat] -HiGHS_jll = "=1.14.0" +HiGHS_jll = "=1.15.0" LinearAlgebra = "1" MathOptIIS = "0.2" MathOptInterface = "1.34" diff --git a/gen/Project.toml b/gen/Project.toml index 46b7e4f..5f84691 100644 --- a/gen/Project.toml +++ b/gen/Project.toml @@ -4,4 +4,4 @@ HiGHS_jll = "8fd58aa0-07eb-5a78-9b36-339c94fd15ea" [compat] Clang = "0.19" -HiGHS_jll = "1.14" +HiGHS_jll = "1.15" diff --git a/src/gen/libhighs.jl b/src/gen/libhighs.jl index 1eb9267..c7ca438 100644 --- a/src/gen/libhighs.jl +++ b/src/gen/libhighs.jl @@ -300,6 +300,22 @@ function Highs_clearSolver(highs) ccall((:Highs_clearSolver, libhighs), HighsInt, (Ptr{Cvoid},), highs) end +""" + Highs_releaseMemory(highs) + +Release all retained memory back to the allocator. + +Clears all solver state and shrinks internal vectors to free unused capacity. Useful in long-running services that reuse a Highs instance across multiple solves to prevent unbounded RSS growth from heap fragmentation. + +# Arguments +* `highs`: A pointer to the Highs instance. +# Returns +A `kHighsStatus` constant indicating whether the call succeeded. +""" +function Highs_releaseMemory(highs) + ccall((:Highs_releaseMemory, libhighs), HighsInt, (Ptr{Cvoid},), highs) +end + """ Highs_presolve(highs) @@ -2710,13 +2726,11 @@ const HighsUInt = Cuint const CMAKE_BUILD_TYPE = "Release" -const BLAS_LIBRARIES = "blastrampoline" - -const HIGHS_GITHASH = "7df0786de3" +const HIGHS_GITHASH = "8396001901" const HIGHS_VERSION_MAJOR = 1 -const HIGHS_VERSION_MINOR = 14 +const HIGHS_VERSION_MINOR = 15 const HIGHS_VERSION_PATCH = 0 diff --git a/test/test_c_wrapper.jl b/test/test_c_wrapper.jl index afb1343..4809c92 100644 --- a/test/test_c_wrapper.jl +++ b/test/test_c_wrapper.jl @@ -8,6 +8,13 @@ module TestCHighs using HiGHS using Test +function runtests() + is_test(name) = startswith("$name", "test_") + @testset "$name" for name in filter(is_test, names(@__MODULE__; all = true)) + getfield(@__MODULE__, name)() + end +end + function small_test_model() cc = [1.0, -2.0] cl = [0.0, 0.0] @@ -26,24 +33,20 @@ function test_Direct_C_call() n_col = convert(Cint, size(colcost, 1)) n_row = convert(Cint, size(rowlower, 1)) n_nz = convert(Cint, size(aindex, 1)) - colcost = convert(Array{Cdouble}, colcost) collower = convert(Array{Cdouble}, collower) colupper = convert(Array{Cdouble}, colupper) - rowlower = convert(Array{Cdouble}, rowlower) rowupper = convert(Array{Cdouble}, rowupper) matstart = convert(Array{Cint}, astart) matindex = convert(Array{Cint}, aindex) matvalue = convert(Array{Cdouble}, avalue) - colvalue, coldual = (Array{Cdouble,1}(undef, n_col), Array{Cdouble,1}(undef, n_col)) rowvalue, rowdual = (Array{Cdouble,1}(undef, n_row), Array{Cdouble,1}(undef, n_row)) colbasisstatus, rowbasisstatus = (Array{Cint,1}(undef, n_col), Array{Cint,1}(undef, n_row)) - modelstatus = Ref{Cint}(42) status = HiGHS.Highs_lpCall( n_col, @@ -70,33 +73,22 @@ function test_Direct_C_call() ) @test status == 0 @test modelstatus[] == HiGHS.kHighsModelStatusOptimal + return end function test_create() ptr = Highs_create() @test ptr != C_NULL - objective = Highs_getObjectiveValue(ptr) @test objective == 0.0 - # model status, the second parameter is # bool scaled_model modelstatus = Highs_getModelStatus(ptr) @test modelstatus[] == 0 # uninitialized LP - - return Highs_destroy(ptr) -end - -function runtests() - for name in names(@__MODULE__; all = true) - if startswith(string(name), "test_") - @testset "$(name)" begin - getfield(@__MODULE__, name)() - end - end - end + Highs_destroy(ptr) + return end -end +end # TestCHighs TestCHighs.runtests() diff --git a/test/test_moi_wrapper.jl b/test/test_moi_wrapper.jl index 295c84a..c1e4716 100644 --- a/test/test_moi_wrapper.jl +++ b/test/test_moi_wrapper.jl @@ -11,12 +11,9 @@ import HiGHS import MathOptInterface as MOI function runtests() - for name in names(@__MODULE__; all = true) - if startswith("$name", "test_") - @testset "$name" begin - getfield(@__MODULE__, name)() - end - end + is_test(name) = startswith("$name", "test_") + @testset "$name" for name in filter(is_test, names(@__MODULE__; all = true)) + getfield(@__MODULE__, name)() end return end @@ -50,6 +47,7 @@ function test_MOI_variable_count_and_empty() @test MOI.get(model, MOI.NumberOfVariables()) == 2 MOI.empty!(model) @test MOI.get(model, MOI.NumberOfVariables()) == 0 + return end function test_HiGHS_custom_options() @@ -221,6 +219,7 @@ function test_SimplexIterations_BarrierIterations() # Not == 0 because HiGHS will use Simplex to clean-up occasionally @test MOI.get(model, MOI.SimplexIterations()) >= 0 @test MOI.get(model, MOI.BarrierIterations()) > 0 + return end function test_NodeCount() @@ -311,6 +310,7 @@ function test_option_type() T = HiGHS._type_for_highs_option(k) @test x isa T end + return end function test_quadratic_sets_objective() @@ -1346,6 +1346,6 @@ function test_relax_integrality_integer() return end -end # module +end # TestMOIHighs TestMOIHighs.runtests() diff --git a/test/test_runtests.jl b/test/test_runtests.jl index c773c81..35038ca 100644 --- a/test/test_runtests.jl +++ b/test/test_runtests.jl @@ -11,12 +11,9 @@ import HiGHS import MathOptInterface as MOI function runtests() - for name in names(@__MODULE__; all = true) - if startswith("$name", "test_") - @testset "$name" begin - getfield(@__MODULE__, name)() - end - end + is_test(name) = startswith("$name", "test_") + @testset "$name" for name in filter(is_test, names(@__MODULE__; all = true)) + getfield(@__MODULE__, name)() end return end @@ -24,14 +21,12 @@ end function test_runtests() model = MOI.Bridges.full_bridge_optimizer(HiGHS.Optimizer(), Float64) MOI.set(model, MOI.Silent(), true) - # Turn presolve off so that we generate infeasibility certificates. This is - # a temporary work-around until we fix this upstream in HiGHS. - MOI.set(model, MOI.RawOptimizerAttribute("presolve"), "off") + MOI.set(model, MOI.RawOptimizerAttribute("parallel"), "on") # Slightly loosen tolerances, particularly for QP tests MOI.Test.runtests(model, MOI.Test.Config(; atol = 1e-7)) return end -end # module +end # TestRunTests TestRunTests.runtests() diff --git a/test/test_runtests_cache.jl b/test/test_runtests_cache.jl index 1e1bbe1..51a739a 100644 --- a/test/test_runtests_cache.jl +++ b/test/test_runtests_cache.jl @@ -11,12 +11,9 @@ import HiGHS import MathOptInterface as MOI function runtests() - for name in names(@__MODULE__; all = true) - if startswith("$name", "test_") - @testset "$name" begin - getfield(@__MODULE__, name)() - end - end + is_test(name) = startswith("$name", "test_") + @testset "$name" for name in filter(is_test, names(@__MODULE__; all = true)) + getfield(@__MODULE__, name)() end return end @@ -30,11 +27,12 @@ function test_runtests_cache() Float64, ) MOI.set(model, MOI.Silent(), true) + MOI.set(model, MOI.RawOptimizerAttribute("parallel"), "on") # Slightly loosen tolerances, particularly for QP tests MOI.Test.runtests(model, MOI.Test.Config(; atol = 1e-7)) return end -end # module +end # TestRunTestsCache TestRunTestsCache.runtests()