• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37532

pending completion
#37532

push

local

web-flow
Bump LBT to v5.8.0 (#49658)

Includes: https://github.com/JuliaLinearAlgebra/libblastrampoline/commit/81316155d

72313 of 83446 relevant lines covered (86.66%)

32311668.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.33
/stdlib/LinearAlgebra/src/triangular.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## Triangular
4

5
# could be renamed to Triangular when that name has been fully deprecated
6
abstract type AbstractTriangular{T,S<:AbstractMatrix} <: AbstractMatrix{T} end
7

8
# First loop through all methods that don't need special care for upper/lower and unit diagonal
9
for t in (:LowerTriangular, :UnitLowerTriangular, :UpperTriangular,
10
          :UnitUpperTriangular)
11
    @eval begin
12
        struct $t{T,S<:AbstractMatrix{T}} <: AbstractTriangular{T,S}
13
            data::S
14

15
            function $t{T,S}(data) where {T,S<:AbstractMatrix{T}}
94,247✔
16
                require_one_based_indexing(data)
94,247✔
17
                checksquare(data)
94,248✔
18
                new{T,S}(data)
94,246✔
19
            end
20
        end
21
        $t(A::$t) = A
1,688✔
22
        $t{T}(A::$t{T}) where {T} = A
56✔
23
        function $t(A::AbstractMatrix)
94,213✔
24
            return $t{eltype(A), typeof(A)}(A)
94,213✔
25
        end
26
        function $t{T}(A::AbstractMatrix) where T
28✔
27
            $t(convert(AbstractMatrix{T}, A))
28✔
28
        end
29

30
        function $t{T}(A::$t) where T
21,359✔
31
            Anew = convert(AbstractMatrix{T}, A.data)
21,359✔
32
            $t(Anew)
21,119✔
33
        end
34
        Matrix(A::$t{T}) where {T} = Matrix{T}(A)
30,654✔
35

36
        AbstractMatrix{T}(A::$t) where {T} = $t{T}(A)
21,331✔
37

38
        size(A::$t, d) = size(A.data, d)
121,509✔
39
        size(A::$t) = size(A.data)
335,294✔
40

41
        # For A<:AbstractTriangular, similar(A[, neweltype]) should yield a matrix with the same
42
        # triangular type and underlying storage type as A. The following method covers these cases.
43
        similar(A::$t, ::Type{T}) where {T} = $t(similar(parent(A), T))
1,254✔
44
        # On the other hand, similar(A, [neweltype,] shape...) should yield a matrix of the underlying
45
        # storage type of A (not wrapped in a triangular type). The following method covers these cases.
46
        similar(A::$t, ::Type{T}, dims::Dims{N}) where {T,N} = similar(parent(A), T, dims)
14,683✔
47

48
        copy(A::$t) = $t(copy(A.data))
4,400✔
49

50
        real(A::$t{<:Real}) = A
81✔
51
        real(A::$t{<:Complex}) = (B = real(A.data); $t(B))
710✔
52
    end
53
end
54

55
similar(A::UpperTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
56
    UpperTriangular(similar(parent(parent(A)), T))
57
similar(A::UnitUpperTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
58
    UnitUpperTriangular(similar(parent(parent(A)), T))
59
similar(A::LowerTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
60
    LowerTriangular(similar(parent(parent(A)), T))
61
similar(A::UnitLowerTriangular{<:Any,<:Union{Adjoint{Ti}, Transpose{Ti}}}, ::Type{T}) where {T,Ti} =
×
62
    UnitLowerTriangular(similar(parent(parent(A)), T))
63

64

65
"""
66
    LowerTriangular(A::AbstractMatrix)
67

68
Construct a `LowerTriangular` view of the matrix `A`.
69

70
# Examples
71
```jldoctest
72
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
73
3×3 Matrix{Float64}:
74
 1.0  2.0  3.0
75
 4.0  5.0  6.0
76
 7.0  8.0  9.0
77

78
julia> LowerTriangular(A)
79
3×3 LowerTriangular{Float64, Matrix{Float64}}:
80
 1.0   ⋅    ⋅
81
 4.0  5.0   ⋅
82
 7.0  8.0  9.0
83
```
84
"""
85
LowerTriangular
86
"""
87
    UpperTriangular(A::AbstractMatrix)
88

89
Construct an `UpperTriangular` view of the matrix `A`.
90

91
# Examples
92
```jldoctest
93
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
94
3×3 Matrix{Float64}:
95
 1.0  2.0  3.0
96
 4.0  5.0  6.0
97
 7.0  8.0  9.0
98

99
julia> UpperTriangular(A)
100
3×3 UpperTriangular{Float64, Matrix{Float64}}:
101
 1.0  2.0  3.0
102
  ⋅   5.0  6.0
103
  ⋅    ⋅   9.0
104
```
105
"""
106
UpperTriangular
107
"""
108
    UnitLowerTriangular(A::AbstractMatrix)
109

110
Construct a `UnitLowerTriangular` view of the matrix `A`.
111
Such a view has the [`oneunit`](@ref) of the [`eltype`](@ref)
112
of `A` on its diagonal.
113

114
# Examples
115
```jldoctest
116
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
117
3×3 Matrix{Float64}:
118
 1.0  2.0  3.0
119
 4.0  5.0  6.0
120
 7.0  8.0  9.0
121

122
julia> UnitLowerTriangular(A)
123
3×3 UnitLowerTriangular{Float64, Matrix{Float64}}:
124
 1.0   ⋅    ⋅
125
 4.0  1.0   ⋅
126
 7.0  8.0  1.0
127
```
128
"""
129
UnitLowerTriangular
130
"""
131
    UnitUpperTriangular(A::AbstractMatrix)
132

133
Construct an `UnitUpperTriangular` view of the matrix `A`.
134
Such a view has the [`oneunit`](@ref) of the [`eltype`](@ref)
135
of `A` on its diagonal.
136

137
# Examples
138
```jldoctest
139
julia> A = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]
140
3×3 Matrix{Float64}:
141
 1.0  2.0  3.0
142
 4.0  5.0  6.0
143
 7.0  8.0  9.0
144

145
julia> UnitUpperTriangular(A)
146
3×3 UnitUpperTriangular{Float64, Matrix{Float64}}:
147
 1.0  2.0  3.0
148
  ⋅   1.0  6.0
149
  ⋅    ⋅   1.0
150
```
151
"""
152
UnitUpperTriangular
153

154
const UpperOrUnitUpperTriangular{T,S} = Union{UpperTriangular{T,S}, UnitUpperTriangular{T,S}}
155
const LowerOrUnitLowerTriangular{T,S} = Union{LowerTriangular{T,S}, UnitLowerTriangular{T,S}}
156
const UpperOrLowerTriangular{T,S} = Union{UpperOrUnitUpperTriangular{T,S}, LowerOrUnitLowerTriangular{T,S}}
157

158
imag(A::UpperTriangular) = UpperTriangular(imag(A.data))
7✔
159
imag(A::LowerTriangular) = LowerTriangular(imag(A.data))
7✔
160
imag(A::UnitLowerTriangular) = LowerTriangular(tril!(imag(A.data),-1))
7✔
161
imag(A::UnitUpperTriangular) = UpperTriangular(triu!(imag(A.data),1))
7✔
162

163
Array(A::AbstractTriangular) = Matrix(A)
494✔
164
parent(A::UpperOrLowerTriangular) = A.data
57,561✔
165

166
# then handle all methods that requires specific handling of upper/lower and unit diagonal
167

168
function Matrix{T}(A::LowerTriangular) where T
8,239✔
169
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
8,239✔
170
    copyto!(B, A.data)
8,512✔
171
    tril!(B)
8,239✔
172
    B
8,239✔
173
end
174
function Matrix{T}(A::UnitLowerTriangular) where T
7,335✔
175
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
7,335✔
176
    copyto!(B, A.data)
7,348✔
177
    tril!(B)
7,335✔
178
    for i = 1:size(B,1)
14,670✔
179
        B[i,i] = 1
65,530✔
180
    end
123,725✔
181
    B
7,335✔
182
end
183
function Matrix{T}(A::UpperTriangular) where T
8,310✔
184
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
8,310✔
185
    copyto!(B, A.data)
8,588✔
186
    triu!(B)
8,310✔
187
    B
8,310✔
188
end
189
function Matrix{T}(A::UnitUpperTriangular) where T
7,485✔
190
    B = Matrix{T}(undef, size(A, 1), size(A, 1))
7,485✔
191
    copyto!(B, A.data)
7,498✔
192
    triu!(B)
7,485✔
193
    for i = 1:size(B,1)
14,964✔
194
        B[i,i] = 1
66,088✔
195
    end
124,697✔
196
    B
7,485✔
197
end
198

199
function full!(A::LowerTriangular)
35✔
200
    B = A.data
35✔
201
    tril!(B)
35✔
202
    B
35✔
203
end
204
function full!(A::UnitLowerTriangular)
35✔
205
    B = A.data
35✔
206
    tril!(B)
35✔
207
    for i = 1:size(A,1)
70✔
208
        B[i,i] = 1
315✔
209
    end
595✔
210
    B
35✔
211
end
212
function full!(A::UpperTriangular)
35✔
213
    B = A.data
35✔
214
    triu!(B)
35✔
215
    B
35✔
216
end
217
function full!(A::UnitUpperTriangular)
35✔
218
    B = A.data
35✔
219
    triu!(B)
35✔
220
    for i = 1:size(A,1)
70✔
221
        B[i,i] = 1
315✔
222
    end
595✔
223
    B
35✔
224
end
225

226
getindex(A::UnitLowerTriangular{T}, i::Integer, j::Integer) where {T} =
771,520✔
227
    i > j ? A.data[i,j] : ifelse(i == j, oneunit(T), zero(T))
228
getindex(A::LowerTriangular, i::Integer, j::Integer) =
1,456,251✔
229
    i >= j ? A.data[i,j] : zero(A.data[j,i])
230
getindex(A::UnitUpperTriangular{T}, i::Integer, j::Integer) where {T} =
789,979✔
231
    i < j ? A.data[i,j] : ifelse(i == j, oneunit(T), zero(T))
232
getindex(A::UpperTriangular, i::Integer, j::Integer) =
2,098,244✔
233
    i <= j ? A.data[i,j] : zero(A.data[j,i])
234

235
function setindex!(A::UpperTriangular, x, i::Integer, j::Integer)
55,409✔
236
    if i > j
55,409✔
237
        x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " *
1,066✔
238
            "($i, $j) of an UpperTriangular matrix to a nonzero value ($x)"))
239
    else
240
        A.data[i,j] = x
54,598✔
241
    end
242
    return A
55,154✔
243
end
244

245
function setindex!(A::UnitUpperTriangular, x, i::Integer, j::Integer)
2,867✔
246
    if i > j
2,867✔
247
        x == 0 || throw(ArgumentError("cannot set index in the lower triangular part " *
1,210✔
248
            "($i, $j) of a UnitUpperTriangular matrix to a nonzero value ($x)"))
249
    elseif i == j
1,909✔
250
        x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " *
251✔
251
            "of a UnitUpperTriangular matrix to a non-unit value ($x)"))
252
    else
253
        A.data[i,j] = x
1,658✔
254
    end
255
    return A
2,552✔
256
end
257

258
function setindex!(A::LowerTriangular, x, i::Integer, j::Integer)
5,063✔
259
    if i < j
5,063✔
260
        x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " *
1,064✔
261
            "($i, $j) of a LowerTriangular matrix to a nonzero value ($x)"))
262
    else
263
        A.data[i,j] = x
4,253✔
264
    end
265
    return A
4,809✔
266
end
267

268
function setindex!(A::UnitLowerTriangular, x, i::Integer, j::Integer)
2,867✔
269
    if i < j
2,867✔
270
        x == 0 || throw(ArgumentError("cannot set index in the upper triangular part " *
1,210✔
271
            "($i, $j) of a UnitLowerTriangular matrix to a nonzero value ($x)"))
272
    elseif i == j
1,909✔
273
        x == 1 || throw(ArgumentError("cannot set index on the diagonal ($i, $j) " *
251✔
274
            "of a UnitLowerTriangular matrix to a non-unit value ($x)"))
275
    else
276
        A.data[i,j] = x
1,658✔
277
    end
278
    return A
2,552✔
279
end
280

281

282
## structured matrix methods ##
283
function Base.replace_in_print_matrix(A::Union{UpperTriangular,UnitUpperTriangular},
21,362✔
284
                                      i::Integer, j::Integer, s::AbstractString)
285
    return i <= j ? s : Base.replace_with_centered_mark(s)
21,362✔
286
end
287
function Base.replace_in_print_matrix(A::Union{LowerTriangular,UnitLowerTriangular},
20,084✔
288
                                      i::Integer, j::Integer, s::AbstractString)
289
    return i >= j ? s : Base.replace_with_centered_mark(s)
20,084✔
290
end
291

292
function istril(A::Union{LowerTriangular,UnitLowerTriangular}, k::Integer=0)
102✔
293
    k >= 0 && return true
102✔
294
    return _istril(A, k)
×
295
end
296
function istriu(A::Union{UpperTriangular,UnitUpperTriangular}, k::Integer=0)
948✔
297
    k <= 0 && return true
948✔
298
    return _istriu(A, k)
×
299
end
300
istril(A::Adjoint, k::Integer=0) = istriu(A.parent, -k)
5,878✔
301
istril(A::Transpose, k::Integer=0) = istriu(A.parent, -k)
1,449✔
302
istriu(A::Adjoint, k::Integer=0) = istril(A.parent, -k)
5,889✔
303
istriu(A::Transpose, k::Integer=0) = istril(A.parent, -k)
1,449✔
304

305
function tril!(A::UpperTriangular, k::Integer=0)
35✔
306
    n = size(A,1)
35✔
307
    if k < 0
35✔
308
        fill!(A.data,0)
974✔
309
        return A
14✔
310
    elseif k == 0
21✔
311
        for j in 1:n, i in 1:j-1
63✔
312
            A.data[i,j] = 0
252✔
313
        end
308✔
314
        return A
7✔
315
    else
316
        return UpperTriangular(tril!(A.data,k))
14✔
317
    end
318
end
319
triu!(A::UpperTriangular, k::Integer=0) = UpperTriangular(triu!(A.data,k))
186✔
320

321
function tril!(A::UnitUpperTriangular{T}, k::Integer=0) where T
35✔
322
    n = size(A,1)
35✔
323
    if k < 0
35✔
324
        fill!(A.data, zero(T))
1,134✔
325
        return UpperTriangular(A.data)
14✔
326
    elseif k == 0
21✔
327
        fill!(A.data, zero(T))
567✔
328
        for i in diagind(A)
14✔
329
            A.data[i] = oneunit(T)
63✔
330
        end
119✔
331
        return UpperTriangular(A.data)
7✔
332
    else
333
        for i in diagind(A)
28✔
334
            A.data[i] = oneunit(T)
126✔
335
        end
238✔
336
        return UpperTriangular(tril!(A.data,k))
14✔
337
    end
338
end
339

340
function triu!(A::UnitUpperTriangular, k::Integer=0)
35✔
341
    for i in diagind(A)
70✔
342
        A.data[i] = oneunit(eltype(A))
315✔
343
    end
595✔
344
    return triu!(UpperTriangular(A.data),k)
35✔
345
end
346

347
function triu!(A::LowerTriangular, k::Integer=0)
35✔
348
    n = size(A,1)
35✔
349
    if k > 0
35✔
350
        fill!(A.data,0)
974✔
351
        return A
14✔
352
    elseif k == 0
21✔
353
        for j in 1:n, i in j+1:n
