Tape based task copying in Turing
Stack allocated objects are always deep copied:
using Libtask
function f()
t = 0
for _ in 1:10
produce(t)
t = 1 + t
end
end
ttask = TapedTask(f)
@show consume(ttask) # 0
@show consume(ttask) # 1
a = copy(ttask)
@show consume(a) # 2
@show consume(a) # 3
@show consume(ttask) # 2
@show consume(ttask) # 3
Heap-allocated Array and Ref objects are deep copied by default:
using Libtask
function f()
t = [0 1 2]
for _ in 1:10
produce(t[1])
t[1] = 1 + t[1]
end
end
ttask = TapedTask(f)
@show consume(ttask) # 0
@show consume(ttask) # 1
a = copy(ttask)
@show consume(a) # 2
@show consume(a) # 3
@show consume(ttask) # 2
@show consume(ttask) # 3
Other heap-allocated objects (e.g., Dict
) are shallow copied, by default:
using Libtask
function f()
t = Dict(1=>10, 2=>20)
while true
produce(t[1])
t[1] = 1 + t[1]
end
end
ttask = TapedTask(f)
@show consume(ttask) # 10
@show consume(ttask) # 11
a = copy(ttask)
@show consume(a) # 12
@show consume(a) # 13
@show consume(ttask) # 14
@show consume(ttask) # 15
Notes:
-
The Turing probabilistic programming language uses this task copying feature in an efficient implementation of the particle filtering sampling algorithm for arbitrary order Markov processes.
-
From v0.6.0, Libtask is implemented by recording all the computing to a tape and copying that tape. Before that version, it is based on a tricky hack on the Julia internals. You can check the commit history of this repo to see the details.