Как я могу избежать ошибки StackOverflow на Джулию? - PullRequest
0 голосов
/ 06 февраля 2019

Это небольшая функция продукта, которая преобразует список констант, список операторов и другой список констант в Julia Expr.Функция работает для небольших наборов констант, однако для получения большего списка из 100 констант и 5 операторов функция генерирует StackOverflow.

function applyProduct(left, operators, right)
    prod = Iterators.product(left, operators, right)
    prod = Iterators.vcat(prod...)
    return Iterators.map(x -> Expr(:call, Symbol(x[2]), Symbol(x[1]), Symbol(x[3])), prod)
end

Моя функция взрывается при функции vcat:

ERROR: LoadError: StackOverflowError:
Stacktrace:
[1] promote_eltypeof(::Tuple{String,typeof(+),Expr}, ::Tuple{String,typeof(+),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1211 (repeats 8406 times)
[2] _cat(::Val{1}, ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1382
[3] #cat#104(::Val{1}, ::Function, ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1511
[4] (::getfield(Base, Symbol("#kw##cat")))(::NamedTuple{(:dims,),Tuple{Val{1}}}, ::typeof(cat), ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\none:0
[5] vcat(::Tuple{String,typeof(*),Expr}, ::Tuple{String,typeof(*),Expr}, ::Tuple{String,typeof(*),Expr}, ::Vararg{Any,N} where N) at .\abstractarray.jl:1449

Это ошибка переполнения стека, поэтому данные каким-то образом хранятся в стеке.Должен ли я объявить что-то, чтобы сохранить это в памяти?

Я хотел бы применить эту операцию к большим наборам констант.Может быть, я не использую самый эффективный подход.

Ответы [ 2 ]

0 голосов
/ 06 февраля 2019

Вы определенно хотите предварительно выделить.И избегайте явного перечисления итератора product и использования карт

function applyproduct(left, op, right)
    itr = Iterators.product(op, left, right)
    thestack = Vector{Expr}(undef, length(itr))

    for (i, t) in enumerate(itr)
        thestack[i] = Expr(:call, Symbol.(t)...)
    end

    return thestack
end

N = 500
left = [String(rand('a':'z', rand(1:5))) for _ in 1:N]
right = [String(rand('a':'z', rand(1:5))) for _ in 1:N]
op = ["+", "-", "/", "^", "<", "≤"]

applyproduct(left, op, right)
# 1500000-element Array{Expr,1}:
#  :(wtolz + kzyxh)
#  :(wtolz - kzyxh)
#  ⋮             

Кроме того, вы можете избежать вызова Expr с помощью:

:($(Symbol(t[1]))($(Symbol(t[2])), $(Symbol(t[3]))))  
# :(adsf - sd)
0 голосов
/ 06 февраля 2019

Не материализуйте список, пока не понадобятся его элементы:

using IterTools
function applyProduct2(left, operators, right)
    prod = Iterators.product(left, operators, right)
    return IterTools.imap(x -> Expr(:call, Symbol(x[2]), Symbol(x[1]), Symbol(x[3])), prod)
end

обратите внимание, что вам может потребоваться установить библиотеку IterTools.jl.

С учетом того, что ваш код падает на vcat где вы пытаетесь назвать это с огромным количеством аргументов.Если вам нужно материализоваться, используйте vec(collect(prod)).

...