63✔
354
            A.data[i,j] = 0
252✔
355
        end
308✔
356
        return A
7✔
357
    else
358
        return LowerTriangular(triu!(A.data,k))
14✔
359
    end
360
end
361

362
tril!(A::LowerTriangular, k::Integer=0) = LowerTriangular(tril!(A.data,k))
70✔
363

364
function triu!(A::UnitLowerTriangular{T}, k::Integer=0) where T
35✔
365
    n = size(A,1)
35✔
366
    if k > 0
35✔
367
        fill!(A.data, zero(T))
1,134✔
368
        return LowerTriangular(A.data)
14✔
369
    elseif k == 0
21✔
370
        fill!(A.data, zero(T))
567✔
371
        for i in diagind(A)
14✔
372
            A.data[i] = oneunit(T)
63✔
373
        end
119✔
374
        return LowerTriangular(A.data)
7✔
375
    else
376
        for i in diagind(A)
28✔
377
            A.data[i] = oneunit(T)
126✔
378
        end
238✔
379
        return LowerTriangular(triu!(A.data,k))
14✔
380
    end
381
end
382

383
function tril!(A::UnitLowerTriangular, k::Integer=0)
35✔
384
    for i in diagind(A)
70✔
385
        A.data[i] = oneunit(eltype(A))
315✔
386
    end
595✔
387
    return tril!(LowerTriangular(A.data),k)
35✔
388
end
389

390
adjoint(A::LowerTriangular) = UpperTriangular(adjoint(A.data))
4,012✔
391
adjoint(A::UpperTriangular) = LowerTriangular(adjoint(A.data))
4,581✔
392
adjoint(A::UnitLowerTriangular) = UnitUpperTriangular(adjoint(A.data))
4,015✔
393
adjoint(A::UnitUpperTriangular) = UnitLowerTriangular(adjoint(A.data))
3,915✔
394
transpose(A::LowerTriangular) = UpperTriangular(transpose(A.data))
3,890✔
395
transpose(A::UpperTriangular) = LowerTriangular(transpose(A.data))
4,127✔
396
transpose(A::UnitLowerTriangular) = UnitUpperTriangular(transpose(A.data))
4,226✔
397
transpose(A::UnitUpperTriangular) = UnitLowerTriangular(transpose(A.data))
3,911✔
398

399
transpose!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L', false, true))
21✔
400
transpose!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L', false, true))
21✔
401
transpose!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U', false, true))
21✔
402
transpose!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U', false, true))
21✔
403
adjoint!(A::LowerTriangular) = UpperTriangular(copytri!(A.data, 'L' , true, true))
21✔
404
adjoint!(A::UnitLowerTriangular) = UnitUpperTriangular(copytri!(A.data, 'L' , true, true))
21✔
405
adjoint!(A::UpperTriangular) = LowerTriangular(copytri!(A.data, 'U' , true, true))
21✔
406
adjoint!(A::UnitUpperTriangular) = UnitLowerTriangular(copytri!(A.data, 'U' , true, true))
21✔
407

408
diag(A::LowerTriangular) = diag(A.data)
34✔
409
diag(A::UnitLowerTriangular) = fill(one(eltype(A)), size(A,1))
159✔
410
diag(A::UpperTriangular) = diag(A.data)
164✔
411
diag(A::UnitUpperTriangular) = fill(one(eltype(A)), size(A,1))
321✔
412

413
# Unary operations
414
-(A::LowerTriangular) = LowerTriangular(-A.data)
9✔
415
-(A::UpperTriangular) = UpperTriangular(-A.data)
162✔
416
function -(A::UnitLowerTriangular)
9✔
417
    Anew = -A.data
9✔
418
    for i = 1:size(A, 1)
18✔
419
        Anew[i, i] = -1
69✔
420
    end
129✔
421
    LowerTriangular(Anew)
9✔
422
end
423
function -(A::UnitUpperTriangular)
9✔
424
    Anew = -A.data
9✔
425
    for i = 1:size(A, 1)
18✔
426
        Anew[i, i] = -1
69✔
427
    end
129✔
428
    UpperTriangular(Anew)
9✔
429
end
430

431
tr(A::LowerTriangular) = tr(A.data)
7✔
432
tr(A::UnitLowerTriangular) = size(A, 1) * oneunit(eltype(A))
7✔
433
tr(A::UpperTriangular) = tr(A.data)
7✔
434
tr(A::UnitUpperTriangular) = size(A, 1) * oneunit(eltype(A))
7✔
435

436
# copy and scale
437
function copyto!(A::T, B::T) where T<:Union{UpperTriangular,UnitUpperTriangular}
1,641✔
438
    n = size(B,1)
1,641✔
439
    for j = 1:n
3,282✔
440
        for i = 1:(isa(B, UnitUpperTriangular) ? j-1 : j)
14,534✔
441
            @inbounds A[i,j] = B[i,j]
25,692✔
442
        end
44,131✔
443
    end
12,921✔
444
    return A
1,641✔
445
end
446
function copyto!(A::T, B::T) where T<:Union{LowerTriangular,UnitLowerTriangular}
56✔
447
    n = size(B,1)
56✔
448
    for j = 1:n
112✔
449
        for i = (isa(B, UnitLowerTriangular) ? j+1 : j):n
952✔
450
            @inbounds A[i,j] = B[i,j]
2,149✔
451
        end
3,836✔
452
    end
924✔
453
    return A
56✔
454
end
455

456
# Define `mul!` for (Unit){Upper,Lower}Triangular matrices times a
457
# number.
458
for (Trig, UnitTrig) in Any[(UpperTriangular, UnitUpperTriangular),
459
                            (LowerTriangular, UnitLowerTriangular)]
460
    for (TB, TC) in Any[(Trig, Number),
461
                        (Number, Trig),
462
                        (UnitTrig, Number),
463
                        (Number, UnitTrig)]
464
        @eval @inline mul!(A::$Trig, B::$TB, C::$TC, alpha::Number, beta::Number) =
3,219✔
465
            _mul!(A, B, C, MulAddMul(alpha, beta))
466
    end
467
end
468

469
@inline function _mul!(A::UpperTriangular, B::UpperTriangular, c::Number, _add::MulAddMul)
696✔
470
    n = checksquare(B)
696✔
471
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
696✔
472
    for j = 1:n
1,392✔
473
        for i = 1:j
5,064✔
474
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
6,952✔
475
        end
11,372✔
476
    end
4,368✔
477
    return A
696✔
478
end
479
@inline function _mul!(A::UpperTriangular, c::Number, B::UpperTriangular, _add::MulAddMul)
15✔
480
    n = checksquare(B)
15✔
481
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
15✔
482
    for j = 1:n
30✔
483
        for i = 1:j
286✔
484
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
755✔
485
        end
1,367✔
486
    end
271✔
487
    return A
15✔
488
end
489
@inline function _mul!(A::UpperTriangular, B::UnitUpperTriangular, c::Number, _add::MulAddMul)
7✔
490
    n = checksquare(B)
7✔
491
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
492
    for j = 1:n
14✔
493
        @inbounds _modify!(_add, c, A, (j,j))
63✔
494
        for i = 1:(j - 1)
119✔
495
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
252✔
496
        end
448✔
497
    end
119✔
498
    return A
7✔
499
end
500
@inline function _mul!(A::UpperTriangular, c::Number, B::UnitUpperTriangular, _add::MulAddMul)
7✔
501
    n = checksquare(B)
7✔
502
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
503
    for j = 1:n
14✔
504
        @inbounds _modify!(_add, c, A, (j,j))
63✔
505
        for i = 1:(j - 1)
119✔
506
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
252✔
507
        end
448✔
508
    end
119✔
509
    return A
7✔
510
end
511
@inline function _mul!(A::LowerTriangular, B::LowerTriangular, c::Number, _add::MulAddMul)
17✔
512
    n = checksquare(B)
17✔
513
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
17✔
514
    for j = 1:n
34✔
515
        for i = j:n
298✔
516
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
767✔
517
        end
1,385✔
518
    end
281✔
519
    return A
17✔
520
end
521
@inline function _mul!(A::LowerTriangular, c::Number, B::LowerTriangular, _add::MulAddMul)
15✔
522
    n = checksquare(B)
15✔
523
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
15✔
524
    for j = 1:n
30✔
525
        for i = j:n
286✔
526
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
755✔
527
        end
1,367✔
528
    end
271✔
529
    return A
15✔
530
end
531
@inline function _mul!(A::LowerTriangular, B::UnitLowerTriangular, c::Number, _add::MulAddMul)
7✔
532
    n = checksquare(B)
7✔
533
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
534
    for j = 1:n
14✔
535
        @inbounds _modify!(_add, c, A, (j,j))
63✔
536
        for i = (j + 1):n
119✔
537
            @inbounds _modify!(_add, B[i,j] * c, A, (i,j))
252✔
538
        end
448✔
539
    end
119✔
540
    return A
7✔
541
end
542
@inline function _mul!(A::LowerTriangular, c::Number, B::UnitLowerTriangular, _add::MulAddMul)
7✔
543
    n = checksquare(B)
7✔
544
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
7✔
545
    for j = 1:n
14✔
546
        @inbounds _modify!(_add, c, A, (j,j))
63✔
547
        for i = (j + 1):n
119✔
548
            @inbounds _modify!(_add, c * B[i,j], A, (i,j))
252✔
549
        end
448✔
550
    end
119✔
551
    return A
7✔
552
end
553

554
rmul!(A::Union{UpperTriangular,LowerTriangular}, c::Number) = mul!(A, A, c)
159✔
555
lmul!(c::Number, A::Union{UpperTriangular,LowerTriangular}) = mul!(A, c, A)
30✔
556

557
function dot(x::AbstractVector, A::UpperTriangular, y::AbstractVector)
42✔
558
    require_one_based_indexing(x, y)
42✔
559
    m = size(A, 1)
42✔
560
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
561
    if iszero(m)
42✔
562
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
563
    end
564
    x₁ = x[1]
42✔
565
    r = dot(x₁, A[1,1], y[1])
42✔
566
    @inbounds for j in 2:m
84✔
567
        yj = y[j]
336✔
568
        if !iszero(yj)
336✔
569
            temp = adjoint(A[1,j]) * x₁
336✔
570
            @simd for i in 2:j
336✔
571
                temp += adjoint(A[i,j]) * x[i]
1,512✔
572
            end
×
573
            r += dot(temp, yj)
336✔
574
        end
575
    end
630✔
576
    return r
42✔
577
end
578
function dot(x::AbstractVector, A::UnitUpperTriangular, y::AbstractVector)
42✔
579
    require_one_based_indexing(x, y)
42✔
580
    m = size(A, 1)
42✔
581
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
582
    if iszero(m)
42✔
583
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
584
    end
585
    x₁ = first(x)
42✔
586
    r = dot(x₁, y[1])
42✔
587
    @inbounds for j in 2:m
84✔
588
        yj = y[j]
336✔
589
        if !iszero(yj)
336✔
590
            temp = adjoint(A[1,j]) * x₁
336✔
591
            @simd for i in 2:j-1
378✔
592
                temp += adjoint(A[i,j]) * x[i]
1,176✔
593
            end
×
594
            r += dot(temp, yj)
420✔
595
            r += dot(x[j], yj)
336✔
596
        end
597
    end
630✔
598
    return r
42✔
599
end
600
function dot(x::AbstractVector, A::LowerTriangular, y::AbstractVector)
42✔
601
    require_one_based_indexing(x, y)
42✔
602
    m = size(A, 1)
42✔
603
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
604
    if iszero(m)
42✔
605
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
606
    end
607
    r = zero(typeof(dot(first(x), first(A), first(y))))
42✔
608
    @inbounds for j in 1:m
84✔
609
        yj = y[j]
378✔
610
        if !iszero(yj)
378✔
611
            temp = adjoint(A[j,j]) * x[j]
378✔
612
            @simd for i in j+1:m
420✔
613
                temp += adjoint(A[i,j]) * x[i]
1,512✔
614
            end
×
615
            r += dot(temp, yj)
378✔
616
        end
617
    end
714✔
618
    return r
42✔
619
end
620
function dot(x::AbstractVector, A::UnitLowerTriangular, y::AbstractVector)
42✔
621
    require_one_based_indexing(x, y)
42✔
622
    m = size(A, 1)
42✔
623
    (length(x) == m == length(y)) || throw(DimensionMismatch())
42✔
624
    if iszero(m)
42✔
625
        return dot(zero(eltype(x)), zero(eltype(A)), zero(eltype(y)))
×
626
    end
627
    r = zero(typeof(dot(first(x), first(y))))
42✔
628
    @inbounds for j in 1:m
84✔
629
        yj = y[j]
378✔
630
        if !iszero(yj)
378✔
631
            temp = x[j]
378✔
632
            @simd for i in j+1:m
420✔
633
                temp += adjoint(A[i,j]) * x[i]
1,876✔
634
            end
×
635
            r += dot(temp, yj)
491✔
636
        end
637
    end
714✔
638
    return r
42✔
639
end
640

641
fillstored!(A::LowerTriangular, x)     = (fillband!(A.data, x, 1-size(A,1), 0); A)
2✔
642
fillstored!(A::UnitLowerTriangular, x) = (fillband!(A.data, x, 1-size(A,1), -1); A)
2✔
643
fillstored!(A::UpperTriangular, x)     = (fillband!(A.data, x, 0, size(A,2)-1); A)
2✔
644
fillstored!(A::UnitUpperTriangular, x) = (fillband!(A.data, x, 1, size(A,2)-1); A)
×
645

