Skip to content

Commit 062ac53

Browse files
authored
[breaking] refactor linear solver loading to use Pkg extensions (#286)
1 parent 79917cc commit 062ac53

12 files changed

+251
-236
lines changed

Project.toml

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
name = "SCS"
22
uuid = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13"
33
repo = "https://github.com/jump-dev/SCS.jl"
4-
version = "1.3.1"
4+
version = "2.0.0"
55

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

12+
[extensions]
13+
SCSSCS_GPU_jllExt = ["SCS_GPU_jll"]
14+
SCSSCS_MKL_jllExt = ["SCS_MKL_jll"]
15+
16+
[weakdeps]
17+
SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4"
18+
SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657"
19+
1420
[compat]
1521
MathOptInterface = "1.20"
1622
Pkg = "<0.0.1, ^1.6"
1723
Requires = "1"
18-
SCS_GPU_jll = "=3.2.3"
19-
SCS_MKL_jll = "=3.2.2, =3.2.3"
20-
SCS_jll = "=3.2.1, =3.2.3"
24+
SCS_GPU_jll = "=3.2.4"
25+
SCS_MKL_jll = "=3.2.4"
26+
SCS_jll = "=3.2.4"
2127
SparseArrays = "<0.0.1, ^1.6"
2228
Test = "<0.0.1, ^1.6"
2329
julia = "1.6"
2430

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

2937
[targets]

README.md

+29-42
Original file line numberDiff line numberDiff line change
@@ -129,70 +129,57 @@ for other options.
129129

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

137-
The find currently available linear solvers one can inspect `SCS.available_solvers`:
138-
```julia
139-
julia> using SCS
140-
141-
julia> SCS.available_solvers
142-
2-element Vector{DataType}:
143-
SCS.DirectSolver
144-
SCS.IndirectSolver
145-
```
134+
* `SCS.DirectSolver` (sparse direct, the default)
135+
* `SCS.IndirectSolver` (sparse indirect, by conjugate gradient)
146136

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

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

154147
### SCS with MKL Pardiso linear solver
155148

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

159-
```julia
160-
julia> import Pkg
152+
To enable the MKL Pardiso (direct sparse) solver one needs to install and load
153+
`SCS_MKL_jll`.
161154

162-
julia> Pkg.add(Pkg.PackageSpec(name = "MKL_jll", version = "2022.2"))
155+
```julia
156+
julia> import Pkg; Pkg.add("SCS_MKL_jll");
163157

164-
julia> using MKL_jll # This must be called before `using SCS`.
158+
julia> using SCS, SCS_MKL_jll
165159

166160
julia> using SCS
167161

168-
julia> SCS.available_solvers
169-
3-element Vector{DataType}:
170-
SCS.DirectSolver
171-
SCS.IndirectSolver
172-
SCS.MKLDirectSolver
162+
julia> SCS.is_available(SCS.MKLDirectSolver)
163+
true
173164
```
174165

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

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

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

182-
```julia
183-
julia> import Pkg
173+
To enable the indirect linear solver on GPU one needs to install and load
174+
`SCS_GPU_jll`.
184175

185-
julia> Pkg.add(Pkg.PackageSpec(name = "CUDA_jll", version = "10.1"))
186-
187-
julia> using CUDA_jll # This must be called before `using SCS`.
176+
```julia
177+
julia> import Pkg; Pkg.add("SCS_GPU_jll");
188178

189-
julia> using SCS
179+
julia> using SCS, SCS_GPU_jll
190180

191-
julia> SCS.available_solvers
192-
3-element Array{DataType,1}:
193-
SCS.DirectSolver
194-
SCS.IndirectSolver
195-
SCS.GpuIndirectSolver
181+
julia> SCS.is_available(SCS.GpuIndirectSolver)
182+
true
196183
```
197184

198185
The `GpuIndirectSolver` is available on `Linux x86_64` platform only.

ext/SCSSCS_GPU_jllExt.jl

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright (c) 2014: SCS.jl contributors
2+
#
3+
# Use of this source code is governed by an MIT-style license that can be found
4+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
5+
6+
module SCSSCS_GPU_jllExt
7+
8+
import SCS
9+
import SCS_GPU_jll
10+
11+
global gpuindirect = SCS_GPU_jll.libscsgpuindir
12+
13+
SCS.is_available(::Type{SCS.GpuIndirectSolver}) = true
14+
15+
SCS.scsint_t(::Type{SCS.GpuIndirectSolver}) = Cint
16+
17+
function SCS.scs_set_default_settings(
18+
::Type{SCS.GpuIndirectSolver},
19+
stgs::SCS.ScsSettings{I},
20+
) where {I<:Cint}
21+
return @ccall gpuindirect.scs_set_default_settings(
22+
stgs::Ref{SCS.ScsSettings{I}},
23+
)::Cvoid
24+
end
25+
26+
function SCS.scs_init(
27+
::Type{SCS.GpuIndirectSolver},
28+
data::SCS.ScsData{I},
29+
cone::SCS.ScsCone{I},
30+
stgs::SCS.ScsSettings{I},
31+
) where {I<:Cint}
32+
return @ccall gpuindirect.scs_init(
33+
data::Ref{SCS.ScsData{I}},
34+
cone::Ref{SCS.ScsCone{I}},
35+
stgs::Ref{SCS.ScsSettings{I}},
36+
)::Ptr{Cvoid}
37+
end
38+
39+
function SCS.scs_update(
40+
::Type{SCS.GpuIndirectSolver},
41+
work::Ptr{Cvoid},
42+
b::Vector{Float64},
43+
c::Vector{Float64},
44+
)
45+
return @ccall direct.scs_update(
46+
work::Ptr{Cvoid},
47+
b::Ref{Float64},
48+
c::Ref{Float64},
49+
)::Cint
50+
end
51+
52+
function SCS.scs_solve(
53+
::Type{SCS.GpuIndirectSolver},
54+
work::Ptr{Cvoid},
55+
solution::SCS.ScsSolution,
56+
info::SCS.ScsInfo{I},
57+
warm_start::Integer,
58+
) where {I<:Cint}
59+
return @ccall gpuindirect.scs_solve(
60+
work::Ptr{Cvoid},
61+
solution::Ref{SCS.ScsSolution},
62+
info::Ref{SCS.ScsInfo{I}},
63+
warm_start::Cint,
64+
)::Cint
65+
end
66+
67+
function SCS.scs_finish(::Type{SCS.GpuIndirectSolver}, work::Ptr{Cvoid})
68+
return @ccall gpuindirect.scs_finish(work::Ptr{Cvoid})::Cvoid
69+
end
70+
71+
function SCS.scs_version(::Type{SCS.GpuIndirectSolver})
72+
return unsafe_string(@ccall gpuindirect.scs_version()::Cstring)
73+
end
74+
75+
end # module

ext/SCSSCS_MKL_jllExt.jl

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright (c) 2022: SCS.jl contributors
2+
#
3+
# Use of this source code is governed by an MIT-style license that can be found
4+
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
5+
6+
module SCSSCS_MKL_jllExt
7+
8+
import SCS
9+
import SCS_MKL_jll
10+
11+
global mkldirect = SCS_MKL_jll.libscsmkl
12+
13+
SCS.is_available(::Type{SCS.MKLDirectSolver}) = true
14+
15+
SCS.scsint_t(::Type{SCS.MKLDirectSolver}) = Clonglong
16+
17+
function SCS.scs_set_default_settings(
18+
::Type{SCS.MKLDirectSolver},
19+
stgs::SCS.ScsSettings{I},
20+
) where {I<:Clonglong}
21+
return @ccall(
22+
mkldirect.scs_set_default_settings(stgs::Ref{SCS.ScsSettings{I}})::Cvoid,
23+
)
24+
end
25+
26+
function SCS.scs_init(
27+
::Type{SCS.MKLDirectSolver},
28+
data::SCS.ScsData{I},
29+
cone::SCS.ScsCone{I},
30+
stgs::SCS.ScsSettings{I},
31+
) where {I<:Clonglong}
32+
return @ccall mkldirect.scs_init(
33+
data::Ref{SCS.ScsData{I}},
34+
cone::Ref{SCS.ScsCone{I}},
35+
stgs::Ref{SCS.ScsSettings{I}},
36+
)::Ptr{Cvoid}
37+
end
38+
39+
function SCS.scs_update(
40+
::Type{SCS.MKLDirectSolver},
41+
work::Ptr{Cvoid},
42+
b::Vector{Float64},
43+
c::Vector{Float64},
44+
)
45+
return @ccall mkldirect.scs_update(
46+
work::Ptr{Cvoid},
47+
b::Ref{Float64},
48+
c::Ref{Float64},
49+
)::Clonglong
50+
end
51+
52+
function SCS.scs_solve(
53+
::Type{SCS.MKLDirectSolver},
54+
work::Ptr{Cvoid},
55+
solution::SCS.ScsSolution,
56+
info::SCS.ScsInfo{I},
57+
warm_start::Integer,
58+
) where {I<:Clonglong}
59+
return @ccall mkldirect.scs_solve(
60+
work::Ptr{Cvoid},
61+
solution::Ref{SCS.ScsSolution},
62+
info::Ref{SCS.ScsInfo{I}},
63+
warm_start::Clonglong,
64+
)::Clonglong
65+
end
66+
67+
function SCS.scs_finish(::Type{SCS.MKLDirectSolver}, work::Ptr{Cvoid})
68+
return @ccall mkldirect.scs_finish(work::Ptr{Cvoid})::Cvoid
69+
end
70+
71+
function SCS.scs_version(::Type{SCS.MKLDirectSolver})
72+
return unsafe_string(@ccall mkldirect.scs_version()::Cstring)
73+
end
74+
75+
end # module

src/SCS.jl

+24-30
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,39 @@
66
module SCS
77

88
import MathOptInterface as MOI
9-
import Requires
9+
import Requires # Remove when Julia 1.9 is the LTS
1010
import SCS_jll
1111
import SparseArrays
1212

13-
function __init__()
14-
global indirect = SCS_jll.libscsindir
15-
global direct = SCS_jll.libscsdir
16-
17-
Requires.@require(
18-
CUDA_jll = "e9e359dc-d701-5aa8-82ae-09bbf812ea83",
19-
begin
20-
import SCS_GPU_jll
21-
global gpuindirect = SCS_GPU_jll.libscsgpuindir
22-
push!(available_solvers, GpuIndirectSolver)
23-
end
24-
)
25-
Requires.@require(
26-
MKL_jll = "856f044c-d86e-5d09-b602-aeab76dc8ba7",
27-
begin
28-
if Sys.islinux() && Sys.ARCH == :x86_64
29-
import SCS_MKL_jll
30-
import SCS_MKL_jll.MKL_jll
31-
global mkldirect = SCS_MKL_jll.libscsmkl
32-
33-
push!(available_solvers, MKLDirectSolver)
34-
end
35-
end
36-
)
37-
return
38-
end
13+
abstract type LinearSolver end
14+
15+
is_available(::Type{<:LinearSolver}) = false
3916

4017
include("c_wrapper.jl")
4118
include("linear_solvers/direct.jl")
4219
include("linear_solvers/indirect.jl")
43-
include("linear_solvers/gpu_indirect.jl")
44-
include("linear_solvers/mkl_direct.jl")
4520
include("MOI_wrapper/MOI_wrapper.jl")
4621

47-
const available_solvers = [DirectSolver, IndirectSolver]
22+
# Code is contained in /ext/SCSSCS_GPU_jllExt
23+
struct GpuIndirectSolver <: LinearSolver end
24+
25+
# Code is contained in /ext/SCSSCS_MKL_jllExt
26+
struct MKLDirectSolver <: LinearSolver end
27+
28+
function __init__()
29+
# Remove when Julia 1.9 is the LTS
30+
@static if !isdefined(Base, :get_extension)
31+
Requires.@require(
32+
SCS_GPU_jll = "af6e375f-46ec-5fa0-b791-491b0dfa44a4",
33+
include("../ext/SCSSCS_GPU_jllExt.jl"),
34+
)
35+
Requires.@require(
36+
SCS_MKL_jll = "3f2553a9-4106-52be-b7dd-865123654657",
37+
include("../ext/SCSSCS_MKL_jllExt.jl"),
38+
)
39+
end
40+
return
41+
end
4842

4943
export scs_solve
5044

src/c_wrapper.jl

-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
# Use of this source code is governed by an MIT-style license that can be found
44
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
55

6-
abstract type LinearSolver end
7-
86
abstract type AbstractSCSType end
97

108
Base.cconvert(::Type{Ptr{Cvoid}}, x::AbstractSCSType) = x

src/linear_solvers/direct.jl

+4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
# Use of this source code is governed by an MIT-style license that can be found
44
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.
55

6+
global direct = SCS_jll.libscsdir
7+
68
struct DirectSolver <: LinearSolver end
79

10+
is_available(::Type{DirectSolver}) = true
11+
812
scsint_t(::Type{DirectSolver}) = Clonglong
913

1014
function scs_set_default_settings(

0 commit comments

Comments
 (0)