I have some objects that are callable, each performing a certain univariate transformation. They are type stable; heavily simplified MWE:
using Base.Test
struct One end
struct Two end
(::One)(x) = x+1
(::Two)(x) = x+2
@inferred (One())(1) # OK
@inferred (Two())(1) # OK
What I want to do is collect them to transform vectors. I am using tuples, so that I can specialize the type, however, the transformation itself is not type stable:
struct Many{T}
t::T
end
m = Many((One(),Two()))
(m::Many)(x) = [t(x) for (t,x) in zip(m.t, x)]
@inferred m([1,2]) # get Array{Int, 1}, infers Array{_, 1}
How can I fix this?
zip
is type-unstable over heterogeneous tuples. If you don’t mind putting x
in a tuple too, then you can use the unregistered Unrolled.jl
julia> using Unrolled
julia> (m::Many)(x) = unrolled_map((t,x)->t(x), m.t, x)
julia> @inferred m((1,2))
(2, 4)
It appears that I don’t need it; map
works fine for both tuples and vectors:
(m::Many)(x) = map((t,x)->t(x), m.t, x)
@inferred m([1,2])
@inferred m((1,2))
@inferred m([1.0,2.0])
@inferred m((1.0,2))
1 Like
Cool! IIRC map
will bail out once your tuples get larger than ~15, so check if you need that.
Apparently Vector
to Vector
works fine even for a lot of elements (eg N=1000
below), but N=15
breaks type inference in
using Base.Test
struct One end
struct Two end
(::One)(x) = x+1
(::Two)(x) = x+2
struct Many{T}
t::T
end
(m::Many)(x) = map((t,x)->t(x), m.t, x)
N = 15
m = Many(ntuple(i->isodd(i) ? One() : Two(), N))
@inferred m(ones(N))
@inferred m(tuple(ones(N)...))
Since ATM I need vector to vector, I will go with map
.