646
# Binary operations
647
+(A::UpperTriangular, B::UpperTriangular) = UpperTriangular(A.data + B.data)
171✔
648
+(A::LowerTriangular, B::LowerTriangular) = LowerTriangular(A.data + B.data)
63✔
649
+(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(A.data + triu(B.data, 1) + I)
50✔
650
+(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(A.data + tril(B.data, -1) + I)
50✔
651
+(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(triu(A.data, 1) + B.data + I)
50✔
652
+(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(tril(A.data, -1) + B.data + I)
49✔
653
+(A::UnitUpperTriangular, B::UnitUpperTriangular) = UpperTriangular(triu(A.data, 1) + triu(B.data, 1) + 2I)
49✔
654
+(A::UnitLowerTriangular, B::UnitLowerTriangular) = LowerTriangular(tril(A.data, -1) + tril(B.data, -1) + 2I)
49✔
655
+(A::AbstractTriangular, B::AbstractTriangular) = copyto!(similar(parent(A)), A) + copyto!(similar(parent(B)), B)
406✔
656

657
-(A::UpperTriangular, B::UpperTriangular) = UpperTriangular(A.data - B.data)
253✔
658
-(A::LowerTriangular, B::LowerTriangular) = LowerTriangular(A.data - B.data)
244✔
659
-(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(A.data - triu(B.data, 1) - I)
50✔
660
-(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(A.data - tril(B.data, -1) - I)
49✔
661
-(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(triu(A.data, 1) - B.data + I)
50✔
662
-(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(tril(A.data, -1) - B.data + I)
49✔
663
-(A::UnitUpperTriangular, B::UnitUpperTriangular) = UpperTriangular(triu(A.data, 1) - triu(B.data, 1))
57✔
664
-(A::UnitLowerTriangular, B::UnitLowerTriangular) = LowerTriangular(tril(A.data, -1) - tril(B.data, -1))
56✔
665
-(A::AbstractTriangular, B::AbstractTriangular) = copyto!(similar(parent(A)), A) - copyto!(similar(parent(B)), B)
396✔
666

667
######################
668
# BlasFloat routines #
669
######################
670

671
lmul!(A::Tridiagonal, B::AbstractTriangular) = A*full!(B) # is this necessary?
112✔
672

673
mul!(C::AbstractMatrix, A::AbstractTriangular, B::AbstractVecOrMat) =
986✔
674
    lmul!(A, inplace_adj_or_trans(B)(C, _parent(B)))
675
@inline mul!(C::AbstractMatrix, A::AbstractTriangular, B::AdjOrTrans{<:Any,<:AbstractVecOrMat}, alpha::Number, beta::Number) =
×
676
    mul!(C, A, copy(B), alpha, beta)
677

678
# preserve triangular structure in in-place multiplication
679
for (cty, aty, bty) in ((:UpperTriangular, :UpperTriangular, :UpperTriangular),
680
                        (:UpperTriangular, :UpperTriangular, :UnitUpperTriangular),
681
                        (:UpperTriangular, :UnitUpperTriangular, :UpperTriangular),
682
                        (:UnitUpperTriangular, :UnitUpperTriangular, :UnitUpperTriangular),
683
                        (:LowerTriangular, :LowerTriangular, :LowerTriangular),
684
                        (:LowerTriangular, :LowerTriangular, :UnitLowerTriangular),
685
                        (:LowerTriangular, :UnitLowerTriangular, :LowerTriangular),
686
                        (:UnitLowerTriangular, :UnitLowerTriangular, :UnitLowerTriangular))
687
    @eval function mul!(C::$cty, A::$aty, B::$bty)
1,327✔
688
        lmul!(A, copyto!(parent(C), B))
2,654✔
689
        return C
1,327✔
690
    end
691

692
    @eval @inline function mul!(C::$cty, A::$aty, B::$bty, alpha::Number, beta::Number)
151✔
693
        if isone(alpha) && iszero(beta)
151✔
694
            return mul!(C, A, B)
56✔
695
        else
696
            return generic_matmatmul!(C, 'N', 'N', A, B, MulAddMul(alpha, beta))
95✔
697
        end
698
    end
699
end
700

701
# direct multiplication/division
702
for (t, uploc, isunitc) in ((:LowerTriangular, 'L', 'N'),
703
                            (:UnitLowerTriangular, 'L', 'U'),
704
                            (:UpperTriangular, 'U', 'N'),
705
                            (:UnitUpperTriangular, 'U', 'U'))
706
    @eval begin
707
        # Vector multiplication
708
        lmul!(A::$t{T,<:StridedMatrix}, b::StridedVector{T}) where {T<:BlasFloat} =
812✔
709
            BLAS.trmv!($uploc, 'N', $isunitc, A.data, b)
710

711
        # Matrix multiplication
712
        lmul!(A::$t{T,<:StridedMatrix}, B::StridedMatrix{T}) where {T<:BlasFloat} =
8,232✔
713
            BLAS.trmm!('L', $uploc, 'N', $isunitc, one(T), A.data, B)
714
        rmul!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} =
2,102✔
715
            BLAS.trmm!('R', $uploc, 'N', $isunitc, one(T), B.data, A)
716

717
        # Left division
718
        ldiv!(A::$t{T,<:StridedMatrix}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
6,943✔
719
            LAPACK.trtrs!($uploc, 'N', $isunitc, A.data, B)
720

721
        # Right division
722
        rdiv!(A::StridedMatrix{T}, B::$t{T,<:StridedMatrix}) where {T<:BlasFloat} =
4,181✔
723
            BLAS.trsm!('R', $uploc, 'N', $isunitc, one(T), B.data, A)
724

725
        # Matrix inverse
726
        inv!(A::$t{T,S}) where {T<:BlasFloat,S<:StridedMatrix} =
16✔
727
            $t{T,S}(LAPACK.trtri!($uploc, $isunitc, A.data))
728

729
        # Error bounds for triangular solve
730
        errorbounds(A::$t{T,<:StridedMatrix}, X::StridedVecOrMat{T}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
160✔
731
            LAPACK.trrfs!($uploc, 'N', $isunitc, A.data, B, X)
732

733
        # Condition numbers
734
        function cond(A::$t{<:BlasFloat,<:StridedMatrix}, p::Real=2)
144✔
735
            checksquare(A)
144✔
736
            if p == 1
144✔
737
                return inv(LAPACK.trcon!('O', $uploc, $isunitc, A.data))
64✔
738
            elseif p == Inf
80✔
739
                return inv(LAPACK.trcon!('I', $uploc, $isunitc, A.data))
64✔
740
            else # use fallback
741
                return cond(copyto!(similar(parent(A)), A), p)
16✔
742
            end
743
        end
744
    end
745
end
746

747
# adjoint/transpose multiplication ('uploc' reversed)
748
for (t, uploc, isunitc) in ((:LowerTriangular, 'U', 'N'),
749
                            (:UnitLowerTriangular, 'U', 'U'),
750
                            (:UpperTriangular, 'L', 'N'),
751
                            (:UnitUpperTriangular, 'L', 'U'))
752
    @eval begin
753
        # Vector multiplication
754
        lmul!(A::$t{<:Any,<:Transpose{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasFloat} =
96✔
755
            BLAS.trmv!($uploc, 'T', $isunitc, parent(parent(A)), b)
756
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasReal} =
52✔
757
            BLAS.trmv!($uploc, 'T', $isunitc, parent(parent(A)), b)
758
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, b::StridedVector{T}) where {T<:BlasComplex} =
80✔
759
            BLAS.trmv!($uploc, 'C', $isunitc, parent(parent(A)), b)
760

761
        # Matrix multiplication
762
        lmul!(A::$t{<:Any,<:Transpose{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasFloat} =
1,072✔
763
            BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), parent(parent(A)), B)
764
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasComplex} =
667✔
765
            BLAS.trmm!('L', $uploc, 'C', $isunitc, one(T), parent(parent(A)), B)
766
        lmul!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedMatrix{T}) where {T<:BlasReal} =
451✔
767
            BLAS.trmm!('L', $uploc, 'T', $isunitc, one(T), parent(parent(A)), B)
768

769
        rmul!(A::StridedMatrix{T}, B::$t{<:Any,<:Transpose{T,<:StridedMatrix}}) where {T<:BlasFloat} =
444✔
770
            BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
771
        rmul!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasComplex} =
200✔
772
            BLAS.trmm!('R', $uploc, 'C', $isunitc, one(T), parent(parent(B)), A)
773
        rmul!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasReal} =
217✔
774
            BLAS.trmm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
775

776
        # Left division
777
        ldiv!(A::$t{<:Any,<:Transpose{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasFloat} =
900✔
778
            LAPACK.trtrs!($uploc, 'T', $isunitc, parent(parent(A)), B)
779
        ldiv!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasReal} =
838✔
780
            LAPACK.trtrs!($uploc, 'T', $isunitc, parent(parent(A)), B)
781
        ldiv!(A::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}, B::StridedVecOrMat{T}) where {T<:BlasComplex} =
789✔
782
            LAPACK.trtrs!($uploc, 'C', $isunitc, parent(parent(A)), B)
783

784
        # Right division
785
        rdiv!(A::StridedMatrix{T}, B::$t{<:Any,<:Transpose{T,<:StridedMatrix}}) where {T<:BlasFloat} =
328✔
786
            BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
787
        rdiv!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasReal} =
152✔
788
            BLAS.trsm!('R', $uploc, 'T', $isunitc, one(T), parent(parent(B)), A)
789
        rdiv!(A::StridedMatrix{T}, B::$t{<:Any,<:Adjoint{T,<:StridedMatrix}}) where {T<:BlasComplex} =
176✔
790
            BLAS.trsm!('R', $uploc, 'C', $isunitc, one(T), parent(parent(B)), A)
791
    end
792
end
793

794
function inv(A::LowerTriangular{T}) where T
61✔
795
    S = typeof((zero(T)*one(T) + zero(T))/one(T))
61✔
796
    LowerTriangular(ldiv!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1))))
61✔
797
end
798
function inv(A::UpperTriangular{T}) where T
334✔
799
    S = typeof((zero(T)*one(T) + zero(T))/one(T))
334✔
800
    UpperTriangular(ldiv!(convert(AbstractArray{S}, A), Matrix{S}(I, size(A, 1), size(A, 1))))
334✔
801
end
802
inv(A::UnitUpperTriangular{T}) where {T} = UnitUpperTriangular(ldiv!(A, Matrix{T}(I, size(A, 1), size(A, 1))))
19✔
803
inv(A::UnitLowerTriangular{T}) where {T} = UnitLowerTriangular(ldiv!(A, Matrix{T}(I, size(A, 1), size(A, 1))))
19✔
804

805
errorbounds(A::AbstractTriangular{T,<:AbstractMatrix}, X::AbstractVecOrMat{T}, B::AbstractVecOrMat{T}) where {T<:Union{BigFloat,Complex{BigFloat}}} =
×
806
    error("not implemented yet! Please submit a pull request.")
807
function errorbounds(A::AbstractTriangular{TA,<:AbstractMatrix}, X::AbstractVecOrMat{TX}, B::AbstractVecOrMat{TB}) where {TA<:Number,TX<:Number,TB<:Number}
128✔
808
    TAXB = promote_type(TA, TB, TX, Float32)
128✔
809
    errorbounds(convert(AbstractMatrix{TAXB}, A), convert(AbstractArray{TAXB}, X), convert(AbstractArray{TAXB}, B))
128✔
810
end
811

812
# Eigensystems
813
## Notice that trecv works for quasi-triangular matrices and therefore the lower sub diagonal must be zeroed before calling the subroutine
814
function eigvecs(A::UpperTriangular{<:BlasFloat,<:StridedMatrix})
5✔
815
    LAPACK.trevc!('R', 'A', BlasInt[], triu!(A.data))
5✔
816
end
817
function eigvecs(A::UnitUpperTriangular{<:BlasFloat,<:StridedMatrix})
5✔
818
    for i = 1:size(A, 1)
10✔
819
        A.data[i,i] = 1
45✔
820
    end
85✔
821
    LAPACK.trevc!('R', 'A', BlasInt[], triu!(A.data))
5✔
822
end
823
function eigvecs(A::LowerTriangular{<:BlasFloat,<:StridedMatrix})
5✔
824
    LAPACK.trevc!('L', 'A', BlasInt[], copy(tril!(A.data)'))
5✔
825
end
826
function eigvecs(A::UnitLowerTriangular{<:BlasFloat,<:StridedMatrix})
5✔
827
    for i = 1:size(A, 1)
10✔
828
        A.data[i,i] = 1
45✔
829
    end
85✔
830
    LAPACK.trevc!('L', 'A', BlasInt[], copy(tril!(A.data)'))
5✔
831
end
832

833
####################
834
# Generic routines #
835
####################
836

837
for (t, unitt) in ((UpperTriangular, UnitUpperTriangular),
838
                   (LowerTriangular, UnitLowerTriangular))
839
    @eval begin
840
        (*)(A::$t, x::Number) = $t(A.data*x)
36✔
841

842
        function (*)(A::$unitt, x::Number)
20✔
843
            B = A.data*x
20✔
844
            for i = 1:size(A, 1)
40✔
845
                B[i,i] = x
180✔
846
            end
340✔
847
            $t(B)
20✔
848
        end
849

850
        (*)(x::Number, A::$t) = $t(x*A.data)
505✔
851

852
        function (*)(x::Number, A::$unitt)
36✔
853
            B = x*A.data
36✔
854
            for i = 1:size(A, 1)
72✔
855
                B[i,i] = x
324✔
856
            end
612✔
857
            $t(B)
36✔
858
        end
859

860
        (/)(A::$t, x::Number) = $t(A.data/x)
58✔
861

862
        function (/)(A::$unitt, x::Number)
14✔
863
            B = A.data/x
14✔
864
            invx = inv(x)
14✔
865
            for i = 1:size(A, 1)
28✔
866
                B[i,i] = invx
126✔
867
            end
238✔
868
            $t(B)
14✔
869
        end
870

871
        (\)(x::Number, A::$t) = $t(x\A.data)
14✔
872

873
        function (\)(x::Number, A::$unitt)
14✔
874
            B = x\A.data
14✔
875
            invx = inv(x)
14✔
876
            for i = 1:size(A, 1)
28✔
877
                B[i,i] = invx
126✔
878
            end
238✔
879
            $t(B)
14✔
880
        end
881
    end
882
end
883

884
## Generic triangular multiplication
885
function lmul!(A::UpperTriangular, B::AbstractVecOrMat)
2,015✔
886
    require_one_based_indexing(A, B)
2,015✔
887
    m, n = size(B, 1), size(B, 2)
2,015✔
888
    if m != size(A, 1)
2,015✔
889
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
890
    end
891
    @inbounds for j = 1:n
3,466✔
892
        for i = 1:m
24,674✔
893
            Bij = A.data[i,i]*B[i,j]
110,323✔
894
            for k = i + 1:m
208,309✔
895
                Bij += A.data[i,k]*B[k,j]
441,054✔
896
            end
783,318✔
897
            B[i,j] = Bij
110,323✔
898
        end
208,309✔
899
    end
22,941✔
900
    B
1,733✔
901
end
902
function lmul!(A::UnitUpperTriangular, B::AbstractVecOrMat)
1,752✔
903
    require_one_based_indexing(A, B)
1,752✔
904
    m, n = size(B, 1), size(B, 2)
1,752✔
905
    if m != size(A, 1)
1,752✔
906
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
907
    end
908
    @inbounds for j = 1:n
2,940✔
909
        for i = 1:m
22,152✔
910
            Bij = B[i,j]
98,648✔
911
            for k = i + 1:m
186,220✔
912
                Bij += A.data[i,k]*B[k,j]
393,184✔
913
            end
698,796✔
914
            B[i,j] = Bij
98,648✔
915
        end
186,220✔
916
    end
20,682✔
917
    B
1,470✔
918
end
919
function lmul!(A::LowerTriangular, B::AbstractVecOrMat)
1,782✔
920
    require_one_based_indexing(A, B)
1,782✔
921
    m, n = size(B, 1), size(B, 2)
1,782✔
922
    if m != size(A, 1)
1,782✔
923
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
924
    end
925
    @inbounds for j = 1:n
3,000✔
926
        for i = m:-1:1
23,012✔
927
            Bij = A.data[i,i]*B[i,j]
102,560✔
928
            for k = 1:i - 1
193,614✔
929
                Bij += A.data[i,k]*B[k,j]
409,899✔
930
            end
727,892✔
931
            B[i,j] = Bij
102,560✔
932
        end
193,614✔
933
    end
21,512✔
934
    B
1,500✔
935
end
936
function lmul!(A::UnitLowerTriangular, B::AbstractVecOrMat)
1,700✔
937
    require_one_based_indexing(A, B)
1,700✔
938
    m, n = size(B, 1), size(B, 2)
1,700✔
939
    if m != size(A, 1)
1,700✔
940
        throw(DimensionMismatch("right hand side B needs first dimension of size $(size(A,1)), has size $m"))
282✔
941
    end
942
    @inbounds for j = 1:n
2,836✔
943
        for i = m:-1:1
22,048✔
944
            Bij = B[i,j]
98,596✔
945
            for k = 1:i - 1
186,168✔
946
                Bij += A.data[i,k]*B[k,j]
393,184✔
947
            end
698,796✔
948
            B[i,j] = Bij
98,596✔
949
        end
186,168✔
950
    end
20,630✔
951
    B
1,418✔
952
end
953

954
function rmul!(A::AbstractMatrix, B::UpperTriangular)
496✔
955
    require_one_based_indexing(A, B)
496✔
956
    m, n = size(A)
496✔
957
    if size(B, 1) != n
496✔
958
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
959
    end
960
    @inbounds for i = 1:m
428✔
961
        for j = n:-1:1
3,876✔
962
            Aij = A[i,j]*B.data[j,j]
17,562✔
963
            for k = 1:j - 1
33,186✔
964
                Aij += A[i,k]*B.data[k,j]
70,848✔
965
            end
126,072✔
966
            A[i,j] = Aij
17,562✔
967
        end
33,186✔
968
    end
3,662✔
969
    A
214✔
970
end
971
function rmul!(A::AbstractMatrix, B::UnitUpperTriangular)
488✔
972
    require_one_based_indexing(A, B)
488✔
973
    m, n = size(A)
488✔
974
    if size(B, 1) != n
488✔
975
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
976
    end
977
    @inbounds for i = 1:m
412✔
978
        for j = n:-1:1
3,716✔
979
            Aij = A[i,j]
16,762✔
980
            for k = 1:j - 1
31,666✔
981
                Aij += A[i,k]*B.data[k,j]
67,248✔
982
            end
119,592✔
983
            A[i,j] = Aij
16,762✔
984
        end
31,666✔
985
    end
3,510✔
986
    A
206✔
987
end
988

989
function rmul!(A::AbstractMatrix, B::LowerTriangular)
488✔
990
    require_one_based_indexing(A, B)
488✔
991
    m, n = size(A)
488✔
992
    if size(B, 1) != n
488✔
993
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
994
    end
995
    @inbounds for i = 1:m
412✔
996
        for j = 1:n
3,716✔
997
            Aij = A[i,j]*B.data[j,j]
16,762✔
998
            for k = j + 1:n
31,666✔
999
                Aij += A[i,k]*B.data[k,j]
67,248✔
1000
            end
119,592✔
1001
            A[i,j] = Aij
16,762✔
1002
        end
31,666✔
1003
    end
3,510✔
1004
    A
206✔
1005
end
1006
function rmul!(A::AbstractMatrix, B::UnitLowerTriangular)
488✔
1007
    require_one_based_indexing(A, B)
488✔
1008
    m, n = size(A)
488✔
1009
    if size(B, 1) != n
488✔
1010
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
282✔
1011
    end
1012
    @inbounds for i = 1:m
412✔
1013
        for j = 1:n
3,716✔
1014
            Aij = A[i,j]
16,762✔
1015
            for k = j + 1:n
31,666✔
1016
                Aij += A[i,k]*B.data[k,j]
67,248✔
1017
            end
119,592✔
1018
            A[i,j] = Aij
16,762✔
1019
        end
31,666✔
1020
    end
3,510✔
1021
    A
206✔
1022
end
1023

1024
#Generic solver using naive substitution
1025
# manually hoisting b[j] significantly improves performance as of Dec 2015
1026
# manually eliding bounds checking significantly improves performance as of Dec 2015
1027
# directly indexing A.data rather than A significantly improves performance as of Dec 2015
1028
# replacing repeated references to A.data with [Adata = A.data and references to Adata]
1029
# does not significantly impact performance as of Dec 2015
1030
# replacing repeated references to A.data[j,j] with [Ajj = A.data[j,j] and references to Ajj]
1031
# does not significantly impact performance as of Dec 2015
1032
function ldiv!(A::UpperTriangular, b::AbstractVector)
14,433✔
1033
    require_one_based_indexing(A, b)
14,433✔
1034
    n = size(A, 2)
14,433✔
1035
    if !(n == length(b))
14,433✔
1036
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
15✔
1037
    end
1038
    @inbounds for j in n:-1:1
28,836✔
1039
        iszero(A.data[j,j]) && throw(SingularException(j))
137,175✔
1040
        bj = b[j] = A.data[j,j] \ b[j]
136,636✔
1041
        for i in j-1:-1:1 # counterintuitively 1:j-1 performs slightly better
257,494✔
1042
            b[i] -= A.data[i,j] * bj
663,753✔
1043
        end
1,198,993✔
1044
    end
257,494✔
1045
    return b
14,380✔
1046
end
1047
function ldiv!(A::UnitUpperTriangular, b::AbstractVector)
3,470✔
1048
    require_one_based_indexing(A, b)
3,470✔
1049
    n = size(A, 2)
3,470✔
1050
    if !(n == length(b))
3,470✔
1051
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
21✔
1052
    end
1053
    @inbounds for j in n:-1:1
6,898✔
1054
        bj = b[j]
31,899✔
1055
        for i in j-1:-1:1 # counterintuitively 1:j-1 performs slightly better
59,989✔
1056
            b[i] -= A.data[i,j] * bj
134,462✔
1057
        end
232,456✔
1058
    end
59,989✔
1059
    return b
3,449✔
1060
end
1061
function ldiv!(A::LowerTriangular, b::AbstractVector)
10,809✔
1062
    require_one_based_indexing(A, b)
10,809✔
1063
    n = size(A, 2)
10,809✔
1064
    if !(n == length(b))
10,809✔
1065
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
15✔
1066
    end
1067
    @inbounds for j in 1:n
21,588✔
1068
        iszero(A.data[j,j]) && throw(SingularException(j))
98,880✔
1069
        bj = b[j] = A.data[j,j] \ b[j]
98,392✔
1070
        for i in j+1:n
184,528✔
1071
            b[i] -= A.data[i,j] * bj
398,723✔
1072
        end
703,332✔
1073
    end
184,528✔
1074
    return b
10,756✔
1075
end
1076
function ldiv!(A::UnitLowerTriangular, b::AbstractVector)
5,013✔
1077
    require_one_based_indexing(A, b)
5,013✔
1078
    n = size(A, 2)
5,013✔
1079
    if !(n == length(b))
5,013✔
1080
        throw(DimensionMismatch("second dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
21✔
1081
    end
1082
    @inbounds for j in 1:n
9,984✔
1083
        bj = b[j]
51,033✔
1084
        for i in j+1:n
96,594✔
1085
            b[i] -= A.data[i,j] * bj
319,908✔
1086
        end
585,497✔
1087
    end
96,594✔
1088
    return b
4,992✔
1089
end
1090
function ldiv!(A::AbstractTriangular, B::AbstractMatrix)
4,621✔
1091
    require_one_based_indexing(A, B)
4,621✔
1092
    nA, mA = size(A)
4,621✔
1093
    n = size(B, 1)
4,621✔
1094
    if nA != n
4,621✔
1095
        throw(DimensionMismatch("second dimension of left hand side A, $mA, and first dimension of right hand side B, $n, must be equal"))
×
1096
    end
1097
    for b in eachcol(B)
9,242✔
1098
        ldiv!(A, b)
39,052✔
1099
    end
73,483✔
1100
    B
4,621✔
1101
end
1102

1103
# in the following transpose and conjugate transpose naive substitution variants,
1104
# accumulating in z rather than b[j,k] significantly improves performance as of Dec 2015
1105
function ldiv!(xA::UpperTriangular{<:Any,<:AdjOrTrans}, b::AbstractVector)
3,905✔
1106
    require_one_based_indexing(xA, b)
3,905✔
1107
    tfun = adj_or_trans(parent(xA))
3,905✔
1108
    A = parent(parent(xA))
3,905✔
1109
    n = size(A, 1)
3,905✔
1110
    if !(n == length(b))
3,905✔
1111
        throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
24✔
1112
    end
1113
    @inbounds for j in n:-1:1
7,762✔
1114
        z = b[j]
36,282✔
1115
        for i in n:-1:j+1
67,527✔
1116
            z -= tfun(A[i,j]) * b[i]
153,120✔
1117
        end
261,659✔
1118
        iszero(A[j,j]) && throw(SingularException(j))
38,104✔
1119
        b[j] = tfun(A[j,j]) \ z
37,566✔
1120
    end
67,527✔
1121
    return b
3,881✔
1122
end
1123

1124
function ldiv!(xA::UnitUpperTriangular{<:Any,<:AdjOrTrans}, b::AbstractVector)
1,793✔
1125
    require_one_based_indexing(xA, b)
1,793✔
1126
    tfun = adj_or_trans(parent(xA))
1,793✔
1127
    A = parent(parent(xA))
1,793✔
1128
    n = size(A, 1)
1,793✔
1129
    if !(n == length(b))
1,793✔
1130
        throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
36✔
1131
    end
1132
    @inbounds for j in n:-1:1
3,514✔
1133
        z = b[j]
17,688✔
1134
        for i in n:-1:j+1
32,259✔
1135
            z -= tfun(A[i,j]) * b[i]
83,115✔
1136
        end
132,911✔
1137
        b[j] = z
18,030✔
1138
    end
32,259✔
1139
    return b
1,757✔
1140
end
1141

1142
function ldiv!(xA::LowerTriangular{<:Any,<:AdjOrTrans}, b::AbstractVector)
5,012✔
1143
    require_one_based_indexing(xA, b)
5,012✔
1144
    tfun = adj_or_trans(parent(xA))
5,012✔
1145
    A = parent(parent(xA))
5,012✔
1146
    n = size(A, 1)
5,012✔
1147
    if !(n == length(b))
5,012✔
1148
        throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
24✔
1149
    end
1150
    @inbounds for j in 1:n
9,976✔
1151
        z = b[j]
47,302✔
1152
        for i in 1:j-1
88,460✔
1153
            z -= tfun(A[i,j]) * b[i]
204,082✔
1154
        end
350,676✔
1155
        iszero(A[j,j]) && throw(SingularException(j))
49,124✔
1156
        b[j] = tfun(A[j,j]) \ z
48,622✔
1157
    end
88,460✔
1158
    return b
4,988✔
1159
end
1160

1161
function ldiv!(xA::UnitLowerTriangular{<:Any,<:AdjOrTrans}, b::AbstractVector)
1,194✔
1162
    require_one_based_indexing(xA, b)
1,194✔
1163
    tfun = adj_or_trans(parent(xA))
1,194✔
1164
    A = parent(parent(xA))
1,194✔
1165
    n = size(A, 1)
1,194✔
1166
    if !(n == length(b))
1,194✔
1167
        throw(DimensionMismatch("first dimension of left hand side A, $n, and length of right hand side b, $(length(b)), must be equal"))
36✔
1168
    end
1169
    @inbounds for j in 1:n
2,316✔
1170
        z = b[j]
11,624✔
1171
        for i in 1:j-1
20,730✔
1172
            z -= tfun(A[i,j]) * b[i]
54,358✔
1173
        end
83,430✔
1174
        b[j] = z
11,930✔
1175
    end
20,730✔
1176
    return b
1,158✔
1177
end
1178

1179
function rdiv!(A::AbstractMatrix, B::UpperTriangular)
542✔
1180
    require_one_based_indexing(A, B)
542✔
1181
    m, n = size(A)
542✔
1182
    if size(B, 1) != n
542✔
1183
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1184
    end
1185
    @inbounds for i = 1:m
742✔
1186
        for j = 1:n
6,786✔
1187
            Aij = A[i,j]
31,097✔
1188
            for k = 1:j - 1
58,801✔
1189
                Aij -= A[i,k]*B.data[k,j]
127,288✔
1190
            end
226,772✔
1191
            iszero(B.data[j,j]) && throw(SingularException(j))
31,097✔
1192
            A[i,j] = Aij/B.data[j,j]
31,097✔
1193
        end
58,801✔
1194
    end
6,415✔
1195
    A
371✔
1196
end
1197
function rdiv!(A::AbstractMatrix, B::UnitUpperTriangular)
502✔
1198
    require_one_based_indexing(B)
502✔
1199
    m, n = size(A)
502✔
1200
    if size(B, 1) != n
502✔
1201
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1202
    end
1203
    @inbounds for i = 1:m
662✔
1204
        for j = 1:n
5,986✔
1205
            Aij = A[i,j]
27,077✔
1206
            for k = 1:j - 1
51,161✔
1207
                Aij -= A[i,k]*B.data[k,j]
109,008✔
1208
            end
193,932✔
1209
            A[i,j] = Aij
27,077✔
1210
        end
51,161✔
1211
    end
5,655✔
1212
    A
331✔
1213
end
1214
function rdiv!(A::AbstractMatrix, B::LowerTriangular)
542✔
1215
    require_one_based_indexing(A, B)
542✔
1216
    m, n = size(A)
542✔
1217
    if size(B, 1) != n
542✔
1218
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1219
    end
1220
    @inbounds for i = 1:m
742✔
1221
        for j = n:-1:1
6,786✔
1222
            Aij = A[i,j]
31,097✔
1223
            for k = j + 1:n
58,801✔
1224
                Aij -= A[i,k]*B.data[k,j]
127,288✔
1225
            end
226,772✔
1226
            iszero(B.data[j,j]) && throw(SingularException(j))
31,097✔
1227
            A[i,j] = Aij/B.data[j,j]
31,097✔
1228
        end
58,801✔
1229
    end
6,415✔
1230
    A
371✔
1231
end
1232
function rdiv!(A::AbstractMatrix, B::UnitLowerTriangular)
502✔
1233
    require_one_based_indexing(A, B)
502✔
1234
    m, n = size(A)
502✔
1235
    if size(B, 1) != n
502✔
1236
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
171✔
1237
    end
1238
    @inbounds for i = 1:m
662✔
1239
        for j = n:-1:1
5,986✔
1240
            Aij = A[i,j]
27,077✔
1241
            for k = j + 1:n
51,161✔
1242
                Aij -= A[i,k]*B.data[k,j]
109,008✔
1243
            end
193,932✔
1244
            A[i,j] = Aij
27,077✔
1245
        end
51,161✔
1246
    end
5,655✔
1247
    A
331✔
1248
end
1249

1250
lmul!(A::UpperTriangular,     B::UpperTriangular) = UpperTriangular(lmul!(A, triu!(B.data)))
12✔
1251
lmul!(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(lmul!(A, triu!(B.data)))
12✔
1252
lmul!(A::LowerTriangular,     B::LowerTriangular) = LowerTriangular(lmul!(A, tril!(B.data)))
12✔
1253
lmul!(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(lmul!(A, tril!(B.data)))
12✔
1254

1255
ldiv!(A::UpperTriangular,     B::UpperTriangular) = UpperTriangular(ldiv!(A, triu!(B.data)))
18✔
1256
ldiv!(A::UnitUpperTriangular, B::UpperTriangular) = UpperTriangular(ldiv!(A, triu!(B.data)))
18✔
1257
ldiv!(A::LowerTriangular,     B::LowerTriangular) = LowerTriangular(ldiv!(A, tril!(B.data)))
18✔
1258
ldiv!(A::UnitLowerTriangular, B::LowerTriangular) = LowerTriangular(ldiv!(A, tril!(B.data)))
18✔
1259

1260
rdiv!(A::UpperTriangular, B::UpperTriangular)     = UpperTriangular(rdiv!(triu!(A.data), B))
1,646✔
1261
rdiv!(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(rdiv!(triu!(A.data), B))
18✔
1262
rdiv!(A::LowerTriangular, B::LowerTriangular)     = LowerTriangular(rdiv!(tril!(A.data), B))
18✔
1263
rdiv!(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(rdiv!(tril!(A.data), B))
18✔
1264

1265
rmul!(A::UpperTriangular, B::UpperTriangular)     = UpperTriangular(rmul!(triu!(A.data), B))
12✔
1266
rmul!(A::UpperTriangular, B::UnitUpperTriangular) = UpperTriangular(rmul!(triu!(A.data), B))
12✔
1267
rmul!(A::LowerTriangular, B::LowerTriangular)     = LowerTriangular(rmul!(tril!(A.data), B))
12✔
1268
rmul!(A::LowerTriangular, B::UnitLowerTriangular) = LowerTriangular(rmul!(tril!(A.data), B))
12✔
1269

1270
# Promotion
1271
## Promotion methods in matmul don't apply to triangular multiplication since
1272
## it is inplace. Hence we have to make very similar definitions, but without
1273
## allocation of a result array. For multiplication and unit diagonal division
1274
## the element type doesn't have to be stable under division whereas that is
1275
## necessary in the general triangular solve problem.
1276

1277
## Some Triangular-Triangular cases. We might want to write tailored methods
1278
## for these cases, but I'm not sure it is worth it.
1279

1280
for (f, f2!) in ((:*, :lmul!), (:\, :ldiv!))
1281
    @eval begin
1282
        function ($f)(A::LowerTriangular, B::LowerTriangular)
691✔
1283
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
691✔
1284
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1285
            BB = copy_similar(B, TAB)
691✔
1286
            return LowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
691✔
1287
        end
1288

1289
        function $(f)(A::UnitLowerTriangular, B::LowerTriangular)
626✔
1290
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
626✔
1291
                         (*)(zero(eltype(A)), zero(eltype(B))))
1292
             BB = copy_similar(B, TAB)
626✔
1293
            return LowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
626✔
1294
        end
1295

1296
        function $(f)(A::LowerTriangular, B::UnitLowerTriangular)
624✔
1297
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
624✔
1298
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1299
             BB = copy_similar(B, TAB)
624✔
1300
            return LowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
624✔
1301
        end
1302

1303
        function $(f)(A::UnitLowerTriangular, B::UnitLowerTriangular)
615✔
1304
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
615✔
1305
                         (*)(zero(eltype(A)), zero(eltype(B))))
1306
             BB = copy_similar(B, TAB)
615✔
1307
            return UnitLowerTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
615✔
1308
        end
1309

1310
        function ($f)(A::UpperTriangular, B::UpperTriangular)
2,483✔
1311
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
2,483✔
1312
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1313
            BB = copy_similar(B, TAB)
2,483✔
1314
            return UpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
2,483✔
1315
        end
1316

1317
        function ($f)(A::UnitUpperTriangular, B::UpperTriangular)
626✔
1318
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
626✔
1319
                         (*)(zero(eltype(A)), zero(eltype(B))))
1320
            BB = copy_similar(B, TAB)
626✔
1321
            return UpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
626✔
1322
        end
1323

1324
        function ($f)(A::UpperTriangular, B::UnitUpperTriangular)
624✔
1325
            TAB = typeof(($f)(zero(eltype(A)), zero(eltype(B))) +
624✔
1326
                         ($f)(zero(eltype(A)), zero(eltype(B))))
1327
            BB = copy_similar(B, TAB)
624✔
1328
            return UpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
624✔
1329
        end
1330

1331
        function ($f)(A::UnitUpperTriangular, B::UnitUpperTriangular)
620✔
1332
            TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
620✔
1333
                         (*)(zero(eltype(A)), zero(eltype(B))))
1334
            BB = copy_similar(B, TAB)
620✔
1335
            return UnitUpperTriangular($f2!(convert(AbstractMatrix{TAB}, A), BB))
620✔
1336
        end
1337
    end
1338
end
1339

1340
function (/)(A::LowerTriangular, B::LowerTriangular)
123✔
1341
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
123✔
1342
                 (/)(zero(eltype(A)), one(eltype(B))))
1343
    AA = copy_similar(A, TAB)
123✔
1344
    return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
123✔
1345
end
1346
function (/)(A::UnitLowerTriangular, B::LowerTriangular)
98✔
1347
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
98✔
1348
                 (/)(zero(eltype(A)), one(eltype(B))))
1349
    AA = copy_similar(A, TAB)
98✔
1350
    return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
98✔
1351
end
1352
function (/)(A::LowerTriangular, B::UnitLowerTriangular)
116✔
1353
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
116✔
1354
                 (/)(zero(eltype(A)), one(eltype(B))))
1355
    AA = copy_similar(A, TAB)
116✔
1356
    return LowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
116✔
1357
end
1358
function (/)(A::UnitLowerTriangular, B::UnitLowerTriangular)
105✔
1359
    TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
105✔
1360
                 (*)(zero(eltype(A)), zero(eltype(B))))
1361
    AA = copy_similar(A, TAB)
105✔
1362
    return UnitLowerTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
105✔
1363
end
1364
function (/)(A::UpperTriangular, B::UpperTriangular)
167✔
1365
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
167✔
1366
                 (/)(zero(eltype(A)), one(eltype(B))))
1367
    AA = copy_similar(A, TAB)
167✔
1368
    return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
167✔
1369
end
1370
function (/)(A::UnitUpperTriangular, B::UpperTriangular)
98✔
1371
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
98✔
1372
                 (/)(zero(eltype(A)), one(eltype(B))))
1373
    AA = copy_similar(A, TAB)
98✔
1374
    return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
98✔
1375
end
1376
function (/)(A::UpperTriangular, B::UnitUpperTriangular)
116✔
1377
    TAB = typeof((/)(zero(eltype(A)), one(eltype(B))) +
116✔
1378
                 (/)(zero(eltype(A)), one(eltype(B))))
1379
    AA = copy_similar(A, TAB)
116✔
1380
    return UpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
116✔
1381
end
1382
function (/)(A::UnitUpperTriangular, B::UnitUpperTriangular)
105✔
1383
    TAB = typeof((*)(zero(eltype(A)), zero(eltype(B))) +
105✔
1384
                 (*)(zero(eltype(A)), zero(eltype(B))))
1385
    AA = copy_similar(A, TAB)
105✔
1386
    return UnitUpperTriangular(rdiv!(AA, convert(AbstractMatrix{TAB}, B)))
105✔
1387
end
1388

1389
_inner_type_promotion(A,B) = promote_type(eltype(A), eltype(B), typeof(zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B))))
19,824✔
1390
## The general promotion methods
1391
function *(A::AbstractTriangular, B::AbstractTriangular)
3,643✔
1392
    TAB = _inner_type_promotion(A,B)
