Skip to content

Commit 4b2b4f2

Browse files
fredrikekreSacha0
authored andcommitted
rewrite diagm with Pairs (#24047)
* rewrite diagm with `Pair`s
1 parent c7cbebf commit 4b2b4f2

24 files changed

+134
-100
lines changed

NEWS.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ Library improvements
316316

317317
* REPL Undo via Ctrl-/ and Ctrl-_
318318

319+
* `diagm` now accepts several diagonal index/vector `Pair`s ([#24047]).
320+
319321
* New function `equalto(x)`, which returns a function that compares its argument to `x`
320322
using `isequal` ([#23812]).
321323

@@ -467,10 +469,16 @@ Deprecated or removed
467469
* The tuple-of-types form of `cfunction`, `cfunction(f, returntype, (types...))`, has been deprecated
468470
in favor of the tuple-type form `cfunction(f, returntype, Tuple{types...})` ([#23066]).
469471

472+
* `diagm(v::AbstractVector, k::Integer=0)` has been deprecated in favor of
473+
`diagm(k => v)` ([#24047]).
474+
475+
* `diagm(x::Number)` has been deprecated in favor of `fill(x, 1, 1)` ([#24047]).
476+
470477
* `diagm(A::SparseMatrixCSC)` has been deprecated in favor of
471478
`spdiagm(sparsevec(A))` ([#23341]).
472479

473-
* `diagm(A::BitMatrix)` has been deprecated, use `diagm(vec(A))` instead ([#23373]).
480+
* `diagm(A::BitMatrix)` has been deprecated, use `diagm(0 => vec(A))` or
481+
`BitMatrix(Diagonal(vec(A)))` instead ([#23373], [#24047]).
474482

475483
* `` (written as `\mscre<TAB>` or `\euler<TAB>`) is now the only (by default) exported
476484
name for Euler's number, and the type has changed from `Irrational{:e}` to

base/deprecated.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1641,7 +1641,7 @@ import .LinAlg: diagm
16411641
@deprecate diagm(A::SparseMatrixCSC) sparse(Diagonal(sparsevec(A)))
16421642

16431643
# PR #23373
1644-
@deprecate diagm(A::BitMatrix) diagm(vec(A))
1644+
@deprecate diagm(A::BitMatrix) BitMatrix(Diagonal(vec(A)))
16451645

16461646
# PR 23341
16471647
@eval GMP @deprecate gmp_version() version() false
@@ -1870,6 +1870,19 @@ end
18701870
nothing
18711871
end
18721872

1873+
function diagm(v::BitVector)
1874+
depwarn(string("diagm(v::BitVector) is deprecated, use diagm(0 => v) or ",
1875+
"BitMatrix(Diagonal(v)) instead"), :diagm)
1876+
return BitMatrix(Diagonal(v))
1877+
end
1878+
function diagm(v::AbstractVector)
1879+
depwarn(string("diagm(v::AbstractVector) is deprecated, use diagm(0 => v) or ",
1880+
"Matrix(Diagonal(v)) instead"), :diagm)
1881+
return Matrix(Diagonal(v))
1882+
end
1883+
@deprecate diagm(v::AbstractVector, k::Integer) diagm(k => v)
1884+
@deprecate diagm(x::Number) fill(x, 1, 1)
1885+
18731886
# issue #20816
18741887
@deprecate strwidth textwidth
18751888
@deprecate charwidth textwidth

base/linalg/bitarray.jl

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ function tril(B::BitMatrix, k::Integer=0)
7474
A
7575
end
7676

77-
## diag and related
77+
## diag
7878

7979
function diag(B::BitMatrix)
8080
n = minimum(size(B))
@@ -85,15 +85,6 @@ function diag(B::BitMatrix)
8585
v
8686
end
8787

88-
function diagm(v::BitVector)
89-
n = length(v)
90-
a = falses(n, n)
91-
for i=1:n
92-
a[i,i] = v[i]
93-
end
94-
a
95-
end
96-
9788
## norm and rank
9889

9990
svd(A::BitMatrix) = svd(float(A))

base/linalg/dense.jl

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ diagind(A::AbstractMatrix, k::Integer=0) = diagind(size(A,1), size(A,2), k)
246246
diag(M, k::Integer=0)
247247
248248
The `k`th diagonal of a matrix, as a vector.
249-
Use [`diagm`](@ref) to construct a diagonal matrix.
249+
250+
See also: [`diagm`](@ref)
250251
251252
# Examples
252253
```jldoctest
@@ -265,29 +266,53 @@ julia> diag(A,1)
265266
diag(A::AbstractMatrix, k::Integer=0) = A[diagind(A,k)]
266267

267268
"""
268-
diagm(v, k::Integer=0)
269+
diagm(kv::Pair{<:Integer,<:AbstractVector}...)
270+
271+
Construct a square matrix from `Pair`s of diagonals and vectors.
272+
Vector `kv.second` will be placed on the `kv.first` diagonal.
273+
`diagm` constructs a full matrix; if you want storage-efficient
274+
versions with fast arithmetic, see [`Diagonal`](@ref), [`Bidiagonal`](@ref)
275+
[`Tridiagonal`](@ref) and [`SymTridiagonal`](@ref).
269276
270-
Construct a matrix by placing `v` on the `k`th diagonal. This constructs a full matrix; if
271-
you want a storage-efficient version with fast arithmetic, use [`Diagonal`](@ref) instead.
277+
See also: [`spdiagm`](@ref)
272278
273279
# Examples
274280
```jldoctest
275-
julia> diagm([1,2,3],1)
281+
julia> diagm(1 => [1,2,3])
276282
4×4 Array{Int64,2}:
277283
0 1 0 0
278284
0 0 2 0
279285
0 0 0 3
280286
0 0 0 0
287+
288+
julia> diagm(1 => [1,2,3], -1 => [4,5])
289+
4×4 Array{Int64,2}:
290+
0 1 0 0
291+
4 0 2 0
292+
0 5 0 3
293+
0 0 0 0
281294
```
282295
"""
283-
function diagm(v::AbstractVector{T}, k::Integer=0) where T
284-
n = length(v) + abs(k)
285-
A = zeros(T,n,n)
286-
A[diagind(A,k)] = v
287-
A
296+
function diagm(kv::Pair{<:Integer,<:AbstractVector}...)
297+
A = diagm_container(kv...)
298+
for p in kv
299+
inds = diagind(A, p.first)
300+
for (i, val) in enumerate(p.second)
301+
A[inds[i]] += val
302+
end
303+
end
304+
return A
305+
end
306+
function diagm_container(kv::Pair{<:Integer,<:AbstractVector}...)
307+
T = promote_type(map(x -> eltype(x.second), kv)...)
308+
n = mapreduce(x -> length(x.second) + abs(x.first), max, kv)
309+
return zeros(T, n, n)
310+
end
311+
function diagm_container(kv::Pair{<:Integer,<:BitVector}...)
312+
n = mapreduce(x -> length(x.second) + abs(x.first), max, kv)
313+
return falses(n, n)
288314
end
289315

290-
diagm(x::Number) = (X = Matrix{typeof(x)}(1,1); X[1,1] = x; X)
291316

292317
function trace(A::Matrix{T}) where T
293318
n = checksquare(A)

base/linalg/diagonal.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ Diagonal{T}(V::AbstractVector) where {T} = Diagonal{T}(convert(AbstractVector{T}
5252
convert(::Type{Diagonal{T}}, D::Diagonal{T}) where {T} = D
5353
convert(::Type{Diagonal{T}}, D::Diagonal) where {T} = Diagonal{T}(convert(AbstractVector{T}, D.diag))
5454
convert(::Type{AbstractMatrix{T}}, D::Diagonal) where {T} = convert(Diagonal{T}, D)
55-
convert(::Type{Matrix}, D::Diagonal) = diagm(D.diag)
55+
convert(::Type{Matrix}, D::Diagonal) = diagm(0 => D.diag)
5656
convert(::Type{Array}, D::Diagonal) = convert(Matrix, D)
5757
full(D::Diagonal) = convert(Array, D)
5858

base/linalg/generic.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -739,13 +739,13 @@ of the [`eltype`](@ref) of `A`.
739739
julia> rank(eye(3))
740740
3
741741
742-
julia> rank(diagm([1, 0, 2]))
742+
julia> rank(diagm(0 => [1, 0, 2]))
743743
2
744744
745-
julia> rank(diagm([1, 0.001, 2]), 0.1)
745+
julia> rank(diagm(0 => [1, 0.001, 2]), 0.1)
746746
2
747747
748-
julia> rank(diagm([1, 0.001, 2]), 0.00001)
748+
julia> rank(diagm(0 => [1, 0.001, 2]), 0.00001)
749749
3
750750
```
751751
"""

base/linalg/lapack.jl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,17 +1161,17 @@ of `A`. `fact` may be `E`, in which case `A` will be equilibrated and copied
11611161
to `AF`; `F`, in which case `AF` and `ipiv` from a previous `LU` factorization
11621162
are inputs; or `N`, in which case `A` will be copied to `AF` and then
11631163
factored. If `fact = F`, `equed` may be `N`, meaning `A` has not been
1164-
equilibrated; `R`, meaning `A` was multiplied by `diagm(R)` from the left;
1165-
`C`, meaning `A` was multiplied by `diagm(C)` from the right; or `B`, meaning
1166-
`A` was multiplied by `diagm(R)` from the left and `diagm(C)` from the right.
1164+
equilibrated; `R`, meaning `A` was multiplied by `Diagonal(R)` from the left;
1165+
`C`, meaning `A` was multiplied by `Diagonal(C)` from the right; or `B`, meaning
1166+
`A` was multiplied by `Diagonal(R)` from the left and `Diagonal(C)` from the right.
11671167
If `fact = F` and `equed = R` or `B` the elements of `R` must all be positive.
11681168
If `fact = F` and `equed = C` or `B` the elements of `C` must all be positive.
11691169
11701170
Returns the solution `X`; `equed`, which is an output if `fact` is not `N`,
11711171
and describes the equilibration that was performed; `R`, the row equilibration
11721172
diagonal; `C`, the column equilibration diagonal; `B`, which may be overwritten
1173-
with its equilibrated form `diagm(R)*B` (if `trans = N` and `equed = R,B`) or
1174-
`diagm(C)*B` (if `trans = T,C` and `equed = C,B`); `rcond`, the reciprocal
1173+
with its equilibrated form `Diagonal(R)*B` (if `trans = N` and `equed = R,B`) or
1174+
`Diagonal(C)*B` (if `trans = T,C` and `equed = C,B`); `rcond`, the reciprocal
11751175
condition number of `A` after equilbrating; `ferr`, the forward error bound for
11761176
each solution vector in `X`; `berr`, the forward error bound for each solution
11771177
vector in `X`; and `work`, the reciprocal pivot growth factor.

base/linalg/svd.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ end
3232
Compute the singular value decomposition (SVD) of `A` and return an `SVD` object.
3333
3434
`U`, `S`, `V` and `Vt` can be obtained from the factorization `F` with `F[:U]`,
35-
`F[:S]`, `F[:V]` and `F[:Vt]`, such that `A = U*diagm(S)*Vt`.
35+
`F[:S]`, `F[:V]` and `F[:Vt]`, such that `A = U*Diagonal(S)*Vt`.
3636
The algorithm produces `Vt` and hence `Vt` is more efficient to extract than `V`.
3737
The singular values in `S` are sorted in descending order.
3838
@@ -52,7 +52,7 @@ julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.]
5252
julia> F = svdfact(A)
5353
Base.LinAlg.SVD{Float64,Float64,Array{Float64,2}}([0.0 1.0 0.0 0.0; 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 -1.0; 0.0 0.0 1.0 0.0], [3.0, 2.23607, 2.0, 0.0], [-0.0 0.0 … -0.0 0.0; 0.447214 0.0 … 0.0 0.894427; -0.0 1.0 … -0.0 0.0; 0.0 0.0 … 1.0 0.0])
5454
55-
julia> F[:U] * diagm(F[:S]) * F[:Vt]
55+
julia> F[:U] * Diagonal(F[:S]) * F[:Vt]
5656
4×5 Array{Float64,2}:
5757
1.0 0.0 0.0 0.0 2.0
5858
0.0 0.0 3.0 0.0 0.0
@@ -71,7 +71,7 @@ svdfact(x::Integer; thin::Bool=true) = svdfact(float(x), thin=thin)
7171
svd(A; thin::Bool=true) -> U, S, V
7272
7373
Computes the SVD of `A`, returning `U`, vector `S`, and `V` such that
74-
`A == U*diagm(S)*V'`. The singular values in `S` are sorted in descending order.
74+
`A == U*Diagonal(S)*V'`. The singular values in `S` are sorted in descending order.
7575
7676
If `thin=true` (default), a thin SVD is returned. For a ``M \\times N`` matrix
7777
`A`, `U` is ``M \\times M`` for a full SVD (`thin=false`) and
@@ -93,7 +93,7 @@ julia> A = [1. 0. 0. 0. 2.; 0. 0. 3. 0. 0.; 0. 0. 0. 0. 0.; 0. 2. 0. 0. 0.]
9393
julia> U, S, V = svd(A)
9494
([0.0 1.0 0.0 0.0; 1.0 0.0 0.0 0.0; 0.0 0.0 0.0 -1.0; 0.0 0.0 1.0 0.0], [3.0, 2.23607, 2.0, 0.0], [-0.0 0.447214 -0.0 0.0; 0.0 0.0 1.0 0.0; … ; -0.0 0.0 -0.0 1.0; 0.0 0.894427 0.0 0.0])
9595
96-
julia> U*diagm(S)*V'
96+
julia> U*Diagonal(S)*V'
9797
4×5 Array{Float64,2}:
9898
1.0 0.0 0.0 0.0 2.0
9999
0.0 0.0 3.0 0.0 0.0
@@ -266,17 +266,17 @@ function getindex(obj::GeneralizedSVD{T}, d::Symbol) where T
266266
elseif d == :D1
267267
m = size(obj.U, 1)
268268
if m - obj.k - obj.l >= 0
269-
return [eye(T, obj.k) zeros(T, obj.k, obj.l); zeros(T, obj.l, obj.k) diagm(obj.a[obj.k + 1:obj.k + obj.l]); zeros(T, m - obj.k - obj.l, obj.k + obj.l)]
269+
return [eye(T, obj.k) zeros(T, obj.k, obj.l); zeros(T, obj.l, obj.k) Diagonal(obj.a[obj.k + 1:obj.k + obj.l]); zeros(T, m - obj.k - obj.l, obj.k + obj.l)]
270270
else
271-
return [eye(T, m, obj.k) [zeros(T, obj.k, m - obj.k); diagm(obj.a[obj.k + 1:m])] zeros(T, m, obj.k + obj.l - m)]
271+
return [eye(T, m, obj.k) [zeros(T, obj.k, m - obj.k); Diagonal(obj.a[obj.k + 1:m])] zeros(T, m, obj.k + obj.l - m)]
272272
end
273273
elseif d == :D2
274274
m = size(obj.U, 1)
275275
p = size(obj.V, 1)
276276
if m - obj.k - obj.l >= 0
277-
return [zeros(T, obj.l, obj.k) diagm(obj.b[obj.k + 1:obj.k + obj.l]); zeros(T, p - obj.l, obj.k + obj.l)]
277+
return [zeros(T, obj.l, obj.k) Diagonal(obj.b[obj.k + 1:obj.k + obj.l]); zeros(T, p - obj.l, obj.k + obj.l)]
278278
else
279-
return [zeros(T, p, obj.k) [diagm(obj.b[obj.k + 1:m]); zeros(T, obj.k + p - m, m - obj.k)] [zeros(T, m - obj.k, obj.k + obj.l - m); eye(T, obj.k + p - m, obj.k + obj.l - m)]]
279+
return [zeros(T, p, obj.k) [Diagonal(obj.b[obj.k + 1:m]); zeros(T, obj.k + p - m, m - obj.k)] [zeros(T, m - obj.k, obj.k + obj.l - m); eye(T, obj.k + p - m, obj.k + obj.l - m)]]
280280
end
281281
elseif d == :R
282282
return obj.R

base/linalg/uniformscaling.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ function isapprox(J::UniformScaling,A::AbstractMatrix;
220220
rtol::Real=rtoldefault(promote_leaf_eltypes(A),eltype(J),atol),
221221
nans::Bool=false, norm::Function=vecnorm)
222222
n = checksquare(A)
223-
Jnorm = norm === vecnorm ? abs(J.λ)*sqrt(n) : (norm === Base.norm ? abs(J.λ) : norm(diagm(fill(J.λ, n))))
223+
Jnorm = norm === vecnorm ? abs(J.λ)*sqrt(n) : (norm === Base.norm ? abs(J.λ) : norm(Diagonal(fill(J.λ, n))))
224224
return norm(A - J) <= max(atol, rtol*max(norm(A), Jnorm))
225225
end
226226
isapprox(A::AbstractMatrix,J::UniformScaling;kwargs...) = isapprox(J,A;kwargs...)

test/arrayops.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ end
232232
tmp[rng...] = A[rng...]
233233
@test tmp == cat(3,zeros(Int,2,3),[0 0 0; 0 47 52],zeros(Int,2,3),[0 0 0; 0 127 132])
234234

235-
@test cat([1,2],1,2,3.,4.,5.) == diagm([1,2,3.,4.,5.])
235+
@test cat([1,2],1,2,3.,4.,5.) == diagm(0 => [1,2,3.,4.,5.])
236236
blk = [1 2;3 4]
237237
tmp = cat([1,3],blk,blk)
238238
@test tmp[1:2,1:2,1] == blk
@@ -2044,7 +2044,7 @@ end # module AutoRetType
20442044
@testset "concatenations of dense matrices/vectors yield dense matrices/vectors" begin
20452045
N = 4
20462046
densevec = ones(N)
2047-
densemat = diagm(ones(N))
2047+
densemat = diagm(0 => ones(N))
20482048
# Test that concatenations of homogeneous pairs of either dense matrices or dense vectors
20492049
# (i.e., Matrix-Matrix concatenations, and Vector-Vector concatenations) yield dense arrays
20502050
for densearray in (densevec, densemat)

0 commit comments

Comments
 (0)