Skip to content

Commit

Permalink
change to positional m,n arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengj committed Apr 18, 2019
1 parent 280337a commit d70278b
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 30 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ New library functions
Standard library changes
------------------------

* `diagm` and `spdiagm` now accept optional `m,n` initial arguments to specify a size ([#31654]).

#### LinearAlgebra


Expand Down
48 changes: 27 additions & 21 deletions stdlib/LinearAlgebra/src/dense.jl
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,14 @@ julia> diag(A,1)
diag(A::AbstractMatrix, k::Integer=0) = A[diagind(A,k)]

"""
diagm(kv::Pair{<:Integer,<:AbstractVector}...; size=nothing)
diagm(kv::Pair{<:Integer,<:AbstractVector}...)
diagm(m::Integer, n::Integer, kv::Pair{<:Integer,<:AbstractVector}...)
Construct a matrix from `Pair`s of diagonals and vectors.
Vector `kv.second` will be placed on the `kv.first` diagonal.
By default (if `size=nothing`), the matrix is square and its size is inferred
from `kv`, but a non-square size `m`×`n` can be passed as a tuple via `size=(m,n)`.
By default the matrix is square and its size is inferred
from `kv`, but a non-square size `m`×`n` (padded with zeros as needed)
can be specified by passing `m,n` as the first arguments.
`diagm` constructs a full matrix; if you want storage-efficient
versions with fast arithmetic, see [`Diagonal`](@ref), [`Bidiagonal`](@ref)
Expand All @@ -274,8 +276,10 @@ julia> diagm(1 => [1,2,3], -1 => [4,5])
0 0 0 0
```
"""
function diagm(kv::Pair{<:Integer,<:AbstractVector}...; size::Union{Nothing,Tuple{<:Integer,<:Integer}}=nothing)
A = diagm_container(kv...; size=size)
diagm(kv::Pair{<:Integer,<:AbstractVector}...) = _diagm(nothing, kv...)
diagm(m::Integer, n::Integer, kv::Pair{<:Integer,<:AbstractVector}...) = _diagm((Int(m),Int(n)), kv...)
function _diagm(size, kv::Pair{<:Integer,<:AbstractVector}...)
A = diagm_container(size, kv...)
for p in kv
inds = diagind(A, p.first)
for (i, val) in enumerate(p.second)
Expand All @@ -284,31 +288,32 @@ function diagm(kv::Pair{<:Integer,<:AbstractVector}...; size::Union{Nothing,Tupl
end
return A
end
function diagm_size(size::Union{Nothing,Tuple{<:Integer,<:Integer}}, kv::Pair{<:Integer,<:AbstractVector}...)
if isnothing(size)
mnmax = mapreduce(x -> length(x.second) + abs(Int(x.first)), max, kv; init=0)
return mnmax, mnmax
else
mmax = mapreduce(x -> length(x.second) - min(0,Int(x.first)), max, kv; init=0)
nmax = mapreduce(x -> length(x.second) + max(0,Int(x.first)), max, kv; init=0)
m, n = size
(m mmax && n nmax) || throw(DimensionMismatch("invalid size=$size"))
return m, n
end
function diagm_size(size::Nothing, kv::Pair{<:Integer,<:AbstractVector}...)
mnmax = mapreduce(x -> length(x.second) + abs(Int(x.first)), max, kv; init=0)
return mnmax, mnmax
end
function diagm_size(size::Tuple{Int,Int}, kv::Pair{<:Integer,<:AbstractVector}...)
mmax = mapreduce(x -> length(x.second) - min(0,Int(x.first)), max, kv; init=0)
nmax = mapreduce(x -> length(x.second) + max(0,Int(x.first)), max, kv; init=0)
m, n = size
(m mmax && n nmax) || throw(DimensionMismatch("invalid size=$size"))
return m, n
end
function diagm_container(kv::Pair{<:Integer,<:AbstractVector}...; size::Union{Nothing,Tuple{<:Integer,<:Integer}}=nothing)
function diagm_container(size, kv::Pair{<:Integer,<:AbstractVector}...)
T = promote_type(map(x -> eltype(x.second), kv)...)
return zeros(T, diagm_size(size, kv...)...)
end
diagm_container(kv::Pair{<:Integer,<:BitVector}...; size::Union{Nothing,Tuple{<:Integer,<:Integer}}=nothing) =
diagm_container(size, kv::Pair{<:Integer,<:BitVector}...) =
return falses(diagm_size(size, kv...)...)

"""
diagm(v::AbstractVector; size=nothing)
diagm(v::AbstractVector)
diagm(m::Integer, n::Integer, v::AbstractVector)
Construct a matrix with elements of the vector as diagonal elements.
By default (if `size=nothing`), the matrix is square and its size is given by
`length(v)`, but a non-square size `m`×`n` can be passed as a tuple via `size=(m,n)`.
`length(v)`, but a non-square size `m`×`n` can be specified
by passing `m,n` as the first arguments.
# Examples
```jldoctest
Expand All @@ -319,7 +324,8 @@ julia> diagm([1,2,3])
0 0 3
```
"""
diagm(v::AbstractVector; size::Union{Nothing,Tuple{<:Integer,<:Integer}}=nothing) = diagm(0 => v; size=size)
diagm(v::AbstractVector) = diagm(0 => v)
diagm(m::Integer, n::Integer, v::AbstractVector) = diagm(m, n, 0 => v)

function tr(A::Matrix{T}) where T
n = checksquare(A)
Expand Down
8 changes: 4 additions & 4 deletions stdlib/LinearAlgebra/test/dense.jl
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ end
x = [7, 8]
for m=1:4, n=2:4
if m < 2 || n < 3
@test_throws DimensionMismatch diagm(0 => x, 1 => x, size=(m,n))
@test_throws DimensionMismatch diagm(0 => x, -1 => x, size=(n,m))
@test_throws DimensionMismatch diagm(m,n, 0 => x, 1 => x)
@test_throws DimensionMismatch diagm(m,n, 0 => x, -1 => x)
else
M = zeros(m,n)
M[1:2,1:3] = [7 7 0; 0 8 8]
@test diagm(0 => x, 1 => x, size=(m,n)) == M
@test diagm(0 => x, -1 => x, size=(n,m)) == M'
@test diagm(m,n, 0 => x, 1 => x) == M
@test diagm(m,n, 0 => x, -1 => x) == M'
end
end
end
Expand Down
10 changes: 7 additions & 3 deletions stdlib/SparseArrays/src/sparsematrix.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3356,12 +3356,14 @@ function spdiagm_internal(kv::Pair{<:Integer,<:AbstractVector}...)
end

"""
spdiagm(kv::Pair{<:Integer,<:AbstractVector}...; size=nothing)
spdiagm(kv::Pair{<:Integer,<:AbstractVector}...)
spdiagm(m::Integer, n::Ingeger, kv::Pair{<:Integer,<:AbstractVector}...)
Construct a sparse diagonal matrix from `Pair`s of vectors and diagonals.
Each vector `kv.second` will be placed on the `kv.first` diagonal. By
default (if `size=nothing`), the matrix is square and its size is inferred
from `kv`, but a non-square size `m`×`n` can be passed as a tuple via `size=(m,n)`.
from `kv`, but a non-square size `m`×`n` (padded with zeros as needed)
can be specified by passing `m,n` as the first arguments.
# Examples
```jldoctest
Expand All @@ -3377,7 +3379,9 @@ julia> spdiagm(-1 => [1,2,3,4], 1 => [4,3,2,1])
[4, 5] = 1
```
"""
function spdiagm(kv::Pair{<:Integer,<:AbstractVector}...; size::Union{Nothing,Tuple{<:Integer,<:Integer}}=nothing)
_spdiagm(kv::Pair{<:Integer,<:AbstractVector}...) = _spdiagm(nothing, kv...)
_spdiagm(m::Integer, n::Integer, kv::Pair{<:Integer,<:AbstractVector}...) = _spdiagm((Int(m),Int(n)), kv...)
function _spdiagm(size, kv::Pair{<:Integer,<:AbstractVector}...)
I, J, V = spdiagm_internal(kv...)
mmax, nmax = dimlub(I), dimlub(J)
mnmax = max(mmax, nmax)
Expand Down
4 changes: 2 additions & 2 deletions stdlib/SparseArrays/test/sparse.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1587,11 +1587,11 @@ end
# non-square:
for m=1:4, n=2:4
if m < 2 || n < 3
@test_throws DimensionMismatch spdiagm(0 => x, 1 => x, size=(m,n))
@test_throws DimensionMismatch spdiagm(m,n, 0 => x, 1 => x)
else
M = zeros(m,n)
M[1:2,1:3] = [1 1 0; 0 1 1]
@test spdiagm(0 => x, 1 => x, size=(m,n)) == M
@test spdiagm(m,n, 0 => x, 1 => x) == M
end
end
end
Expand Down

0 comments on commit d70278b

Please sign in to comment.