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

[breaking] refactor linear solver loading to use Pkg extensions #286

Merged
merged 17 commits into from
Nov 20, 2023
20 changes: 14 additions & 6 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,37 @@
name = "SCS"
uuid = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13"
repo = "https://github.com/jump-dev/SCS.jl"
version = "1.3.1"
version = "2.0.0"

[deps]
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4"
SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657"
SCS_jll = "f4f2fc5b-1d94-523c-97ea-2ab488bedf4b"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[extensions]
SCSSCS_GPU_jllExt = ["SCS_GPU_jll"]
SCSSCS_MKL_jllExt = ["SCS_MKL_jll"]

[weakdeps]
SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4"
SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657"

[compat]
MathOptInterface = "1.20"
Pkg = "<0.0.1, ^1.6"
Requires = "1"
SCS_GPU_jll = "=3.2.3"
SCS_MKL_jll = "=3.2.2, =3.2.3"
SCS_jll = "=3.2.1, =3.2.3"
SCS_GPU_jll = "=3.2.4"
SCS_MKL_jll = "=3.2.4"
SCS_jll = "=3.2.4"
SparseArrays = "<0.0.1, ^1.6"
Test = "<0.0.1, ^1.6"
julia = "1.6"

[extras]
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4"
SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
Expand Down
71 changes: 29 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,70 +129,57 @@ for other options.

