Skip to content
Open
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions gen/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"
SuiteSparse_jll = "bea87d4a-7f5b-5778-9afe-8cc45184846c"

[compat]
Clang = "0.18"
JuliaFormatter = "1.0.45"
Clang = "0.18, 0.19"
JuliaFormatter = "2"
5 changes: 4 additions & 1 deletion gen/generator.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ else
end
include_dir = joinpath(artifact_dir, "include", "suitesparse") |> normpath

config_h = joinpath(include_dir, "SuiteSparse_config.h")
@assert isfile(config_h)

cholmod_h = joinpath(include_dir, "cholmod.h")
@assert isfile(cholmod_h)

Expand All @@ -42,7 +45,7 @@ options["general"]["output_file_path"] = joinpath(@__DIR__, "..", "src/solvers/w
args = get_default_args()
push!(args, "-I$include_dir")

header_files = [cholmod_h, SuiteSparseQR_C_h, umfpack_h]
header_files = [config_h, cholmod_h, SuiteSparseQR_C_h, umfpack_h]

ctx = create_context(header_files, args, options)

Expand Down
94 changes: 94 additions & 0 deletions src/solvers/LibSuiteSparse.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,106 @@
module LibSuiteSparse

using SuiteSparse_jll
import Libdl

const TRUE = Int32(1)
const FALSE = Int32(0)

include("wrappers.jl")

const SUITESPARSE_MIN_VERSION = v"6.0.0"
const BUILD_VERSION = VersionNumber(
SUITESPARSE_MAIN_VERSION,
SUITESPARSE_SUB_VERSION,
SUITESPARSE_SUBSUB_VERSION
)

public init_suitesparse

"""
LibSuiteSparse.init_suitesparse

Internal function which is used to initialize the SuiteSparse libraries to the correct
memory management functions. Any package which directly wraps one of the following
SuiteSparse libraries *must* ensure that this function is called before the use of that
library: AMD, CAMD, COLAMD, CCOLAMD, UMFPACK, CXSparse, CHOLMOD, KLU, BTF, LDL, RBio,
SPQR, SPEX, and ParU

# Notes:
- Currently this function only sets the memory management functions of SuiteSparse_config,
however there are also override functions for `printf`, `hypot`, and `divcomplex`.
- SuiteSparse_config, and this initialization function, is not a dependency of CSparse,
GraphBLAS, or LAGraph.
"""
const init_suitesparse = Base.OncePerProcess{Nothing}() do
try
### Check if the linked library is compatible with the Julia code
if Libdl.dlsym_e(Libdl.dlopen("libsuitesparseconfig"), :SuiteSparse_version) != C_NULL
current_version_array = Vector{Cint}(undef, 3)
SuiteSparse_version(current_version_array)
current_version = VersionNumber(current_version_array...)
else # SuiteSparse < 4.2.0 does not include SuiteSparse_version()
current_version = v"0.0.0"
end


if current_version < SUITESPARSE_MIN_VERSION
@warn """
SuiteSparse version incompatibility

Julia was compiled with SuiteSparse version $BUILD_VERSION. It is
currently linked with a version older than
$(SUITESPARSE_MIN_VERSION). This might cause Julia to
terminate when working with sparse matrix factorizations,
e.g. solving systems of equations with \\.

It is recommended that you use Julia with a recent version
of SuiteSparse, or download the generic binaries
from www.julialang.org, which ship with the correct
versions of all dependencies.
"""
elseif BUILD_VERSION.major != current_version.major
@warn """
SuiteSparse version incompatibility

Julia was compiled with SuiteSparse version $BUILD_VERSION. It is
currently linked with version $current_version.
This might cause Julia to terminate when working with
sparse matrix factorizations, e.g. solving systems of
equations with \\.

It is recommended that you use Julia with the same major
version of SuiteSparse as the one used during the build, or
download the generic binaries from www.julialang.org,
which ship with the correct versions of all dependencies.
"""
end

current_version >= v"6.0.0" && SuiteSparse_start()

# Register gc tracked allocator if SuiteSparse is new enough
if current_version >= v"7.0.0"
SuiteSparse_config_malloc_func_set(cglobal(:jl_malloc, Ptr{Cvoid}))
SuiteSparse_config_calloc_func_set(cglobal(:jl_calloc, Ptr{Cvoid}))
SuiteSparse_config_realloc_func_set(cglobal(:jl_realloc, Ptr{Cvoid}))
SuiteSparse_config_free_func_set(cglobal(:jl_free, Ptr{Cvoid}))
elseif current_version >= v"4.2.0"
cnfg = cglobal((:SuiteSparse_config, libsuitesparseconfig), Ptr{Cvoid})
unsafe_store!(cnfg, cglobal(:jl_malloc, Ptr{Cvoid}), 1)
unsafe_store!(cnfg, cglobal(:jl_calloc, Ptr{Cvoid}), 2)
unsafe_store!(cnfg, cglobal(:jl_realloc, Ptr{Cvoid}), 3)
unsafe_store!(cnfg, cglobal(:jl_free, Ptr{Cvoid}), 4)
end

current_version >= v"6.0.0" && atexit() do
SuiteSparse_finish()
end

catch ex
@error "Error during initialization of module LibSuiteSparse" exception=ex,catch_backtrace()
end
end

# exports
const PREFIXES = ["cholmod_", "CHOLMOD_", "umfpack_"]
for name in names(@__MODULE__; all=true), prefix in PREFIXES
Expand Down
73 changes: 2 additions & 71 deletions src/solvers/cholmod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import LinearAlgebra: (\), AdjointFactorization,

using SparseArrays
using SparseArrays: getcolptr, AbstractSparseVecOrMat
import Libdl

export
Dense,
Factor,
Expand Down Expand Up @@ -174,86 +172,19 @@ function newcommon(; print = 0) # no printing from CHOLMOD by default
end

function getcommon(::Type{Int32})
init_once()
LibSuiteSparse.init_suitesparse()
return get!(newcommon, task_local_storage(), :cholmod_common)::Ref{cholmod_common}
end

function getcommon(::Type{Int64})
init_once()
LibSuiteSparse.init_suitesparse()
return get!(newcommon_l, task_local_storage(), :cholmod_common_l)::Ref{cholmod_common}
end

getcommon() = getcommon(Int)

const BUILD_VERSION = VersionNumber(CHOLMOD_MAIN_VERSION, CHOLMOD_SUB_VERSION, CHOLMOD_SUBSUB_VERSION)

const init_once = Base.OncePerProcess{Nothing}() do
try
### Check if the linked library is compatible with the Julia code
if Libdl.dlsym_e(Libdl.dlopen("libcholmod"), :cholmod_version) != C_NULL
current_version_array = Vector{Cint}(undef, 3)
cholmod_version(current_version_array)
current_version = VersionNumber(current_version_array...)
else # CHOLMOD < 2.1.1 does not include cholmod_version()
current_version = v"0.0.0"
end


if current_version < CHOLMOD_MIN_VERSION
@warn """
CHOLMOD version incompatibility

Julia was compiled with CHOLMOD version $BUILD_VERSION. It is
currently linked with a version older than
$(CHOLMOD_MIN_VERSION). This might cause Julia to
terminate when working with sparse matrix factorizations,
e.g. solving systems of equations with \\.

It is recommended that you use Julia with a recent version
of CHOLMOD, or download the generic binaries
from www.julialang.org, which ship with the correct
versions of all dependencies.
"""
elseif BUILD_VERSION.major != current_version.major
@warn """
CHOLMOD version incompatibility

Julia was compiled with CHOLMOD version $BUILD_VERSION. It is
currently linked with version $current_version.
This might cause Julia to terminate when working with
sparse matrix factorizations, e.g. solving systems of
equations with \\.

It is recommended that you use Julia with the same major
version of CHOLMOD as the one used during the build, or
download the generic binaries from www.julialang.org,
which ship with the correct versions of all dependencies.
"""
end

# Register gc tracked allocator if CHOLMOD is new enough
if current_version >= v"4.0.3"
ccall((:SuiteSparse_config_malloc_func_set, libsuitesparseconfig),
Cvoid, (Ptr{Cvoid},), cglobal(:jl_malloc, Ptr{Cvoid}))
ccall((:SuiteSparse_config_calloc_func_set, libsuitesparseconfig),
Cvoid, (Ptr{Cvoid},), cglobal(:jl_calloc, Ptr{Cvoid}))
ccall((:SuiteSparse_config_realloc_func_set, libsuitesparseconfig),
Cvoid, (Ptr{Cvoid},), cglobal(:jl_realloc, Ptr{Cvoid}))
ccall((:SuiteSparse_config_free_func_set, libsuitesparseconfig),
Cvoid, (Ptr{Cvoid},), cglobal(:jl_free, Ptr{Cvoid}))
elseif current_version >= v"3.0.0"
cnfg = cglobal((:SuiteSparse_config, libsuitesparseconfig), Ptr{Cvoid})
unsafe_store!(cnfg, cglobal(:jl_malloc, Ptr{Cvoid}), 1)
unsafe_store!(cnfg, cglobal(:jl_calloc, Ptr{Cvoid}), 2)
unsafe_store!(cnfg, cglobal(:jl_realloc, Ptr{Cvoid}), 3)
unsafe_store!(cnfg, cglobal(:jl_free, Ptr{Cvoid}), 4)
end

catch ex
@error "Error during initialization of module CHOLMOD" exception=ex,catch_backtrace()
end
end

####################
# Type definitions #
####################
Expand Down
5 changes: 3 additions & 2 deletions src/solvers/umfpack.jl
Original file line number Diff line number Diff line change
Expand Up @@ -325,15 +325,15 @@ is provided or `q` is `nothing`, UMFPACK's default is used. If the permutation i
zero-based copy is made.

The `control` vector defaults to the Julia SparseArrays package's default configuration for UMFPACK (NB: this is modified from the UMFPACK defaults to
disable iterative refinement), but can be changed by passing a vector of length `UMFPACK_CONTROL`, see the UMFPACK manual for possible configurations.
disable iterative refinement), but can be changed by passing a vector of length `UMFPACK_CONTROL`, see the UMFPACK manual for possible configurations.
For example to reenable iterative refinement:

umfpack_control = SparseArrays.UMFPACK.get_umfpack_control(Float64, Int64) # read Julia default configuration for a Float64 sparse matrix
SparseArrays.UMFPACK.show_umf_ctrl(umfpack_control) # optional - display values
umfpack_control[SparseArrays.UMFPACK.JL_UMFPACK_IRSTEP] = 2.0 # reenable iterative refinement (2 is UMFPACK default max iterative refinement steps)

Alu = lu(A; control = umfpack_control)
x = Alu \\ b # solve Ax = b, including UMFPACK iterative refinement
x = Alu \\ b # solve Ax = b, including UMFPACK iterative refinement

The individual components of the factorization `F` can be accessed by indexing:

Expand Down Expand Up @@ -1036,6 +1036,7 @@ for Tv in (:Float64, :ComplexF64), Ti in UmfpackIndexTypes
# the control and info arrays
_defaults = Symbol(umf_nm("defaults", Tv, Ti))
@eval function get_umfpack_control(::Type{$Tv}, ::Type{$Ti})
LibSuiteSparse.init_suitesparse()
control = Vector{Float64}(undef, UMFPACK_CONTROL)
$_defaults(control)
# Put julia's config here
Expand Down
80 changes: 40 additions & 40 deletions src/solvers/wrappers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,6 @@ function SuiteSparse_config_printf_func_get()
@ccall libsuitesparseconfig.SuiteSparse_config_printf_func_get()::Ptr{Cvoid}
end