3,643✔
1393
    BB = copy_similar(B, TAB)
3,649✔
1394
    lmul!(convert(AbstractArray{TAB}, A), BB)
3,643✔
1395
end
1396

1397
for mat in (:AbstractVector, :AbstractMatrix)
1398
    ### Multiplication with triangle to the left and hence rhs cannot be transposed.
1399
    @eval function *(A::AbstractTriangular, B::$mat)
6,142✔
1400
        require_one_based_indexing(B)
6,142✔
1401
        TAB = _inner_type_promotion(A,B)
6,142✔
1402
        BB = copy_similar(B, TAB)
8,610✔
1403
        lmul!(convert(AbstractArray{TAB}, A), BB)
6,142✔
1404
    end
1405
    ### Left division with triangle to the left hence rhs cannot be transposed. No quotients.
1406
    @eval function \(A::Union{UnitUpperTriangular,UnitLowerTriangular}, B::$mat)
3,677✔
1407
        require_one_based_indexing(B)
3,677✔
1408
        TAB = _inner_type_promotion(A,B)
3,677✔
1409
        BB = copy_similar(B, TAB)
5,183✔
1410
        ldiv!(convert(AbstractArray{TAB}, A), BB)
3,677✔
1411
    end
1412
    ### Left division with triangle to the left hence rhs cannot be transposed. Quotients.
