Vcat broadcast to all columns?

An intermediate, and decent, solution could be if you implement your own scalar_vcat function that lets you write

V1 = scalar_vcat(V, 1)

That would be clear, and also optimal, performance-wise. Rolling your own specialized solutions instead of relying on built-in funcionality is quite idiomatic in Julia.

Sure, and this is common in Julia. But it is always enabled through explicit dot-broadcasting, so that should probably be part of a built-in solution.

2 Likes

Yes, in the short term, by the way, it would be easy to put up a “ScalarCat” package with all that functionality and be happy, anyway these packages are necessary to test any functionality before proposing something definitive to Base.

@DNF note also that the fact that vcat is slow for multidimensional matrices is not a fundamental limitation of the column-major representation in Julia. It is feasible to implement matrices efficiently with extra space row-wise to allow resizing and pushing: Restriction to the last dimension · Issue #3 · JuliaArrays/ElasticArrays.jl · GitHub

This performance limitation could be lifted, in principle, if that was implemented. Maybe someday it will, so it in this sense it is correct to not limit the expressiveness of the language for that performance reason.

Yes, but I don’t think I was the one arguing for that.

1 Like

[A 0; 0 B] seems like neat syntax, especially as one can already do [A I; I B] when using the LinearAlgebra package. Maybe adding special objects (sorry, I have no idea what I is here) Zeros and Ones to LinearAlgebra, which behave like I, would be a better solution for supporting scientific notation.

In the case of [A Ones] it’s not clear how wide the Ones array is, but with [A Ones] * B it is clear how wide it needs to be. I’m not sure if the second case can be made to work, though. In the first case, there could be an additional compile-time or run-time parameter (Ones{1} or Ones(n)) that defaults to 1. In this case, I’d get what I need by simply writing [x; Ones].

From what I understand, the primary gain is that the same syntax [A; 1] may work for both Arrays and StaticArrays (while preserving static size information), and not so much about performance.

In this context, it’s a shame that concatenation uses sizes instead of axes. Ideally, something like this should preserve static size information:

julia> a = SMatrix{2,2,Int,4}(1:4)
2×2 SMatrix{2, 2, Int64, 4} with indices SOneTo(2)×SOneTo(2):
 1  3
 2  4

julia> Ones((SOneTo(1),axes(a,2))) |> axes
(SOneTo(1), SOneTo(2))

julia> [a; Ones((SOneTo(1),axes(a,2)))]
3×2 Matrix{Float64}:
 1.0  3.0
 2.0  4.0
 1.0  1.0

The two functionalities I was referring to are concatenation and single dimension expansion, others in this thread have also noted this as an issue. My idea with resize is to do something like:

x = rand(2, 1000)
resize(x, size(x,1)+1, size(x,2))
foreach(i->x[end,i]=1, 1:size(x,2))

or alternatively:

x = rand(2, 1000)
resize(x, size(x,1)+1, size(x,2); initval_for_new_elements=1)

but as I said, Stefan Karpinsky was not keen on a change like this so it is probably not the right solution to promote.

I do feel that your Zeros and Ones idea will fit into Julias syntax. I am not a big fan of I without an explicit size specification, but now that it is part of Julia, then having some similar “constants” would make it less of an outsider.

2 Likes

Efficiencies apart, could be something like this:

julia> struct ConstRow{T}
               val::T
       end

julia> 

julia> import Base: vcat, hcat

julia> vcat(m, c::ConstRow) = vcat(m, [ c.val for i in axes(m,1) ]')
vcat (generic function with 29 methods)

julia> m = zeros(3,3)
3×3 Matrix{Float64}:
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> vcat(m, ConstRow(1))
4×3 Matrix{Float64}:
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0
 1.0  1.0  1.0

That actually looks neat, IMO.

Shouldn’t it be axes(m,2) so that it works on 3x6 matrices for example?

1 Like

Yes, it should.