Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor dynamic loading of solvers (and IESoptLib) to using extensions #8

Merged
merged 4 commits into from
Jun 9, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -5,7 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.0.0] - 2023-06-01
## [1.0.1] - 2024-06-09

Added extensions to properly handle loading `IESoptLib` and various solvers.

### Changed

- `IESoptLib` and `HiGHS` are no longer required dependencies.

### Fixed

- Dynamic loading of weakdeps now works properly.

## [1.0.0] - 2024-06-01

### Added

20 changes: 11 additions & 9 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
name = "IESopt"
uuid = "ed3f0a38-8ad9-4cf8-877e-929e8d190fe9"
version = "1.0.0"
version = "1.0.1"

[deps]
ArgCheck = "dce04be8-c92d-5529-be00-80e4d2c0e197"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
IESoptLib = "b98f706d-40ec-4ce6-a66c-1c6e71d3cef6"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
@@ -33,16 +31,20 @@ CPLEX = "a076750e-1247-5638-91d2-ce28b192dca0"
Cbc = "9961bab8-2fa3-5c5a-9d89-47fab24efd76"
GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
Gurobi = "2e9cd046-0924-5485-92f1-d5272153d98b"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
IESoptLib = "b98f706d-40ec-4ce6-a66c-1c6e71d3cef6"
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
SCIP = "82193955-e24f-5292-bf16-6f2c5261a85f"

[extensions]
CPLEX = "CPLEX"
Cbc = "Cbc"
GLPK = "GLPK"
Gurobi = "Gurobi"
Ipopt = "Ipopt"
SCIP = "SCIP"
LoadIESoptLib = "IESoptLib"
OptExtCbc = "Cbc"
OptExtCPLEX = "CPLEX"
OptExtGLPK = "GLPK"
OptExtGurobi = "Gurobi"
OptExtHiGHS = "HiGHS"
OptExtIpopt = "Ipopt"
OptExtSCIP = "SCIP"

[compat]
ArgCheck = "2.3.0"
9 changes: 9 additions & 0 deletions ext/LoadIESoptLib/LoadIESoptLib.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module LoadIESoptLib

import IESopt, IESoptLib

function IESopt._load_IESoptLib(::Bool)
return IESoptLib
end

Check warning on line 8 in ext/LoadIESoptLib/LoadIESoptLib.jl

Codecov / codecov/patch

ext/LoadIESoptLib/LoadIESoptLib.jl#L5-L8

Added lines #L5 - L8 were not covered by tests
end
11 changes: 11 additions & 0 deletions ext/OptExtCPLEX/OptExtCPLEX.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtCPLEX

import IESopt, CPLEX

struct OptType end

function IESopt._get_solver_module(::OptType)
return CPLEX
end

end
11 changes: 11 additions & 0 deletions ext/OptExtCbc/OptExtCbc.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtCbc

import IESopt, Cbc

struct OptType end

function IESopt._get_solver_module(::OptType)
return Cbc

Check warning on line 8 in ext/OptExtCbc/OptExtCbc.jl

Codecov / codecov/patch

ext/OptExtCbc/OptExtCbc.jl#L7-L8

Added lines #L7 - L8 were not covered by tests
end

end
11 changes: 11 additions & 0 deletions ext/OptExtGLPK/OptExtGLPK.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtGLPK

import IESopt, GLPK

struct OptType end

function IESopt._get_solver_module(::OptType)
return GLPK

Check warning on line 8 in ext/OptExtGLPK/OptExtGLPK.jl

Codecov / codecov/patch

ext/OptExtGLPK/OptExtGLPK.jl#L7-L8

Added lines #L7 - L8 were not covered by tests
end

end
11 changes: 11 additions & 0 deletions ext/OptExtGurobi/OptExtGurobi.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtGurobi

import IESopt, Gurobi

struct OptType end

function IESopt._get_solver_module(::OptType)
return Gurobi

Check warning on line 8 in ext/OptExtGurobi/OptExtGurobi.jl

Codecov / codecov/patch

ext/OptExtGurobi/OptExtGurobi.jl#L7-L8

Added lines #L7 - L8 were not covered by tests
end