1413
    @eval function \(A::Union{UpperTriangular,LowerTriangular}, B::$mat)
9,594✔
1414
        require_one_based_indexing(B)
9,594✔
1415
        TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A)))
9,594✔
1416
        BB = copy_similar(B, TAB)
12,558✔
1417
        ldiv!(convert(AbstractArray{TAB}, A), BB)
9,594✔
1418
    end
1419
    ### Right division with triangle to the right hence lhs cannot be transposed. No quotients.
1420
    @eval function /(A::$mat, B::Union{UnitUpperTriangular, UnitLowerTriangular})
1,993✔
1421
        require_one_based_indexing(A)
1,993✔
1422
        TAB = _inner_type_promotion(A,B)
1,993✔
1423
        AA = copy_similar(A, TAB)
2,789✔
1424
        rdiv!(AA, convert(AbstractArray{TAB}, B))
1,993✔
1425
    end
1426
    ### Right division with triangle to the right hence lhs cannot be transposed. Quotients.
1427
    @eval function /(A::$mat, B::Union{UpperTriangular,LowerTriangular})
2,017✔
1428
        require_one_based_indexing(A)
2,017✔
1429
        TAB = typeof((zero(eltype(A))*zero(eltype(B)) + zero(eltype(A))*zero(eltype(B)))/one(eltype(A)))
2,017✔
1430
        AA = copy_similar(A, TAB)
2,813✔
1431
        rdiv!(AA, convert(AbstractArray{TAB}, B))
2,017✔
1432
    end
1433
end
1434
### Multiplication with triangle to the right and hence lhs cannot be transposed.
1435
# Only for AbstractMatrix, hence outside the above loop.
1436
function *(A::AbstractMatrix, B::AbstractTriangular)
4,369✔
1437
    require_one_based_indexing(A)
4,369✔
1438
    TAB = _inner_type_promotion(A,B)
4,369✔
1439
    AA = copy_similar(A, TAB)
5,999✔
1440
    rmul!(AA, convert(AbstractArray{TAB}, B))
4,369✔
1441
end
1442
# ambiguity resolution with definitions in matmul.jl
1443
*(v::AdjointAbsVec, A::AbstractTriangular) = adjoint(adjoint(A) * v.parent)
404✔
1444
*(v::TransposeAbsVec, A::AbstractTriangular) = transpose(transpose(A) * v.parent)
344✔
1445

1446
# Complex matrix power for upper triangular factor, see:
1447
#   Higham and Lin, "A Schur-Padé algorithm for fractional powers of a Matrix",
1448
#     SIAM J. Matrix Anal. & Appl., 32 (3), (2011) 1056–1078.
1449
#   Higham and Lin, "An improved Schur-Padé algorithm for fractional powers of
1450
#     a matrix and their Fréchet derivatives", SIAM. J. Matrix Anal. & Appl.,
1451
#     34(3), (2013) 1341–1360.
1452
function powm!(A0::UpperTriangular{<:BlasFloat}, p::Real)
60✔
1453
    if abs(p) >= 1
60✔
1454
        throw(ArgumentError("p must be a real number in (-1,1), got $p"))
2✔
1455
    end
1456

1457
    normA0 = opnorm(A0, 1)
58✔
1458
    rmul!(A0, 1/normA0)
58✔
1459

1460
    theta = [1.53e-5, 2.25e-3, 1.92e-2, 6.08e-2, 1.25e-1, 2.03e-1, 2.84e-1]
406✔
1461
    n = checksquare(A0)
58✔
1462

1463
    A, m, s = invsquaring(A0, theta)
58✔
1464
    A = I - A
58✔
1465

1466
    # Compute accurate diagonal of I - T
1467
    sqrt_diag!(A0, A, s)
58✔
1468
    for i = 1:n
116✔
1469
        A[i, i] = -A[i, i]
202✔
1470
    end
346✔
1471
    # Compute the Padé approximant
1472
    c = 0.5 * (p - m) / (2 * m - 1)
58✔
1473
    triu!(A)
58✔
1474
    S = c * A
58✔
1475
    Stmp = similar(S)
58✔
1476
    for j = m-1:-1:1
116✔
1477
        j4 = 4 * j
248✔
1478
        c = (-p - j) / (j4 + 2)
248✔
1479
        for i = 1:n
496✔
1480
            @inbounds S[i, i] = S[i, i] + 1
884✔
1481
        end
1,520✔
1482
        copyto!(Stmp, S)
248✔
1483
        mul!(S, A, c)
884✔
1484
        ldiv!(Stmp, S.data)
248✔
1485

1486
        c = (p - j) / (j4 - 2)
248✔
1487
        for i = 1:n
496✔
1488
            @inbounds S[i, i] = S[i, i] + 1
884✔
1489
        end
1,520✔
1490
        copyto!(Stmp, S)
248✔
1491
        mul!(S, A, c)
884✔
1492
        ldiv!(Stmp, S.data)
248✔
1493
    end
438✔
1494
    for i = 1:n
116✔
1495
        S[i, i] = S[i, i] + 1
202✔
1496
    end
346✔
1497
    copyto!(Stmp, S)
58✔
1498
    mul!(S, A, -p)
202✔
1499
    ldiv!(Stmp, S.data)
58✔
1500
    for i = 1:n
116✔
1501
        @inbounds S[i, i] = S[i, i] + 1
202✔
1502
    end
346✔
1503

1504
    blockpower!(A0, S, p/(2^s))
58✔
1505
    for m = 1:s
116✔
1506
        mul!(Stmp.data, S, S)
234✔
1507
        copyto!(S, Stmp)
234✔
1508
        blockpower!(A0, S, p/(2^(s-m)))
234✔
1509
    end
410✔
1510
    rmul!(S, normA0^p)
58✔
1511
    return S
58✔
1512
end
1513
powm(A::LowerTriangular, p::Real) = copy(transpose(powm!(copy(transpose(A)), p::Real)))
2✔
1514

1515
# Complex matrix logarithm for the upper triangular factor, see:
1516
#   Al-Mohy and Higham, "Improved inverse scaling and squaring algorithms for
1517
#     the matrix logarithm", SIAM J. Sci. Comput., 34(4), (2012), pp. C153–C169.
1518
#   Al-Mohy, Higham and Relton, "Computing the Frechet derivative of the matrix
1519
#     logarithm and estimating the condition number", SIAM J. Sci. Comput.,
1520
#     35(4), (2013), C394–C410.
1521
#
1522
# Based on the code available at http://eprints.ma.man.ac.uk/1851/02/logm.zip,
1523
# Copyright (c) 2011, Awad H. Al-Mohy and Nicholas J. Higham
1524
# Julia version relicensed with permission from original authors
1525
log(A::UpperTriangular{T}) where {T<:BlasFloat} = log_quasitriu(A)
257✔
1526
log(A::UnitUpperTriangular{T}) where {T<:BlasFloat} = log_quasitriu(A)
26✔
1527
log(A::LowerTriangular) = copy(transpose(log(copy(transpose(A)))))
4✔
1528
log(A::UnitLowerTriangular) = copy(transpose(log(copy(transpose(A)))))
4✔
1529

1530
function log_quasitriu(A0::AbstractMatrix{T}) where T<:BlasFloat
296✔
1531
    # allocate real A if log(A) will be real and complex A otherwise
1532
    n = checksquare(A0)
296✔
1533
    if isreal(A0) && (!istriu(A0) || !any(x -> real(x) < zero(real(T)), diag(A0)))
865✔
1534
        A = T <: Complex ? real(A0) : copy(A0)
91✔
1535
    else
1536
        A = T <: Complex ? copy(A0) : complex(A0)
205✔
1537
    end
1538
    if A0 isa UnitUpperTriangular
296✔
1539
        A = UpperTriangular(parent(A))
26✔
1540
        @inbounds for i in 1:n
52✔
1541
            A[i,i] = 1
234✔
1542
        end
442✔
1543
    end
1544
    Y0 = _log_quasitriu!(A0, A)
387✔
1545
    # return complex result for complex input
1546
    Y = T <: Complex ? complex(Y0) : Y0
322✔
1547

1548
    if A0 isa UpperTriangular || A0 isa UnitUpperTriangular
296✔
1549
        return UpperTriangular(Y)
283✔
1550
    else
1551
        return Y
13✔
1552
    end
1553
end
1554
# type-stable implementation of log_quasitriu
1555
# A is a copy of A0 that is overwritten while computing the result. It has the same eltype
1556
# as the result.
1557
function _log_quasitriu!(A0, A)
296✔
1558
    # Find Padé degree m and s while replacing A with A^(1/2^s)
