Итерация по узлам
Для данного объекта 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)