@@ -2323,7 +2323,7 @@ sqrt(A::UnitLowerTriangular) = copy(transpose(sqrt(copy(transpose(A)))))
2323
2323
# Auxiliary functions for matrix square root
2324
2324
2325
2325
# square root of upper triangular or real upper quasitriangular matrix
2326
- function sqrt_quasitriu (A0)
2326
+ function sqrt_quasitriu (A0; blockwidth = eltype (A0) <: Complex ? 512 : 256 )
2327
2327
n = checksquare (A0)
2328
2328
T = eltype (A0)
2329
2329
Tr = typeof (sqrt (real (zero (T))))
@@ -2350,7 +2350,7 @@ function sqrt_quasitriu(A0)
2350
2350
A = A0
2351
2351
R = zeros (Tc, n, n)
2352
2352
end
2353
- _sqrt_quasitriu! (R, A)
2353
+ _sqrt_quasitriu! (R, A; blockwidth = blockwidth, n = n )
2354
2354
Rc = eltype (A0) <: Real ? R : complex (R)
2355
2355
if A0 isa UpperTriangular
2356
2356
return UpperTriangular (Rc)
@@ -2361,7 +2361,32 @@ function sqrt_quasitriu(A0)
2361
2361
end
2362
2362
end
2363
2363
2364
- function _sqrt_quasitriu! (R, A)
2364
+ # in-place recursive sqrt of upper quasi-triangular matrix A from
2365
+ # Deadman E., Higham N.J., Ralha R. (2013) Blocked Schur Algorithms for Computing the Matrix
2366
+ # Square Root. Applied Parallel and Scientific Computing. PARA 2012. Lecture Notes in
2367
+ # Computer Science, vol 7782. https://doi.org/10.1007/978-3-642-36803-5_12
2368
+ function _sqrt_quasitriu! (R, A; blockwidth= 64 , n= checksquare (A))
2369
+ if n ≤ blockwidth || ! (eltype (R) <: BlasFloat ) # base case, perform "point" algorithm
2370
+ _sqrt_quasitriu_block! (R, A)
2371
+ else # compute blockwise recursion
2372
+ split = div (n, 2 )
2373
+ iszero (A[split+ 1 , split]) || (split += 1 ) # don't split 2x2 diagonal block
2374
+ r1 = 1 : split
2375
+ r2 = (split + 1 ): n
2376
+ n1, n2 = split, n - split
2377
+ A11, A12, A22 = @views A[r1,r1], A[r1,r2], A[r2,r2]
2378
+ R11, R12, R22 = @views R[r1,r1], R[r1,r2], R[r2,r2]
2379
+ # solve diagonal blocks recursively
2380
+ _sqrt_quasitriu! (R11, A11; blockwidth= blockwidth, n= n1)
2381
+ _sqrt_quasitriu! (R22, A22; blockwidth= blockwidth, n= n2)
2382
+ # solve off-diagonal block
2383
+ R12 .= .- A12
2384
+ _sylvester_quasitriu! (R11, R22, R12; blockwidth= blockwidth, nA= n1, nB= n2, raise= false )
2385
+ end
2386
+ return R
2387
+ end
2388
+
2389
+ function _sqrt_quasitriu_block! (R, A)
2365
2390
_sqrt_quasitriu_diag_block! (R, A)
2366
2391
_sqrt_quasitriu_offdiag_block! (R, A)
2367
2392
return R
@@ -2514,6 +2539,83 @@ Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_2x2!(R, A, i, j)
2514
2539
return R
2515
2540
end
2516
2541
2542
+ # solve Sylvester's equation AX + XB = -C using blockwise recursion until the dimension of
2543
+ # A and B are no greater than blockwidth, based on Algorithm 1 from
2544
+ # Jonsson I, Kågström B. Recursive blocked algorithms for solving triangular systems—
2545
+ # Part I: one-sided and coupled Sylvester-type matrix equations. (2002) ACM Trans Math Softw.
2546
+ # 28(4), https://doi.org/10.1145/592843.592845.
2547
+ # specify raise=false to avoid breaking the recursion if a LAPACKException is thrown when
2548
+ # computing one of the blocks.
2549
+ function _sylvester_quasitriu! (A, B, C; blockwidth= 64 , nA= checksquare (A), nB= checksquare (B), raise= true )
2550
+ if 1 ≤ nA ≤ blockwidth && 1 ≤ nB ≤ blockwidth
2551
+ _sylvester_quasitriu_base! (A, B, C; raise= raise)
2552
+ elseif nA ≥ 2 nB ≥ 2
2553
+ _sylvester_quasitriu_split1! (A, B, C; blockwidth= blockwidth, nA= nA, nB= nB, raise= raise)
2554
+ elseif nB ≥ 2 nA ≥ 2
2555
+ _sylvester_quasitriu_split2! (A, B, C; blockwidth= blockwidth, nA= nA, nB= nB, raise= raise)
2556
+ else
2557
+ _sylvester_quasitriu_splitall! (A, B, C; blockwidth= blockwidth, nA= nA, nB= nB, raise= raise)
2558
+ end
2559
+ return C
2560
+ end
2561
+ function _sylvester_quasitriu_base! (A, B, C; raise= true )
2562
+ try
2563
+ _, scale = LAPACK. trsyl! (' N' , ' N' , A, B, C)
2564
+ rmul! (C, - inv (scale))
2565
+ catch e
2566
+ if ! (e isa LAPACKException) || raise
2567
+ throw (e)
2568
+ end
2569
+ end
2570
+ return C
2571
+ end
2572
+ function _sylvester_quasitriu_split1! (A, B, C; nA= checksquare (A), kwargs... )
2573
+ iA = div (nA, 2 )
2574
+ iszero (A[iA + 1 , iA]) || (iA += 1 ) # don't split 2x2 diagonal block
2575
+ rA1, rA2 = 1 : iA, (iA + 1 ): nA
2576
+ nA1, nA2 = iA, nA- iA
2577
+ A11, A12, A22 = @views A[rA1,rA1], A[rA1,rA2], A[rA2,rA2]
2578
+ C1, C2 = @views C[rA1,:], C[rA2,:]
2579
+ _sylvester_quasitriu! (A22, B, C2; nA= nA2, kwargs... )
2580
+ mul! (C1, A12, C2, true , true )
2581
+ _sylvester_quasitriu! (A11, B, C1; nA= nA1, kwargs... )
2582
+ return C
2583
+ end
2584
+ function _sylvester_quasitriu_split2! (A, B, C; nB= checksquare (B), kwargs... )
2585
+ iB = div (nB, 2 )
2586
+ iszero (B[iB + 1 , iB]) || (iB += 1 ) # don't split 2x2 diagonal block
2587
+ rB1, rB2 = 1 : iB, (iB + 1 ): nB
2588
+ nB1, nB2 = iB, nB- iB
2589
+ B11, B12, B22 = @views B[rB1,rB1], B[rB1,rB2], B[rB2,rB2]
2590
+ C1, C2 = @views C[:,rB1], C[:,rB2]
2591
+ _sylvester_quasitriu! (A, B11, C1; nB= nB1, kwargs... )
2592
+ mul! (C2, C1, B12, true , true )
2593
+ _sylvester_quasitriu! (A, B22, C2; nB= nB2, kwargs... )
2594
+ return C
2595
+ end
2596
+ function _sylvester_quasitriu_splitall! (A, B, C; nA= checksquare (A), nB= checksquare (B), kwargs... )
2597
+ iA = div (nA, 2 )
2598
+ iszero (A[iA + 1 , iA]) || (iA += 1 ) # don't split 2x2 diagonal block
2599
+ iB = div (nB, 2 )
2600
+ iszero (B[iB + 1 , iB]) || (iB += 1 ) # don't split 2x2 diagonal block
2601
+ rA1, rA2 = 1 : iA, (iA + 1 ): nA
2602
+ nA1, nA2 = iA, nA- iA
2603
+ rB1, rB2 = 1 : iB, (iB + 1 ): nB
2604
+ nB1, nB2 = iB, nB- iB
2605
+ A11, A12, A22 = @views A[rA1,rA1], A[rA1,rA2], A[rA2,rA2]
2606
+ B11, B12, B22 = @views B[rB1,rB1], B[rB1,rB2], B[rB2,rB2]
2607
+ C11, C21, C12, C22 = @views C[rA1,rB1], C[rA2,rB1], C[rA1,rB2], C[rA2,rB2]
2608
+ _sylvester_quasitriu! (A22, B11, C21; nA= nA2, nB= nB1, kwargs... )
2609
+ mul! (C11, A12, C21, true , true )
2610
+ _sylvester_quasitriu! (A11, B11, C11; nA= nA1, nB= nB1, kwargs... )
2611
+ mul! (C22, C21, B12, true , true )
2612
+ _sylvester_quasitriu! (A22, B22, C22; nA= nA2, nB= nB2, kwargs... )
2613
+ mul! (C12, A12, C22, true , true )
2614
+ mul! (C12, C11, B12, true , true )
2615
+ _sylvester_quasitriu! (A11, B22, C12; nA= nA1, nB= nB2, kwargs... )
2616
+ return C
2617
+ end
2618
+
2517
2619
# End of auxiliary functions for matrix square root
2518
2620
2519
2621
# Generic eigensystems
0 commit comments