I would say that the first question is “Can you make it (at all) with one function?”. I.e is there a way to have a generic code which, when called with arguments of different types, always computes what you want it to compute. In your case, since you broadcast some operations in the “matrix” case but not the “vector” case, none of your implementations work as intended for the other type (or maybe I did not understand what you intended to compute).
When you have a function, you can try to see whether it is type stable.
I’m not exactly sure what you’re trying to achieve here, but perhaps this is not too far from what you want:
function fun(a, m)
c = zero(a[1,:])
for i in 1:length(m)
@. c += a[i, :]*m[i]
end
return c
end
Vector of Integers (note that it differs from your fun_vec
implementation in that it returns a 1-element vector instead of a scalar)
julia> m = [1, 2, 3];
julia> v = [4, 5, 6];
julia> fun(v, m)
1-element Array{Int64,1}:
32
Matrix of integers:
julia> a = [4 7;
5 8;
6 9];
julia> fun(a, m)
2-element Array{Int64,1}:
32
50
Vector of Floating-Points:
julia> m = Float64.(m);
julia> v = Float64.(v);
julia> fun(v, m)
1-element Array{Float64,1}:
32.0
All these should be type-stable. For example in the last case where m
and v
are Float64
arrays:
julia> @code_warntype fun(v,m)
Body::Array{Float64,1}
2 1 ── %1 = (Base.arraysize)(a, 1)::Int64 │╻╷╷╷ getindex
│ %2 = (Base.slt_int)(%1, 0)::Bool ││╻╷╷╷ to_indices
│ (Base.ifelse)(%2, 0, %1) │││┃││││ axes
│ (Base.ifelse)(false, 0, 1) ││││╻╷╷╷╷ to_indices
│ %5 = %new(Base.OneTo{Int64}, 1)::Base.OneTo{Int64} │││││┃││ uncolon
│ %6 = %new(Base.Slice{Base.OneTo{Int64}}, %5)::Base.Slice{Base.OneTo{Int64}} ││││││╻ Type
└─── goto #6 if not true ││╻ _getindex
2 ── %8 = (Core.tuple)(1, %6)::Tuple{Int64,Base.Slice{Base.OneTo{Int64}}} │││
│ %9 = (Base.arraysize)(a, 1)::Int64 │││╻╷╷ checkbounds
│ %10 = (Base.slt_int)(%9, 0)::Bool ││││╻╷╷╷ checkbounds
│ %11 = (Base.ifelse)(%10, 0, %9)::Int64 │││││┃││││ axes
│ %12 = (Base.sle_int)(1, 1)::Bool ││││││╻╷ checkindex
│ %13 = (Base.sle_int)(1, %11)::Bool │││││││┃ <=
│ %14 = (Base.and_int)(%12, %13)::Bool │││││││╻ &
│ (Base.ifelse)(false, 0, 1) │││││││╻╷╷ Type
│ %16 = (Base.and_int)(%14, true)::Bool ││││││╻ &
└─── goto #4 if not %16 ││││
...
One of the key points here is to initialize c
in the correct way, so that it has the adequate type (both in terms of array dimensionality and element type).