391391# in A to matrices of type T and sizes given by n[k:end]. n is an array
392392# so that the same promotion code can be used for hvcat. We pass the type T
393393# so that we can re-use this code for sparse-matrix hcat etcetera.
394+ promote_to_arrays_ (n:: Int , :: Type , a:: Number ) = a
394395promote_to_arrays_ (n:: Int , :: Type{Matrix} , J:: UniformScaling{T} ) where {T} = copyto! (Matrix {T} (undef, n,n), J)
395396promote_to_arrays_ (n:: Int , :: Type , A:: AbstractVecOrMat ) = A
396397promote_to_arrays (n,k, :: Type ) = ()
@@ -401,11 +402,11 @@ promote_to_arrays(n,k, ::Type{T}, A, B, C) where {T} =
401402 (promote_to_arrays_ (n[k], T, A), promote_to_arrays_ (n[k+ 1 ], T, B), promote_to_arrays_ (n[k+ 2 ], T, C))
402403promote_to_arrays (n,k, :: Type{T} , A, B, Cs... ) where {T} =
403404 (promote_to_arrays_ (n[k], T, A), promote_to_arrays_ (n[k+ 1 ], T, B), promote_to_arrays (n,k+ 2 , T, Cs... )... )
404- promote_to_array_type (A:: Tuple{Vararg{Union{AbstractVecOrMat,UniformScaling}}} ) = Matrix
405+ promote_to_array_type (A:: Tuple{Vararg{Union{AbstractVecOrMat,UniformScaling,Number }}} ) = Matrix
405406
406407for (f,dim,name) in ((:hcat ,1 ," rows" ), (:vcat ,2 ," cols" ))
407408 @eval begin
408- function $f (A:: Union{AbstractVecOrMat,UniformScaling} ...)
409+ function $f (A:: Union{AbstractVecOrMat,UniformScaling,Number } ...)
409410 n = - 1
410411 for a in A
411412 if ! isa (a, UniformScaling)
@@ -418,13 +419,13 @@ for (f,dim,name) in ((:hcat,1,"rows"), (:vcat,2,"cols"))
418419 end
419420 end
420421 n == - 1 && throw (ArgumentError ($ (" $f of only UniformScaling objects cannot determine the matrix size" )))
421- return $ f (promote_to_arrays (fill (n,length (A)),1 , promote_to_array_type (A), A... )... )
422+ return cat (promote_to_arrays (fill (n, length (A)), 1 , promote_to_array_type (A), A... )... , dims = Val ( 3 - $ dim) )
422423 end
423424 end
424425end
425426
426427
427- function hvcat (rows:: Tuple{Vararg{Int}} , A:: Union{AbstractVecOrMat,UniformScaling} ...)
428+ function hvcat (rows:: Tuple{Vararg{Int}} , A:: Union{AbstractVecOrMat,UniformScaling,Number } ...)
428429 require_one_based_indexing (A... )
429430 nr = length (rows)
430431 sum (rows) == length (A) || throw (ArgumentError (" mismatch between row sizes and number of arguments" ))
@@ -467,16 +468,27 @@ function hvcat(rows::Tuple{Vararg{Int}}, A::Union{AbstractVecOrMat,UniformScalin
467468 j = 0
468469 for i = 1 : nr
469470 if rows[i] > 0 && n[j+ 1 ] == - 1 # this row consists entirely of UniformScalings
470- nci = nc ÷ rows[i]
471- nci * rows[i] != nc && throw (DimensionMismatch (" indivisible UniformScaling sizes" ))
471+ nci, r = divrem (nc, rows[i])
472+ r != 0 && throw (DimensionMismatch (" indivisible UniformScaling sizes" ))
472473 for k = 1 : rows[i]
473474 n[j+ k] = nci
474475 end
475476 end
476477 j += rows[i]
477478 end
478479 end
479- return hvcat (rows, promote_to_arrays (n,1 , promote_to_array_type (A), A... )... )
480+ Atyp = promote_to_array_type (A)
481+ Amat = promote_to_arrays (n, 1 , Atyp, A... )
482+ # We have two methods for promote_to_array_type, one returning Matrix and
483+ # another one returning SparseMatrixCSC (in SparseArrays.jl). In the dense
484+ # case, we cannot call hvcat for the promoted UniformScalings because this
485+ # causes a stack overflow. In the sparse case, however, we cannot call
486+ # typed_hvcat because we need a sparse output.
487+ if Atyp == Matrix
488+ return typed_hvcat (promote_eltype (Amat... ), rows, Amat... )
489+ else
490+ return hvcat (rows, Amat... )
491+ end
480492end
481493
482494# # Matrix construction from UniformScaling
0 commit comments