如何在Julia 1.0中进行记忆或记忆

时间:2018-08-28 04:45:59

标签: julia

我一直试图用朱莉娅(Julia)的斐波那契功能进行记忆。这就是我想出的。

未经修改的原始代码(出于控制目的)

function fib(x)
    if x < 3
        return 1
    else
        return fib(x-2) + fib(x-1)
    end
end

这是我的第一次尝试

memory=Dict()

function memfib(x)
    global memory
    if haskey(memory,x)
        return memory[x]
    else
        if x < 3
            return memory[x] = 1
        else
            return memory[x] = memfib(x-2) + memfib(x-1)
        end
    end
end

我的第二次尝试

memory=Dict()

function membetafib(x)
    global memory
    return haskey(memory,x) ? memory[x] : x < 3 ? memory[x]=1 : memory[x] = membetafib(x-2) + membetafib(x-1)
end

我的第三次尝试

memory=Dict()

function memgammafib!(memory,x)
    return haskey(memory,x) ? memory[x] : x < 3 ? memory[x]=1 : memory[x] = memgammafib!(memory,x-2) + memgammafib!(memory,x-1)
end

还有其他我不知道的方法吗?

3 个答案:

答案 0 :(得分:14)

正如评论中指出的那样,Memoize.jl软件包无疑是最简单的选择。这要求您在定义时标记该方法。

但是,到目前为止,最强大的方法是使用Cassette.jl,它使您可以将备忘录添加到预先存在的功能中,例如

fib(x) = x < 3 ? 1 : fib(x-2) + fib(x-1)

using Cassette
Cassette.@context MemoizeCtx
function Cassette.overdub(ctx::MemoizeCtx, ::typeof(fib), x)
       get(ctx.metadata, x) do
           result = recurse(ctx, fib, x)
           ctx.metadata[x] = result
           return result
       end
   end

对正在发生的事情的一些描述:

  • MemoizeCtx是我们正在定义的盒式磁带“上下文”
  • 运行
  • overdub而不是原始函数定义
    • 我们用它来检查元数据字典中是否存在arg。
    • recurse(...)告诉Cassette调用该函数,但忽略顶级overload

现在我们可以通过备忘录运行该功能

Cassette.overdub(MemoizeCtx(metadata=Dict{Int,Int}()), fib, 80)

现在更酷的是,我们可以采用一个调用fib的现有函数,并在该函数的内部 中记住对fib的调用:

function foo()
    println("calling fib")
    @show fib(80)
    println("done.")
end
Cassette.overdub(MemoizeCtx(metadata=Dict{Int,Int}()), foo)

(盒式磁带在编译器上仍然相当困难,因此第一次运行可能需要一段时间,但之后会很快)。

答案 1 :(得分:5)

最简单的方法是使用get!

const fibmem = Dict{Int,Int}()
function fib(n)
    get!(fibmem, n) do
        n < 3 ? 1 : fib(n-1) + fib(n-2)
    end
end

请注意fibmem之外的const指定符。这样可以避免使用global,并且可以使代码更快,因为它允许编译器在fib中使用类型推断。

答案 2 :(得分:1)

由于函数的参数是整数,因此可以使用简单的数组,该数组的速度比Dict快(请确保在高速缓存中为大参数使用BigInt s以避免溢出) ):

function fib(n, cache=sizehint!(BigInt[0,1],n))
    n < length(cache) && return cache[n+1]
    f = fib(n-1,cache) + fib(n-2,cache)
    push!(cache,f)
    return f
end