Документация Engee

Создание и компиляция функций (build_function)

В любой момент вызываемые функции могут быть сгенерированы из IR Symbolics с помощью Symbolics.toexpr. При этом выполняется определенная очистка для возвращения выражения без лишних частей, что обычно соответствует выражениям, которые можно написать в функциях, например для решателей дифференциальных уравнений или библиотек оптимизации. Эти функции можно автоматически распараллелить. Они также могут специализировать такие типы Julia, как статические массивы и разреженные матрицы.

Основным процессом компиляции IR Symbolics является build_function. build_function принимает операцию или AbstractArray операций и генерирует компилируемую версию модели для численных решателей. Форма этого вывода зависит от target. По умолчанию целевой объект выводит код Julia, но доступны и другие форматы, такие как C, Stan и MATLAB. Они могут быть сгенерированы как выражения, которые затем могут быть вычислены в вызываемую функцию, либо могут быть вызваны компиляторы для соответствующих целевых объектов для непосредственного возвращения дескриптора функции.

build_function

# Symbolics.build_functionFunction

build_function

Генерирует пригодную для численного использования функцию из Symbolics Num.

build_function(ex, args...;
               expression = Val{true},
               target = JuliaTarget(),
               parallel=nothing,
               kwargs...)

Аргументы

  • ex: компилируемое Num

  • args: аргументы функции

  • expression: следует ли генерировать код или генерировать скомпилированную форму. По умолчанию expression = Val{true}, что означает, что возвращается код функции. Если Val{false}, возвращаемое значение компилируется.

Именованные аргументы

  • target: выходной объект процесса компиляции. Возможные значения:

    • JuliaTarget: генерирует функцию Julia

    • CTarget: генерирует функцию C

    • StanTarget: генерирует функцию для компиляции с использованием языка вероятностного программирования Stan

    • MATLABTarget: генерирует анонимную функция для использования в средах MATLAB и Octave

  • parallel: тип параллелизма, который следует использовать в генерируемой функции. Значение по умолчанию — SerialForm(), т. е. параллелизм отсутствует, если ex — это единственное выражение или массив, содержащий не более 1500 ненулевых выражений. Если ex является массивом, содержащим более 1500 ненулевых выражений, используется ShardedForm(80, 4). Дополнительные сведения о ShardedForm см. ниже. Обратите внимание, что параллельные формы не экспортируются и поэтому должны быть выбраны как Symbolics.SerialForm(). Вот возможные варианты.

    • SerialForm(): последовательное выполнение.

    • ShardedForm(cutoff, ncalls): делит выходную функцию на подфункции. which contain at most cutoff number of output rhss. These sub-functions are called by the top-level function that buildfunction returns. This helps in reducing the compile time of the generated function.

    • MultithreadedForm(): многопоточное выполнение со статическим разделением, равномерно распределяющим количество выражений на поток. splitting the number of expressions per thread.

  • fname: используется некоторыми целевыми объектами для имени функции в целевом пространстве.

Обратите внимание, что не все целевые объекты построения поддерживают полный интерфейс компиляции. Более подробные сведения см. в документации по конкретному целевому объекту.

Определения, относящиеся к конкретным целевым объектам

# Symbolics._build_function — _Method

_build_function(target::JuliaTarget, rhss::AbstractArray, args...;
                   conv=toexpr,
                   expression = Val{true},
                   expression_module = @__MODULE__(),
                   checkbounds = false,
                   postprocess_fbody=ex -> ex,
                   linenumbers = false,
                   outputidxs=nothing,
                   skipzeros = false,
                   force_SA = false,
                   wrap_code = (nothing, nothing),
                   fillzeros = skipzeros && !(rhss isa SparseMatrixCSC),
                   states = LazyState(),
                   iip_config = (true, true),
                   parallel=nothing, cse = false, kwargs...)

Целевой объект функции построения: JuliaTarget

function _build_function(target::JuliaTarget, rhss, args...;
                         conv = toexpr,
                         expression = Val{true},
                         checkbounds = false,
                         linenumbers = false,
                         headerfun = addheader, outputidxs=nothing,
                         convert_oop = true, force_SA = false,
                         skipzeros = outputidxs===nothing,
                         fillzeros = skipzeros && !(typeof(rhss)<:SparseMatrixCSC),
                         parallel=SerialForm(), kwargs...)

