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

Расширения

Начиная с версии Julia v1.9 пакеты могут предоставлять код расширения, который загружается при загрузке внешних пакетов.

Makie

При загрузке Makie предоставляется шаблон графика.

ChainRulesCore

При загрузке ChainRulesCore определяются правила frule и rrule для интеграции с другими пакетами автоматического дифференцирования.

MutableArithmetics

При загрузке пакета MutableArithmetics расширение предоставляет функциональные возможности для ряда типов многочленов, описанных далее. До версии v1.9 те же функциональные возможности предоставлял внешний пакет PolynomialsMutableArithmetics.

Хотя многочлены типа Polynomial являются изменяемыми объектами, такие операции, как +, - и *, всегда создают новые многочлены, не изменяя их аргументы. В некоторых случаях время, требуемое для выделения памяти и копирования коэффициентов многочленов, может быть заметным. Ситуация усугубляется, когда коэффициенты имеют, например, тип BigInt или BigFloat, который сам по себе является изменяемым. Во избежание этого можно изменить существующие многочлены так, чтобы они содержали результат операции, с помощью API MutableArithmetics (MA).

Рассмотрим, например, следующие массивы многочленов.

using Polynomials
d, m, n = 30, 20, 20
p(d) = Polynomial(big.(1:d))
A = [p(d) for i in 1:m, j in 1:n]
b = [p(d) for i in 1:n]

В данном случае массивы представляют собой изменяемые объекты, элементы которых — это изменяемые многочлены с изменяемыми коэффициентами (типа BigInt). Чтобы сократить объем выделяемой памяти для этих трех уровней вложенности изменяемых объектов, задействуется API MA. Вызов A * b требует примерно 2 млн выделений объемом 40 МиБ, так как изменяемость не используется.

using MutableArithmetics  # или `using PolynomialsMutableArithmetics` для регистрации `Polynomials` в `MutableArithmetics`

const MA = MutableArithmetics
MA.operate(*, A, b)

использует изменяемость, поэтому происходит всего 4 тысячи выделений объемом примерно 70 КиБ.

Если итоговый вектор уже размещен в памяти, например:

z(d) = Polynomial([zero(BigInt) for i in 1:d])
c = [z(2d - 1) for i in 1:m]

то его изменяемость можно использовать с помощью вызова

MA.operate!(MA.add_mul, c, A, b)

для снижения числа выделений до трех, а их объема до 48 байтов.

Эти оставшиеся выделения обусловлены необходимостью использовать буфер BigInt для хранения результата промежуточных вычислений. Этот буфер можно предварительно разместить в памяти:

buffer = MA.buffer_for(MA.add_mul, typeof(c), typeof(A), typeof(b))
MA.buffered_operate!(buffer, MA.add_mul, c, A, b)

и тогда во второй строке память выделяться не будет.

Макрос MA.@rewrite преобразует выражение в эквивалентный код, который использует изменяемость промежуточных результатов. Например, следующее выражение:

MA.@rewrite(A1 * b1 + A2 * b2)

преобразуется в следующий код:

c = MA.operate!(MA.add_mul, MA.Zero(), A1, b1)
MA.operate!(MA.add_mul, c, A2, b2)

что равносильно

c = MA.operate(*, A1, b1)
MA.mutable_operate!(MA.add_mul, c, A2, b2)

Обратите внимание, что в настоящее время только типы Polynomial и Polynomials.PnPolynomial реализуют этот API и только частично.

PolyCompat

Хотя данный компонент не является расширением, старый тип Poly, использовавшийся в этом пакете до версии v0.7, реализован в качестве альтернативного базиса и при желании доступен для применения посредством оператора using Polynomials.PolyCompat. Это сделано для поддержки старой базы кода.