@@ -6,7 +6,7 @@ import Base: (*), convert, copy, eltype, getindex, show, size,
6
6
linearindexing, LinearFast, LinearSlow
7
7
8
8
import Base. LinAlg: (\ ), A_mul_Bc, A_mul_Bt, Ac_ldiv_B, Ac_mul_B, At_ldiv_B, At_mul_B,
9
- cholfact, cholfact!, det, diag, ishermitian, isposdef,
9
+ cholfact, det, diag, ishermitian, isposdef,
10
10
issym, ldltfact, logdet
11
11
12
12
import Base. SparseMatrix: sparse, nnz
@@ -132,10 +132,10 @@ end
132
132
# Type definitions #
133
133
# ###################
134
134
135
- # The three core data types for CHOLMOD: Dense, Sparse and Factor. CHOLMOD
136
- # manages the memory, so the Julia versions only wrap a pointer to a struct.
137
- # Therefore finalizers should be registret each time a pointer is returned from
138
- # CHOLMOD.
135
+ # The three core data types for CHOLMOD: Dense, Sparse and Factor.
136
+ # CHOLMOD manages the memory, so the Julia versions only wrap a
137
+ # pointer to a struct. Therefore finalizers should be registered each
138
+ # time a pointer is returned from CHOLMOD.
139
139
140
140
# Dense
141
141
immutable C_Dense{T<: VTypes }
@@ -273,6 +273,28 @@ type Factor{Tv,Ti} <: Factorization{Tv}
273
273
p:: Ptr{C_Factor{Tv,Ti}}
274
274
end
275
275
276
+ # FactorComponent, for encoding particular factors from a factorization
277
+ type FactorComponent{Tv,Ti,S} <: AbstractMatrix{Tv}
278
+ F:: Factor{Tv,Ti}
279
+
280
+ function FactorComponent (F:: Factor{Tv,Ti} )
281
+ s = unsafe_load (F. p)
282
+ if s. is_ll != 0
283
+ S == :L || S == :U || S == :PtL || S == :UP || throw (CHOLMODException (string (S, " not supported for sparse LLt matrices; try :L, :U, :PtL, or :UP" )))
284
+ else
285
+ S == :L || S == :U || S == :PtL || S == :UP ||
286
+ S == :D || S == :LD || S == :DU || S == :PtLD || S == :DUP ||
287
+ throw (CHOLMODException (string (S, " not supported for sparse LDLt matrices; try :L, :U, :PtL, :UP, :D, :LD, :DU, :PtLD, or :DUP" )))
288
+ end
289
+ new (F)
290
+ end
291
+ end
292
+ function FactorComponent {Tv,Ti} (F:: Factor{Tv,Ti} , sym:: Symbol )
293
+ FactorComponent {Tv,Ti,sym} (F)
294
+ end
295
+
296
+ Factor (FC:: FactorComponent ) = Factor (FC. F)
297
+
276
298
# ################
277
299
# Thin wrappers #
278
300
# ################
@@ -478,7 +500,7 @@ for Ti in IndexTypes
478
500
s
479
501
end
480
502
481
- function transpose {Tv<:VTypes} (A:: Sparse{Tv,$Ti} , values:: Integer )
503
+ function transpose_ {Tv<:VTypes} (A:: Sparse{Tv,$Ti} , values:: Integer )
482
504
s = Sparse (ccall ((@cholmod_name (" transpose" , $ Ti),:libcholmod ), Ptr{C_Sparse{Tv,$ Ti}},
483
505
(Ptr{C_Sparse{Tv,$ Ti}}, Cint, Ptr{UInt8}),
484
506
A. p, values, common ($ Ti)))
@@ -637,6 +659,12 @@ for Ti in IndexTypes
637
659
finalizer (f, free!)
638
660
f
639
661
end
662
+ function factorize! {Tv<:VTypes} (A:: Sparse{Tv,$Ti} , F:: Factor{Tv,$Ti} , cmmn:: Vector{UInt8} )
663
+ @isok ccall ((@cholmod_name (" factorize" , $ Ti),:libcholmod ), Cint,
664
+ (Ptr{C_Sparse{Tv,$ Ti}}, Ptr{C_Factor{Tv,$ Ti}}, Ptr{UInt8}),
665
+ A. p, F. p, cmmn)
666
+ F
667
+ end
640
668
function factorize_p! {Tv<:VTypes} (A:: Sparse{Tv,$Ti} , β:: Real , F:: Factor{Tv,$Ti} , cmmn:: Vector{UInt8} )
641
669
# note that β is passed as a complex number (double beta[2]),
642
670
# but the CHOLMOD manual says that only beta[0] (real part) is used
@@ -691,6 +719,13 @@ for Ti in IndexTypes
691
719
end
692
720
end
693
721
722
+ function get_perm (F:: Factor )
723
+ s = unsafe_load (F. p)
724
+ p = pointer_to_array (s. Perm, s. n, false )
725
+ p+ 1
726
+ end
727
+ get_perm (FC:: FactorComponent ) = get_perm (Factor (FC))
728
+
694
729
# ########################
695
730
# High level interfaces #
696
731
# ########################
@@ -879,9 +914,37 @@ function sparse{Ti}(A::Sparse{Complex{Float64},Ti}) # Notice! Cannot be type sta
879
914
end
880
915
return convert (Hermitian{Complex{Float64},SparseMatrixCSC{Complex{Float64},Ti}}, A)
881
916
end
882
- sparse (L:: Factor ) = sparse (Sparse (L))
917
+ function sparse (F:: Factor )
918
+ s = unsafe_load (F. p)
919
+ if s. is_ll != 0
920
+ L = Sparse (F)
921
+ A = sparse (L* L' )
922
+ else
923
+ LD = sparse (F[:LD ])
924
+ L, d = getLd! (LD)
925
+ A = scale (L, d)* L'
926
+ end
927
+ p = get_perm (F)
928
+ if p != [1 : s. n;]
929
+ pinv = Array (Int, length (p))
930
+ for k = 1 : length (p)
931
+ pinv[p[k]] = k
932
+ end
933
+ A = A[pinv,pinv]
934
+ end
935
+ A
936
+ end
937
+
883
938
sparse (D:: Dense ) = sparse (Sparse (D))
884
939
940
+ function sparse {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:L} )
941
+ F = Factor (FC)
942
+ s = unsafe_load (F. p)
943
+ s. is_ll != 0 || throw (CHOLMODException (" sparse: supported only for :LD on LDLt factorizations" ))
944
+ sparse (Sparse (F))
945
+ end
946
+ sparse {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:LD} ) = sparse (Sparse (Factor (FC)))
947
+
885
948
# Calculate the offset into the stype field of the cholmod_sparse_struct and
886
949
# change the value
887
950
let offidx= findfirst (fieldnames (C_Sparse) .== :stype )
@@ -905,14 +968,25 @@ eltype{T<:VTypes}(A::Sparse{T}) = T
905
968
nnz (F:: Factor ) = nnz (Sparse (F))
906
969
907
970
function show (io:: IO , F:: Factor )
908
- s = unsafe_load (F. p)
909
971
println (io, typeof (F))
972
+ showfactor (io, F)
973
+ end
974
+
975
+ function show (io:: IO , FC:: FactorComponent )
976
+ println (io, typeof (FC))
977
+ showfactor (io, Factor (FC))
978
+ end
979
+
980
+ function showfactor (io:: IO , F:: Factor )
981
+ s = unsafe_load (F. p)
910
982
@printf (io, " type: %12s\n " , s. is_ll!= 0 ? " LLt" : " LDLt" )
911
983
@printf (io, " method: %10s\n " , s. is_super!= 0 ? " supernodal" : " simplicial" )
912
984
@printf (io, " maxnnz: %10d\n " , Int (s. nzmax))
913
985
@printf (io, " nnz: %13d\n " , nnz (F))
914
986
end
915
987
988
+
989
+
916
990
isvalid (A:: Dense ) = check_dense (A)
917
991
isvalid (A:: Sparse ) = check_sparse (A)
918
992
isvalid (A:: Factor ) = check_factor (A)
@@ -936,7 +1010,22 @@ function size(F::Factor, i::Integer)
936
1010
return 1
937
1011
end
938
1012
1013
+
939
1014
linearindexing (:: Dense ) = LinearFast ()
1015
+
1016
+ size (FC:: FactorComponent , i:: Integer ) = size (FC. F, i)
1017
+ size (FC:: FactorComponent ) = size (FC. F)
1018
+
1019
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:L} ) = FactorComponent {Tv,Ti,:U} (FC. F)
1020
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:U} ) = FactorComponent {Tv,Ti,:L} (FC. F)
1021
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:PtL} ) = FactorComponent {Tv,Ti,:UP} (FC. F)
1022
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:UP} ) = FactorComponent {Tv,Ti,:PtL} (FC. F)
1023
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:D} ) = FC
1024
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:LD} ) = FactorComponent {Tv,Ti,:DU} (FC. F)
1025
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:DU} ) = FactorComponent {Tv,Ti,:LD} (FC. F)
1026
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:PtLD} ) = FactorComponent {Tv,Ti,:DUP} (FC. F)
1027
+ ctranspose {Tv,Ti} (FC:: FactorComponent{Tv,Ti,:DUP} ) = FactorComponent {Tv,Ti,:PtLD} (FC. F)
1028
+
940
1029
function getindex (A:: Dense , i:: Integer )
941
1030
s = unsafe_load (A. p)
942
1031
0 < i <= s. nrow* s. ncol || throw (BoundsError ())
@@ -957,6 +1046,27 @@ function getindex{T}(A::Sparse{T}, i0::Integer, i1::Integer)
957
1046
((r1 > r2) || (unsafe_load (s. i, r1) + 1 != i0)) ? zero (T) : unsafe_load (s. x, r1)
958
1047
end
959
1048
1049
+ function getindex (F:: Factor , sym:: Symbol )
1050
+ sym == :p && return get_perm (F)
1051
+ FactorComponent (F, sym)
1052
+ end
1053
+
1054
+ function getLd! (S:: SparseMatrixCSC )
1055
+ d = Array (eltype (S), size (S, 1 ))
1056
+ fill! (d, 0 )
1057
+ col = 1
1058
+ for k = 1 : length (S. nzval)
1059
+ while k >= S. colptr[col+ 1 ]
1060
+ col += 1
1061
+ end
1062
+ if S. rowval[k] == col
1063
+ d[col] = S. nzval[k]
1064
+ S. nzval[k] = 1
1065
+ end
1066
+ end
1067
+ S, d
1068
+ end
1069
+
960
1070
# # Multiplication
961
1071
(* )(A:: Sparse , B:: Sparse ) = ssmult (A, B, 0 , true , true )
962
1072
(* )(A:: Sparse , B:: Dense ) = sdmult! (A, false , 1. , 0. , B, zeros (size (A, 1 ), size (B, 2 )))
@@ -966,7 +1076,7 @@ function A_mul_Bc{Tv<:VRealTypes,Ti<:ITypes}(A::Sparse{Tv,Ti}, B::Sparse{Tv,Ti})
966
1076
cm = common (Ti)
967
1077
968
1078
if ! is (A,B)
969
- aa1 = transpose (B, 2 )
1079
+ aa1 = transpose_ (B, 2 )
970
1080
# # result of ssmult will have stype==0, contain numerical values and be sorted
971
1081
return ssmult (A, aa1, 0 , true , true )
972
1082
end
@@ -984,7 +1094,7 @@ function A_mul_Bc{Tv<:VRealTypes,Ti<:ITypes}(A::Sparse{Tv,Ti}, B::Sparse{Tv,Ti})
984
1094
end
985
1095
986
1096
function Ac_mul_B (A:: Sparse , B:: Sparse )
987
- aa1 = transpose (A, 2 )
1097
+ aa1 = transpose_ (A, 2 )
988
1098
if is (A,B)
989
1099
return A_mul_Bc (aa1, aa1)
990
1100
end
@@ -1071,6 +1181,57 @@ update!{T<:VTypes}(F::Factor{T}, A::SparseMatrixCSC{T}; kws...) = update!(F, Spa
1071
1181
1072
1182
# # Solvers
1073
1183
1184
+ for (T, f) in ((:Dense , :solve ), (:Sparse , :spsolve ))
1185
+ @eval begin
1186
+ # Solve Lx = b and L'x=b where A = L*L'
1187
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:L} , B:: $T )
1188
+ ($ f)(CHOLMOD_L, Factor (L), B)
1189
+ end
1190
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:U} , B:: $T )
1191
+ ($ f)(CHOLMOD_Lt, Factor (L), B)
1192
+ end
1193
+ # Solve PLx = b and L'P'x=b where A = P*L*L'*P'
1194
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:PtL} , B:: $T )
1195
+ F = Factor (L)
1196
+ ($ f)(CHOLMOD_L, F, ($ f)(CHOLMOD_P, F, B)) # Confusingly, CHOLMOD_P solves P'x = b
1197
+ end
1198
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:UP} , B:: $T )
1199
+ F = Factor (L)
1200
+ ($ f)(CHOLMOD_Pt, F, ($ f)(CHOLMOD_Lt, F, B))
1201
+ end
1202
+ # Solve various equations for A = L*D*L' and A = P*L*D*L'*P'
1203
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:D} , B:: $T )
1204
+ ($ f)(CHOLMOD_D, Factor (L), B)
1205
+ end
1206
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:LD} , B:: $T )
1207
+ ($ f)(CHOLMOD_LD, Factor (L), B)
1208
+ end
1209
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:DU} , B:: $T )
1210
+ ($ f)(CHOLMOD_DLt, Factor (L), B)
1211
+ end
1212
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:PtLD} , B:: $T )
1213
+ F = Factor (L)
1214
+ ($ f)(CHOLMOD_LD, F, ($ f)(CHOLMOD_P, F, B))
1215
+ end
1216
+ function (\ ){T,Ti}(L:: FactorComponent{T,Ti,:DUP} , B:: $T )
1217
+ F = Factor (L)
1218
+ ($ f)(CHOLMOD_Pt, F, ($ f)(CHOLMOD_DLt, F, B))
1219
+ end
1220
+ end
1221
+ end
1222
+
1223
+ function (\ )(L:: FactorComponent , b:: Vector )
1224
+ reshape (convert (Matrix, L\ Dense (b)), length (b))
1225
+ end
1226
+ function (\ )(L:: FactorComponent , B:: Matrix )
1227
+ convert (Matrix, L\ Dense (B))
1228
+ end
1229
+ function (\ )(L:: FactorComponent , B:: SparseMatrixCSC )
1230
+ sparse (L\ Sparse (B,0 ))
1231
+ end
1232
+
1233
+ Ac_ldiv_B (L:: FactorComponent , B) = ctranspose (L)\ B
1234
+
1074
1235
(\ )(L:: Factor , B:: Dense ) = solve (CHOLMOD_A, L, B)
1075
1236
(\ )(L:: Factor , b:: Vector ) = reshape (convert (Matrix, solve (CHOLMOD_A, L, Dense (b))), length (b))
1076
1237
(\ )(L:: Factor , B:: Matrix ) = convert (Matrix, solve (CHOLMOD_A, L, Dense (B)))
0 commit comments