Генерирует функцию Julia, которая может быть использована для дальнейших вычислений. Если expression=Val{false}, возвращается функция Julia, которая использует RuntimeGeneratedFunctions.jl, чтобы исключить проблемы с «возрастом мира».

Если rhss является скаляром, генерируемая функция — это функция со скалярным выводом. В противном случае, если это AbstractArray, выводом являются две функции, одна из которых предназначена для вывода AbstractArray не на месте, а вторая является изменяемой. Выводимые функции соответствуют заданному порядку аргументов, т. е. f(u,p,args…​) для функций не на месте и скалярных функций и f!(du,u,p,args..) для версии на месте.

Специальные именованные аргументы

  • parallel: тип параллелизма, который следует использовать в генерируемой функции. Значение по умолчанию — SerialForm(), т. е. параллелизм отсутствует. Обратите внимание, что параллельные формы не экспортируются и поэтому должны быть выбраны как Symbolics.SerialForm(). Вот возможные варианты.

    • SerialForm(): последовательное выполнение.

    • ShardedForm(cutoff, ncalls): делит выходную функцию на подфункции. which contain at most cutoff number of output rhss. These sub-functions are called by the top-level function that buildfunction returns.

    • MultithreadedForm(): многопоточное выполнение со статическим разделением, равномерно распределяющим количество выражений на поток. splitting the number of expressions per thread.

  • conv: функция преобразования символьных типов в выражения. По умолчанию используется функция toexpr.

  • checkbounds: включать ли проверку границ внутри сгенерированной функции. Значение по умолчанию — false, означающее, что применяется @inbounds.

  • linenumbers: определяет, сохранять ли в сгенерированном выражении функции номера строк. Значение по умолчанию — true.

  • convert_oop: определяет, должна ли версия OOP пытаться преобразовать выходные данные в соответствии с типом первых входных данных. Полезно для таких случаев, как использование массивов LabelledArray или других типов массивов, которые несут дополнительную информацию. Значение по умолчанию — true.

  • force_SA: возвращает выходные данные версию OOP в виде StaticArray. По умолчанию имеет значение false и выводит статический массив, если первый аргумент является статическим массивом.

  • skipzeros: нужно ли пропускать заполнение нулей в версии на месте, если функция заполнения равна 0.

  • fillzeros: нужно ли выполнять fill(out,0) перед вычислениями, чтобы обеспечить безопасность при работе с skipzeros.

# Symbolics._build_function — _Method

Целевой объект функции построения: CTarget

function _build_function(target::CTarget, eqs::Array{<:Equation}, args...;
                         conv = toexpr, expression = Val{true},
                         fname = :diffeqf,
                         lhsname=:du,rhsnames=[Symbol("RHS$i") for i in 1:length(args)],
                         libpath=tempname(),compiler=:gcc)

Создает функцию C на месте. Работает только в массивах уравнений. Если expression == Val{false}, то создается функция на C, затем она компилируется и возвращается лямбда этой скомпилированной функции. Компиляцией управляют следующие специальные именованные аргументы.

  • libpath: путь для хранения двоичного файла. По умолчанию используется временный путь.

  • compiler: какой компилятор C следует использовать. По умолчанию используется :gcc, который на данный момент является единственным доступным вариантом.

# Symbolics._build_function — _Method

Целевой объект функции построения: StanTarget

function _build_function(target::StanTarget, eqs::Array{<:Equation}, vs, ps, iv;
                         conv = toexpr, expression = Val{true},
                         fname = :diffeqf, lhsname=:internal_var___du,
                         rhsnames=[:internal_var___u,:internal_var___p,:internal_var___t])

Создает функцию Stan на месте, совместимую с решателями дифференциальных уравнений Stan. В отличие от других целевых объектов построения, этот требует (vs, ps, iv) в качестве аргументов функции. Работает только в массивах уравнений.

# Symbolics._build_function — _Method

Целевой объект функции построения: MATLABTarget

function _build_function(target::MATLABTarget, eqs::Array{<:Equation}, args...;
                         conv = toexpr, expression = Val{true},
                         lhsname=:internal_var___du,
                         rhsnames=[:internal_var___u,:internal_var___p,:internal_var___t])

Создает анонимную функцию @(t,rhsnames[1]) не на месте, которая будет использоваться в MATLAB. Она совместима с решателями дифференциальных уравнений MATLAB. Работает только в выражениях и массивах выражений.