`SCS` uses a linear solver internally, see
[this section](https://www.cvxgrp.org/scs/linear_solver/index.html#linear-system-solver)
of `SCS` documentation. `SCS.jl` ships with
* `SCS.DirectSolver` (sparse direct, the default) and
* `SCS.LinearSolver` (sparse indirect, by conjugate gradient)
enabled.
of `SCS` documentation. `SCS.jl` ships with the following linear solvers:

The find currently available linear solvers one can inspect `SCS.available_solvers`:
```julia
julia> using SCS

julia> SCS.available_solvers
2-element Vector{DataType}:
SCS.DirectSolver
SCS.IndirectSolver
```
* `SCS.DirectSolver` (sparse direct, the default)
* `SCS.IndirectSolver` (sparse indirect, by conjugate gradient)

To select the linear solver of choice:
To select the linear solver, set the `linear_solver` option, or pass the solver
as the first argument when using `scs_solve` directly (see the low-level wrapper
section below). For example:

* pass the `linear_solver` option to [`optimizer_with_attributes`](@ref), or to
[`MOI.OptimizerWithAttributes`](@ref);
* specify the solver as the first argument when using `scs_solve` directly
(see the low-level wrapper section below).
```julia
using JuMP, SCS
model = Model(SCS.Optimizer)
set_attribute(model, "linear_solver", SCS.IndirectSolver)
```

### SCS with MKL Pardiso linear solver

To enable the MKL Pardiso (direct sparse) solver one needs to load `MKL_jll`
**before** `SCS`:
**SCS.jl v2.0 introduced a breaking change. You now need to use `SCS_MKL_jll`
instead of `MKL_jll`.**

```julia
julia> import Pkg
To enable the MKL Pardiso (direct sparse) solver one needs to install and load
`SCS_MKL_jll`.

julia> Pkg.add(Pkg.PackageSpec(name = "MKL_jll", version = "2022.2"))
```julia
julia> import Pkg; Pkg.add("SCS_MKL_jll");

julia> using MKL_jll # This must be called before `using SCS`.
julia> using SCS, SCS_MKL_jll

julia> using SCS

julia> SCS.available_solvers
3-element Vector{DataType}:
SCS.DirectSolver
SCS.IndirectSolver
SCS.MKLDirectSolver
julia> SCS.is_available(SCS.MKLDirectSolver)
true
```

The `MKLDirectSolver` is available on `Linux x86_64` platform only.

### SCS with Sparse GPU indirect solver (CUDA only)

To enable the indirect linear solver on GPU one needs to load `CUDA_jll`
**before** `SCS`:
**SCS.jl v2.0 introduced a breaking change. You now need to use `SCS_GPU_jll`
instead of `CUDA_jll`.**

```julia
julia> import Pkg
To enable the indirect linear solver on GPU one needs to install and load
`SCS_GPU_jll`.

julia> Pkg.add(Pkg.PackageSpec(name = "CUDA_jll", version = "10.1"))

julia> using CUDA_jll # This must be called before `using SCS`.
```julia
julia> import Pkg; Pkg.add("SCS_GPU_jll");

julia> using SCS
julia> using SCS, SCS_GPU_jll

julia> SCS.available_solvers
3-element Array{DataType,1}:
SCS.DirectSolver
SCS.IndirectSolver
SCS.GpuIndirectSolver
julia> SCS.is_available(SCS.GpuIndirectSolver)
true
```

The `GpuIndirectSolver` is available on `Linux x86_64` platform only.
Expand Down
75 changes: 75 additions & 0 deletions ext/SCSSCS_GPU_jllExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright (c) 2014: SCS.jl contributors
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

module SCSSCS_GPU_jllExt

import SCS
import SCS_GPU_jll

global gpuindirect = SCS_GPU_jll.libscsgpuindir

SCS.is_available(::Type{SCS.GpuIndirectSolver}) = true

Check warning on line 13 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L13

Added line #L13 was not covered by tests

SCS.scsint_t(::Type{SCS.GpuIndirectSolver}) = Cint

Check warning on line 15 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L15

Added line #L15 was not covered by tests

function SCS.scs_set_default_settings(

Check warning on line 17 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L17

Added line #L17 was not covered by tests
::Type{SCS.GpuIndirectSolver},
stgs::SCS.ScsSettings{I},
) where {I<:Cint}
return @ccall gpuindirect.scs_set_default_settings(

Check warning on line 21 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L21

Added line #L21 was not covered by tests
stgs::Ref{SCS.ScsSettings{I}},
)::Cvoid
end

function SCS.scs_init(

Check warning on line 26 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L26

Added line #L26 was not covered by tests
::Type{SCS.GpuIndirectSolver},
data::SCS.ScsData{I},
cone::SCS.ScsCone{I},
stgs::SCS.ScsSettings{I},
) where {I<:Cint}
return @ccall gpuindirect.scs_init(

Check warning on line 32 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L32

Added line #L32 was not covered by tests
data::Ref{SCS.ScsData{I}},
cone::Ref{SCS.ScsCone{I}},
stgs::Ref{SCS.ScsSettings{I}},
)::Ptr{Cvoid}
end

function SCS.scs_update(

Check warning on line 39 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L39

Added line #L39 was not covered by tests
::Type{SCS.GpuIndirectSolver},
work::Ptr{Cvoid},
b::Vector{Float64},
c::Vector{Float64},
)
return @ccall direct.scs_update(

Check warning on line 45 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L45

Added line #L45 was not covered by tests
work::Ptr{Cvoid},
b::Ref{Float64},
c::Ref{Float64},
)::Cint
end

function SCS.scs_solve(

Check warning on line 52 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L52

Added line #L52 was not covered by tests
::Type{SCS.GpuIndirectSolver},
work::Ptr{Cvoid},
solution::SCS.ScsSolution,
info::SCS.ScsInfo{I},
warm_start::Integer,
) where {I<:Cint}
return @ccall gpuindirect.scs_solve(

Check warning on line 59 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L59

Added line #L59 was not covered by tests
work::Ptr{Cvoid},
solution::Ref{SCS.ScsSolution},
info::Ref{SCS.ScsInfo{I}},
warm_start::Cint,
)::Cint
end

function SCS.scs_finish(::Type{SCS.GpuIndirectSolver}, work::Ptr{Cvoid})
return @ccall gpuindirect.scs_finish(work::Ptr{Cvoid})::Cvoid

Check warning on line 68 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L67-L68

Added lines #L67 - L68 were not covered by tests
end

function SCS.scs_version(::Type{SCS.GpuIndirectSolver})
return unsafe_string(@ccall gpuindirect.scs_version()::Cstring)

Check warning on line 72 in ext/SCSSCS_GPU_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_GPU_jllExt.jl#L71-L72

Added lines #L71 - L72 were not covered by tests
end

end # module
75 changes: 75 additions & 0 deletions ext/SCSSCS_MKL_jllExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright (c) 2022: SCS.jl contributors
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

module SCSSCS_MKL_jllExt

import SCS
import SCS_MKL_jll

global mkldirect = SCS_MKL_jll.libscsmkl

SCS.is_available(::Type{SCS.MKLDirectSolver}) = true

SCS.scsint_t(::Type{SCS.MKLDirectSolver}) = Clonglong

function SCS.scs_set_default_settings(
::Type{SCS.MKLDirectSolver},
stgs::SCS.ScsSettings{I},
) where {I<:Clonglong}
return @ccall(
mkldirect.scs_set_default_settings(stgs::Ref{SCS.ScsSettings{I}})::Cvoid,
)
end

function SCS.scs_init(
::Type{SCS.MKLDirectSolver},
data::SCS.ScsData{I},
cone::SCS.ScsCone{I},
stgs::SCS.ScsSettings{I},
) where {I<:Clonglong}
return @ccall mkldirect.scs_init(
data::Ref{SCS.ScsData{I}},
cone::Ref{SCS.ScsCone{I}},
stgs::Ref{SCS.ScsSettings{I}},
)::Ptr{Cvoid}
end

function SCS.scs_update(

Check warning on line 39 in ext/SCSSCS_MKL_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_MKL_jllExt.jl#L39

Added line #L39 was not covered by tests
::Type{SCS.MKLDirectSolver},
work::Ptr{Cvoid},
b::Vector{Float64},
c::Vector{Float64},
)
return @ccall mkldirect.scs_update(

Check warning on line 45 in ext/SCSSCS_MKL_jllExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/SCSSCS_MKL_jllExt.jl#L45

Added line #L45 was not covered by tests
work::Ptr{Cvoid},
b::Ref{Float64},
c::Ref{Float64},
)::Clonglong
end

function SCS.scs_solve(
::Type{SCS.MKLDirectSolver},
work::Ptr{Cvoid},
solution::SCS.ScsSolution,
info::SCS.ScsInfo{I},
warm_start::Integer,
) where {I<:Clonglong}
return @ccall mkldirect.scs_solve(
work::Ptr{Cvoid},
solution::Ref{SCS.ScsSolution},
info::Ref{SCS.ScsInfo{I}},
warm_start::Clonglong,
)::Clonglong
end

function SCS.scs_finish(::Type{SCS.MKLDirectSolver}, work::Ptr{Cvoid})
return @ccall mkldirect.scs_finish(work::Ptr{Cvoid})::Cvoid
end

function SCS.scs_version(::Type{SCS.MKLDirectSolver})
return unsafe_string(@ccall mkldirect.scs_version()::Cstring)
end

end # module
54 changes: 24 additions & 30 deletions src/SCS.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,45 +6,39 @@
module SCS

import MathOptInterface as MOI
import Requires
import Requires # Remove when Julia 1.9 is the LTS
import SCS_jll
import SparseArrays

function __init__()
global indirect = SCS_jll.libscsindir
global direct = SCS_jll.libscsdir

Requires.@require(
CUDA_jll = "e9e359dc-d701-5aa8-82ae-09bbf812ea83",
begin
import SCS_GPU_jll
global gpuindirect = SCS_GPU_jll.libscsgpuindir
push!(available_solvers, GpuIndirectSolver)
end
)
Requires.@require(
MKL_jll = "856f044c-d86e-5d09-b602-aeab76dc8ba7",
begin
if Sys.islinux() && Sys.ARCH == :x86_64
import SCS_MKL_jll
import SCS_MKL_jll.MKL_jll
global mkldirect = SCS_MKL_jll.libscsmkl

push!(available_solvers, MKLDirectSolver)
end
end
)
return
end
abstract type LinearSolver end

is_available(::Type{<:LinearSolver}) = false

include("c_wrapper.jl")
include("linear_solvers/direct.jl")
include("linear_solvers/indirect.jl")
include("linear_solvers/gpu_indirect.jl")
include("linear_solvers/mkl_direct.jl")
include("MOI_wrapper/MOI_wrapper.jl")

const available_solvers = [DirectSolver, IndirectSolver]
# Code is contained in /ext/SCSSCS_GPU_jllExt
struct GpuIndirectSolver <: LinearSolver end

# Code is contained in /ext/SCSSCS_MKL_jllExt
struct MKLDirectSolver <: LinearSolver end

function __init__()
# Remove when Julia 1.9 is the LTS
@static if !isdefined(Base, :get_extension)

Check warning on line 30 in src/SCS.jl

View check run for this annotation

Codecov / codecov/patch

src/SCS.jl#L30

Added line #L30 was not covered by tests
Requires.@require(
SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4",
include("../ext/SCSSCS_GPU_jllExt.jl"),
)
Requires.@require(
SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657",
include("../ext/SCSSCS_MKL_jllExt.jl"),
)
end
return
end

export scs_solve

Expand Down
2 changes: 0 additions & 2 deletions src/c_wrapper.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

abstract type LinearSolver end

abstract type AbstractSCSType end

Base.cconvert(::Type{Ptr{Cvoid}}, x::AbstractSCSType) = x
Expand Down
4 changes: 4 additions & 0 deletions src/linear_solvers/direct.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

global direct = SCS_jll.libscsdir

struct DirectSolver <: LinearSolver end

is_available(::Type{DirectSolver}) = true

scsint_t(::Type{DirectSolver}) = Clonglong

function scs_set_default_settings(
Expand Down
Loading
Loading