function cholmod_version(version)
@ccall libcholmod.cholmod_version(version::Ptr{Cint})::Cint
end

function cholmod_l_version(version)
@ccall libcholmod.cholmod_l_version(version::Ptr{Cint})::Cint
end

function SuiteSparse_config_malloc_func_get()
@ccall libsuitesparseconfig.SuiteSparse_config_malloc_func_get()::Ptr{Cvoid}
end
Expand Down Expand Up @@ -155,6 +147,14 @@ function SuiteSparse_BLAS_integer_size()
@ccall libsuitesparseconfig.SuiteSparse_BLAS_integer_size()::Csize_t
end

function cholmod_version(version)
@ccall libcholmod.cholmod_version(version::Ptr{Cint})::Cint
end

function cholmod_l_version(version)
@ccall libcholmod.cholmod_l_version(version::Ptr{Cint})::Cint
end

@enum cholmod_query_t::UInt32 begin
CHOLMOD_QUERY_HAS_GPL = 0
CHOLMOD_QUERY_HAS_CHECK = 1
Expand Down Expand Up @@ -3348,38 +3348,6 @@ function umfpack_toc(stats)
@ccall libumfpack.umfpack_toc(stats::Ptr{Cdouble})::Cvoid
end

const CHOLMOD_PATTERN = 0

