diff --git a/Project.toml b/Project.toml index c5c0a97..ef9d922 100644 --- a/Project.toml +++ b/Project.toml @@ -1,20 +1,22 @@ name = "SCS" uuid = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13" repo = "https://github.com/jump-dev/SCS.jl" -version = "1.1.2" +version = "1.1.3" [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" [compat] MathOptInterface = "1" Requires = "1" -SCS_GPU_jll = "=3.2.0" -SCS_jll = "=3.2.0" +SCS_GPU_jll = "=3.2.1" +SCS_MKL_jll = "=3.2.2" +SCS_jll = "=3.2.1" julia = "1.6" [extras] diff --git a/README.md b/README.md index 1ac5040..256bed9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Install SCS.jl using the Julia package manager: ```julia import Pkg; Pkg.add("SCS") ``` -In addition to installing the SCS.jl package, this will also download and +In addition to installing the `SCS.jl` package, this will also download and install the SCS binaries. (You do not need to install SCS separately.) To use a custom binary, read the [Custom solver binaries](https://jump.dev/JuMP.jl/stable/developers/custom_solver_binaries/) @@ -85,14 +85,60 @@ Common options are: See the [`glbopts.h` header](https://github.com/cvxgrp/scs/blob/3aaa93c7aa04c7001df5e51b81f21b126dfa99b3/include/glbopts.h#L35) for other options. -Select one of the linear solvers using the `linear_solver` option. The values -available are `SCS.DirectSolver` (the default) and `SCS.IndirectSolver`. A third -option for using a GPU is experimental, see the section below. +### Linear solvers -#### SCS on GPU +`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. + +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 +``` + +To select the linear solver of choice + * pass the `linear_solver` option to `JuMP.optimizer_with_attributes`, or to `MOI.OptimizerWithAttributes`; + * specify the solver as the first argument when using `scs_solve` directly (see scetion Low-level wrapper below). + +#### SCS with MKL Pardiso linear solver + +To enable the MKL Pardiso (direct sparse) solver one needs to load `MKL_jll` +**before** `SCS`: + +```julia +julia> import Pkg + +julia> Pkg.add(Pkg.PackageSpec(name = "MKL_jll", version = "2022.2")) + +julia> using MKL_jll # This must be called before `using SCS`. + +julia> using SCS + +julia> SCS.available_solvers +3-element Vector{DataType}: + SCS.DirectSolver + SCS.IndirectSolver + SCS.MKLDirectSolver +``` + +The `MKLDirectSolver` is available on `Linux x86_64` platform only. + +#### SCS with Sparse GPU indirect solver (CUDA only) + +> Note: as of version 1.0 the support for the GPU solver is broken (see +[this issue](https://github.com/jump-dev/SCS.jl/issues/245)). + +To enable the indirect linear solver on gpu one needs to load `CUDA_jll` +**before** `SCS`: -An experimental `SCS.GpuIndirectSolver` can be used on Linux. Note that -`CUDA_jll` must be installed and loaded **before* `SCS`. ```julia julia> import Pkg @@ -107,16 +153,10 @@ julia> SCS.available_solvers SCS.DirectSolver SCS.IndirectSolver SCS.GpuIndirectSolver - -julia> optimizer = SCS.Optimizer(); - -julia> MOI.set( - optimizer, - MOI.RawParameter("linear_solver"), - SCS.GpuIndirectSolver, - ) ``` +The `GpuIndirectSolver` is available on `Linux x86_64` platform only. + ### Low-level wrapper SCS.jl provides a low-level interface to solve a problem directly, without diff --git a/src/SCS.jl b/src/SCS.jl index f64a1a9..89a7ed5 100644 --- a/src/SCS.jl +++ b/src/SCS.jl @@ -13,6 +13,7 @@ import SparseArrays function __init__() global indirect = SCS_jll.libscsindir global direct = SCS_jll.libscsdir + Requires.@require( CUDA_jll = "e9e359dc-d701-5aa8-82ae-09bbf812ea83", begin @@ -21,6 +22,18 @@ function __init__() 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 @@ -28,6 +41,7 @@ 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] diff --git a/src/linear_solvers/direct.jl b/src/linear_solvers/direct.jl index 8800b1a..c5263bb 100644 --- a/src/linear_solvers/direct.jl +++ b/src/linear_solvers/direct.jl @@ -61,6 +61,8 @@ function scs_finish(::Type{DirectSolver}, work::Ptr{Cvoid}) return @ccall direct.scs_finish(work::Ptr{Cvoid})::Cvoid end -function scs_version() +function scs_version(::Type{DirectSolver}) return unsafe_string(@ccall direct.scs_version()::Cstring) end + +scs_version() = scs_version(DirectSolver) diff --git a/src/linear_solvers/gpu_indirect.jl b/src/linear_solvers/gpu_indirect.jl index 2d52845..264933c 100644 --- a/src/linear_solvers/gpu_indirect.jl +++ b/src/linear_solvers/gpu_indirect.jl @@ -60,3 +60,7 @@ end function scs_finish(::Type{GpuIndirectSolver}, work::Ptr{Cvoid}) return @ccall gpuindirect.scs_finish(work::Ptr{Cvoid})::Cvoid end + +function scs_version(::Type{GpuIndirectSolver}) + return unsafe_string(@ccall gpuindirect.scs_version()::Cstring) +end diff --git a/src/linear_solvers/indirect.jl b/src/linear_solvers/indirect.jl index 12d30a1..d5d8c31 100644 --- a/src/linear_solvers/indirect.jl +++ b/src/linear_solvers/indirect.jl @@ -60,3 +60,7 @@ end function scs_finish(::Type{IndirectSolver}, work::Ptr{Cvoid}) return @ccall indirect.scs_finish(work::Ptr{Cvoid})::Cvoid end + +function scs_version(::Type{IndirectSolver}) + return unsafe_string(@ccall indirect.scs_version()::Cstring) +end diff --git a/src/linear_solvers/mkl_direct.jl b/src/linear_solvers/mkl_direct.jl new file mode 100644 index 0000000..5271378 --- /dev/null +++ b/src/linear_solvers/mkl_direct.jl @@ -0,0 +1,66 @@ +# 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. + +struct MKLDirectSolver <: LinearSolver end + +scsint_t(::Type{MKLDirectSolver}) = Clonglong + +function scs_set_default_settings( + ::Type{MKLDirectSolver}, + stgs::ScsSettings{I}, +) where {I<:Clonglong} + return @ccall( + mkldirect.scs_set_default_settings(stgs::Ref{ScsSettings{I}})::Cvoid, + ) +end + +function scs_init( + ::Type{MKLDirectSolver}, + data::ScsData{I}, + cone::ScsCone{I}, + stgs::ScsSettings{I}, +) where {I<:Clonglong} + return @ccall mkldirect.scs_init( + data::Ref{ScsData{I}}, + cone::Ref{ScsCone{I}}, + stgs::Ref{ScsSettings{I}}, + )::Ptr{Cvoid} +end + +function scs_update( + ::Type{MKLDirectSolver}, + work::Ptr{Cvoid}, + b::Vector{Float64}, + c::Vector{Float64}, +) + return @ccall mkldirect.scs_update( + work::Ptr{Cvoid}, + b::Ref{Float64}, + c::Ref{Float64}, + )::Clonglong +end + +function scs_solve( + ::Type{MKLDirectSolver}, + work::Ptr{Cvoid}, + solution::ScsSolution, + info::ScsInfo{I}, + warm_start::Integer, +) where {I<:Clonglong} + return @ccall mkldirect.scs_solve( + work::Ptr{Cvoid}, + solution::Ref{ScsSolution}, + info::Ref{ScsInfo{I}}, + warm_start::Clonglong, + )::Clonglong +end + +function scs_finish(::Type{MKLDirectSolver}, work::Ptr{Cvoid}) + return @ccall mkldirect.scs_finish(work::Ptr{Cvoid})::Cvoid +end + +function scs_version(::Type{MKLDirectSolver}) + return unsafe_string(@ccall mkldirect.scs_version()::Cstring) +end diff --git a/test/MOI_wrapper.jl b/test/MOI_wrapper.jl index f0bf727..824bd6d 100644 --- a/test/MOI_wrapper.jl +++ b/test/MOI_wrapper.jl @@ -26,6 +26,10 @@ test_DirectSolver() = _test_runtests(SCS.DirectSolver) test_IndirectSolver() = _test_runtests(SCS.IndirectSolver) +@static if Sys.islinux() && Sys.ARCH == :x86_64 + test_MKLDirectSolver() = _test_runtests(SCS.MKLDirectSolver) +end + function _test_runtests(linear_solver) optimizer = SCS.Optimizer() MOI.set( diff --git a/test/runtests.jl b/test/runtests.jl index c10db60..bf9f1f9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -11,12 +11,25 @@ if get(ENV, "BUILDKITE", "false") == "true" end using Test +# MKL_jll is not in our Project.toml, so we need to install it. +import Pkg +Pkg.add(Pkg.PackageSpec(name = "MKL_jll", version = "2022")) +using MKL_jll # MKL_jll must be loaded _before_ SCS! using SCS +if Sys.islinux() && Sys.ARCH == :x86_64 + @test SCS.MKLDirectSolver in SCS.available_solvers +end + include("test_problems.jl") -for s in SCS.available_solvers - feasible_basic_problems(s) - test_options(s) +@test SCS.scs_version() isa String +@test VersionNumber(SCS.scs_version()) >= v"3.2.0" +for solver in SCS.available_solvers + @test SCS.scs_version(solver) isa String + @test VersionNumber(SCS.scs_version(solver)) >= v"3.2.0" + + feasible_basic_problems(solver) + test_options(solver) end include("MOI_wrapper.jl")