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

Итерация по узлам

Для данного объекта AbstractInterpolation itp возвращает итератор по его узлам с использованием knots(itp):

using Interpolations
itp = interpolate(rand(4), options...)
kiter = knots(itp) # Итератор по узлам
collect(kiter) # Массив узлов [1, 2, 3, 4]

Для нескольких измерений итератор возвращает кортежи позиций ((x, y, ...)) с перебором в первую очередь по первой координате.

julia> itp = interpolate(ones(3,3), BSpline(Linear()));

julia> kiter = knots(itp);

julia> collect(kiter)
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 1)  (1, 2)  (1, 3)
 (2, 1)  (2, 2)  (2, 3)
 (3, 1)  (3, 2)  (3, 3)

Количество элементов и размер итератора можно определить следующим образом:

julia> length(kiter)
9

julia> size(kiter)
(3, 3)

Экстраполируемые узлы

Для данного объекта AbstractExtrapolation etp метод knots(etp) также выполняет итерацию по узлам по следующим правилам:

  • Для Throw, Flat и Line выполняется однократная итерация.

  • Для Periodic и Reflect создается бесконечная последовательность узлов, начинающаяся с первого узла.

Так как для Periodic и Reflect создаются бесконечные последовательности узлов, значения length и size не определены. Для Throw, Flat и Line значения length и size определяются обычным образом.

Периодическое граничное условие

При граничном условии Periodic узлы повторяются бесконечно, причем первый и последний узлы находятся в одной позиции. (Поэтому в приведенном ниже примере etp(2.0) = 1.0, а не 4.0.)

julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation(x, x.^2, extrapolation_bc=Periodic());

julia> kiter = knots(etp);

julia> k = Iterators.take(kiter, 6) |> collect
6-element Vector{Float64}:
 1.0
 1.5
 1.75
 2.0
 2.5
 2.75

Экстраполяция в сгенерированные узлы etp.(k) подтверждает, что экстраполированные узлы соответствуют правильным входящим узлам (то есть etp(k[1]) == etp(k[4])).

julia> etp.(k)
6-element Vector{Float64}:
 1.0
 2.25
 3.0625
 1.0
 2.25
 3.0625

Отражение

При граничном условии Reflect узлы повторяются бесконечно по приведенной ниже схеме (члены смещения для краткости опущены).

k[1], k[2], ..., k[end-1], k[end], k[end+1], ... k[2], k[1], k[2], ...
julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation(x, x.^2, extrapolation_bc=Reflect());

julia> kiter = knots(etp);

julia> k = Iterators.take(kiter, 6) |> collect
6-element Vector{Float64}:
 1.0
 1.5
 1.75
 2.0
 2.25
 2.5

Вычисление экстраполяции в etp.(k) подтверждает, что экстраполированные узлы соответствуют правильным входящим узлам.

julia> etp.(k)
6-element Vector{Float64}:
 1.0
 2.25
 3.0625
 4.0
 3.0625
 2.25

Несколько измерений

Как и в случае с AbstractInterpolation, итерация по узлам поддерживается и для многомерной экстраполяции.

julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation((x, x), x.*x');

julia> knots(etp) |> collect
4×4 Matrix{Tuple{Float64, Float64}}:
 (1.0, 1.0)   (1.0, 1.5)   (1.0, 1.75)   (1.0, 2.0)
 (1.5, 1.0)   (1.5, 1.5)   (1.5, 1.75)   (1.5, 2.0)
 (1.75, 1.0)  (1.75, 1.5)  (1.75, 1.75)  (1.75, 2.0)
 (2.0, 1.0)   (2.0, 1.5)   (2.0, 1.75)   (2.0, 2.0)

Так как для некоторых граничных условий создается бесконечная последовательность узлов, итерация по узлам может «зацикливаться» на одной оси:

julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation((x, x), x.*x', extrapolation_bc=(Periodic(), Throw()));

julia> knots(etp) |> k -> Iterators.take(k, 6) |> collect
6-element Vector{Tuple{Float64, Float64}}:
 (1.0, 1.0)
 (1.5, 1.0)
 (1.75, 1.0)
 (2.0, 1.0)
 (2.5, 1.0)
 (2.75, 1.0)

Для решения этой проблемы можно переупорядочить оси так, чтобы сначала располагались неповторяющиеся узлы:

julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation((x, x), x.*x', extrapolation_bc=(Throw(), Periodic()));

julia> knots(etp) |> k -> Iterators.take(k, 6) |> collect
6-element Vector{Tuple{Float64, Float64}}:
 (1.0, 1.0)
 (1.5, 1.0)
 (1.75, 1.0)
 (2.0, 1.0)
 (1.0, 1.5)
 (1.5, 1.5)

Направленные граничные условия

Если граничные условия являются направленными, прямое граничное условие используется для определения того, будет ли итератор создавать бесконечную последовательность узлов.

Например, следующая экстраполяция etp будет выдавать ошибку для значений меньше 1.0, но для значений больше 2.0 будет использоваться экстраполяция Periodic. В результате итератор создает бесконечную последовательность узлов, начинающуюся с 1.0.

julia> x = [1.0, 1.2, 1.3, 2.0];

julia> etp = linear_interpolation(x, x.^2, extrapolation_bc=((Throw(), Periodic()),));

julia> kiter = knots(etp);

julia> kiter |> k -> Iterators.take(k, 5) |> collect
5-element Vector{Float64}:
 1.0
 1.2
 1.3
 2.0
 2.2

Проверить, имеет ли итератор конечную длину, можно также с помощью Base.IteratorSize:

julia> Base.IteratorSize(kiter)
Base.IsInfinite()

Если поменять граничные условия местами, получится конечная последовательность узлов от 1.0 до 2.0.

julia> x = [1.0, 1.2, 1.3, 2.0];

julia> etp = linear_interpolation(x, x.^2, extrapolation_bc=((Periodic(), Throw()),));

julia> kiter = knots(etp);

julia> collect(kiter)
4-element Vector{Float64}:
 1.0
 1.2
 1.3
 2.0

Как и следовало ожидать, теперь у итератора есть определенная длина:

julia> Base.IteratorSize(kiter)
Base.HasLength()

julia> length(kiter)
4

julia> size(kiter)
(4,)

knotsbetween

Для данного объекта AbstractInterpolation itp или результатов выполнения knots(itp) возвращает итератор по узлам между start и stop.

using Interpolations
itp = interpolate(rand(4), options...)
krange = knotsbetween(itp; start=1.2, stop=3.0)
collect(kiter) # Массив узлов между 1,2 и 3,0

Для итерации по всем узлам больше start можно опустить stop:

julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation(x, x.^2, extrapolation_bc=Periodic());

julia> krange = knotsbetween(etp; start=4.0);

julia> Iterators.take(krange, 5) |> collect
5-element Vector{Float64}:
 4.5
 4.75
 5.0
 5.5
 5.75

Если опустить start, итерация будет производиться от первого узла до stop:

julia> krange = knotsbetween(etp; stop=4.0);

julia> collect(krange)
9-element Vector{Float64}:
 1.0
 1.5
 1.75
 2.0
 2.5
 2.75
 3.0
 3.5
 3.75

Если не указать ни start, ни stop, произойдет ошибка:

julia> knotsbetween(etp)
ERROR: ArgumentError: At least one of `start` or `stop` must be specified
[...]

Несколько измерений

При использовании с многомерным интерполянтом knotsbetween позволяет выполнять итерацию по узлам так, что start[i] < k[i] stop[i], где i — индекс измерения.

julia> x = [1.0, 1.5, 1.75, 2.0];

julia> etp = linear_interpolation((x, x), x.*x');

julia> knotsbetween(etp; start=(1.2, 1.5), stop=(1.8, 3.0)) |> collect
2×2 Matrix{Tuple{Float64, Float64}}:
 (1.5, 1.75)   (1.5, 2.0)
 (1.75, 1.75)  (1.75, 2.0)