Итерационные решатели как итераторы
В расширенных случаях вам может потребоваться получить доступ к внутренним структурам данных решателя, внедрять код, который будет выполняться после каждой итерации, иметь полный контроль над выделениями или уменьшить затраты на инициализацию. Все это можно сделать в рамках использования итераторов в IterativeSolvers.jl.
На этом этапе методы BiCGStab(l), CG, Чебышева, GMRES, MINRES, QMR и стационарные методы реализуются как итераторы. Однако пакет пока не экспортирует сами итераторы и вспомогательные методы. |
Принципы реализации итераторов
Перечисленные выше решатели, по сути, являются тонкой оболочкой вокруг итератора. Помимо прочего, они инициализируют итерируемый объект, выполняют цикл по итератору и возвращают результат:
function my_solver!(x, A, b)
iterable = MySolverIterable(x, A, b)
for item in iterable end
return iterable.x
end
Вместо вызова my_solver!(x, A, b)
можно также самостоятельно инициализировать итерируемый объект и выполнить цикл for
.
Пример: отказ от ненужной инициализации
Метод Якоби для SparseMatrixCSC
имеет некоторые затраты при инициализации. Нам нужно не только выделить временный вектор, но и найти индексы диагонали (и проверить, что их значения ненулевые). Текущая реализация инициализирует итерируемый объект следующим образом.
jacobi_iterable(x, A::SparseMatrixCSC, b; maxiter::Int = 10) =
JacobiIterable{eltype(x), typeof(x)}(OffDiagonal(A, DiagonalIndices(A)), x, similar(x), b, maxiter)
Теперь, если вы применяете итерацию Якоби несколько раз с одной и той же матрицей в течение нескольких итераций, имеет смысл инициализировать итерируемую матрицу только один раз и впоследствии использовать ее повторно:
julia> using LinearAlgebra, SparseArrays, IterativeSolvers
julia> A = spdiagm(-1 => -ones(3), 0 => 2*ones(4), 1 => -ones(3));
julia> b1 = [1.0, 2, 3, 4];
julia> b2 = [-1.0, 1, -1, 1];
julia> x = [0.0, -1, 1, 0];
julia> my_iterable = IterativeSolvers.jacobi_iterable(x, A, b1, maxiter = 2);
julia> norm(b1 - A * x) / norm(b1)
1.2909944487358056
julia> for item in my_iterable
println("Iteration for rhs 1")
end
Iteration for rhs 1
Iteration for rhs 1
julia> norm(b1 - A * x) / norm(b1)
0.8228507357554791
julia> # Копирование следующей правой части в итерируемый объект
copyto!(my_iterable.b, b2);
julia> norm(b2 - A * x) / norm(b2)
2.6368778887161235
julia> for item in my_iterable
println("Iteration for rhs 2")
end
Iteration for rhs 2
Iteration for rhs 2
julia> norm(b2 - A * x) / norm(b2)
1.610815496107484
Другие варианты использования
В число других вариантов использования входят следующие:
-
вычисление (гармонических) значений Ритца из матрицы Хессенберга в GMRES;
-
сравнение приближенной невязки таких методов, как GMRES и BiCGStab(l), с истинной невязкой во время итераций;
-
обновление предобуславливателя в гибких методах.