28
28
29
29
MKL_LOAD_FAILED = false
30
30
31
- mkl_is_available () = (LOCAL_MKL_FOUND || MKL_jll. is_available ()) && ! MKL_LOAD_FAILED
31
+ mkl_is_available () = (LOCAL_MKL_FOUND || MKL_jll. is_available ()) && ! MKL_LOAD_FAILED
32
32
33
33
if LinearAlgebra. BLAS. vendor () === :mkl && LinearAlgebra. BlasInt == Int64
34
34
const MklInt = Int64
@@ -128,7 +128,7 @@ function __init__()
128
128
elseif MKL_jll. is_available ()
129
129
libmkl_rt[] = MKL_jll. libmkl_rt_path
130
130
end
131
-
131
+
132
132
if ! haskey (ENV , " PARDISOLICMESSAGE" )
133
133
ENV [" PARDISOLICMESSAGE" ] = 1
134
134
end
@@ -137,7 +137,7 @@ function __init__()
137
137
@warn " MKLROOT not set, MKL Pardiso solver will not be functional"
138
138
end
139
139
140
- if mkl_is_available ()
140
+ if mkl_is_available ()
141
141
try
142
142
libmklpardiso = Libdl. dlopen (libmkl_rt[])
143
143
mklpardiso_f = Libdl. dlsym (libmklpardiso, " pardiso" )
@@ -146,7 +146,7 @@ function __init__()
146
146
MKL_LOAD_FAILED = true
147
147
end
148
148
end
149
-
149
+
150
150
# This is apparently needed for MKL to not get stuck on 1 thread when
151
151
# libpardiso is loaded in the block below...
152
152
if libmkl_rt[] != = " "
@@ -241,6 +241,85 @@ function fix_iparm!(ps::AbstractPardisoSolver, T::Symbol)
241
241
end
242
242
end
243
243
244
+ # Copied from SparseArrays.jl but with a tweak
245
+ # to check symmetry of the sparsity pattern
246
+ function _is_hermsym (A:: SparseMatrixCSC , check:: Function )
247
+ m, n = size (A)
248
+ if m != n; return false ; end
249
+
250
+ colptr = SparseArrays. getcolptr (A)
251
+ rowval = rowvals (A)
252
+ nzval = nonzeros (A)
253
+ tracker = copy (SparseArrays. getcolptr (A))
254
+ for col in axes (A,2 )
255
+ # `tracker` is updated such that, for symmetric matrices,
256
+ # the loop below starts from an element at or below the
257
+ # diagonal element of column `col`"
258
+ for p = tracker[col]: colptr[col+ 1 ]- 1
259
+ val = nzval[p]
260
+ row = rowval[p]
261
+
262
+ # Ignore stored zeros
263
+ if iszero (val)
264
+ continue
265
+ end
266
+
267
+ # If the matrix was symmetric we should have updated
268
+ # the tracker to start at the diagonal or below. Here
269
+ # we are above the diagonal so the matrix can't be symmetric.
270
+ if row < col
271
+ return false
272
+ end
273
+
274
+ # Diagonal element
275
+ if row == col
276
+ if ! check (val, val)
277
+ return false
278
+ end
279
+ else
280
+ offset = tracker[row]
281
+
282
+ # If the matrix is unsymmetric, there might not exist
283
+ # a rowval[offset]
284
+ if offset > length (rowval)
285
+ return false
286
+ end
287
+
288
+ row2 = rowval[offset]
289
+
290
+ # row2 can be less than col if the tracker didn't
291
+ # get updated due to stored zeros in previous elements.
292
+ # We therefore "catch up" here while making sure that
293
+ # the elements are actually zero.
294
+ while row2 < col
295
+ if _isnotzero (nzval[offset])
296
+ return false
297
+ end
298
+ offset += 1
299
+ row2 = rowval[offset]
300
+ tracker[row] += 1
301
+ end
302
+
303
+ # Non zero A[i,j] exists but A[j,i] does not exist
304
+ if row2 > col
305
+ return false
306
+ end
307
+
308
+ # A[i,j] and A[j,i] exists
309
+ if row2 == col
310
+ if ! check (val, nzval[offset])
311
+ return false
312
+ end
313
+ tracker[row] += 1
314
+ end
315
+ end
316
+ end
317
+ end
318
+ return true
319
+ end
320
+
321
+ isstructurallysymmetric (A:: SparseMatrixCSC ) = _is_hermsym (A, (x,y) -> true )
322
+
244
323
function solve! (ps:: AbstractPardisoSolver , X:: StridedVecOrMat{Tv} ,
245
324
A:: SparseMatrixCSC{Tv,Ti} , B:: StridedVecOrMat{Tv} ,
246
325
T:: Symbol = :N ) where {Ti, Tv <: PardisoNumTypes }
@@ -253,38 +332,72 @@ function solve!(ps::AbstractPardisoSolver, X::StridedVecOrMat{Tv},
253
332
# - On pos def exception, solve instead with symmetric indefinite.
254
333
# - If complex and symmetric, solve with symmetric complex solver
255
334
# - Else solve as unsymmetric.
256
- if ishermitian (A)
257
- eltype (A) <: Union{Float32, Float64} ? set_matrixtype! (ps, REAL_SYM_POSDEF) : set_matrixtype! (ps, COMPLEX_HERM_POSDEF)
258
- pardisoinit (ps)
259
- fix_iparm! (ps, T)
260
- eltype (A) <: Union{Float32, ComplexF32} ? set_iparm! (ps, 28 , 1 ) : nothing
261
- try
335
+ if Tv <: Union{Float32, Float64}
336
+ if issymmetric (A)
337
+ set_matrixtype! (ps, REAL_SYM_POSDEF)
338
+ pardisoinit (ps)
339
+ fix_iparm! (ps, T)
340
+ Tv == Float32 && set_iparm! (ps, 28 , 1 )
341
+ try
342
+ pardiso (ps, X, get_matrix (ps, A, T), B)
343
+ catch e
344
+ set_phase! (ps, RELEASE_ALL)
345
+ pardiso (ps, X, A, B)
346
+ set_phase! (ps, ANALYSIS_NUM_FACT_SOLVE_REFINE)
347
+ if ! isa (e, PardisoPosDefException)
348
+ rethrow ()
349
+ end
350
+ set_matrixtype! (ps, REAL_SYM_INDEF)
351
+ pardisoinit (ps)
352
+ fix_iparm! (ps, T)
353
+ Tv == Float32 && set_iparm! (ps, 28 , 1 )
354
+ pardiso (ps, X, get_matrix (ps, A, T), B)
355
+ end
356
+ else
357
+ if isstructurallysymmetric (A)
358
+ set_matrixtype! (ps, REAL_SYM)
359
+ else
360
+ set_matrixtype! (ps, REAL_NONSYM)
361
+ end
362
+ pardisoinit (ps)
363
+ fix_iparm! (ps, T)
364
+ Tv == Float32 && set_iparm! (ps, 28 , 1 )
262
365
pardiso (ps, X, get_matrix (ps, A, T), B)
263
- catch e
264
- set_phase! (ps, RELEASE_ALL)
265
- pardiso (ps, X, A, B)
266
- set_phase! (ps, ANALYSIS_NUM_FACT_SOLVE_REFINE)
267
- if ! isa (e, PardisoPosDefException)
268
- rethrow ()
366
+ end
367
+ else # Tv <: Union{ComplexF64, ComplexF32}
368
+ if ishermitian (A)
369
+ set_matrixtype! (ps, COMPLEX_HERM_POSDEF)
370
+ pardisoinit (ps)
371
+ fix_iparm! (ps, T)
372
+ Tv == ComplexF32 && set_iparm! (ps, 28 , 1 )
373
+ try
374
+ pardiso (ps, X, get_matrix (ps, A, T), B)
375
+ catch e
376
+ set_phase! (ps, RELEASE_ALL)
377
+ pardiso (ps, X, A, B)
378
+ set_phase! (ps, ANALYSIS_NUM_FACT_SOLVE_REFINE)
379
+ if ! isa (e, PardisoPosDefException)
380
+ rethrow ()
381
+ end
382
+ set_matrixtype! (ps, COMPLEX_HERM_INDEF)
383
+ pardisoinit (ps)
384
+ fix_iparm! (ps, T)
385
+ Tv == ComplexF32 && set_iparm! (ps, 28 , 1 )
386
+ pardiso (ps, X, get_matrix (ps, A, T), B)
387
+ end
388
+ else
389
+ if issymmetric (A)
390
+ set_matrixtype! (ps, COMPLEX_SYM)
391
+ elseif isstructurallysymmetric (A)
392
+ set_matrixtype! (ps, COMPLEX_STRUCT_SYM)
393
+ else
394
+ set_matrixtype! (ps, COMPLEX_NONSYM)
269
395
end
270
- eltype (A) <: Union{Float32, Float64} ? set_matrixtype! (ps, REAL_SYM_INDEF) : set_matrixtype! (ps, COMPLEX_HERM_INDEF)
271
396
pardisoinit (ps)
272
397
fix_iparm! (ps, T)
273
- eltype (A) <: Union{Float32, ComplexF32} ? set_iparm! (ps, 28 , 1 ) : nothing
398
+ Tv == ComplexF32 && set_iparm! (ps, 28 , 1 )
274
399
pardiso (ps, X, get_matrix (ps, A, T), B)
275
400
end
276
- elseif issymmetric (A)
277
- set_matrixtype! (ps, COMPLEX_SYM)
278
- pardisoinit (ps)
279
- fix_iparm! (ps, T)
280
- eltype (A) <: Union{Float32, ComplexF32} ? set_iparm! (ps, 28 , 1 ) : nothing
281
- pardiso (ps, X, get_matrix (ps, A, T), B)
282
- else
283
- eltype (A) <: Union{Float32, Float64} ? set_matrixtype! (ps, REAL_NONSYM) : set_matrixtype! (ps, COMPLEX_NONSYM)
284
- pardisoinit (ps)
285
- fix_iparm! (ps, T)
286
- eltype (A) <: Union{Float32, ComplexF32} ? set_iparm! (ps, 28 , 1 ) : nothing
287
- pardiso (ps, X, get_matrix (ps, A, T), B)
288
401
end
289
402
290
403
# Release memory, TODO : We are running the convert on IA and JA here
@@ -344,7 +457,7 @@ function pardiso(ps::AbstractPardisoSolver, X::StridedVecOrMat{Tv}, A::SparseMat
344
457
end
345
458
346
459
N = size (A, 2 )
347
-
460
+
348
461
resize! (ps. perm, size (B, 1 ))
349
462
350
463
NRHS = size (B, 2 )
0 commit comments