# Get type containing the types of a set?

Given a set of variables `[a,b,c...]`, I want to find the type `T` such that `typeof(a)<:T, typeof(b)<:T, ...`.

The reason I want to do this is that I have cache variables in my ODE system, which need to be able to adapt if one of the parameters or initial conditions is of type `Particles` or `Dual`. I know there is a `dualcache` thing in DiffEqBase.jl, but I would like a similar type of thing for arbitrary types.

Thanks!

Your question and use case seem a bit different. Your question is asking for the most specific type `T` such that all elements of `x=[a,b,c,...]` are subtypes. Hereâ€™s a solution

``````typetree(T::DataType) = typetree!([T],supertype(T))
function typetree!(list, T::DataType)
push!(list,supertype(T))
return typetree!(list,supertype(T))
end
typetree!(list,T::Type{Any}) = return list

x = Any[2.0,1,UInt8(0)]
types = typetree.(typeof.(x))
umbrella_type = first(intersect(types...))
``````

This recursively builds type trees for each type in `x` and then finds the set intersection. Since `intersect` preserves ordering, the first element of the intersection is the â€śumbrellaâ€ť type for the collection.

Iâ€™m sure thereâ€™s a more elegant solution. However, it seems like your application just needs to know if any one of the elements of `x = [a,b,c...]` are of a specific type, which you can do with `any(typeof.(x).==Particle)` or `any(typeof.(x).==Dual)`.

1 Like

Your question and use case seem a bit different. Your question is asking for the most specific type `T` such that all elements of `x=[a,b,c,...]` are subtypes. Hereâ€™s a solutionâ€¦

Thanks!

However, it seems like your application just needs to know if any one of the elements of `x = [a,b,c...]` are of a specific type, which you can do with `any(typeof.(x).==Particle)` or `any(typeof.(x).==Dual)`

Well, no I donâ€™t think this works exactly. My use case was for my ODE function to work with any `T <: Real` as a parameter, so I need my cache to be some concrete type `T2` such that `T<:T2`. I agree that it seems like overkill to use your solution for a problem where at most, I probably just have to add one or two lines if I want a new parameter type. I guess I was hoping there was a quick solution I was missing.

My use case was for my ODE function to work with any `T <: Real` as a parameter, so I need my cache to be some concrete type `T2` such that `T<:T2`

Ah, gotcha. I didnâ€™t realize how the cache factored in.

Check out â€śtypejoinâ€ť as well (or maybe itâ€™s called jointypeâ€¦ try both)

Unfortunately not all concrete types `<:Real` are `isbits` so I canâ€™t reinterpretâ€¦ and usually `typejoin` doesnâ€™t give concrete types.

I think `promote_type` is what I was looking for, thanks @phg!
Here is my exploration if anyone is curious, or knows if I made an error somewhere. This minimal example uses the initial conditions, but I think the problem is similar with a cache variable.

``````using OrdinaryDiffEq
using Revise
using ForwardDiff

function f(du,u,p,t)
du .= -p[2]*p[1]*u
end

u_0 = [10.0]
params = (1.0,2.0)
prob = ODEProblem(f,u_0,(0.0,10.0),params)
solve(prob,Tsit5()) #make sure it works with no fancy stuff

using MonteCarloMeasurements
params = (1.0,Particles(10,Normal(1.0,2.0)))
prob = ODEProblem(f,u_0,(0.0,10.0),params)
#solve(prob,Tsit5()) #this does not work

u_0 = typeof(params[2])[10.0]
prob = ODEProblem(f,u_0,(0.0,10.0),params)
# solve(prob,Tsit5()) #this does work!

#how to do this for (most) general types T<:Real?

element_types = typeof.(params)
u_0_2 = promote_type(element_types...)[10.0]
prob2 = ODEProblem(f,u_0_2,(0.0,10.0),params)
solve(prob2,Tsit5()) #this works, but maybe it's slower?

using BenchmarkTools
@btime solve(prob,Tsit5())
@btime solve(prob2,Tsit5())

#seems to work?
#  252.864 ÎĽs (6876 allocations: 841.17 KiB)
# 253.666 ÎĽs (6876 allocations: 841.17 KiB)
``````

I wanted this to cover not just like, Particles, but also ForwardDiff with respect to particles, so `Dual{Particles}` and whatnot.

I donâ€™t think promoting the initial state to `Particles` will make it slower, since if your parameters are `Particles`, the state will become `Particles` eventually. By promoting the state manually, the ODE solver knows what types to use for internal variables.

On an unrelated note, maybe this is an MWE, but if not, youâ€™ll probably see much better performance with `StaticParticles` if your really only want 10 particles. If you really want a lot of particles, stick with the regular ones.

I did test it, and the performance is the same.

And yes, itâ€™s a MWE.