end
11 changes: 11 additions & 0 deletions ext/OptExtHiGHS/OptExtHiGHS.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtHiGHS

import IESopt, HiGHS

struct OptType end

function IESopt._get_solver_module(::OptType)
return HiGHS
end

end
11 changes: 11 additions & 0 deletions ext/OptExtIpopt/OptExtIpopt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtIpopt

import IESopt, Ipopt

struct OptType end

function IESopt._get_solver_module(::OptType)
return Ipopt

Check warning on line 8 in ext/OptExtIpopt/OptExtIpopt.jl

Codecov / codecov/patch

ext/OptExtIpopt/OptExtIpopt.jl#L7-L8

Added lines #L7 - L8 were not covered by tests
end

end
11 changes: 11 additions & 0 deletions ext/OptExtSCIP/OptExtSCIP.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OptExtSCIP

import IESopt, SCIP

struct OptType end

function IESopt._get_solver_module(::OptType)
return SCIP

Check warning on line 8 in ext/OptExtSCIP/OptExtSCIP.jl

Codecov / codecov/patch

ext/OptExtSCIP/OptExtSCIP.jl#L7-L8

Added lines #L7 - L8 were not covered by tests
end

end
35 changes: 20 additions & 15 deletions src/IESopt.jl
Original file line number Diff line number Diff line change
@@ -12,8 +12,8 @@
_is_precompiling() = ccall(:jl_generating_output, Cint, ()) == 1

# Setup `IESoptLib.jl`, if available.
import IESoptLib
const Library = IESoptLib
_load_IESoptLib(::Any) = nothing
const Library = _load_IESoptLib(true)

# Constant paths that might be used somewhere.
const _dummy_path = normpath(@__DIR__, "utils", "dummy")
@@ -386,23 +386,28 @@
@critical "Can't determine proper solver" solver
end

try
Base.require(IESopt, Symbol(solver))
catch
@error "It seems the requested solver is not installed; trying to install and precompile it" solver
solver_module = (
try
Pkg.add(solver)
Base.require(IESopt, Symbol(solver))
@info "Trying to activate solver extension" solver
Base.retry_load_extensions()
opt_ext = Base.get_extension(@__MODULE__, Symbol("OptExt$(solver)"))
_get_solver_module(opt_ext.OptType())
catch
@critical "Could not install the requested solver" solver
@error "It seems the requested solver is not installed; trying to install and precompile it" solver
try
Pkg.add(solver)
@info "Trying again to activate solver extension" solver
Base.retry_load_extensions()
opt_ext = Base.get_extension(@__MODULE__, Symbol("OptExt$(solver)"))
_get_solver_module(opt_ext.OptType())

Check warning on line 402 in src/IESopt.jl

Codecov / codecov/patch

src/IESopt.jl#L396-L402

Added lines #L396 - L402 were not covered by tests
catch
@critical "Could not install the requested solver" solver

Check warning on line 404 in src/IESopt.jl

Codecov / codecov/patch

src/IESopt.jl#L404

Added line #L404 was not covered by tests
end
@critical "Solver installed, but can not proceed from here; please execute your code again"

Check warning on line 406 in src/IESopt.jl

Codecov / codecov/patch

src/IESopt.jl#L406

Added line #L406 was not covered by tests
end
@critical "Solver installed, but can not proceed from here; please execute your code again"
end

# withpkg(f, pkgid::Base.PkgId) = Base.invokelatest(f, IESopt.require(pkgid))
)

# withpkg(Base.PkgId(Pkg.Types.Context().env.project.deps[solver], solver)) do s
let s = getfield(IESopt, Symbol(solver))
let s = solver_module
if !_is_multiobjective(model)
if _iesopt_config(model).optimization.solver.mode == "direct"
@critical "Automatic direct mode is currently not supported"
12 changes: 7 additions & 5 deletions src/precompile/precompile_tools.jl
Original file line number Diff line number Diff line change
@@ -3,11 +3,13 @@
const dir = _PATHS[:examples]

@compile_workload begin
model = IESopt.generate!(normpath(dir, "01_basic_single_node.iesopt.yaml"); verbosity=false)
IESopt.optimize!(model)
if !isnothing(Library)
model = IESopt.generate!(normpath(dir, "01_basic_single_node.iesopt.yaml"); verbosity=false)
IESopt.optimize!(model)

