Considering this function, which I've just moved from a recursive design to
an iterative paradigm
const Sub = Base.ImmutableDict{Any, Tuple{EClass, Any}}
const SubBuf = Vector{Sub}
# https://www.hpl.hp.com/techreports/2003/HPL-2003-148.pdf
# page 48
"""
From [https://www.hpl.hp.com/techreports/2003/HPL-2003-148.pdf](https://www.hpl.hp.com/techreports/2003/HPL-2003-148.pdf)
The iterator `ematchlist` matches a list of terms `t` to a list of E-nodes by first finding
all substitutions that match the first term to the first E-node, and then extending
each such substitution in all possible ways that match the remaining terms to
the remaining E-nodes. The base case of this recursion is the empty list, which
requires no extension to the substitution; the other case relies on Match to find the
substitutions that match the first term to the first E-node.
"""
function ematchlist(e::EGraph, t::AbstractVector{Pattern}, v::AbstractVector{Int64}, sub::Sub, buf::SubBuf)::SubBuf
lt = length(t)
lv = length(v)
!(lt == lv) && (return buf)
# currbuf = buf
currbuf = SubBuf()
push!(currbuf, sub)
for i ∈ 1:lt
newbuf = SubBuf()
while !isempty(currbuf)
currsub = pop!(currbuf)
ematchstep(e, t[i], v[i], currsub, newbuf, nothing)
end
currbuf = newbuf
end
for sub1 ∈ currbuf
push!(buf, sub1)
end
return buf
end
Allocating new buffers every time is expensive, and I have basically no performance gain from the recursive version. How can I optimize this loop, removing unnecessary "buffer creations", knowing that i have my output buf
already waiting to be "push!-ed" ? A thing worth noting is that the subcall to ematchstep
pushes new elements to newbuf
.
Last updated: Nov 22 2024 at 04:41 UTC