@@ -18,7 +18,7 @@ using LinearAlgebra
1818using LinearAlgebra: RealHermSymComplexHerm, AdjOrTrans
1919import LinearAlgebra: (\ ), AdjointFactorization,
2020 cholesky, cholesky!, det, diag, ishermitian, isposdef,
21- issuccess, issymmetric, ldlt, ldlt!, logdet,
21+ issuccess, issymmetric, ldiv!, ldlt, ldlt!, logdet,
2222 lowrankdowndate, lowrankdowndate!, lowrankupdate, lowrankupdate!
2323
2424using SparseArrays
@@ -913,6 +913,32 @@ function Base.convert(::Type{Dense{Tnew}}, A::Dense{T}) where {Tnew, T}
913913end
914914Base. convert (:: Type{Dense{T}} , A:: Dense{T} ) where T = A
915915
916+ # Just calling Dense(x) or Dense(b) will allocate new
917+ # `cholmod_dense_struct`s in CHOLMOD. Instead, we want to reuse
918+ # the existing memory. We can do this by creating new
919+ # `cholmod_dense_struct`s and filling them manually.
920+ function wrap_dense_and_ptr (x:: StridedVecOrMat{T} ) where {T <: VTypes }
921+ dense_x = cholmod_dense_struct ()
922+ dense_x. nrow = size (x, 1 )
923+ dense_x. ncol = size (x, 2 )
924+ dense_x. nzmax = length (x)
925+ dense_x. d = stride (x, 2 )
926+ dense_x. x = pointer (x)
927+ dense_x. z = C_NULL
928+ dense_x. xtype = xtyp (eltype (x))
929+ dense_x. dtype = dtyp (eltype (x))
930+ return dense_x, pointer_from_objref (dense_x)
931+ end
932+ # We need to use a special handling for the case of `Dense`
933+ # input arrays since the `pointer` refers to the pointer to the
934+ # `cholmod_dense`, not to the array values themselves as for
935+ # standard arrays.
936+ function wrap_dense_and_ptr (x:: Dense{T} ) where {T <: VTypes }
937+ dense_x_ptr = x. ptr
938+ dense_x = unsafe_load (dense_x_ptr)
939+ return dense_x, pointer_from_objref (dense_x)
940+ end
941+
916942# This constructor assumes zero based colptr and rowval
917943function Sparse (m:: Integer , n:: Integer ,
918944 colptr0:: Vector{Ti} , rowval0:: Vector{Ti} ,
@@ -1913,6 +1939,66 @@ const AbstractSparseVecOrMatInclAdjAndTrans = Union{AbstractSparseVecOrMat, AdjO
19131939 throw (ArgumentError (" self-adjoint sparse system solve not implemented for sparse rhs B," *
19141940 " consider to convert B to a dense array" ))
19151941
1942+ # in-place ldiv!
1943+ for TI in IndexTypes
1944+ @eval function ldiv! (x:: StridedVecOrMat{T} ,
1945+ L:: Factor{T, $TI} ,
1946+ b:: StridedVecOrMat{T} ) where {T<: VTypes }
1947+ if x === b
1948+ throw (ArgumentError (" output array must not be aliased with input array" ))
1949+ end
1950+ if size (L, 1 ) != size (b, 1 )
1951+ throw (DimensionMismatch (" Factorization and RHS should have the same number of rows. " *
1952+ " Factorization has $(size (L, 2 )) rows, but RHS has $(size (b, 1 )) rows." ))
1953+ end
1954+ if size (L, 2 ) != size (x, 1 )
1955+ throw (DimensionMismatch (" Factorization and solution should match sizes. " *
1956+ " Factorization has $(size (L, 1 )) columns, but solution has $(size (x, 1 )) rows." ))
1957+ end
1958+ if size (x, 2 ) != size (b, 2 )
1959+ throw (DimensionMismatch (" Solution and RHS should have the same number of columns. " *
1960+ " Solution has $(size (x, 2 )) columns, but RHS has $(size (b, 2 )) columns." ))
1961+ end
1962+ if ! issuccess (L)
1963+ s = unsafe_load (pointer (L))
1964+ if s. is_ll == 1
1965+ throw (LinearAlgebra. PosDefException (s. minor))
1966+ else
1967+ throw (LinearAlgebra. ZeroPivotException (s. minor))
1968+ end
1969+ end
1970+
1971+ # Just calling Dense(x) or Dense(b) will allocate new
1972+ # `cholmod_dense_struct`s in CHOLMOD. Instead, we want to reuse
1973+ # the existing memory. We can do this by creating new
1974+ # `cholmod_dense_struct`s and filling them manually.
1975+ dense_x, dense_x_ptr = wrap_dense_and_ptr (x)
1976+ dense_b, dense_b_ptr = wrap_dense_and_ptr (b)
1977+
1978+ X_Handle = Ptr {cholmod_dense_struct} (dense_x_ptr)
1979+ Y_Handle = Ptr {cholmod_dense_struct} (C_NULL )
1980+ E_Handle = Ptr {cholmod_dense_struct} (C_NULL )
1981+ status = GC. @preserve x dense_x b dense_b begin
1982+ $ (cholname (:solve2 , TI))(
1983+ CHOLMOD_A, L,
1984+ Ref (dense_b), C_NULL ,
1985+ Ref (X_Handle), C_NULL ,
1986+ Ref (Y_Handle),
1987+ Ref (E_Handle),
1988+ getcommon ($ TI))
1989+ end
1990+ if Y_Handle != C_NULL
1991+ free! (Y_Handle)
1992+ end
1993+ if E_Handle != C_NULL
1994+ free! (E_Handle)
1995+ end
1996+ @assert ! iszero (status)
1997+
1998+ return x
1999+ end
2000+ end
2001+
19162002# # Other convenience methods
19172003function diag (F:: Factor{Tv, Ti} ) where {Tv, Ti}
19182004 f = unsafe_load (typedpointer (F))
0 commit comments