Check warning on line 8 in src/precompile/precompile_tools.jl

Codecov / codecov/patch

src/precompile/precompile_tools.jl#L7-L8

Added lines #L7 - L8 were not covered by tests

IESopt.generate!(normpath(dir, "08_basic_investment.iesopt.yaml"); verbosity=false)
IESopt.generate!(normpath(dir, "09_csv_only.iesopt.yaml"); verbosity=false)
IESopt.generate!(normpath(dir, "46_constants_in_objective.iesopt.yaml"); verbosity=false)
IESopt.generate!(normpath(dir, "08_basic_investment.iesopt.yaml"); verbosity=false)
IESopt.generate!(normpath(dir, "09_csv_only.iesopt.yaml"); verbosity=false)
IESopt.generate!(normpath(dir, "46_constants_in_objective.iesopt.yaml"); verbosity=false)

Check warning on line 12 in src/precompile/precompile_tools.jl

Codecov / codecov/patch

src/precompile/precompile_tools.jl#L10-L12

Added lines #L10 - L12 were not covered by tests
end
end
end
15 changes: 2 additions & 13 deletions src/utils/utils.jl
Original file line number Diff line number Diff line change
@@ -6,21 +6,10 @@
end)
end

function _try_loading_solver()
_try_import(solver::String) = IESopt.eval(Meta.parse("""try; import $(solver); true; catch; false; end;"""))
active = join([s for s in _ALL_SOLVER_INTERFACES if _try_import(s)], ", ")

if _is_precompiling()
else
@info "Activating solver interfaces" active
end

return active
function _get_solver_module(solver::Any)
@critical "No solver extension prepared" solver

Check warning on line 10 in src/utils/utils.jl

Codecov / codecov/patch

src/utils/utils.jl#L9-L10

Added lines #L9 - L10 were not covered by tests
end

# Immediately try to load solver interfaces.
const ACTIVE_SOLVER_INTERFACES = _try_loading_solver()

include("general.jl")
include("logging.jl")
include("packing.jl")
19 changes: 18 additions & 1 deletion test/Manifest.toml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

julia_version = "1.10.3"
manifest_format = "2.0"
project_hash = "0f16b3954517e2989a6dcca15fd8260750ad1699"
project_hash = "9607dd83595c424ac800baa2c8a1382aa8a1b1e7"

[[deps.Aqua]]
deps = ["Compat", "Pkg", "Test"]
@@ -119,6 +119,23 @@ version = "0.10.36"
[deps.ForwardDiff.weakdeps]
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

[[deps.HiGHS]]
deps = ["HiGHS_jll", "MathOptInterface", "PrecompileTools", "SparseArrays"]
git-tree-sha1 = "a216e32299172b83abfe699604584f413ffbb045"
uuid = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
version = "1.9.0"

[[deps.HiGHS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Zlib_jll"]
git-tree-sha1 = "9a550d55c49334beb538c5ad9504f07fc29a13dc"
uuid = "8fd58aa0-07eb-5a78-9b36-339c94fd15ea"
version = "1.7.0+0"

[[deps.IESoptLib]]
git-tree-sha1 = "495ca907bf5587464b386b573828db8d5d3aa885"
uuid = "b98f706d-40ec-4ce6-a66c-1c6e71d3cef6"
version = "0.1.0"

[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
2 changes: 2 additions & 0 deletions test/Project.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
[deps]
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
IESoptLib = "b98f706d-40ec-4ce6-a66c-1c6e71d3cef6"
JET = "c3a54625-cd67-489e-a8e7-0a5a0ff4e31b"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
1 change: 1 addition & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import HiGHS
using IESopt, Suppressor
using Test, Aqua, JET
import JuMP
2 changes: 0 additions & 2 deletions test/src/examples.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const HiGHS = IESopt.HiGHS

function _test_example_default_solver(filename::String; obj::Float64, verbosity::Union{Bool, String}=false, kwargs...)
@testset "$(split(filename, ".")[1])" begin
model = @suppress generate!(joinpath(PATH_EXAMPLES, filename); verbosity=verbosity, kwargs...)