Расширения
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)
Обратите внимание, что в настоящее время только типы |
PolyCompat
Хотя данный компонент не является расширением, старый тип Poly
, использовавшийся в этом пакете до версии v0.7
, реализован в качестве альтернативного базиса и при желании доступен для применения посредством оператора using Polynomials.PolyCompat
. Это сделано для поддержки старой базы кода.