-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
recursive conversion #149
Comments
There is nothing like this implemented in Setfield.jl. But it can be done with a traversal, a multi location variant of a lens. I will try to supply a gist. Feel free to ping me again in a week if I don't. |
using ConstructionBase
function mapproperties(f, obj)
pnames = propertynames(obj)
if isempty(pnames)
return obj
else
ctor = constructorof(typeof(obj))
new_props = map(pnames) do p
f(getproperty(obj, p))
end
return ctor(new_props...)
end
end
struct Properties end
function modify(f, o, ::Properties)
mapproperties(f, o)
end
struct Recursive{Descent, SEC}
descent_condition::Descent
sec::SEC
end
function modify(f, obj, r::Recursive)
modify(obj, r.sec) do o
if r.descent_condition(o)
modify(f, o, r)
else
f(o)
end
end
end
using Test
obj = (a=1, b=2)
@test mapproperties(x -> x+1, obj) === (a=2, b=3)
obj = (a=1, b=(1,2), c=(A=1, B=(1,2,3), D=4))
rp = Recursive(x -> !(x isa Tuple), Properties())
@test modify(collect, obj, rp) == (a = 1, b = [1, 2], c = (A = 1, B = [1, 2, 3], D = 4))
I think this should cover your use case? |
Thank you a lot!!! I was eager to use it by first
but it fails. Do I use it wrong?
I get
|
So let's see if I understand this correctly: |
using ConstructionBase
function mapproperties(f, obj)
pnames = propertynames(obj)
if isempty(pnames)
return obj
else
ctor = constructorof(typeof(obj))
new_props = map(pnames) do p
f(getproperty(obj, p))
end
return ctor(new_props...)
end
end
const CuArray = Tuple
modify_cuarrays(f, arr::Array) = map(x -> modify_cuarrays(f, x), arr)
modify_cuarrays(f, arr::CuArray) = f(arr)
modify_cuarrays(f, obj) = mapproperties(x -> modify_cuarrays(f, x), obj)
using Test
obj = (a=1, b=(1,2), c=(A=1, B=(1,2,3), D=4, E=[(5,6),7]))
@test modify_cuarrays(collect, obj) == (a = 1, b = [1, 2], c = (A = 1, B = [1, 2, 3], D = 4, E = Any[[5, 6], 7])) Better? |
I needed to add
and it then seem to work. I will close it when I am sure. Thank you a lot, you saved me from a lot of pain modifying the struct..... |
Out of curiosity, what goes wrong with |
I am not sure it was not a mistake of mine actually julia> tocpu(brm)
ERROR: MethodError: no method matching StructArrays.StructArray(::Array{Float64,1}, ::Array{Float64,1}, ::Array{Int64,1}, ::Array{Float64,1}, ::Array{Float64,1}, ::Array{Int64,1})
Closest candidates are:
StructArrays.StructArray(::AbstractArray{T,N} where N; unwrap) where T at /home/rveltz/.julia/packages/StructArrays/OtfvU/src/structarray.jl:85
StructArrays.StructArray(::Any; unwrap) at /home/rveltz/.julia/packages/StructArrays/OtfvU/src/structarray.jl:81
Stacktrace:
[1] mapproperties(::var"#41#42"{var"#50#52",Recursive{var"#49#51",Properties}}, ::StructArrays.StructArray{NamedTuple{(:x, :param, :itnewton, :ds, :theta, :step),Tuple{Float64,Float64,Int64,Float64,Float64,Int64}},1,NamedTuple{(:x, :param, :itnewton, :ds, :theta, :step),Tuple{Array{Float64,1},Array{Float64,1},Array{Int64,1},Array{Float64,1},Array{Float64,1},Array{Int64,1}}},Int64}) at ./REPL[47]:10
[2] modify(::Function, ::StructArrays.StructArray{NamedTuple{(:x, :param, :itnewton, :ds, :theta, :step),Tuple{Float64,Float64,Int64,Float64,Float64,Int64}},1,NamedTuple{(:x, :param, :itnewton, :ds, :theta, :step),Tuple{Array{Float64,1},Array{Float64,1},Array{Int64,1},Array{Float64,1},Array{Float64,1},Array{Int64,1}}},Int64}, ::Properties) at ./REPL[44]:2 |
Okay constructorof would need a special implementation for StructArray. |
I really think this is super useful for GPU applications. |
I think it can be further cleaned up into: tocpu(x::CuArray) = Array(x)
tocpu(obj) = mapproperties(tocpu, obj)
tocpu(x::Array) = map(tocpu, x)
tocpu(x::StructArray) = x # or better fix constructorof(::StructArray) Yeah I guess it comes up at quite some places. For instance Flux.jl has some functionality to convert between gpu and cpu I think. |
Hi,
I have an issue of converting
CuArray
s toArray
s in order to be able to save to disk. I have an involved composite struct withCuArray
appearing in many fields (this is this one).I would like to be able to do this conversion automatically. I do it by hand using
Setfield
and this is really tough.Is there a way to replace automatically and recursively
CuArray
byArray
and making the associated conversion?Thank you for your help,
Best regards,
The text was updated successfully, but these errors were encountered: