Skip to content

Commit

Permalink
rewrite diagm with Pair's
Browse files Browse the repository at this point in the history
  • Loading branch information
fredrikekre committed Oct 11, 2017
1 parent 93a38b7 commit c05f686
Show file tree
Hide file tree
Showing 24 changed files with 131 additions and 100 deletions.
10 changes: 9 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ Library improvements

* REPL Undo via Ctrl-/ and Ctrl-_

* `diagm` now accepts several diagonal index/vector pairs ([#24047]).

* New function `equalto(x)`, which returns a function that compares its argument to `x`
using `isequal` ([#23812]).

Expand Down Expand Up @@ -464,10 +466,16 @@ Deprecated or removed
* The tuple-of-types form of `cfunction`, `cfunction(f, returntype, (types...))`, has been deprecated
in favor of the tuple-type form `cfunction(f, returntype, Tuple{types...})` ([#23066]).

* `diagm(v::AbstractVector, k::Integer=0)` has been deprecated in favor of
`diagm(k => v)` ([#24047]).

* `diagm(x::Number)` has been deprecated in favor of `fill(x, 1, 1)` ([#24047]).

* `diagm(A::SparseMatrixCSC)` has been deprecated in favor of
`spdiagm(sparsevec(A))` ([#23341]).

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

* `` (written as `\mscre<TAB>` or `\euler<TAB>`) is now the only (by default) exported
name for Euler's number, and the type has changed from `Irrational{:e}` to
Expand Down
15 changes: 14 additions & 1 deletion base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1641,7 +1641,7 @@ import .LinAlg: diagm
@deprecate diagm(A::SparseMatrixCSC) sparse(Diagonal(sparsevec(A)))

# PR #23373
@deprecate diagm(A::BitMatrix) diagm(vec(A))
@deprecate diagm(A::BitMatrix) BitMatrix(Diagonal(vec(A)))

# PR 23341
@eval GMP @deprecate gmp_version() version() false
Expand Down Expand Up @@ -1870,6 +1870,19 @@ end
nothing
end

function diagm(v::BitVector)
depwarn(string("diagm(v::BitVector) is deprecated, use diagm(0 => v) or ",
"BitMatrix(Diagonal(v)) instead"), :diagm)
return BitMatrix(Diagonal(v))
end
function diagm(v::AbstractVector)
depwarn(string("diagm(v::AbstractVector) is deprecated, use diagm(0 => v) or ",
"Matrix(Diagonal(v)) instead"), :diagm)
return Matrix(Diagonal(v))
end
@deprecate diagm(v::AbstractVector, k::Integer) diagm(k => v)
@deprecate diagm(x::Number) fill(x, 1, 1)

# issue #20816
@deprecate strwidth textwidth
@deprecate charwidth textwidth
Expand Down
11 changes: 1 addition & 10 deletions base/linalg/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ function tril(B::BitMatrix, k::Integer=0)
A
end

## diag and related
## diag

function diag(B::BitMatrix)
n = minimum(size(B))
Expand All @@ -85,15 +85,6 @@ function diag(B::BitMatrix)
v
end

function diagm(v::BitVector)
n = length(v)
a = falses(n, n)
for i=1:n
a[i,i] = v[i]
end
a
end

## norm and rank

svd(A::BitMatrix) = svd(float(A))
Expand Down
44 changes: 33 additions & 11 deletions base/linalg/dense.jl
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ diagind(A::AbstractMatrix, k::Integer=0) = diagind(size(A,1), size(A,2), k)
diag(M, k::Integer=0)
The `k`th diagonal of a matrix, as a vector.
Use [`diagm`](@ref) to construct a diagonal matrix.
See also: [`diagm`](@ref)
# Examples
```jldoctest
Expand All @@ -265,29 +266,50 @@ julia> diag(A,1)
diag(A::AbstractMatrix, k::Integer=0) = A[diagind(A,k)]

"""
diagm(v, k::Integer=0)
diagm(kv::Pair{<:Integer,<:AbstractVector}...)
Construct a square matrix from `Pair`s of diagonals and vectors.
Vector `kv.second` will be placed on the `kv.first` diagonal.
Construct a matrix by placing `v` on the `k`th diagonal. This constructs a full matrix; if
you want a storage-efficient version with fast arithmetic, use [`Diagonal`](@ref) instead.
See also: [`spdiagm`](@ref), [`Diagonal`](@ref)
# Examples
```jldoctest
julia> diagm([1,2,3],1)
julia> diagm(1 => [1,2,3])
4×4 Array{Int64,2}:
0 1 0 0
0 0 2 0
0 0 0 3
0 0 0 0
julia> diagm(1 => [1,2,3], -1 => [4,5])
4×4 Array{Int64,2}:
0 1 0 0
4 0 2 0
0 5 0 3
0 0 0 0
```
"""
function diagm(v::AbstractVector{T}, k::Integer=0) where T
n = length(v) + abs(k)
A = zeros(T,n,n)
A[diagind(A,k)] = v
A
function diagm(kv::Pair{<:Integer,<:AbstractVector}...)
A = diagm_container(kv...)
for p in kv
inds = diagind(A, p.first)
for (i, val) in enumerate(p.second)
A[inds[i]] += val
end
end
return A
end
function diagm_container(kv::Pair{<:Integer,<:AbstractVector}...)
T = promote_type(map(x -> eltype(x.second), kv)...)
n = mapreduce(x -> length(x.second) + abs(x.first), max, kv)
return zeros(T, n, n)
end
function diagm_container(kv::Pair{<:Integer,<:BitVector}...)
n = mapreduce(x -> length(x.second) + abs(x.first), max, kv)
return falses(n, n)
end

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

function trace(A::Matrix{T}) where T
n = checksquare(A)
Expand Down
2 changes: 1 addition & 1 deletion base/linalg/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Diagonal{T}(V::AbstractVector) where {T} = Diagonal{T}(convert(AbstractVector{T}
convert(::Type{Diagonal{T}}, D::Diagonal{T}) where {T} = D
convert(::Type{Diagonal{T}}, D::Diagonal) where {T} = Diagonal{T}(convert(AbstractVector{T}, D.diag))
convert(::Type{AbstractMatrix{T}}, D::Diagonal) where {T} = convert(Diagonal{T}, D)
convert(::Type{Matrix}, D::Diagonal) = diagm(D.diag)
convert(::Type{Matrix}, D::Diagonal) = diagm(0 => D.diag)
convert(::Type{Array}, D::Diagonal) = convert(Matrix, D)
full(D::Diagonal) = convert(Array, D)

Expand Down
6 changes: 3 additions & 3 deletions base/linalg/generic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -739,13 +739,13 @@ of the [`eltype`](@ref) of `A`.
julia> rank(eye(3))
3
julia> rank(diagm([1, 0, 2]))
julia> rank(0 => diagm([1, 0, 2]))
2
julia> rank(diagm([1, 0.001, 2]), 0.1)
julia> rank(diagm(0 => [1, 0.001, 2]), 0.1)
2
julia> rank(diagm([1, 0.001, 2]), 0.00001)
julia> rank(diagm(0 => [1, 0.001, 2]), 0.00001)
3
```
"""
Expand Down
10 changes: 5 additions & 5 deletions base/linalg/lapack.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1161,17 +1161,17 @@ of `A`. `fact` may be `E`, in which case `A` will be equilibrated and copied
to `AF`; `F`, in which case `AF` and `ipiv` from a previous `LU` factorization
are inputs; or `N`, in which case `A` will be copied to `AF` and then
factored. If `fact = F`, `equed` may be `N`, meaning `A` has not been
equilibrated; `R`, meaning `A` was multiplied by `diagm(R)` from the left;
`C`, meaning `A` was multiplied by `diagm(C)` from the right; or `B`, meaning
`A` was multiplied by `diagm(R)` from the left and `diagm(C)` from the right.
equilibrated; `R`, meaning `A` was multiplied by `Diagonal(R)` from the left;
`C`, meaning `A` was multiplied by `Diagonal(C)` from the right; or `B`, meaning
`A` was multiplied by `Diagonal(R)` from the left and `Diagonal(C)` from the right.
If `fact = F` and `equed = R` or `B` the elements of `R` must all be positive.
If `fact = F` and `equed = C` or `B` the elements of `C` must all be positive.
Returns the solution `X`; `equed`, which is an output if `fact` is not `N`,
and describes the equilibration that was performed; `R`, the row equilibration
diagonal; `C`, the column equilibration diagonal; `B`, which may be overwritten
with its equilibrated form `diagm(R)*B` (if `trans = N` and `equed = R,B`) or
`diagm(C)*B` (if `trans = T,C` and `equed = C,B`); `rcond`, the reciprocal
with its equilibrated form `Diagonal(R)*B` (if `trans = N` and `equed = R,B`) or
`Diagonal(C)*B` (if `trans = T,C` and `equed = C,B`); `rcond`, the reciprocal
condition number of `A` after equilbrating; `ferr`, the forward error bound for
each solution vector in `X`; `berr`, the forward error bound for each solution
vector in `X`; and `work`, the reciprocal pivot growth factor.
Expand Down
16 changes: 8 additions & 8 deletions base/linalg/svd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ end
Compute the singular value decomposition (SVD) of `A` and return an `SVD` object.
`U`, `S`, `V` and `Vt` can be obtained from the factorization `F` with `F[:U]`,
`F[:S]`, `F[:V]` and `F[:Vt]`, such that `A = U*diagm(S)*Vt`.
`F[:S]`, `F[:V]` and `F[:Vt]`, such that `A = U*Diagonal(S)*Vt`.
The algorithm produces `Vt` and hence `Vt` is more efficient to extract than `V`.
The singular values in `S` are sorted in descending order.
Expand All @@ -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.]
julia> F = svdfact(A)
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])
julia> F[:U] * diagm(F[:S]) * F[:Vt]
julia> F[:U] * Diagonal(F[:S]) * F[:Vt]
4×5 Array{Float64,2}:
1.0 0.0 0.0 0.0 2.0
0.0 0.0 3.0 0.0 0.0
Expand All @@ -71,7 +71,7 @@ svdfact(x::Integer; thin::Bool=true) = svdfact(float(x), thin=thin)
svd(A; thin::Bool=true) -> U, S, V
Computes the SVD of `A`, returning `U`, vector `S`, and `V` such that
`A == U*diagm(S)*V'`. The singular values in `S` are sorted in descending order.
`A == U*Diagonal(S)*V'`. The singular values in `S` are sorted in descending order.
If `thin=true` (default), a thin SVD is returned. For a ``M \\times N`` matrix
`A`, `U` is ``M \\times M`` for a full SVD (`thin=false`) and
Expand All @@ -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.]
julia> U, S, V = svd(A)
([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])
julia> U*diagm(S)*V'
julia> U*Diagonal(S)*V'
4×5 Array{Float64,2}:
1.0 0.0 0.0 0.0 2.0
0.0 0.0 3.0 0.0 0.0
Expand Down Expand Up @@ -266,17 +266,17 @@ function getindex(obj::GeneralizedSVD{T}, d::Symbol) where T
elseif d == :D1
m = size(obj.U, 1)
if m - obj.k - obj.l >= 0
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)]
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)]
else
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)]
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)]
end
elseif d == :D2
m = size(obj.U, 1)
p = size(obj.V, 1)
if m - obj.k - obj.l >= 0
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)]
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)]
else
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)]]
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)]]
end
elseif d == :R
return obj.R
Expand Down
2 changes: 1 addition & 1 deletion base/linalg/uniformscaling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ function isapprox(J::UniformScaling,A::AbstractMatrix;
rtol::Real=rtoldefault(promote_leaf_eltypes(A),eltype(J),atol),
nans::Bool=false, norm::Function=vecnorm)
n = checksquare(A)
Jnorm = norm === vecnorm ? abs(J.λ)*sqrt(n) : (norm === Base.norm ? abs(J.λ) : norm(diagm(fill(J.λ, n))))
Jnorm = norm === vecnorm ? abs(J.λ)*sqrt(n) : (norm === Base.norm ? abs(J.λ) : norm(Diagonal(fill(J.λ, n))))
return norm(A - J) <= max(atol, rtol*max(norm(A), Jnorm))
end
isapprox(A::AbstractMatrix,J::UniformScaling;kwargs...) = isapprox(J,A;kwargs...)
Expand Down
4 changes: 2 additions & 2 deletions test/arrayops.jl
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ end
tmp[rng...] = A[rng...]
@test tmp == cat(3,zeros(Int,2,3),[0 0 0; 0 47 52],zeros(Int,2,3),[0 0 0; 0 127 132])

@test cat([1,2],1,2,3.,4.,5.) == diagm([1,2,3.,4.,5.])
@test cat([1,2],1,2,3.,4.,5.) == diagm(0 => [1,2,3.,4.,5.])
blk = [1 2;3 4]
tmp = cat([1,3],blk,blk)
@test tmp[1:2,1:2,1] == blk
Expand Down Expand Up @@ -2044,7 +2044,7 @@ end # module AutoRetType
@testset "concatenations of dense matrices/vectors yield dense matrices/vectors" begin
N = 4
densevec = ones(N)
densemat = diagm(ones(N))
densemat = diagm(0 => ones(N))
# Test that concatenations of homogeneous pairs of either dense matrices or dense vectors
# (i.e., Matrix-Matrix concatenations, and Vector-Vector concatenations) yield dense arrays
for densearray in (densevec, densemat)
Expand Down
6 changes: 5 additions & 1 deletion test/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1402,7 +1402,11 @@ timesofar("cat")
@check_bit_operation qr(b1)

b1 = bitrand(v1)
@check_bit_operation diagm(b1) BitMatrix
@check_bit_operation diagm(0 => b1) BitMatrix

b1 = bitrand(v1)
b2 = bitrand(v1)
@check_bit_operation diagm(-1 => b1, 1 => b2) BitMatrix

b1 = bitrand(n1, n1)
@check_bit_operation diag(b1)
Expand Down
2 changes: 1 addition & 1 deletion test/broadcast.jl
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ for arr in (identity, as_sub)
@test A == fill(7, 2, 2)
A = arr(zeros(3,3))
broadcast_setindex!(A, 10:12, 1:3, 1:3)
@test A == diagm(10:12)
@test A == diagm(0 => 10:12)
@test_throws BoundsError broadcast_setindex!(A, 7, [1,-1], [1 2])

for f in ((==), (<) , (!=), (<=))
Expand Down
2 changes: 1 addition & 1 deletion test/linalg/arnoldi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ end
# Ensure singular values from svds are in
# the correct order
@testset "singular values ordered correctly" begin
B = sparse(diagm([1.0, 2.0, 34.0, 5.0, 6.0]))
B = sparse(Diagonal([1.0, 2.0, 34.0, 5.0, 6.0]))
S3 = svds(B, ritzvec=false, nsv=2)
@test S3[1][:S] [34.0, 6.0]
S4 = svds(B, nsv=2)
Expand Down
12 changes: 6 additions & 6 deletions test/linalg/bidiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@ srand(1)
@testset "Constructor and basic properties" begin
@test size(T, 1) == size(T, 2) == n
@test size(T) == (n, n)
@test Array(T) == diagm(dv) + diagm(ev, uplo == :U ? 1 : -1)
@test Array(T) == diagm(0 => dv, (uplo == :U ? 1 : -1) => ev)
@test Bidiagonal(Array(T), uplo) == T
@test big.(T) == T
@test Array(abs.(T)) == abs.(diagm(dv)) + abs.(diagm(ev, uplo == :U ? 1 : -1))
@test Array(real(T)) == real(diagm(dv)) + real(diagm(ev, uplo == :U ? 1 : -1))
@test Array(imag(T)) == imag(diagm(dv)) + imag(diagm(ev, uplo == :U ? 1 : -1))
@test Array(abs.(T)) == abs.(diagm(0 => dv, (uplo == :U ? 1 : -1) => ev))
@test Array(real(T)) == real(diagm(0 => dv, (uplo == :U ? 1 : -1) => ev))
@test Array(imag(T)) == imag(diagm(0 => dv, (uplo == :U ? 1 : -1) => ev))
end

@testset for func in (conj, transpose, adjoint)
Expand Down Expand Up @@ -241,7 +241,7 @@ srand(1)
Test.test_approx_eq_modphase(u1, u2)
Test.test_approx_eq_modphase(v1, v2)
end
@test 0 vecnorm(u2*diagm(d2)*v2'-Tfull) atol=n*max(n^2*eps(relty),vecnorm(u1*diagm(d1)*v1'-Tfull))
@test 0 vecnorm(u2*Diagonal(d2)*v2'-Tfull) atol=n*max(n^2*eps(relty),vecnorm(u1*Diagonal(d1)*v1'-Tfull))
@inferred svdvals(T)
@inferred svd(T)
end
Expand All @@ -264,7 +264,7 @@ srand(1)
TriSym = SymTridiagonal(T.dv, T.ev)
@test Array(TriSym*T) Array(TriSym)*Array(T)
# test pass-through of A_mul_B! for AbstractTriangular*Bidiagonal
Tri = UpperTriangular(diagm(T.ev, 1))
Tri = UpperTriangular(diagm(1 => T.ev))
@test Array(Tri*T) Array(Tri)*Array(T)
end

Expand Down
2 changes: 1 addition & 1 deletion test/linalg/blas.jl
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ srand(100)
bH = zeros(elty,2,n)
bH[1,2:n] = ev
bH[2,:] = dv
fullH = diagm(dv) + diagm(conj(ev),-1) + diagm(ev,1)
fullH = diagm(0 => dv, -1 => conj(ev), 1 => ev)
@test BLAS.hbmv('U',1,bH,x) fullH*x
end
end
Expand Down
Loading

0 comments on commit c05f686

Please sign in to comment.