1559
    m, s = _find_params_log_quasitriu!(A)
296✔
1560

1561
    # Compute accurate superdiagonal of A
1562
    _pow_superdiag_quasitriu!(A, A0, 0.5^s)
585✔
1563

1564
    # Compute accurate block diagonal of A
1565
    _sqrt_pow_diag_quasitriu!(A, A0, s)
296✔
1566

1567
    # Get the Gauss-Legendre quadrature points and weights
1568
    R = zeros(Float64, m, m)
10,005✔
1569
    for i = 1:m - 1
583✔
1570
        R[i,i+1] = i / sqrt((2 * i)^2 - 1)
1,393✔
1571
        R[i+1,i] = R[i,i+1]
1,393✔
1572
    end
2,499✔
1573
    x,V = eigen(R)
592✔
1574
    w = Vector{Float64}(undef, m)
296✔
1575
    for i = 1:m
592✔
1576
        x[i] = (x[i] + 1) / 2
3,378✔
1577
        w[i] = V[1,i]^2
1,689✔
1578
    end
3,082✔
1579

1580
    # Compute the Padé approximation
1581
    t = eltype(A)
296✔
1582
    n = size(A, 1)
296✔
1583
    Y = zeros(t, n, n)
10,036✔
1584
    B = similar(A)
296✔
1585
    for k = 1:m
592✔
1586
        B .= t(x[k]) .* A
1,750✔
1587
        @inbounds for i in 1:n
3,378✔
1588
            B[i,i] += 1
8,216✔
1589
        end
14,743✔
1590
        Y .+= t(w[k]) .* rdiv_quasitriu!(A, B)
3,378✔
1591
    end
3,082✔
1592

1593
    # Scale back
1594
    lmul!(2.0^s, Y)
585✔
1595

1596
    # Compute accurate diagonal and superdiagonal of log(A)
1597
    _log_diag_quasitriu!(Y, A0)
296✔
1598

1599
    return Y
296✔
1600
end
1601

1602
# Auxiliary functions for matrix logarithm and matrix power
1603

1604
# Find Padé degree m and s while replacing A with A^(1/2^s)
1605
#   Al-Mohy and Higham, "Improved inverse scaling and squaring algorithms for
1606
#     the matrix logarithm", SIAM J. Sci. Comput., 34(4), (2012), pp. C153–C169.
1607
#   from Algorithm 4.1
1608
function _find_params_log_quasitriu!(A)
296✔
1609
    maxsqrt = 100
296✔
1610
    theta = [1.586970738772063e-005,
2,072✔
1611
         2.313807884242979e-003,
1612
         1.938179313533253e-002,
1613
         6.209171588994762e-002,
1614
         1.276404810806775e-001,
1615
         2.060962623452836e-001,
1616
         2.879093714241194e-001]
1617
    tmax = size(theta, 1)
296✔
1618
    n = size(A, 1)
296✔
1619
    p = 0
296✔
1620
    m = 0
296✔
1621

1622
    # Find s0, the smallest s such that the ρ(triu(A)^(1/2^s) - I) ≤ theta[tmax], where ρ(X)
1623
    # is the spectral radius of X
1624
    d = complex.(@view(A[diagind(A)]))
296✔
1625
    dm1 = d .- 1
592✔
1626
    s = 0
296✔
1627
    while norm(dm1, Inf) > theta[tmax] && s < maxsqrt
1,387✔
1628
        d .= sqrt.(d)
1,091✔
1629
        dm1 .= d .- 1
2,182✔
1630
        s = s + 1
1,091✔
1631
    end
1,091✔
1632
    s0 = s
296✔
1633

1634
    # Compute repeated roots
1635
    for k = 1:min(s, maxsqrt)
558✔
1636
        _sqrt_quasitriu!(A isa UpperTriangular ? parent(A) : A, A)
1,091✔
1637
    end
1,920✔
1638

1639
    # these three never needed at the same time, so reuse the same temporary
1640
    AmI = AmI4 = AmI5 = A - I
296✔
1641
    AmI2 = AmI * AmI
296✔
1642
    AmI3 = AmI2 * AmI
296✔
1643
    d2 = sqrt(opnorm(AmI2, 1))
296✔
1644
    d3 = cbrt(opnorm(AmI3, 1))
296✔
1645
    alpha2 = max(d2, d3)
296✔
1646
    foundm = false
296✔
1647
    if alpha2 <= theta[2]
296✔
1648
        m = alpha2 <= theta[1] ? 1 : 2
9✔
1649
        foundm = true
9✔
1650
    end
1651

1652
    while !foundm
640✔
1653
        more_sqrt = false
631✔
1654
        mul!(AmI4, AmI2, AmI2)
631✔
1655
        d4 = opnorm(AmI4, 1)^(1/4)
631✔
1656
        alpha3 = max(d3, d4)
631✔
1657
        if alpha3 <= theta[tmax]
631✔
1658
            local j
×
1659
            for outer j = 3:tmax
732✔
1660
                if alpha3 <= theta[j]
1,504✔
1661
                    break
366✔
1662
                end
1663
            end
1,138✔
1664
            if j <= 6
366✔
1665
                m = j
224✔
1666
                break
224✔
1667
            elseif alpha3 / 2 <= theta[5] && p < 2
142✔
1668
                more_sqrt = true
103✔
1669
                p = p + 1
103✔
1670
           end
1671
        end
1672

1673
        if !more_sqrt
407✔
1674
            mul!(AmI5, AmI3, AmI2)
304✔
1675
            d5 = opnorm(AmI5, 1)^(1/5)
304✔
1676
            alpha4 = max(d4, d5)
304✔
1677
            eta = min(alpha3, alpha4)
304✔
1678
            if eta <= theta[tmax]
304✔
1679
                j = 0
62✔
1680
                for outer j = 6:tmax
124✔
1681
                    if eta <= theta[j]
121✔
1682
                        m = j
62✔
1683
                        break
62✔
1684
                    end
1685
                end
59✔
1686
                break
62✔
1687
            end
1688
        end
1689

1690
        if s == maxsqrt
345✔
1691
            m = tmax
1✔
1692
            break
1✔
1693
        end
1694
        _sqrt_quasitriu!(A isa UpperTriangular ? parent(A) : A, A)
344✔
1695
        copyto!(AmI, A)
344✔
1696
        for i in 1:n
688✔
1697
            @inbounds AmI[i,i] -= 1
1,766✔
1698
        end
3,188✔
1699
        mul!(AmI2, AmI, AmI)
344✔
1700
        mul!(AmI3, AmI2, AmI)
344✔
1701
        d3 = cbrt(opnorm(AmI3, 1))
344✔
1702
        s = s + 1
344✔
1703
    end
344✔
1704
    return m, s
296✔
1705
end
1706

1707
# Compute accurate diagonal of A = A0^s - I
1708
function sqrt_diag!(A0::UpperTriangular, A::UpperTriangular, s)
58✔
1709
    n = checksquare(A0)
58✔
1710
    T = eltype(A)
58✔
1711
    @inbounds for i = 1:n
116✔
1712
        a = complex(A0[i,i])
202✔
1713
        A[i,i] = _sqrt_pow(a, s)
202✔
1714
    end
202✔
1715
end
1716
# Compute accurate block diagonal of A = A0^s - I for upper quasi-triangular A0 produced
1717
# by the Schur decomposition. Diagonal is made of 1x1 and 2x2 blocks.
1718
# 2x2 blocks are real with non-negative conjugate pair eigenvalues
1719
function _sqrt_pow_diag_quasitriu!(A, A0, s)
296✔
1720
    n = checksquare(A0)
296✔
1721
    t = typeof(sqrt(zero(eltype(A))))
296✔
1722
    i = 1
296✔
1723
    @inbounds while i < n
296✔
1724
        if iszero(A0[i+1,i])  # 1x1 block
2,199✔
1725
            A[i,i] = _sqrt_pow(t(A0[i,i]), s)
1,095✔
1726
            i += 1
1,095✔
1727
        else  # real 2x2 block
1728
            @views _sqrt_pow_diag_block_2x2!(A[i:i+1,i:i+1], A0[i:i+1,i:i+1], s)
17✔
1729
            i += 2
17✔
1730
        end
1731
    end
1,112✔
1732
    if i == n  # last block is 1x1
296✔
1733
        @inbounds A[n,n] = _sqrt_pow(t(A0[n,n]), s)
289✔
1734
    end
1735
    return A
296✔
1736
end
1737
# compute a^(1/2^s)-1
1738
#   Al-Mohy, "A more accurate Briggs method for the logarithm",
1739
#      Numer. Algorithms, 59, (2012), 393–402.
1740
#   Algorithm 2
1741
function _sqrt_pow(a::Number, s)
1,586✔
1742
    T = typeof(sqrt(zero(a)))
1,586✔
1743
    s == 0 && return T(a) - 1
1,586✔
1744
    s0 = s
1,559✔
1745
    if imag(a) >= 0 && real(a) <= 0 && !iszero(a)  # angle(a) ≥ π / 2
1,559✔
1746
        a = sqrt(a)
139✔
1747
        s0 = s - 1
139✔
1748
    end
1749
    z0 = a - 1
1,559✔
1750
    a = sqrt(a)
1,559✔
1751
    r = 1 + a
1,559✔
1752
    for j = 1:s0-1
3,102✔
1753
        a = sqrt(a)
4,426✔
1754
        r = r * (1 + a)
4,426✔
1755
    end
7,309✔
1756
    return z0 / r
1,559✔
1757
end
1758
# compute A0 = A^(1/2^s)-I for 2x2 real matrices A and A0
1759
# A has non-negative conjugate pair eigenvalues
1760
# "Improved Inverse Scaling and Squaring Algorithms for the Matrix Logarithm"
1761
# SIAM J. Sci. Comput., 34(4), (2012) C153–C169. doi: 10.1137/110852553
1762
# Algorithm 5.1
1763
Base.@propagate_inbounds function _sqrt_pow_diag_block_2x2!(A, A0, s)
17✔
1764
    _sqrt_real_2x2!(A, A0)
17✔
1765
    if isone(s)
17✔
1766
        A[1,1] -= 1
×
1767
        A[2,2] -= 1
×
1768
    else
1769
        # Z = A - I
1770
        z11, z21, z12, z22 = A[1,1] - 1, A[2,1], A[1,2], A[2,2] - 1
17✔
1771
        # A = sqrt(A)
1772
        _sqrt_real_2x2!(A, A)
17✔
1773
        # P = A + I
1774
        p11, p21, p12, p22 = A[1,1] + 1, A[2,1], A[1,2], A[2,2] + 1
17✔
1775
        for i in 1:(s - 2)
34✔
1776
            # A = sqrt(A)
1777
            _sqrt_real_2x2!(A, A)
423✔
1778
            a11, a21, a12, a22 = A[1,1], A[2,1], A[1,2], A[2,2]
423✔
1779
            # P += P * A
1780
            r11 = p11*(1 + a11) + p12*a21
423✔
1781
            r22 = p21*a12 + p22*(1 + a22)
423✔
1782
            p21 = p21*(1 + a11) + p22*a21
423✔
1783
            p12 = p11*a12 + p12*(1 + a22)
423✔
1784
            p11 = r11
423✔
1785
            p22 = r22
423✔
1786
        end
829✔
1787
        # A = Z / P
1788
        c = inv(p11*p22 - p21*p12)
17✔
1789
        A[1,1] = (p22*z11 - p21*z12) * c
17✔
1790
        A[2,1] = (p22*z21 - p21*z22) * c
17✔
1791
        A[1,2] = (p11*z12 - p12*z11) * c
17✔
1792
        A[2,2] = (p11*z22 - p12*z21) * c
17✔
1793
    end
1794
    return A
17✔
1795
end
1796
# Compute accurate superdiagonal of A = A0^s - I for upper quasi-triangular A0 produced
1797
# by a Schur decomposition.
1798
# Higham and Lin, "A Schur–Padé Algorithm for Fractional Powers of a Matrix"
1799
# SIAM J. Matrix Anal. Appl., 32(3), (2011), 1056–1078.
1800
# Equation 5.6
1801
# see also blockpower for when A0 is upper triangular
1802
function _pow_superdiag_quasitriu!(A, A0, p)
296✔
1803
    n = checksquare(A0)
296✔
1804
    t = eltype(A)
296✔
1805
    k = 1
296✔
1806
    @inbounds while k < n
296✔
1807
        if !iszero(A[k+1,k])
2,192✔
1808
            k += 2
10✔
1809
            continue
10✔
1810
        end
1811
        if !(k == n - 1 || iszero(A[k+2,k+1]))
1,910✔
1812
            k += 3
7✔
1813
            continue
7✔
1814
        end
1815
        Ak = t(A0[k,k])
1,248✔
1816
        Akp1 = t(A0[k+1,k+1])
1,248✔
1817

1818
        Akp = Ak^p
1,088✔
1819
        Akp1p = Akp1^p
1,088✔
1820

1821
        if Ak == Akp1
1,088✔
1822
            A[k,k+1] = p * A0[k,k+1] * Ak^(p-1)
285✔
1823
        elseif 2 * abs(Ak) < abs(Akp1) || 2 * abs(Akp1) < abs(Ak) || iszero(Akp1 + Ak)
1,591✔
1824
            A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
431✔
1825
        else
1826
            logAk = log(Ak)
372✔
1827
            logAkp1 = log(Akp1)
372✔
1828
            z = (Akp1 - Ak)/(Akp1 + Ak)
372✔
1829
            if abs(z) > 1
482✔
1830
                A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
73✔
1831
            else
1832
                w = atanh(z) + im * pi * (unw(logAkp1-logAk) - unw(log1p(z)-log1p(-z)))
299✔
1833
                dd = 2 * exp(p*(logAk+logAkp1)/2) * sinh(p*w) / (Akp1 - Ak);
505✔
1834
                A[k,k+1] = A0[k,k+1] * dd
299✔
1835
            end
1836
        end
1837
        k += 1
1,088✔
1838
    end
1,401✔
1839
end
1840

1841
# Compute accurate block diagonal and superdiagonal of A = log(A0) for upper
1842
# quasi-triangular A0 produced by the Schur decomposition.
1843
function _log_diag_quasitriu!(A, A0)
296✔
1844
    n = checksquare(A0)
296✔
1845
    t = eltype(A)
296✔
1846
    k = 1
296✔
1847
    @inbounds while k < n
296✔
1848
        if iszero(A0[k+1,k])  # 1x1 block
1,512✔
1849
            Ak = t(A0[k,k])
851✔
1850
            logAk = log(Ak)
751✔
1851
            A[k,k] = logAk
751✔
1852
            if k < n - 2 && iszero(A0[k+2,k+1])
1,094✔
1853
                Akp1 = t(A0[k+1,k+1])
404✔
1854
                logAkp1 = log(Akp1)
344✔
1855
                A[k+1,k+1] = logAkp1
344✔
1856
                if Ak == Akp1
344✔
1857
                    A[k,k+1] = A0[k,k+1] / Ak
103✔
1858
                elseif 2 * abs(Ak) < abs(Akp1) || 2 * abs(Akp1) < abs(Ak) || iszero(Akp1 + Ak)
485✔
1859
                    A[k,k+1] = A0[k,k+1] * (logAkp1 - logAk) / (Akp1 - Ak)
125✔
1860
                else
1861
                    z = (Akp1 - Ak)/(Akp1 + Ak)
116✔
1862
                    if abs(z) > 1
148✔
1863
                        A[k,k+1] = A0[k,k+1] * (logAkp1 - logAk) / (Akp1 - Ak)
