# 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*p*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)[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.