const CHOLMOD_REAL = 1

const CHOLMOD_COMPLEX = 2

const CHOLMOD_ZOMPLEX = 3

const CHOLMOD_DOUBLE = 0

const CHOLMOD_SINGLE = 4

const CHOLMOD_INT = 0

const CHOLMOD_LONG = 2

const CHOLMOD_DATE = "Feb 20, 2025"

const CHOLMOD_MAIN_VERSION = 5

const CHOLMOD_SUB_VERSION = 3

const CHOLMOD_SUBSUB_VERSION = 1

SUITESPARSE_VER_CODE(main, sub) = main * 1000 + sub

CHOLMOD_VER_CODE(main, sub) = SUITESPARSE_VER_CODE(main, sub)

const CHOLMOD_VERSION = CHOLMOD_VER_CODE(5, 3)

const _FILE_OFFSET_BITS = 64

const SUITESPARSE_OPENMP_MAX_THREADS = 1

const SUITESPARSE_OPENMP_GET_NUM_THREADS = 1
Expand Down Expand Up @@ -3412,6 +3380,8 @@ const SUITESPARSE_SUB_VERSION = 10

const SUITESPARSE_SUBSUB_VERSION = 1

SUITESPARSE_VER_CODE(main, sub) = main * 1000 + sub

const SUITESPARSE_VERSION = SUITESPARSE_VER_CODE(7, 10)

function SUITESPARSE__VERCODE(main, sub, patch)
Expand All @@ -3420,6 +3390,36 @@ end

const SUITESPARSE__VERSION = SUITESPARSE__VERCODE(7, 10, 1)

const CHOLMOD_PATTERN = 0

const CHOLMOD_REAL = 1

const CHOLMOD_COMPLEX = 2

const CHOLMOD_ZOMPLEX = 3

const CHOLMOD_DOUBLE = 0

const CHOLMOD_SINGLE = 4

const CHOLMOD_INT = 0

const CHOLMOD_LONG = 2

const CHOLMOD_DATE = "Feb 20, 2025"

const CHOLMOD_MAIN_VERSION = 5

const CHOLMOD_SUB_VERSION = 3

const CHOLMOD_SUBSUB_VERSION = 1

CHOLMOD_VER_CODE(main, sub) = SUITESPARSE_VER_CODE(main, sub)

const CHOLMOD_VERSION = CHOLMOD_VER_CODE(5, 3)

const _FILE_OFFSET_BITS = 64

const CHOLMOD__VERSION = SUITESPARSE__VERCODE(5, 3, 1)

const CHOLMOD_DEVICE_SUPERNODE_BUFFERS = 6
Expand Down
Loading