32✔
1864
                    else
1865
                        w = atanh(z) + im * pi * (unw(logAkp1-logAk) - unw(log1p(z)-log1p(-z)))
84✔
1866
                        A[k,k+1] = 2 * A0[k,k+1] * w / (Akp1 - Ak)
84✔
1867
                    end
1868
                end
1869
                k += 2
344✔
1870
            else
1871
                k += 1
1,158✔
1872
            end
1873
        else  # real 2x2 block
1874
            @views _log_diag_block_2x2!(A[k:k+1,k:k+1], A0[k:k+1,k:k+1])
17✔
1875
            k += 2
17✔
1876
        end
1877
    end
768✔
1878
    if k == n  # last 1x1 block
296✔
1879
        @inbounds A[n,n] = log(t(A0[n,n]))
309✔
1880
    end
1881
    return A
296✔
1882
end
1883
# compute A0 = log(A) for 2x2 real matrices A and A0, where A0 is a diagonal 2x2 block
1884
# produced by real Schur decomposition.
1885
# Al-Mohy, Higham and Relton, "Computing the Frechet derivative of the matrix
1886
# logarithm and estimating the condition number", SIAM J. Sci. Comput.,
1887
# 35(4), (2013), C394–C410.
1888
# Eq. 6.1
1889
Base.@propagate_inbounds function _log_diag_block_2x2!(A, A0)
17✔
1890
    a, b, c = A0[1,1], A0[1,2], A0[2,1]
17✔
1891
    # avoid underflow/overflow for large/small b and c
1892
    s = sqrt(abs(b)) * sqrt(abs(c))
17✔
1893
    θ = atan(s, a)
17✔
1894
    t = θ / s
17✔
1895
    au = abs(a)
17✔
1896
    if au > s
17✔
1897
        a1 = log1p((s / au)^2) / 2 + log(au)
7✔
1898
    else
1899
        a1 = log1p((au / s)^2) / 2 + log(s)
10✔
1900
    end
1901
    A[1,1] = a1
17✔
1902
    A[2,1] = c*t
17✔
1903
    A[1,2] = b*t
17✔
1904
    A[2,2] = a1
17✔
1905
    return A
17✔
1906
end
1907

1908
# Used only by powm at the moment
1909
# Repeatedly compute the square roots of A so that in the end its
1910
# eigenvalues are close enough to the positive real line
1911
function invsquaring(A0::UpperTriangular, theta)
58✔
1912
    require_one_based_indexing(theta)
58✔
1913
    # assumes theta is in ascending order
1914
    maxsqrt = 100
58✔
1915
    tmax = size(theta, 1)
58✔
1916
    n = checksquare(A0)
58✔
1917
    A = complex(copy(A0))
58✔
1918
    p = 0
58✔
1919
    m = 0
58✔
1920

1921
    # Compute repeated roots
1922
    d = complex(diag(A))
58✔
1923
    dm1 = d .- 1
116✔
1924
    s = 0
58✔
1925
    while norm(dm1, Inf) > theta[tmax] && s < maxsqrt
206✔
1926
        d .= sqrt.(d)
148✔
1927
        dm1 .= d .- 1
296✔
1928
        s = s + 1
148✔
1929
    end
148✔
1930
    s0 = s
58✔
1931
    for k = 1:min(s, maxsqrt)
102✔
1932
        A = sqrt(A)
148✔
1933
    end
252✔
1934

1935
    AmI = A - I
58✔
1936
    d2 = sqrt(opnorm(AmI^2, 1))
58✔
1937
    d3 = cbrt(opnorm(AmI^3, 1))
58✔
1938
    alpha2 = max(d2, d3)
58✔
1939
    foundm = false
58✔
1940
    if alpha2 <= theta[2]
58✔
1941
        m = alpha2 <= theta[1] ? 1 : 2
×
1942
        foundm = true
×
1943
    end
1944

1945
    while !foundm
186✔
1946
        more = false
186✔
1947
        if s > s0
186✔
1948
            d3 = cbrt(opnorm(AmI^3, 1))
114✔
1949
        end
1950
        d4 = opnorm(AmI^4, 1)^(1/4)
186✔
1951
        alpha3 = max(d3, d4)
186✔
1952
        if alpha3 <= theta[tmax]
186✔
1953
            local j
×
1954
            for outer j = 3:tmax
284✔
1955
                if alpha3 <= theta[j]
610✔
1956
                    break
142✔
1957
                elseif alpha3 / 2 <= theta[5] && p < 2
468✔
1958
                    more = true
116✔
1959
                    p = p + 1
116✔
1960
                end
1961
            end
468✔
1962
            if j <= 6
142✔
1963
                m = j
58✔
1964
                foundm = true
58✔
1965
                break
58✔
1966
            elseif alpha3 / 2 <= theta[5] && p < 2
84✔
1967
                more = true
×
1968
                p = p + 1
×
1969
           end
1970
        end
1971

1972
        if !more
128✔
1973
            d5 = opnorm(AmI^5, 1)^(1/5)
86✔
1974
            alpha4 = max(d4, d5)
86✔
1975
            eta = min(alpha3, alpha4)
86✔
1976
            if eta <= theta[tmax]
86✔
1977
                j = 0
56✔
1978
                for outer j = 6:tmax
112✔
1979
                    if eta <= theta[j]
56✔
1980
                        m = j
14✔
1981
                        break
14✔
1982
                    end
1983
                    break
42✔
1984
                end
×
1985
            end
1986
            if s == maxsqrt
86✔
1987
                m = tmax
×
1988
                break
×
1989
            end
1990
            A = sqrt(A)
86✔
1991
            AmI = A - I
86✔
1992
            s = s + 1
86✔
1993
        end
1994
    end
128✔
1995

1996
    # Compute accurate superdiagonal of T
1997
    p = 1 / 2^s
58✔
1998
    A = complex(A)
58✔
1999
    blockpower!(A, A0, p)
58✔
2000
    return A,m,s
58✔
2001
end
2002

2003
# Compute accurate diagonal and superdiagonal of A = A0^p
2004
function blockpower!(A::UpperTriangular, A0::UpperTriangular, p)
350✔
2005
    n = checksquare(A0)
350✔
2006
    @inbounds for k = 1:n-1
700✔
2007
        Ak = complex(A0[k,k])
924✔
2008
        Akp1 = complex(A0[k+1,k+1])
924✔
2009

2010
        Akp = Ak^p
924✔
2011
        Akp1p = Akp1^p
924✔
2012

2013
        A[k,k] = Akp
924✔
2014
        A[k+1,k+1] = Akp1p
924✔
2015

2016
        if Ak == Akp1
924✔
2017
            A[k,k+1] = p * A0[k,k+1] * Ak^(p-1)
98✔
2018
        elseif 2 * abs(Ak) < abs(Akp1) || 2 * abs(Akp1) < abs(Ak) || iszero(Akp1 + Ak)
1,610✔
2019
            A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
98✔
2020
        else
2021
            logAk = log(Ak)
728✔
2022
            logAkp1 = log(Akp1)
728✔
2023
            z = (Akp1 - Ak)/(Akp1 + Ak)
728✔
2024
            if abs(z) > 1
728✔
2025
                A[k,k+1] = A0[k,k+1] * (Akp1p - Akp) / (Akp1 - Ak)
×
2026
            else
2027
                w = atanh(z) + im * pi * (unw(logAkp1-logAk) - unw(log1p(z)-log1p(-z)))
728✔
2028
                dd = 2 * exp(p*(logAk+logAkp1)/2) * sinh(p*w) / (Akp1 - Ak);
1,456✔
2029
                A[k,k+1] = A0[k,k+1] * dd
728✔
2030
            end
2031
        end
2032
    end
924✔
2033
end
2034

2035
# Unwinding number
2036
unw(x::Real) = 0
262✔
2037
unw(x::Number) = ceil((imag(x) - pi) / (2 * pi))
1,960✔
2038

2039
# compute A / B for upper quasi-triangular B, possibly overwriting B
2040
function rdiv_quasitriu!(A, B)
1,689✔
2041
    n = checksquare(A)
1,689✔
2042
    AG = copy(A)
1,689✔
2043
    # use Givens rotations to annihilate 2x2 blocks
2044
    @inbounds for k in 1:(n-1)
3,363✔
2045
        s = B[k+1,k]
12,859✔
2046
        iszero(s) && continue  # 1x1 block
6,527✔
2047
        G = first(givens(B[k+1,k+1], s, k, k+1))
85✔
2048
        rmul!(B, G)
400✔
2049
        rmul!(AG, G)
85✔
2050
    end
11,380✔
2051
    return rdiv!(AG, UpperTriangular(B))
1,689✔
2052
end
2053

2054
# End of auxiliary functions for matrix logarithm and matrix power
2055

2056
sqrt(A::UpperTriangular) = sqrt_quasitriu(A)
581✔
2057
function sqrt(A::UnitUpperTriangular{T}) where T
18✔
2058
    B = A.data
18✔
2059
    n = checksquare(B)
18✔
2060
    t = typeof(sqrt(zero(T)))
18✔
2061
    R = Matrix{t}(I, n, n)
18✔
2062
    tt = typeof(zero(t)*zero(t))
18✔
2063
    half = inv(R[1,1]+R[1,1]) # for general, algebraic cases. PR#20214
20✔
2064
    @inbounds for j = 1:n
36✔
2065
        for i = j-1:-1:1
258✔
2066
            r::tt = B[i,j]
516✔
2067
            @simd for k = i+1:j-1
636✔
2068
                r -= R[i,k]*R[k,j]
1,180✔
2069
            end
×
2070
            r==0 || (R[i,j] = half*r)
1,032✔
2071
        end
912✔
2072
    end
258✔
2073
    return UnitUpperTriangular(R)
18✔
2074
end
2075
sqrt(A::LowerTriangular) = copy(transpose(sqrt(copy(transpose(A)))))
7✔
2076
sqrt(A::UnitLowerTriangular) = copy(transpose(sqrt(copy(transpose(A)))))
7✔
2077

2078
# Auxiliary functions for matrix square root
2079

2080
# square root of upper triangular or real upper quasitriangular matrix
2081
function sqrt_quasitriu(A0; blockwidth = eltype(A0) <: Complex ? 512 : 256)
1,338✔
2082
    n = checksquare(A0)
669✔
2083
    T = eltype(A0)
669✔
2084
    Tr = typeof(sqrt(real(zero(T))))
669✔
2085
    Tc = typeof(sqrt(complex(zero(T))))
669✔
2086
    if isreal(A0)
2,117✔
2087
        is_sqrt_real = true
283✔
2088
        if istriu(A0)
283✔
2089
            for i in 1:n
398✔
2090
                Aii = real(A0[i,i])
592✔
2091
                if Aii < zero(Aii)
592✔
2092
                    is_sqrt_real = false
40✔
2093
                    break
40✔
2094
                end
2095
            end
552✔
2096
        end
2097
        if is_sqrt_real
283✔
2098
            R = zeros(Tr, n, n)
27,006✔
2099
            A = real(A0)
243✔
2100
        else
2101
            R = zeros(Tc, n, n)
347✔
2102
            A = A0
323✔
2103
        end
2104
    else
2105
        A = A0
386✔
2106
        R = zeros(Tc, n, n)
386✔
2107
    end
2108
    _sqrt_quasitriu!(R, A; blockwidth=blockwidth, n=n)
910✔
2109
    Rc = eltype(A0) <: Real ? R : complex(R)
763✔
2110
    if A0 isa UpperTriangular
669✔
2111
        return UpperTriangular(Rc)
581✔
2112
    elseif A0 isa UnitUpperTriangular
88✔
2113
        return UnitUpperTriangular(Rc)
×
2114
    else
2115
        return Rc
88✔
2116
    end
2117
end
2118

2119
# in-place recursive sqrt of upper quasi-triangular matrix A from
2120
# Deadman E., Higham N.J., Ralha R. (2013) Blocked Schur Algorithms for Computing the Matrix
2121
# Square Root. Applied Parallel and Scientific Computing. PARA 2012. Lecture Notes in
2122
# Computer Science, vol 7782. https://doi.org/10.1007/978-3-642-36803-5_12
2123
function _sqrt_quasitriu!(R, A; blockwidth=64, n=checksquare(A))
4,333✔
2124
    if n ≤ blockwidth || !(eltype(R) <: BlasFloat) # base case, perform "point" algorithm
2,198✔
2125
        _sqrt_quasitriu_block!(R, A)
2,135✔
2126
    else  # compute blockwise recursion
2127
        split = div(n, 2)
31✔
2128
        iszero(A[split+1, split]) || (split += 1) # don't split 2x2 diagonal block
39✔
2129
        r1 = 1:split
31✔
2130
        r2 = (split + 1):n
31✔
2131
        n1, n2 = split, n - split
31✔
2132
        A11, A12, A22 = @views A[r1,r1], A[r1,r2], A[r2,r2]
31✔
2133
        R11, R12, R22 = @views R[r1,r1], R[r1,r2], R[r2,r2]
31✔
2134
        # solve diagonal blocks recursively
2135
        _sqrt_quasitriu!(R11, A11; blockwidth=blockwidth, n=n1)
31✔
2136
        _sqrt_quasitriu!(R22, A22; blockwidth=blockwidth, n=n2)
31✔
2137
        # solve off-diagonal block
2138
        R12 .= .- A12
62✔
2139
        _sylvester_quasitriu!(R11, R22, R12; blockwidth=blockwidth, nA=n1, nB=n2, raise=false)
31✔
2140
    end
2141
    return R
2,166✔
2142
end
2143

2144
function _sqrt_quasitriu_block!(R, A)
2,135✔
2145
    _sqrt_quasitriu_diag_block!(R, A)
2,135✔
2146
    _sqrt_quasitriu_offdiag_block!(R, A)
2,135✔
2147
    return R
2,135✔
2148
end
2149

2150
function _sqrt_quasitriu_diag_block!(R, A)
2,135✔
2151
    n = size(R, 1)
2,135✔
2152
    ta = eltype(R) <: Complex ? complex(eltype(A)) : eltype(A)
2,135✔
2153
    i = 1
2,135✔
2154
    @inbounds while i < n
2,135✔
2155
        if iszero(A[i + 1, i])
13,841✔
2156
            R[i, i] = sqrt(ta(A[i, i]))
6,987✔
2157
            i += 1
6,987✔
2158
        else
2159
            # this branch is never reached when A is complex triangular
2160
            @views _sqrt_real_2x2!(R[i:(i + 1), i:(i + 1)], A[i:(i + 1), i:(i + 1)])
736✔
2161
            i += 2
736✔
2162
        end
2163
    end
7,723✔
2164
    if i == n
2,135✔
2165
        R[n, n] = sqrt(ta(A[n, n]))
1,697✔
2166
    end
2167
    return R
2,135✔
2168
end
2169

2170
function _sqrt_quasitriu_offdiag_block!(R, A)
2,135✔
2171
    n = size(R, 1)
2,135✔
2172
    j = 1
2,135✔
2173
    @inbounds while j ≤ n
2,135✔
2174
        jsize_is_2 = j < n && !iszero(A[j + 1, j])
15,538✔
2175
        i = j - 1
9,420✔
2176
        while i > 0
76,010✔
2177
            isize_is_2 = i > 1 && !iszero(A[i, i - 1])
83,841✔
2178
            if isize_is_2
66,590✔
2179
                if jsize_is_2
831✔
2180
                    _sqrt_quasitriu_offdiag_block_2x2!(R, A, i - 1, j)
414✔
2181
                else
2182
                    _sqrt_quasitriu_offdiag_block_2x1!(R, A, i - 1, j)
