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

JuliaLang / julia / #37527

pending completion
#37527

push

local

web-flow
make `IRShow.method_name` inferrable (#49607)

18 of 18 new or added lines in 3 files covered. (100.0%)

68710 of 81829 relevant lines covered (83.97%)

33068903.12 hits per line

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

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

3
# Bidiagonal matrices
4
struct Bidiagonal{T,V<:AbstractVector{T}} <: AbstractMatrix{T}
5
    dv::V      # diagonal
6
    ev::V      # sub/super diagonal
7
    uplo::Char # upper bidiagonal ('U') or lower ('L')
8
    function Bidiagonal{T,V}(dv, ev, uplo::AbstractChar) where {T,V<:AbstractVector{T}}
5,104✔
9
        require_one_based_indexing(dv, ev)
5,104✔
10
        if length(ev) != max(length(dv)-1, 0)
5,104✔
11
            throw(DimensionMismatch("length of diagonal vector is $(length(dv)), length of off-diagonal vector is $(length(ev))"))
16✔
12
        end
13
        (uplo != 'U' && uplo != 'L') && throw_uplo()
5,088✔
14
        new{T,V}(dv, ev, uplo)
5,064✔
15
    end
16
end
17
function Bidiagonal{T,V}(dv, ev, uplo::Symbol) where {T,V<:AbstractVector{T}}
2,725✔
18
    Bidiagonal{T,V}(dv, ev, char_uplo(uplo))
3,969✔
19
end
20
function Bidiagonal{T}(dv::AbstractVector, ev::AbstractVector, uplo::Union{Symbol,AbstractChar}) where {T}
56✔
21
    Bidiagonal(convert(AbstractVector{T}, dv)::AbstractVector{T},
64✔
22
               convert(AbstractVector{T}, ev)::AbstractVector{T},
23
               uplo)
24
end
25
function Bidiagonal{T,V}(A::Bidiagonal) where {T,V<:AbstractVector{T}}
48✔
26
    Bidiagonal{T,V}(A.dv, A.ev, A.uplo)
48✔
27
end
28

29
"""
30
    Bidiagonal(dv::V, ev::V, uplo::Symbol) where V <: AbstractVector
31

32
Constructs an upper (`uplo=:U`) or lower (`uplo=:L`) bidiagonal matrix using the
33
given diagonal (`dv`) and off-diagonal (`ev`) vectors. The result is of type `Bidiagonal`
34
and provides efficient specialized linear solvers, but may be converted into a regular
35
matrix with [`convert(Array, _)`](@ref) (or `Array(_)` for short). The length of `ev`
36
must be one less than the length of `dv`.
37

38
# Examples
39
```jldoctest
40
julia> dv = [1, 2, 3, 4]
41
4-element Vector{Int64}:
42
 1
43
 2
44
 3
45
 4
46

47
julia> ev = [7, 8, 9]
48
3-element Vector{Int64}:
49
 7
50
 8
51
 9
52

53
julia> Bu = Bidiagonal(dv, ev, :U) # ev is on the first superdiagonal
54
4×4 Bidiagonal{Int64, Vector{Int64}}:
55
 1  7  â‹…  â‹…
56
 â‹…  2  8  â‹…
57
 â‹…  â‹…  3  9
58
 â‹…  â‹…  â‹…  4
59

60
julia> Bl = Bidiagonal(dv, ev, :L) # ev is on the first subdiagonal
61
4×4 Bidiagonal{Int64, Vector{Int64}}:
62
 1  â‹…  â‹…  â‹…
63
 7  2  â‹…  â‹…
64
 â‹…  8  3  â‹…
65
 â‹…  â‹…  9  4
66
```
67
"""
68
function Bidiagonal(dv::V, ev::V, uplo::Symbol) where {T,V<:AbstractVector{T}}
77✔
69
    Bidiagonal{T,V}(dv, ev, uplo)
85✔
70
end
71
function Bidiagonal(dv::V, ev::V, uplo::AbstractChar) where {T,V<:AbstractVector{T}}
2,355✔
72
    Bidiagonal{T,V}(dv, ev, uplo)
2,355✔
73
end
74

75
#To allow Bidiagonal's where the "dv" is Vector{T} and "ev" Vector{S},
76
#where T and S can be promoted
77
function Bidiagonal(dv::Vector{T}, ev::Vector{S}, uplo::Symbol) where {T,S}
2,640✔
78
    TS = promote_type(T,S)
2,640✔
79
    return Bidiagonal{TS,Vector{TS}}(dv, ev, uplo)
3,320✔
80
end
81

82
"""
83
    Bidiagonal(A, uplo::Symbol)
84

85
Construct a `Bidiagonal` matrix from the main diagonal of `A` and
86
its first super- (if `uplo=:U`) or sub-diagonal (if `uplo=:L`).
87

88
# Examples
89
```jldoctest
90
julia> A = [1 1 1 1; 2 2 2 2; 3 3 3 3; 4 4 4 4]
91
4×4 Matrix{Int64}:
92
 1  1  1  1
93
 2  2  2  2
94
 3  3  3  3
95
 4  4  4  4
96

97
julia> Bidiagonal(A, :U) # contains the main diagonal and first superdiagonal of A
98
4×4 Bidiagonal{Int64, Vector{Int64}}:
99
 1  1  â‹…  â‹…
100
 â‹…  2  2  â‹…
101
 â‹…  â‹…  3  3
102
 â‹…  â‹…  â‹…  4
103

104
julia> Bidiagonal(A, :L) # contains the main diagonal and first subdiagonal of A
105
4×4 Bidiagonal{Int64, Vector{Int64}}:
106
 1  â‹…  â‹…  â‹…
107
 2  2  â‹…  â‹…
108
 â‹…  3  3  â‹…
109
 â‹…  â‹…  4  4
110
```
111
"""
112
function Bidiagonal(A::AbstractMatrix, uplo::Symbol)
232✔
113
    Bidiagonal(diag(A, 0), diag(A, uplo === :U ? 1 : -1), uplo)
232✔
114
end
115

116

117
Bidiagonal(A::Bidiagonal) = A
12✔
118
Bidiagonal{T}(A::Bidiagonal{T}) where {T} = A
1✔
119
Bidiagonal{T}(A::Bidiagonal) where {T} = Bidiagonal{T}(A.dv, A.ev, A.uplo)
11✔
120

121
bidiagzero(::Bidiagonal{T}, i, j) where {T} = zero(T)
238,813✔
122
function bidiagzero(A::Bidiagonal{<:AbstractMatrix}, i, j)
74✔
123
    Tel = eltype(eltype(A.dv))
74✔
124
    if i < j && A.uplo == 'U' #= top right zeros =#
74✔
125
        return zeros(Tel, size(A.ev[i], 1), size(A.ev[j-1], 2))
9✔
126
    elseif j < i && A.uplo == 'L' #= bottom left zeros =#
65✔
127
        return zeros(Tel, size(A.ev[i-1], 1), size(A.ev[j], 2))
17✔
128
    else
129
        return zeros(Tel, size(A.dv[i], 1), size(A.dv[j], 2))
48✔
130
    end
131
end
132

133
@inline function getindex(A::Bidiagonal{T}, i::Integer, j::Integer) where T
333,677✔
134
    @boundscheck checkbounds(A, i, j)
333,694✔
135
    if i == j
333,660✔
136
        return @inbounds A.dv[i]
51,253✔
137
    elseif A.uplo == 'U' && (i == j - 1)
282,407✔
138
        return @inbounds A.ev[i]
23,224✔
139
    elseif A.uplo == 'L' && (i == j + 1)
259,183✔
140
        return @inbounds A.ev[j]
20,296✔
141
    else
142
        return bidiagzero(A, i, j)
238,887✔
143
    end
144
end
145

146
@inline function setindex!(A::Bidiagonal, x, i::Integer, j::Integer)
12,468✔
147
    @boundscheck checkbounds(A, i, j)
12,485✔
148
    if i == j
12,451✔
149
        @inbounds A.dv[i] = x
3,754✔
150
    elseif A.uplo == 'U' && (i == j - 1)
8,697✔
151
        @inbounds A.ev[i] = x
1,596✔
152
    elseif A.uplo == 'L' && (i == j + 1)
7,101✔
153
        @inbounds A.ev[j] = x
1,580✔
154
    elseif !iszero(x)
5,521✔
155
        throw(ArgumentError(string("cannot set entry ($i, $j) off the ",
53✔
156
            "$(istriu(A) ? "upper" : "lower") bidiagonal band to a nonzero value ($x)")))
157
    end
158
    return x
12,398✔
159
end
160

161
## structured matrix methods ##
162
function Base.replace_in_print_matrix(A::Bidiagonal,i::Integer,j::Integer,s::AbstractString)
32✔
163
    if A.uplo == 'U'
32✔
164
        i==j || i==j-1 ? s : Base.replace_with_centered_mark(s)
16✔
165
    else
166
        i==j || i==j+1 ? s : Base.replace_with_centered_mark(s)
16✔
167
    end
168
end
169

170
#Converting from Bidiagonal to dense Matrix
171
function Matrix{T}(A::Bidiagonal) where T
3,728✔
172
    n = size(A, 1)
3,728✔
173
    B = zeros(T, n, n)
207,077✔
174
    n == 0 && return B
3,728✔
175
    @inbounds for i = 1:n - 1
7,404✔
176
        B[i,i] = A.dv[i]
21,821✔
177
        if A.uplo == 'U'
21,821✔
178
            B[i,i+1] = A.ev[i]
11,181✔
179
        else
180
            B[i+1,i] = A.ev[i]
10,642✔
181
        end
182
    end
39,948✔
183
    B[n,n] = A.dv[n]
3,710✔
184
    return B
3,710✔
185
end
186
Matrix(A::Bidiagonal{T}) where {T} = Matrix{promote_type(T, typeof(zero(T)))}(A)
3,697✔
187
Array(A::Bidiagonal) = Matrix(A)
472✔
188
promote_rule(::Type{Matrix{T}}, ::Type{<:Bidiagonal{S}}) where {T,S} =
6✔
189
    @isdefined(T) && @isdefined(S) ? Matrix{promote_type(T,S)} : Matrix
190
promote_rule(::Type{Matrix}, ::Type{<:Bidiagonal}) = Matrix
×
191

192
#Converting from Bidiagonal to Tridiagonal
193
function Tridiagonal{T}(A::Bidiagonal) where T
2✔
194
    dv = convert(AbstractVector{T}, A.dv)
2✔
195
    ev = convert(AbstractVector{T}, A.ev)
2✔
196
    z = fill!(similar(ev), zero(T))
18✔
197
    A.uplo == 'U' ? Tridiagonal(z, dv, ev) : Tridiagonal(ev, dv, z)
2✔
198
end
199
promote_rule(::Type{<:Tridiagonal{T}}, ::Type{<:Bidiagonal{S}}) where {T,S} =
5✔
200
    @isdefined(T) && @isdefined(S) ? Tridiagonal{promote_type(T,S)} : Tridiagonal
201
promote_rule(::Type{<:Tridiagonal}, ::Type{<:Bidiagonal}) = Tridiagonal
×
202

203
# When asked to convert Bidiagonal to AbstractMatrix{T}, preserve structure by converting to Bidiagonal{T} <: AbstractMatrix{T}
204
AbstractMatrix{T}(A::Bidiagonal) where {T} = convert(Bidiagonal{T}, A)
4✔
205

206
convert(::Type{T}, m::AbstractMatrix) where {T<:Bidiagonal} = m isa T ? m : T(m)::T
49✔
207

208
similar(B::Bidiagonal, ::Type{T}) where {T} = Bidiagonal(similar(B.dv, T), similar(B.ev, T), B.uplo)
522✔
209
similar(B::Bidiagonal, ::Type{T}, dims::Union{Dims{1},Dims{2}}) where {T} = similar(B.dv, T, dims)
1,194✔
210

211
tr(B::Bidiagonal) = sum(B.dv)
33✔
212

213
function kron(A::Diagonal, B::Bidiagonal)
×
214
    # `_droplast!` is only guaranteed to work with `Vector`
215
    kdv = _makevector(kron(diag(A), B.dv))
×
216
    kev = _droplast!(_makevector(kron(diag(A), _pushzero(B.ev))))
×
217
    Bidiagonal(kdv, kev, B.uplo)
×
218
end
219

220
###################
221
# LAPACK routines #
222
###################
223

224
#Singular values
225
svdvals!(M::Bidiagonal{<:BlasReal}) = LAPACK.bdsdc!(M.uplo, 'N', M.dv, M.ev)[1]
×
226
function svd!(M::Bidiagonal{<:BlasReal}; full::Bool = false)
24✔
227
    d, e, U, Vt, Q, iQ = LAPACK.bdsdc!(M.uplo, 'I', M.dv, M.ev)
12✔
228
    SVD(U, d, Vt)
12✔
229
end
230
function svd(M::Bidiagonal; kw...)
24✔
231
    svd!(copy(M), kw...)
12✔
232
end
233

234
####################
235
# Generic routines #
236
####################
237

238
function show(io::IO, M::Bidiagonal)
16✔
239
    # TODO: make this readable and one-line
240
    summary(io, M)
16✔
241
    print(io, ":\n diag:")
16✔
242
    print_matrix(io, (M.dv)')
16✔
243
    print(io, M.uplo == 'U' ? "\n super:" : "\n sub:")
16✔
244
    print_matrix(io, (M.ev)')
16✔
245
end
246

247
size(M::Bidiagonal) = (length(M.dv), length(M.dv))
372,961✔
248
function size(M::Bidiagonal, d::Integer)
16,877✔
249
    if d < 1
16,877✔
250
        throw(ArgumentError("dimension must be ≥ 1, got $d"))
8✔
251
    elseif d <= 2
16,869✔
252
        return length(M.dv)
16,861✔
253
    else
254
        return 1
8✔
255
    end
256
end
257

258
#Elementary operations
259
for func in (:conj, :copy, :real, :imag)
260
    @eval ($func)(M::Bidiagonal) = Bidiagonal(($func)(M.dv), ($func)(M.ev), M.uplo)
111✔
261
end
262

263
adjoint(B::Bidiagonal) = Adjoint(B)
18✔
264
transpose(B::Bidiagonal) = Transpose(B)
18✔
265
adjoint(B::Bidiagonal{<:Number}) = Bidiagonal(conj(B.dv), conj(B.ev), B.uplo == 'U' ? :L : :U)
407✔
266
transpose(B::Bidiagonal{<:Number}) = Bidiagonal(B.dv, B.ev, B.uplo == 'U' ? :L : :U)
422✔
267
permutedims(B::Bidiagonal) = Bidiagonal(B.dv, B.ev, B.uplo == 'U' ? 'L' : 'U')
80✔
268
function permutedims(B::Bidiagonal, perm)
32✔
269
    Base.checkdims_perm(B, B, perm)
32✔
270
    NTuple{2}(perm) == (2, 1) ? permutedims(B) : B
32✔
271
end
272
function Base.copy(aB::Adjoint{<:Any,<:Bidiagonal})
18✔
273
    B = aB.parent
18✔
274
    return Bidiagonal(map(x -> copy.(adjoint.(x)), (B.dv, B.ev))..., B.uplo == 'U' ? :L : :U)
54✔
275
end
276
function Base.copy(tB::Transpose{<:Any,<:Bidiagonal})
17✔
277
    B = tB.parent
17✔
278
    return Bidiagonal(map(x -> copy.(transpose.(x)), (B.dv, B.ev))..., B.uplo == 'U' ? :L : :U)
51✔
279
end
280

281
iszero(M::Bidiagonal) = iszero(M.dv) && iszero(M.ev)
109✔
282
isone(M::Bidiagonal) = all(isone, M.dv) && iszero(M.ev)
108✔
283
function istriu(M::Bidiagonal, k::Integer=0)
354✔
284
    if M.uplo == 'U'
354✔
285
        if k <= 0
144✔
286
            return true
80✔
287
        elseif k == 1
64✔
288
            return iszero(M.dv)
32✔
289
        else # k >= 2
290
            return iszero(M.dv) && iszero(M.ev)
32✔
291
        end
292
    else # M.uplo == 'L'
293
        if k <= -1
109✔
294
            return true
19✔
295
        elseif k == 0
90✔
296
            return iszero(M.ev)
42✔
297
        else # k >= 1
298
            return iszero(M.ev) && iszero(M.dv)
48✔
299
        end
300
    end
301
end
302
function istril(M::Bidiagonal, k::Integer=0)
234✔
303
    if M.uplo == 'U'
234✔
304
        if k >= 1
86✔
305
            return true
21✔
306
        elseif k == 0
65✔
307
            return iszero(M.ev)
17✔
308
        else # k <= -1
309
            return iszero(M.ev) && iszero(M.dv)
48✔
310
        end
311
    else # M.uplo == 'L'
312
        if k >= 0
107✔
313
            return true
43✔
314
        elseif k == -1
64✔
315
            return iszero(M.dv)
32✔
316
        else # k <= -2
317
            return iszero(M.dv) && iszero(M.ev)
32✔
318
        end
319
    end
320
end
321
isdiag(M::Bidiagonal) = iszero(M.ev)
69✔
322

323
function tril!(M::Bidiagonal{T}, k::Integer=0) where T
196✔
324
    n = length(M.dv)
196✔
325
    if !(-n - 1 <= k <= n - 1)
163✔
326
        throw(ArgumentError(string("the requested diagonal, $k, must be at least ",
33✔
327
            "$(-n - 1) and at most $(n - 1) in an $n-by-$n matrix")))
328
    elseif M.uplo == 'U' && k < 0
130✔
329
        fill!(M.dv, zero(T))
321✔
330
        fill!(M.ev, zero(T))
289✔
331
    elseif k < -1
97✔
332
        fill!(M.dv, zero(T))
160✔
333
        fill!(M.ev, zero(T))
16✔
334
    elseif M.uplo == 'U' && k == 0
81✔
335
        fill!(M.ev, zero(T))
16✔
336
    elseif M.uplo == 'L' && k == -1
65✔
337
        fill!(M.dv, zero(T))
17✔
338
    end
339
    return M
130✔
340
end
341

342
function triu!(M::Bidiagonal{T}, k::Integer=0) where T
196✔
343
    n = length(M.dv)
196✔
344
    if !(-n + 1 <= k <= n + 1)
163✔
345
        throw(ArgumentError(string("the requested diagonal, $k, must be at least",
33✔
346
            "$(-n + 1) and at most $(n + 1) in an $n-by-$n matrix")))
347
    elseif M.uplo == 'L' && k > 0
130✔
348
        fill!(M.dv, zero(T))
321✔
349
        fill!(M.ev, zero(T))
289✔
350
    elseif k > 1
97✔
351
        fill!(M.dv, zero(T))
160✔
352
        fill!(M.ev, zero(T))
16✔
353
    elseif M.uplo == 'L' && k == 0
81✔
354
        fill!(M.ev, zero(T))
16✔
355
    elseif M.uplo == 'U' && k == 1
65✔
356
        fill!(M.dv, zero(T))
17✔
357
    end
358
    return M
130✔
359
end
360

361
function diag(M::Bidiagonal{T}, n::Integer=0) where T
2,751✔
362
    # every branch call similar(..., ::Int) to make sure the
363
    # same vector type is returned independent of n
364
    if n == 0
2,751✔
365
        return copyto!(similar(M.dv, length(M.dv)), M.dv)
89✔
366
    elseif (n == 1 && M.uplo == 'U') ||  (n == -1 && M.uplo == 'L')
5,211✔
367
        return copyto!(similar(M.ev, length(M.ev)), M.ev)
85✔
368
    elseif -size(M,1) <= n <= size(M,1)
2,542✔
369
        return fill!(similar(M.dv, size(M,1)-abs(n)), zero(T))
2,510✔
370
    else
371
        throw(ArgumentError(string("requested diagonal, $n, must be at least $(-size(M, 1)) ",
32✔
372
            "and at most $(size(M, 2)) for an $(size(M, 1))-by-$(size(M, 2)) matrix")))
373
    end
374
end
375

376
function +(A::Bidiagonal, B::Bidiagonal)
243✔
377
    if A.uplo == B.uplo || length(A.dv) == 0
364✔
378
        Bidiagonal(A.dv+B.dv, A.ev+B.ev, A.uplo)
123✔
379
    else
380
        newdv = A.dv+B.dv
120✔
381
        Tridiagonal((A.uplo == 'U' ? (typeof(newdv)(B.ev), newdv, typeof(newdv)(A.ev)) : (typeof(newdv)(A.ev), newdv, typeof(newdv)(B.ev)))...)
120✔
382
    end
383
end
384

385
function -(A::Bidiagonal, B::Bidiagonal)
241✔
386
    if A.uplo == B.uplo || length(A.dv) == 0
361✔
387
        Bidiagonal(A.dv-B.dv, A.ev-B.ev, A.uplo)
121✔
388
    else
389
        newdv = A.dv-B.dv
120✔
390
        Tridiagonal((A.uplo == 'U' ? (typeof(newdv)(-B.ev), newdv, typeof(newdv)(A.ev)) : (typeof(newdv)(A.ev), newdv, typeof(newdv)(-B.ev)))...)
120✔
391
    end
392
end
393

394
-(A::Bidiagonal)=Bidiagonal(-A.dv,-A.ev,A.uplo)
25✔
395
*(A::Bidiagonal, B::Number) = Bidiagonal(A.dv*B, A.ev*B, A.uplo)
50✔
396
*(B::Number, A::Bidiagonal) = Bidiagonal(B*A.dv, B*A.ev, A.uplo)
51✔
397
/(A::Bidiagonal, B::Number) = Bidiagonal(A.dv/B, A.ev/B, A.uplo)
49✔
398
\(B::Number, A::Bidiagonal) = Bidiagonal(B\A.dv, B\A.ev, A.uplo)
33✔
399

400
function ==(A::Bidiagonal, B::Bidiagonal)
727✔
401
    if A.uplo == B.uplo
727✔
402
        return A.dv == B.dv && A.ev == B.ev
684✔
403
    else
404
        return iszero(A.ev) && iszero(B.ev) && A.dv == B.dv
43✔
405
    end
406
end
407

408
const BiTriSym = Union{Bidiagonal,Tridiagonal,SymTridiagonal}
409
const BiTri = Union{Bidiagonal,Tridiagonal}
410
@inline mul!(C::AbstractVector, A::BiTriSym, B::AbstractVector, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
456✔
411
@inline mul!(C::AbstractMatrix, A::BiTriSym, B::AbstractMatrix, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
2,814✔
412
@inline mul!(C::AbstractMatrix, A::BiTriSym, B::Transpose{<:Any,<:AbstractVecOrMat}, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
32✔
413
@inline mul!(C::AbstractMatrix, A::BiTriSym, B::Adjoint{<:Any,<:AbstractVecOrMat}, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
32✔
414
@inline mul!(C::AbstractMatrix, A::BiTriSym, B::Diagonal, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
368✔
415
@inline mul!(C::AbstractMatrix, A::AbstractMatrix, B::BiTriSym, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
1,210✔
416
@inline mul!(C::AbstractMatrix, A::Adjoint{<:Any,<:AbstractVecOrMat}, B::BiTriSym, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
1✔
417
@inline mul!(C::AbstractMatrix, A::Transpose{<:Any,<:AbstractVecOrMat}, B::BiTriSym, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
×
418
@inline mul!(C::AbstractMatrix, A::BiTriSym, B::BiTriSym, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
1,377✔
419
@inline mul!(C::AbstractMatrix, A::Diagonal, B::BiTriSym, alpha::Number, beta::Number) = _mul!(C, A, B, MulAddMul(alpha, beta))
432✔
420

421
function check_A_mul_B!_sizes(C, A, B)
3,382✔
422
    mA, nA = size(A)
3,382✔
423
    mB, nB = size(B)
3,382✔
424
    mC, nC = size(C)
3,382✔
425
    if mA != mC
3,382✔
426
        throw(DimensionMismatch("first dimension of A, $mA, and first dimension of output C, $mC, must match"))
×
427
    elseif nA != mB
3,382✔
428
        throw(DimensionMismatch("second dimension of A, $nA, and first dimension of B, $mB, must match"))
3✔
429
    elseif nB != nC
3,379✔
430
        throw(DimensionMismatch("second dimension of output C, $nC, and second dimension of B, $nB, must match"))
×
431
    end
432
end
433

434
# function to get the internally stored vectors for Bidiagonal and [Sym]Tridiagonal
435
# to avoid allocations in _mul! below (#24324, #24578)
436
_diag(A::Tridiagonal, k) = k == -1 ? A.dl : k == 0 ? A.d : A.du
5,472✔
437
_diag(A::SymTridiagonal, k) = k == 0 ? A.dv : A.ev
2,532✔
438
function _diag(A::Bidiagonal, k)
7,428✔
439
    if k == 0
7,428✔
440
        return A.dv
2,476✔
441
    elseif (A.uplo == 'L' && k == -1) || (A.uplo == 'U' && k == 1)
6,206✔
442
        return A.ev
2,476✔
443
    else
444
        return diag(A, k)
2,476✔
445
    end
446
end
447

448
function _mul!(C::AbstractMatrix, A::BiTriSym, B::BiTriSym, _add::MulAddMul = MulAddMul())
1,377✔
449
    check_A_mul_B!_sizes(C, A, B)
1,377✔
450
    n = size(A,1)
1,375✔
451
    n <= 3 && return mul!(C, Array(A), Array(B), _add.alpha, _add.beta)
1,375✔
452
    # We use `_rmul_or_fill!` instead of `_modify!` here since using
453
    # `_modify!` in the following loop will not update the
454
    # off-diagonal elements for non-zero beta.
455
    _rmul_or_fill!(C, _add.beta)
2,676✔
456
    iszero(_add.alpha) && return C
1,338✔
457
    Al = _diag(A, -1)
1,670✔
458
    Ad = _diag(A, 0)
1,338✔
459
    Au = _diag(A, 1)
1,662✔
460
    Bl = _diag(B, -1)
1,678✔
461
    Bd = _diag(B, 0)
1,338✔
462
    Bu = _diag(B, 1)
1,670✔
463
    @inbounds begin
1,338✔
464
        # first row of C
465
        C[1,1] += _add(A[1,1]*B[1,1] + A[1, 2]*B[2, 1])
2,548✔
466
        C[1,2] += _add(A[1,1]*B[1,2] + A[1,2]*B[2,2])
1,498✔
467
        C[1,3] += _add(A[1,2]*B[2,3])
2,548✔
468
        # second row of C
469
        C[2,1] += _add(A[2,1]*B[1,1] + A[2,2]*B[2,1])
2,548✔
470
        C[2,2] += _add(A[2,1]*B[1,2] + A[2,2]*B[2,2] + A[2,3]*B[3,2])
2,548✔
471
        C[2,3] += _add(A[2,2]*B[2,3] + A[2,3]*B[3,3])
1,498✔
472
        C[2,4] += _add(A[2,3]*B[3,4])
2,548✔
473
        for j in 3:n-2
2,652✔
474
            Ajjâ‚‹1   = Al[j-1]
4,304✔
475
            Ajj     = Ad[j]
4,304✔
476
            Ajj₊1   = Au[j]
4,304✔
477
            Bjâ‚‹1jâ‚‹2 = Bl[j-2]
4,304✔
478
            Bjâ‚‹1jâ‚‹1 = Bd[j-1]
4,304✔
479
            Bjâ‚‹1j   = Bu[j-1]
4,304✔
480
            Bjjâ‚‹1   = Bl[j-1]
4,304✔
481
            Bjj     = Bd[j]
4,304✔
482
            Bjj₊1   = Bu[j]
4,304✔
483
            Bj₊1j   = Bl[j]
4,304✔
484
            Bj₊1j₊1 = Bd[j+1]
4,304✔
485
            Bj₊1j₊2 = Bu[j+1]
4,304✔
486
            C[j,j-2]  += _add( Ajjâ‚‹1*Bjâ‚‹1jâ‚‹2)
4,464✔
487
            C[j, j-1] += _add(Ajjâ‚‹1*Bjâ‚‹1jâ‚‹1 + Ajj*Bjjâ‚‹1)
4,464✔
488
            C[j, j  ] += _add(Ajj₋1*Bj₋1j   + Ajj*Bjj       + Ajj₊1*Bj₊1j)
4,464✔
489
            C[j, j+1] += _add(Ajj  *Bjj₊1   + Ajj₊1*Bj₊1j₊1)
4,464✔
490
            C[j, j+2] += _add(Ajj₊1*Bj₊1j₊2)
4,464✔
491
        end
7,294✔
492
        # row before last of C
493
        C[n-1,n-3] += _add(A[n-1,n-2]*B[n-2,n-3])
2,548✔
494
        C[n-1,n-2] += _add(A[n-1,n-1]*B[n-1,n-2] + A[n-1,n-2]*B[n-2,n-2])
1,498✔
495
        C[n-1,n-1] += _add(A[n-1,n-2]*B[n-2,n-1] + A[n-1,n-1]*B[n-1,n-1] + A[n-1,n]*B[n,n-1])
2,548✔
496
        C[n-1,n  ] += _add(A[n-1,n-1]*B[n-1,n  ] + A[n-1,  n]*B[n  ,n  ])
1,498✔
497
        # last row of C
498
        C[n,n-2] += _add(A[n,n-1]*B[n-1,n-2])
2,548✔
499
        C[n,n-1] += _add(A[n,n-1]*B[n-1,n-1] + A[n,n]*B[n,n-1])
2,548✔
500
        C[n,n  ] += _add(A[n,n-1]*B[n-1,n  ] + A[n,n]*B[n,n  ])
1,498✔
501
    end # inbounds
502
    C
1,338✔
503
end
504

505
function _mul!(C::AbstractMatrix, A::BiTriSym, B::Diagonal, _add::MulAddMul = MulAddMul())
368✔
506
    require_one_based_indexing(C)
368✔
507
    check_A_mul_B!_sizes(C, A, B)
368✔
508
    n = size(A,1)
368✔
509
    iszero(n) && return C
368✔
510
    n <= 3 && return mul!(C, Array(A), Array(B), _add.alpha, _add.beta)
368✔
511
    _rmul_or_fill!(C, _add.beta)  # see the same use above
736✔
512
    iszero(_add.alpha) && return C
368✔
513
    Al = _diag(A, -1)
476✔
514
    Ad = _diag(A, 0)
368✔
515
    Au = _diag(A, 1)
460✔
516
    Bd = B.diag
368✔
517
    @inbounds begin
368✔
518
        # first row of C
519
        C[1,1] += _add(A[1,1]*B[1,1])
368✔
520
        C[1,2] += _add(A[1,2]*B[2,2])
736✔
521
        # second row of C
522
        C[2,1] += _add(A[2,1]*B[1,1])
736✔
523
        C[2,2] += _add(A[2,2]*B[2,2])
368✔
524
        C[2,3] += _add(A[2,3]*B[3,3])
736✔
525
        for j in 3:n-2
736✔
526
            C[j, j-1] += _add(Al[j-1]*Bd[j-1])
2,576✔
527
            C[j, j  ] += _add(Ad[j  ]*Bd[j  ])
1,288✔
528
            C[j, j+1] += _add(Au[j  ]*Bd[j+1])
2,576✔
529
        end
2,208✔
530
        # row before last of C
531
        C[n-1,n-2] += _add(A[n-1,n-2]*B[n-2,n-2])
736✔
532
        C[n-1,n-1] += _add(A[n-1,n-1]*B[n-1,n-1])
368✔
533
        C[n-1,n  ] += _add(A[n-1,  n]*B[n  ,n  ])
736✔
534
        # last row of C
535
        C[n,n-1] += _add(A[n,n-1]*B[n-1,n-1])
736✔
536
        C[n,n  ] += _add(A[n,n  ]*B[n,  n  ])
368✔
537
    end # inbounds
538
    C
368✔
539
end
540

541
function _mul!(C::AbstractVecOrMat, A::BiTriSym, B::AbstractVecOrMat, _add::MulAddMul = MulAddMul())
3,334✔
542
    require_one_based_indexing(C, B)
3,334✔
543
    nA = size(A,1)
3,334✔
544
    nB = size(B,2)
3,334✔
545
    if !(size(C,1) == size(B,1) == nA)
3,334✔
546
        throw(DimensionMismatch("A has first dimension $nA, B has $(size(B,1)), C has $(size(C,1)) but all must match"))
31✔
547
    end
548
    if size(C,2) != nB
3,303✔
549
        throw(DimensionMismatch("A has second dimension $nA, B has $(size(B,2)), C has $(size(C,2)) but all must match"))
21✔
550
    end
551
    iszero(nA) && return C
3,282✔
552
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
3,281✔
553
    nA <= 3 && return mul!(C, Array(A), Array(B), _add.alpha, _add.beta)
3,281✔
554
    l = _diag(A, -1)
1,608✔
555
    d = _diag(A, 0)
1,318✔
556
    u = _diag(A, 1)
1,600✔
557
    @inbounds begin
1,318✔
558
        for j = 1:nB
2,599✔
559
            b₀, b₊ = B[1, j], B[2, j]
10,064✔
560
            _modify!(_add, d[1]*b₀ + u[1]*b₊, C, (1, j))
8,484✔
561
            for i = 2:nA - 1
16,968✔
562
                b₋, b₀, b₊ = b₀, b₊, B[i + 1, j]
68,542✔
563
                _modify!(_add, l[i - 1]*b₋ + d[i]*b₀ + u[i]*b₊, C, (i, j))
58,990✔
564
            end
109,496✔
565
            _modify!(_add, l[nA - 1]*b₀ + d[nA]*b₊, C, (nA, j))
8,484✔
566
        end
15,650✔
567
    end
568
    C
1,318✔
569
end
570

571
function _mul!(C::AbstractMatrix, A::AbstractMatrix, B::BiTriSym, _add::MulAddMul = MulAddMul())
1,205✔
572
    require_one_based_indexing(C, A)
1,205✔
573
    check_A_mul_B!_sizes(C, A, B)
1,205✔
574
    iszero(_add.alpha) && return _rmul_or_fill!(C, _add.beta)
1,204✔
575
    n = size(A,1)
1,141✔
576
    m = size(B,2)
1,141✔
577
    if n <= 3 || m <= 1
1,492✔
578
        return mul!(C, Array(A), Array(B), _add.alpha, _add.beta)
791✔
579
    end
580
    Bl = _diag(B, -1)
410✔
581
    Bd = _diag(B, 0)
350✔
582
    Bu = _diag(B, 1)
402✔
583
    @inbounds begin
350✔
584
        # first and last column of C
585
        B11 = Bd[1]
350✔
586
        B21 = Bl[1]
350✔
587
        Bmm = Bd[m]
350✔
588
        Bmâ‚‹1m = Bu[m-1]
350✔
589
        for i in 1:n
700✔
590
            _modify!(_add, A[i,1] * B11 + A[i, 2] * B21, C, (i, 1))
3,354✔
591
            _modify!(_add, A[i, m-1] * Bmâ‚‹1m + A[i, m] * Bmm, C, (i, m))
3,408✔
592
        end
6,034✔
593
        # middle columns of C
594
        for j = 2:m-1
700✔
595
            Bjâ‚‹1j = Bu[j-1]
2,616✔
596
            Bjj = Bd[j]
2,616✔
597
            Bj₊1j = Bl[j]
2,616✔
598
            for i = 1:n
5,232✔
599
                _modify!(_add, A[i, j-1] * Bj₋1j + A[i, j]*Bjj + A[i, j+1] * Bj₊1j, C, (i, j))
27,246✔
600
            end
48,840✔
601
        end
4,882✔
602
    end # inbounds
603
    C
350✔
604
end
605

606
function _mul!(C::AbstractMatrix, A::Diagonal, B::BiTriSym, _add::MulAddMul = MulAddMul())
432✔
607
    require_one_based_indexing(C)
432✔
608
    check_A_mul_B!_sizes(C, A, B)
432✔
609
    n = size(A,1)
432✔
610
    n <= 3 && return mul!(C, Array(A), Array(B), _add.alpha, _add.beta)
432✔
611
    _rmul_or_fill!(C, _add.beta)  # see the same use above
864✔
612
    iszero(_add.alpha) && return C
432✔
613
    Ad = A.diag
432✔
614
    Bl = _diag(B, -1)
556✔
615
    Bd = _diag(B, 0)
432✔
616
    Bu = _diag(B, 1)
572✔
617
    @inbounds begin
432✔
618
        # first row of C
619
        C[1,1] += _add(A[1,1]*B[1,1])
432✔
620
        C[1,2] += _add(A[1,1]*B[1,2])
852✔
621
        # second row of C
622
        C[2,1] += _add(A[2,2]*B[2,1])
852✔
623
        C[2,2] += _add(A[2,2]*B[2,2])
432✔
624
        C[2,3] += _add(A[2,2]*B[2,3])
852✔
625
        for j in 3:n-2
864✔
626
            Ajj       = Ad[j]
1,672✔
627
            C[j, j-1] += _add(Ajj*Bl[j-1])
3,056✔
628
            C[j, j  ] += _add(Ajj*Bd[j])
1,672✔
629
            C[j, j+1] += _add(Ajj*Bu[j])
3,056✔
630
        end
2,912✔
631
        # row before last of C
632
        C[n-1,n-2] += _add(A[n-1,n-1]*B[n-1,n-2])
852✔
633
        C[n-1,n-1] += _add(A[n-1,n-1]*B[n-1,n-1])
432✔
634
        C[n-1,n  ] += _add(A[n-1,n-1]*B[n-1,n  ])
852✔
635
        # last row of C
636
        C[n,n-1] += _add(A[n,n]*B[n,n-1])
852✔
637
        C[n,n  ] += _add(A[n,n]*B[n,n  ])
432✔
638
    end # inbounds
639
    C
432✔
640
end
641

642
function *(A::UpperOrUnitUpperTriangular, B::Bidiagonal)
212✔
643
    TS = promote_op(matprod, eltype(A), eltype(B))
424✔
644
    C = mul!(similar(A, TS, size(A)), A, B)
212✔
645
    return B.uplo == 'U' ? UpperTriangular(C) : C
212✔
646
end
647

648
function *(A::LowerOrUnitLowerTriangular, B::Bidiagonal)
212✔
649
    TS = promote_op(matprod, eltype(A), eltype(B))
424✔
650
    C = mul!(similar(A, TS, size(A)), A, B)
212✔
651
    return B.uplo == 'L' ? LowerTriangular(C) : C
212✔
652
end
653

654
function *(A::Bidiagonal, B::UpperOrUnitUpperTriangular)
180✔
655
    TS = promote_op(matprod, eltype(A), eltype(B))
360✔
656
    C = mul!(similar(B, TS, size(B)), A, B)
180✔
657
    return A.uplo == 'U' ? UpperTriangular(C) : C
180✔
658
end
659

660
function *(A::Bidiagonal, B::LowerOrUnitLowerTriangular)
180✔
661
    TS = promote_op(matprod, eltype(A), eltype(B))
360✔
662
    C = mul!(similar(B, TS, size(B)), A, B)
180✔
663
    return A.uplo == 'L' ? LowerTriangular(C) : C
180✔
664
end
665

666
function *(A::Diagonal, B::SymTridiagonal)
84✔
667
    TS = promote_op(*, eltype(A), eltype(B))
168✔
668
    out = Tridiagonal(similar(A, TS, size(A, 1)-1), similar(A, TS, size(A, 1)), similar(A, TS, size(A, 1)-1))
84✔
669
    mul!(out, A, B)
84✔
670
end
671

672
function *(A::SymTridiagonal, B::Diagonal)
84✔
673
    TS = promote_op(*, eltype(A), eltype(B))
168✔
674
    out = Tridiagonal(similar(A, TS, size(A, 1)-1), similar(A, TS, size(A, 1)), similar(A, TS, size(A, 1)-1))
84✔
675
    mul!(out, A, B)
84✔
676
end
677

678
function dot(x::AbstractVector, B::Bidiagonal, y::AbstractVector)
16✔
679
    require_one_based_indexing(x, y)
16✔
680
    nx, ny = length(x), length(y)
16✔
681
    (nx == size(B, 1) == ny) || throw(DimensionMismatch())
16✔
682
    if nx ≤ 1
16✔
683
        nx == 0 && return dot(zero(eltype(x)), zero(eltype(B)), zero(eltype(y)))
12✔
684
        return dot(x[1], B.dv[1], y[1])
4✔
685
    end
686
    ev, dv = B.ev, B.dv
4✔
687
    @inbounds if B.uplo == 'U'
4✔
688
        xâ‚€ = x[1]
2✔
689
        r = dot(x[1], dv[1], y[1])
2✔
690
        for j in 2:nx-1
4✔
691
            xâ‚‹, xâ‚€ = xâ‚€, x[j]
6✔
692
            r += dot(adjoint(ev[j-1])*xâ‚‹ + adjoint(dv[j])*xâ‚€, y[j])
6✔
693
        end
10✔
694
        r += dot(adjoint(ev[nx-1])*xâ‚€ + adjoint(dv[nx])*x[nx], y[nx])
2✔
695
        return r
2✔
696
    else # B.uplo == 'L'
697
        xâ‚€ = x[1]
2✔
698
        x₊ = x[2]
2✔
699
        r = dot(adjoint(dv[1])*x₀ + adjoint(ev[1])*x₊, y[1])
2✔
700
        for j in 2:nx-1
4✔
701
            x₀, x₊ = x₊, x[j+1]
6✔
702
            r += dot(adjoint(dv[j])*x₀ + adjoint(ev[j])*x₊, y[j])
6✔
703
        end
10✔
704
        r += dot(x₊, dv[nx], y[nx])
2✔
705
        return r
2✔
706
    end
707
end
708

709
#Linear solvers
710
#Generic solver using naive substitution
711
ldiv!(A::Bidiagonal, b::AbstractVecOrMat) = @inline ldiv!(b, A, b)
36✔
712
function ldiv!(c::AbstractVecOrMat, A::Bidiagonal, b::AbstractVecOrMat)
523✔
713
    require_one_based_indexing(c, A, b)
523✔
714
    N = size(A, 2)
523✔
715
    mb, nb = size(b, 1), size(b, 2)
523✔
716
    if N != mb
523✔
717
        throw(DimensionMismatch("second dimension of A, $N, does not match first dimension of b, $mb"))
100✔
718
    end
719
    mc, nc = size(c, 1), size(c, 2)
423✔
720
    if mc != mb || nc != nb
846✔
721
        throw(DimensionMismatch("size of result, ($mc, $nc), does not match the size of b, ($mb, $nb)"))
×
722
    end
723

724
    if N == 0
423✔
725
        return copyto!(c, b)
16✔
726
    end
727

728
    zi = findfirst(iszero, A.dv)
3,819✔
729
    isnothing(zi) || throw(SingularException(zi))
411✔
730

731
    @inbounds for j in 1:nb
774✔
732
        if A.uplo == 'L' #do colwise forward substitution
3,214✔
733
            c[1,j] = bi1 = A.dv[1] \ b[1,j]
2,477✔
734
            for i in 2:N
3,182✔
735
                c[i,j] = bi1 = A.dv[i] \ (b[i,j] - A.ev[i - 1] * bi1)
22,088✔
736
            end
26,505✔
737
        else #do colwise backward substitution
738
            c[N,j] = bi1 = A.dv[N] \ b[N,j]
2,557✔
739
            for i in (N - 1):-1:1
3,246✔
740
                c[i,j] = bi1 = A.dv[i] \ (b[i,j] - A.ev[i] * bi1)
22,422✔
741
            end
14,322✔
742
        end
743
    end
6,025✔
744
    return c
403✔
745
end
746
ldiv!(A::Transpose{<:Any,<:Bidiagonal}, b::AbstractVecOrMat) = @inline ldiv!(b, A, b)
×
747
ldiv!(A::Adjoint{<:Any,<:Bidiagonal}, b::AbstractVecOrMat) = @inline ldiv!(b, A, b)
×
748
ldiv!(c::AbstractVecOrMat, A::Transpose{<:Any,<:Bidiagonal}, b::AbstractVecOrMat) =
×
749
    (_rdiv!(transpose(c), transpose(b), transpose(A)); return c)
×
750
ldiv!(c::AbstractVecOrMat, A::Adjoint{<:Any,<:Bidiagonal}, b::AbstractVecOrMat) =
×
751
    (_rdiv!(adjoint(c), adjoint(b), adjoint(A)); return c)
×
752

753
### Generic promotion methods and fallbacks
754
\(A::Bidiagonal, B::AbstractVecOrMat) = ldiv!(_initarray(\, eltype(A), eltype(B), B), A, B)
316✔
755
\(tA::Transpose{<:Any,<:Bidiagonal}, B::AbstractVecOrMat) = copy(tA) \ B
8✔
756
\(adjA::Adjoint{<:Any,<:Bidiagonal}, B::AbstractVecOrMat) = copy(adjA) \ B
10✔
757

758
### Triangular specializations
759
function \(B::Bidiagonal, U::UpperTriangular)
22✔
760
    A = ldiv!(_initarray(\, eltype(B), eltype(U), U), B, U)
28✔
761
    return B.uplo == 'U' ? UpperTriangular(A) : A
22✔
762
end
763
function \(B::Bidiagonal, U::UnitUpperTriangular)
16✔
764
    A = ldiv!(_initarray(\, eltype(B), eltype(U), U), B, U)
16✔
765
    return B.uplo == 'U' ? UpperTriangular(A) : A
16✔
766
end
767
function \(B::Bidiagonal, L::LowerTriangular)
22✔
768
    A = ldiv!(_initarray(\, eltype(B), eltype(L), L), B, L)
28✔
769
    return B.uplo == 'L' ? LowerTriangular(A) : A
22✔
770
end
771
function \(B::Bidiagonal, L::UnitLowerTriangular)
16✔
772
    A = ldiv!(_initarray(\, eltype(B), eltype(L), L), B, L)
16✔
773
    return B.uplo == 'L' ? LowerTriangular(A) : A
16✔
774
end
775

776
function \(U::UpperTriangular, B::Bidiagonal)
48✔
777
    A = ldiv!(U, copy_similar(B, _init_eltype(\, eltype(U), eltype(B))))
48✔
778
    return B.uplo == 'U' ? UpperTriangular(A) : A
48✔
779
end
780
function \(U::UnitUpperTriangular, B::Bidiagonal)
16✔
781
    A = ldiv!(U, copy_similar(B, _init_eltype(\, eltype(U), eltype(B))))
16✔
782
    return B.uplo == 'U' ? UpperTriangular(A) : A
16✔
783
end
784
function \(L::LowerTriangular, B::Bidiagonal)
48✔
785
    A = ldiv!(L, copy_similar(B, _init_eltype(\, eltype(L), eltype(B))))
48✔
786
    return B.uplo == 'L' ? LowerTriangular(A) : A
48✔
787
end
788
function \(L::UnitLowerTriangular, B::Bidiagonal)
16✔
789
    A = ldiv!(L, copy_similar(B, _init_eltype(\, eltype(L), eltype(B))))
16✔
790
    return B.uplo == 'L' ? LowerTriangular(A) : A
16✔
791
end
792
### Diagonal specialization
793
function \(B::Bidiagonal, D::Diagonal)
48✔
794
    A = ldiv!(_initarray(\, eltype(B), eltype(D), D), B, D)
48✔
795
    return B.uplo == 'U' ? UpperTriangular(A) : LowerTriangular(A)
48✔
796
end
797

798
function _rdiv!(C::AbstractMatrix, A::AbstractMatrix, B::Bidiagonal)
271✔
799
    require_one_based_indexing(C, A, B)
271✔
800
    m, n = size(A)
271✔
801
    if size(B, 1) != n
271✔
802
        throw(DimensionMismatch("right hand side B needs first dimension of size $n, has size $(size(B,1))"))
16✔
803
    end
804
    mc, nc = size(C)
255✔
805
    if mc != m || nc != n
510✔
806
        throw(DimensionMismatch("expect output to have size ($m, $n), but got ($mc, $nc)"))
×
807
    end
808

809
    zi = findfirst(iszero, B.dv)
2,337✔
810
    isnothing(zi) || throw(SingularException(zi))
255✔
811

812
    if B.uplo == 'L'
255✔
813
        diagB = B.dv[n]
126✔
814
        for i in 1:m
252✔
815
            C[i,n] = A[i,n] / diagB
1,822✔
816
        end
2,178✔
817
        for j in n-1:-1:1
252✔
818
            diagB = B.dv[j]
1,026✔
819
            offdiagB = B.ev[j]
1,026✔
820
            for i in 1:m
2,052✔
821
                C[i,j] = (A[i,j] - C[i,j+1]*offdiagB)/diagB
16,116✔
822
            end
19,014✔
823
        end
1,926✔
824
    else
825
        diagB = B.dv[1]
129✔
826
        for i in 1:m
258✔
827
            C[i,1] = A[i,1] / diagB
1,900✔
828
        end
2,235✔
829
        for j in 2:n
258✔
830
            diagB = B.dv[j]
1,053✔
831
            offdiagB = B.ev[j-1]
1,053✔
832
            for i = 1:m
2,106✔
833
                C[i,j] = (A[i,j] - C[i,j-1]*offdiagB)/diagB
16,446✔
834
            end
19,527✔
835
        end
1,053✔
836
    end
837
    C
255✔
838
end
839
rdiv!(A::AbstractMatrix, B::Bidiagonal) = @inline _rdiv!(A, A, B)
16✔
840
rdiv!(A::AbstractMatrix, B::Adjoint{<:Any,<:Bidiagonal}) = @inline _rdiv!(A, A, B)
×
841
rdiv!(A::AbstractMatrix, B::Transpose{<:Any,<:Bidiagonal}) = @inline _rdiv!(A, A, B)
×
842
_rdiv!(C::AbstractMatrix, A::AbstractMatrix, B::Adjoint{<:Any,<:Bidiagonal}) =
×
843
    (ldiv!(adjoint(C), adjoint(B), adjoint(A)); return C)
×
844
_rdiv!(C::AbstractMatrix, A::AbstractMatrix, B::Transpose{<:Any,<:Bidiagonal}) =
×
845
    (ldiv!(transpose(C), transpose(B), transpose(A)); return C)
×
846

847
/(A::AbstractMatrix, B::Bidiagonal) = _rdiv!(_initarray(/, eltype(A), eltype(B), A), A, B)
130✔
848

849
### Triangular specializations
850
function /(U::UpperTriangular, B::Bidiagonal)
22✔
851
    A = _rdiv!(_initarray(/, eltype(U), eltype(B), U), U, B)
28✔
852
    return B.uplo == 'U' ? UpperTriangular(A) : A
22✔
853
end
854
function /(U::UnitUpperTriangular, B::Bidiagonal)
16✔
855
    A = _rdiv!(_initarray(/, eltype(U), eltype(B), U), U, B)
16✔
856
    return B.uplo == 'U' ? UpperTriangular(A) : A
16✔
857
end
858
function /(L::LowerTriangular, B::Bidiagonal)
22✔
859
    A = _rdiv!(_initarray(/, eltype(L), eltype(B), L), L, B)
28✔
860
    return B.uplo == 'L' ? LowerTriangular(A) : A
22✔
861
end
862
function /(L::UnitLowerTriangular, B::Bidiagonal)
16✔
863
    A = _rdiv!(_initarray(/, eltype(L), eltype(B), L), L, B)
16✔
864
    return B.uplo == 'L' ? LowerTriangular(A) : A
16✔
865
end
866
function /(B::Bidiagonal, U::UpperTriangular)
16✔
867
    A = rdiv!(copy_similar(B, _init_eltype(/, eltype(B), eltype(U))), U)
16✔
868
    return B.uplo == 'U' ? UpperTriangular(A) : A
16✔
869
end
870
function /(B::Bidiagonal, U::UnitUpperTriangular)
16✔
871
    A = rdiv!(copy_similar(B, _init_eltype(/, eltype(B), eltype(U))), U)
16✔
872
    return B.uplo == 'U' ? UpperTriangular(A) : A
16✔
873
end
874
function /(B::Bidiagonal, L::LowerTriangular)
16✔
875
    A = rdiv!(copy_similar(B, _init_eltype(/, eltype(B), eltype(L))), L)
16✔
876
    return B.uplo == 'L' ? LowerTriangular(A) : A
16✔
877
end
878
function /(B::Bidiagonal, L::UnitLowerTriangular)
16✔
879
    A = rdiv!(copy_similar(B, _init_eltype(/, eltype(B), eltype(L))), L)
16✔
880
    return B.uplo == 'L' ? LowerTriangular(A) : A
16✔
881
end
882
### Diagonal specialization
883
function /(D::Diagonal, B::Bidiagonal)
48✔
884
    A = _rdiv!(_initarray(/, eltype(D), eltype(B), D), D, B)
48✔
885
    return B.uplo == 'U' ? UpperTriangular(A) : LowerTriangular(A)
48✔
886
end
887

888
/(A::AbstractMatrix, B::Transpose{<:Any,<:Bidiagonal}) = A / copy(B)
8✔
889
/(A::AbstractMatrix, B::Adjoint{<:Any,<:Bidiagonal}) = A / copy(B)
8✔
890
# disambiguation
891
/(A::AdjointAbsVec, B::Bidiagonal) = adjoint(adjoint(B) \ parent(A))
×
892
/(A::TransposeAbsVec, B::Bidiagonal) = transpose(transpose(B) \ parent(A))
32✔
893
/(A::AdjointAbsVec, B::Transpose{<:Any,<:Bidiagonal}) = adjoint(adjoint(B) \ parent(A))
×
894
/(A::TransposeAbsVec, B::Transpose{<:Any,<:Bidiagonal}) = transpose(transpose(B) \ parent(A))
×
895
/(A::AdjointAbsVec, B::Adjoint{<:Any,<:Bidiagonal}) = adjoint(adjoint(B) \ parent(A))
×
896
/(A::TransposeAbsVec, B::Adjoint{<:Any,<:Bidiagonal}) = transpose(transpose(B) \ parent(A))
×
897

898
factorize(A::Bidiagonal) = A
16✔
899
function inv(B::Bidiagonal{T}) where T
48✔
900
    n = size(B, 1)
48✔
901
    dest = zeros(typeof(oneunit(T)\one(T)), (n, n))
4,206✔
902
    ldiv!(dest, B, Diagonal{typeof(one(T)\one(T))}(I, n))
426✔
903
    return B.uplo == 'U' ? UpperTriangular(dest) : LowerTriangular(dest)
48✔
904
end
905

906
# Eigensystems
907
eigvals(M::Bidiagonal) = copy(M.dv)
12✔
908
function eigvecs(M::Bidiagonal{T}) where T
12✔
909
    n = length(M.dv)
12✔
910
    Q = Matrix{T}(undef, n,n)
12✔
911
    blks = [0; findall(iszero, M.ev); n]
12✔
912
    v = zeros(T, n)
102✔
913
    if M.uplo == 'U'
12✔
914
        for idx_block = 1:length(blks) - 1, i = blks[idx_block] + 1:blks[idx_block + 1] #index of eigenvector
12✔
915
            fill!(v, zero(T))
600✔
916
            v[blks[idx_block] + 1] = one(T)
60✔
917
            for j = blks[idx_block] + 1:i - 1 #Starting from j=i, eigenvector elements will be 0
114✔
918
                v[j+1] = (M.dv[i] - M.dv[j])/M.ev[j] * v[j]
270✔
919
            end
486✔
920
            c = norm(v)
60✔
921
            for j = 1:n
120✔
922
                Q[j, i] = v[j] / c
600✔
923
            end
1,140✔
924
        end
60✔
925
    else
926
        for idx_block = 1:length(blks) - 1, i = blks[idx_block + 1]:-1:blks[idx_block] + 1 #index of eigenvector
12✔
927
            fill!(v, zero(T))
600✔
928
            v[blks[idx_block+1]] = one(T)
60✔
929
            for j = (blks[idx_block+1] - 1):-1:max(1, (i - 1)) #Starting from j=i, eigenvector elements will be 0
120✔
930
                v[j] = (M.dv[i] - M.dv[j+1])/M.ev[j] * v[j+1]
324✔
931
            end
588✔
932
            c = norm(v)
60✔
933
            for j = 1:n
120✔
934
                Q[j, i] = v[j] / c
600✔
935
            end
1,140✔
936
        end
60✔
937
    end
938
    Q #Actually Triangular
12✔
939
end
940
eigen(M::Bidiagonal) = Eigen(eigvals(M), eigvecs(M))
12✔
941

942
Base._sum(A::Bidiagonal, ::Colon) = sum(A.dv) + sum(A.ev)
5✔
943
function Base._sum(A::Bidiagonal, dims::Integer)
15✔
944
    res = Base.reducedim_initarray(A, dims, zero(eltype(A)))
15✔
945
    n = length(A.dv)
12✔
946
    if n == 0
12✔
947
        # Just to be sure. This shouldn't happen since there is a check whether
948
        # length(A.dv) == length(A.ev) + 1 in the constructor.
949
        return res
×
950
    elseif n == 1
12✔
951
        res[1] = A.dv[1]
4✔
952
        return res
4✔
953
    end
954
    @inbounds begin
8✔
955
        if (dims == 1 && A.uplo == 'U') || (dims == 2 && A.uplo == 'L')
14✔
956
            res[1] = A.dv[1]
3✔
957
            for i = 2:length(A.dv)
6✔
958
                res[i] = A.ev[i-1] + A.dv[i]
6✔
959
            end
9✔
960
        elseif (dims == 1 && A.uplo == 'L') || (dims == 2 && A.uplo == 'U')
8✔
961
            for i = 1:length(A.dv)-1
6✔
962
                res[i] = A.ev[i] + A.dv[i]
6✔
963
            end
9✔
964
            res[end] = A.dv[end]
3✔
965
        elseif dims >= 3
2✔
966
            if A.uplo == 'U'
2✔
967
                for i = 1:length(A.dv)-1
2✔
968
                    res[i,i]   = A.dv[i]
2✔
969
                    res[i,i+1] = A.ev[i]
2✔
970
                end
3✔
971
            else
972
                for i = 1:length(A.dv)-1
2✔
973
                    res[i,i]   = A.dv[i]
2✔
974
                    res[i+1,i] = A.ev[i]
2✔
975
                end
2✔
976
            end
977
            res[end,end] = A.dv[end]
2✔
978
        end
979
    end
980
    res
8✔
981
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