417✔
2183
                end
2184
                i -= 2
831✔
2185
            else
2186
                if jsize_is_2
65,759✔
2187
                    _sqrt_quasitriu_offdiag_block_1x2!(R, A, i, j)
250✔
2188
                else
2189
                    _sqrt_quasitriu_offdiag_block_1x1!(R, A, i, j)
65,510✔
2190
                end
2191
                i -= 1
65,759✔
2192
            end
2193
        end
66,590✔
2194
        j += 2 - !jsize_is_2
9,420✔
2195
    end
9,420✔
2196
    return R
2,135✔
2197
end
2198

2199
# real square root of 2x2 diagonal block of quasi-triangular matrix from real Schur
2200
# decomposition. Eqs 6.8-6.9 and Algorithm 6.5 of
2201
# Higham, 2008, "Functions of Matrices: Theory and Computation", SIAM.
2202
Base.@propagate_inbounds function _sqrt_real_2x2!(R, A)
1,193✔
2203
    # in the real Schur form, A[1, 1] == A[2, 2], and A[2, 1] * A[1, 2] < 0
2204
    θ, a21, a12 = A[1, 1], A[2, 1], A[1, 2]
1,193✔
2205
    # avoid overflow/underflow of μ
2206
    # for real sqrt, |d| ≤ 2 max(|a12|,|a21|)
2207
    μ = sqrt(abs(a12)) * sqrt(abs(a21))
1,193✔
2208
    α = _real_sqrt(θ, μ)
1,307✔
2209
    c = 2α
1,193✔
2210
    R[1, 1] = α
1,193✔
2211
    R[2, 1] = a21 / c
1,193✔
2212
    R[1, 2] = a12 / c
1,193✔
2213
    R[2, 2] = α
1,193✔
2214
    return R
1,193✔
2215
end
2216

2217
# real part of square root of θ+im*μ
2218
@inline function _real_sqrt(θ, μ)
1,193✔
2219
    t = sqrt((abs(θ) + hypot(θ, μ)) / 2)
1,278✔
2220
    return θ ≥ 0 ? t : μ / 2t
1,307✔
2221
end
2222

2223
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_1x1!(R, A, i, j)
65,509✔
2224
    Rii = R[i, i]
65,509✔
2225
    Rjj = R[j, j]
65,509✔
2226
    iszero(Rii) && iszero(Rjj) && return R
65,509✔
2227
    t = eltype(R)
65,508✔
2228
    tt = typeof(zero(t)*zero(t))
65,508✔
2229
    r = tt(-A[i, j])
65,508✔
2230
    @simd for k in (i + 1):(j - 1)
72,384✔
2231
        r += R[i, k] * R[k, j]
2,991,358✔
2232
    end
×
2233
    iszero(r) && return R
65,508✔
2234
    R[i, j] = sylvester(Rii, Rjj, r)
56,944✔
2235
    return R
56,944✔
2236
end
2237

2238
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_1x2!(R, A, i, j)
250✔
2239
    jrange = j:(j + 1)
250✔
2240
    t = eltype(R)
250✔
2241
    tt = typeof(zero(t)*zero(t))
250✔
2242
    r1 = tt(-A[i, j])
250✔
2243
    r2 = tt(-A[i, j + 1])
250✔
2244
    @simd for k in (i + 1):(j - 1)
360✔
2245
        rik = R[i, k]
476✔
2246
        r1 += rik * R[k, j]
476✔
2247
        r2 += rik * R[k, j + 1]
476✔
2248
    end
×
2249
    Rjj = @view R[jrange, jrange]
250✔
2250
    Rij = @view R[i, jrange]
250✔
2251
    Rij[1] = r1
250✔
2252
    Rij[2] = r2
250✔
2253
    _sylvester_1x2!(R[i, i], Rjj, Rij)
250✔
2254
    return R
250✔
2255
end
2256

2257
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_2x1!(R, A, i, j)
417✔
2258
    irange = i:(i + 1)
417✔
2259
    t = eltype(R)
417✔
2260
    tt = typeof(zero(t)*zero(t))
417✔
2261
    r1 = tt(-A[i, j])
417✔
2262
    r2 = tt(-A[i + 1, j])
417✔
2263
    @simd for k in (i + 2):(j - 1)
546✔
2264
        rkj = R[k, j]
1,003✔
2265
        r1 += R[i, k] * rkj
1,003✔
2266
        r2 += R[i + 1, k] * rkj
1,003✔
2267
    end
×
2268
    Rii = @view R[irange, irange]
417✔
2269
    Rij = @view R[irange, j]
417✔
2270
    Rij[1] = r1
417✔
2271
    Rij[2] = r2
417✔
2272
    @views _sylvester_2x1!(Rii, R[j, j], Rij)
417✔
2273
    return R
417✔
2274
end
2275

2276
Base.@propagate_inbounds function _sqrt_quasitriu_offdiag_block_2x2!(R, A, i, j)
414✔
2277
    irange = i:(i + 1)
414✔
2278
    jrange = j:(j + 1)
414✔
2279
    t = eltype(R)
414✔
2280
    tt = typeof(zero(t)*zero(t))
414✔
2281
    for i′ in irange, j′ in jrange
1,242✔
2282
        Cij = tt(-A[i′, j′])
1,656✔
2283
        @simd for k in (i + 2):(j - 1)
2,332✔
2284
            Cij += R[i′, k] * R[k, j′]
3,464✔
2285
        end
×
2286
        R[i′, j′] = Cij
1,656✔
2287
    end
2,070✔
2288
    Rii = @view R[irange, irange]
414✔
2289
    Rjj = @view R[jrange, jrange]
414✔
2290
    Rij = @view R[irange, jrange]
414✔
2291
    if !iszero(Rij) && !all(isnan, Rij)
414✔
2292
        _sylvester_2x2!(Rii, Rjj, Rij)
411✔
2293
    end
2294
    return R
414✔
2295
end
2296

2297
# solve Sylvester's equation AX + XB = -C using blockwise recursion until the dimension of
2298
# A and B are no greater than blockwidth, based on Algorithm 1 from
2299
# Jonsson I, Kågström B. Recursive blocked algorithms for solving triangular systems—
2300
# Part I: one-sided and coupled Sylvester-type matrix equations. (2002) ACM Trans Math Softw.
2301
# 28(4), https://doi.org/10.1145/592843.592845.
2302
# specify raise=false to avoid breaking the recursion if a LAPACKException is thrown when
2303
# computing one of the blocks.
2304
function _sylvester_quasitriu!(A, B, C; blockwidth=64, nA=checksquare(A), nB=checksquare(B), raise=true)
1,154✔
2305
    if 1 ≤ nA ≤ blockwidth && 1 ≤ nB ≤ blockwidth
539✔
2306
        _sylvester_quasitriu_base!(A, B, C; raise=raise)
398✔
2307
    elseif nA ≥ 2nB ≥ 2
141✔
2308
        _sylvester_quasitriu_split1!(A, B, C; blockwidth=blockwidth, nA=nA, nB=nB, raise=raise)
12✔
2309
    elseif nB ≥ 2nA ≥ 2
129✔
2310
        _sylvester_quasitriu_split2!(A, B, C; blockwidth=blockwidth, nA=nA, nB=nB, raise=raise)
12✔
2311
    else
2312
        _sylvester_quasitriu_splitall!(A, B, C; blockwidth=blockwidth, nA=nA, nB=nB, raise=raise)
117✔
2313
    end
2314
    return C
499✔
2315
end
2316
function _sylvester_quasitriu_base!(A, B, C; raise=true)
796✔
2317
    try
398✔
2318
        _, scale = LAPACK.trsyl!('N', 'N', A, B, C)
398✔
2319
        rmul!(C, -inv(scale))
398✔
2320
    catch e
2321
        if !(e isa LAPACKException) || raise
296✔
2322
            throw(e)
148✔
2323
        end
2324
    end
2325
    return C
382✔
2326
end
2327
function _sylvester_quasitriu_split1!(A, B, C; nA=checksquare(A), kwargs...)
24✔
2328
    iA = div(nA, 2)
12✔
2329
    iszero(A[iA + 1, iA]) || (iA += 1)  # don't split 2x2 diagonal block
12✔
2330
    rA1, rA2 = 1:iA, (iA + 1):nA
12✔
2331
    nA1, nA2 = iA, nA-iA
12✔
2332
    A11, A12, A22 = @views A[rA1,rA1], A[rA1,rA2], A[rA2,rA2]
12✔
2333
    C1, C2 = @views C[rA1,:], C[rA2,:]
12✔
2334
    _sylvester_quasitriu!(A22, B, C2; nA=nA2, kwargs...)
24✔
2335
    mul!(C1, A12, C2, true, true)
8✔
2336
    _sylvester_quasitriu!(A11, B, C1; nA=nA1, kwargs...)
16✔
2337
    return C
8✔
2338
end
2339
function _sylvester_quasitriu_split2!(A, B, C; nB=checksquare(B), kwargs...)
24✔
2340
    iB = div(nB, 2)
12✔
2341
    iszero(B[iB + 1, iB]) || (iB += 1)  # don't split 2x2 diagonal block
12✔
2342
    rB1, rB2 = 1:iB, (iB + 1):nB
12✔
2343
    nB1, nB2 = iB, nB-iB
12✔
2344
    B11, B12, B22 = @views B[rB1,rB1], B[rB1,rB2], B[rB2,rB2]
12✔
2345
    C1, C2 = @views C[:,rB1], C[:,rB2]
12✔
2346
    _sylvester_quasitriu!(A, B11, C1; nB=nB1, kwargs...)
24✔
2347
    mul!(C2, C1, B12, true, true)
8✔
2348
    _sylvester_quasitriu!(A, B22, C2; nB=nB2, kwargs...)
16✔
2349
    return C
8✔
2350
end
2351
function _sylvester_quasitriu_splitall!(A, B, C; nA=checksquare(A), nB=checksquare(B), kwargs...)
234✔
2352
    iA = div(nA, 2)
117✔
2353
    iszero(A[iA + 1, iA]) || (iA += 1)  # don't split 2x2 diagonal block
128✔
2354
    iB = div(nB, 2)
117✔
2355
    iszero(B[iB + 1, iB]) || (iB += 1)  # don't split 2x2 diagonal block
136✔
2356
    rA1, rA2 = 1:iA, (iA + 1):nA
117✔
2357
    nA1, nA2 = iA, nA-iA
117✔
2358
    rB1, rB2 = 1:iB, (iB + 1):nB
117✔
2359
    nB1, nB2 = iB, nB-iB
117✔
2360
    A11, A12, A22 = @views A[rA1,rA1], A[rA1,rA2], A[rA2,rA2]
117✔
2361
    B11, B12, B22 = @views B[rB1,rB1], B[rB1,rB2], B[rB2,rB2]
117✔
2362
    C11, C21, C12, C22 = @views C[rA1,rB1], C[rA2,rB1], C[rA1,rB2], C[rA2,rB2]
117✔
2363
    _sylvester_quasitriu!(A22, B11, C21; nA=nA2, nB=nB1, kwargs...)
129✔
2364
    mul!(C11, A12, C21, true, true)
101✔
2365
    _sylvester_quasitriu!(A11, B11, C11; nA=nA1, nB=nB1, kwargs...)
109✔
2366
    mul!(C22, C21, B12, true, true)
101✔
2367
    _sylvester_quasitriu!(A22, B22, C22; nA=nA2, nB=nB2, kwargs...)
109✔
2368
    mul!(C12, A12, C22, true, true)
101✔
2369
    mul!(C12, C11, B12, true, true)
101✔
2370
    _sylvester_quasitriu!(A11, B22, C12; nA=nA1, nB=nB2, kwargs...)
109✔
2371
    return C
101✔
2372
end
2373

2374
# End of auxiliary functions for matrix square root
2375

2376
# Generic eigensystems
2377
eigvals(A::AbstractTriangular) = diag(A)
100✔
2378
function eigvecs(A::AbstractTriangular{T}) where T
4✔
2379
    TT = promote_type(T, Float32)
4✔
2380
    if TT <: BlasFloat
4✔
2381
        return eigvecs(convert(AbstractMatrix{TT}, A))
4✔
2382
    else
2383
        throw(ArgumentError("eigvecs type $(typeof(A)) not supported. Please submit a pull request."))
×
2384
    end
2385
end
2386
det(A::UnitUpperTriangular{T}) where {T} = one(T)
7✔
2387
det(A::UnitLowerTriangular{T}) where {T} = one(T)
7✔
2388
logdet(A::UnitUpperTriangular{T}) where {T} = zero(T)
7✔
2389
logdet(A::UnitLowerTriangular{T}) where {T} = zero(T)
7✔
2390
logabsdet(A::UnitUpperTriangular{T}) where {T} = zero(T), one(T)
7✔
2391
logabsdet(A::UnitLowerTriangular{T}) where {T} = zero(T), one(T)
7✔
2392
det(A::UpperTriangular) = prod(diag(A.data))
259✔
2393
det(A::LowerTriangular) = prod(diag(A.data))
7✔
2394
function logabsdet(A::Union{UpperTriangular{T},LowerTriangular{T}}) where T
28✔
2395
    sgn = one(T)
28✔
2396
    abs_det = zero(real(T))
28✔
2397
    @inbounds for i in 1:size(A,1)
56✔
2398
        diag_i = A.data[i,i]
252✔
2399
        sgn *= sign(diag_i)
252✔
2400
        abs_det += log(abs(diag_i))
292✔
2401
    end
476✔
2402
    return abs_det, sgn
28✔
2403
end
2404

2405
eigen(A::AbstractTriangular) = Eigen(eigvals(A), eigvecs(A))
20✔
2406

2407
# Generic singular systems
2408
for func in (:svd, :svd!, :svdvals)
2409
    @eval begin
2410
        ($func)(A::AbstractTriangular; kwargs...) = ($func)(copyto!(similar(parent(A)), A); kwargs...)
112✔
2411
    end
2412
end
2413

2414
factorize(A::AbstractTriangular) = A
28✔
2415

2416
# disambiguation methods: /(Adjoint of AbsVec, <:AbstractTriangular)
2417
/(u::AdjointAbsVec, A::Union{LowerTriangular,UpperTriangular}) = adjoint(adjoint(A) \ u.parent)
×
2418
/(u::AdjointAbsVec, A::Union{UnitLowerTriangular,UnitUpperTriangular}) = adjoint(adjoint(A) \ u.parent)
×
2419
# disambiguation methods: /(Transpose of AbsVec, <:AbstractTriangular)
2420
/(u::TransposeAbsVec, A::Union{LowerTriangular,UpperTriangular}) = transpose(transpose(A) \ u.parent)
×
2421
/(u::TransposeAbsVec, A::Union{UnitLowerTriangular,UnitUpperTriangular}) = transpose(transpose(A) \ u.parent)
×
2422
# disambiguation methods: /(Transpose of AbsVec, Adj/Trans of <:AbstractTriangular)
2423
for (tritype, comptritype) in ((:LowerTriangular, :UpperTriangular),
2424
                               (:UnitLowerTriangular, :UnitUpperTriangular),
2425
                               (:UpperTriangular, :LowerTriangular),
2426
                               (:UnitUpperTriangular, :UnitLowerTriangular))
2427
    @eval /(u::TransposeAbsVec, A::$tritype{<:Any,<:Adjoint}) = transpose($comptritype(conj(parent(parent(A)))) \ u.parent)
×
2428
    @eval /(u::TransposeAbsVec, A::$tritype{<:Any,<:Transpose}) = transpose(transpose(A) \ u.parent)
×
2429
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc