Linear solvers
Most NEP-solvers require
The user can specify which linear solver or eigenvalue solver he/she wants to use. It is also possible to use external or user-defined solvers.
Linear system of equations
As a user, you can provide a creator object to many NEP-solvers via the keyword argument linsolvercreator
. The creator object corresponds to one (or several) linear system solvers. By default, DefaultLinSolverCreator
is used which tries to determine an appropriate linear solver based on the NEP-type. In the next section, we list the default linear solvers.
If you wish to define your own linear solver, you need to define your own type inheriting from LinSolver
as well as a LinSolverCreator
. See the documenation for LinSolver
and the tutorial on linear solvers.
LinSolver
-objects and creators
struct FactorizeLinSolver <: LinSolver
This represents the linear solver associated with julia factorize()
. See LinSolver
and FactorizeLinSolverCreator
for examples.
FactorizeLinSolverCreator(;umfpack_refinements,max_factorizations,nep,precomp_values)
FactorizeLinSolverCreator
-objects can instantiate FactorizeLinSolver
objects via the create_linsolver
function.
The FactorizeLinSolver
is based on factorize
-calls. The time point of the call to factorize
can be controlled by parameters to FactorizeLinSolverCreator
:
By default, the
factorize
call is carried out by the instantiation of theFactorizeLinSolver
, i.e., when the NEP-solver callscreate_linsolver
.You can also precompute the factorization, at the time point when you instantiate
FactorizeLinSolverCreator
. If you setprecomp_values::Vector{Number}
to a non-empty vector, and setnep
kwarg, the factorization (of all λ-values in theprecomp_values
) will be computed when theFactorizeLinSolverCreator
is instantiated. If the NEP-solver calls acreate_linsolver
with a λ-value from that vector, the factorization will be used (otherwise it will be computed).
Further recycling is possible. If the variable max_factorizations
is set to a positive value, the object will store that many factorizations for possible reuse. Every lin_solve
-call then computes a factorization, unless a lin_solve
-call for that λ
has been computed earlier. This procedure can at most store max_factorization
(which can be set Inf
).
See also: FactorizeLinSolver
, create_linsolver
struct BackslashLinSolver <: LinSolver
This represents a linear solver corresponding to the backslash operator (no pre-factorization).
See also: LinSolver
and BackslashLinSolverCreator
struct BackslashLinSolverCreator <: LinSolverCreator
Creator to for the BackslashLinSolver
, i.e., usage of backslash to make linear solves. Specify objects of this type if you want the solver to use backslash.
See also: BackslashLinSolver
, create_linsolver
struct GMRESLinSolver <: LinSolver
This represents a solver done with the julia GMRES implementation.
See also: LinSolver
, GMRESLinSolverCreator
GMRESLinSolverCreator(;kwargs...)
This is the creator for the GMRES-method. Instantiate this object if you want to use GMRES as your linear system solver. The kwargs
are stored and used as keyword arguments in the call to gmres. See list of keyword in the IterativeSolvers.jl manual.
DefaultLinSolverCreator
This is the default linear solver if no other is specified (for most methods). It is a FactorizeLinSolverCreator
.
See also: LinSolver
, create_linsolver
, lin_solve
, FactorizeLinSolverCreator
, FactorizeLinSolver
Advanced usage
abstract type LinSolver
Structs inheriting from this type are able to solve linear systems associated with a NEP, for a specific λ
-value. The most common are direct solvers such as FactorizeLinSolver
, BackslashLinSolver
and iterative solvers such as GMRESLinSolver
.
The LinSolver objects are usually created by the NEP-algorithms through creator functions, which are passed as parameters.
Example
The most common usecase is that you want to pass a linsolvercreator
-function as a parameter to the NEP-algorithm. This example shows how you can use solvers based on backslash or factorize()
. In the example, BackslashLinSolver
does not exploit that the system matrix remains the same throughout the algorithm and is therefore slower.
julia> nep=nep_gallery("qdep0");
julia> using BenchmarkTools
julia> v0=ones(size(nep,1));
julia> @btime λ,v=quasinewton(nep,λ=-1,v=v0, linsolvercreator=DefaultLinSolverCreator());
181.017 ms (3779 allocations: 58.61 MiB)
julia> @btime λ,v=quasinewton(nep,λ=-1,v=v0, linsolvercreator=BackslashLinSolverCreator());
2.040 s (4510 allocations: 553.24 MiB)
Example
The LinSolver
s are constructed for extendability. This example creates our own LinSolver
which uses an explicit formula for the inverse if the NEP has dimension 2x2.
Create the types and a creator.
julia> using LinearAlgebra
julia> struct MyLinSolver <: LinSolver
M::Matrix{ComplexF64}
end
julia> function my_linsolvercreator(nep,λ)
M=compute_Mder(nep,λ);
return MyLinSolver(M);
end
Explicit import lin_solve
to show how to solve a linear system.
julia> import NonlinearEigenproblems.LinSolvers.lin_solve;
julia> function lin_solve(solver::MyLinSolver,b::AbstractVecOrMat;tol=0)
M=solver.M;
invM=(1/(det(M)))*[M[2,2] -M[1,2];-M[2,1] M[1,1]]
return invM*b
end
julia> nep=SPMF_NEP([[1.0 3.0; 4.0 5.0], [2.0 1.0; -1 2.0]], [S->S^2,S->exp(S)])
julia> λ,v=quasinewton(nep,λ=-1,v=[1;1],linsolvercreator=my_linsolvercreator);
See also: lin_solve
, FactorizeLinSolver
, FactorizeLinSolver
, DefaultLinSolverCreator
, BackslashLinSolver
, BackslashLinSolverCreator
, GMRESLinSolver
, GMRESLinSolverCreator
NonlinearEigenproblems.LinSolvers.lin_solve
— Function.lin_solve(solver::LinSolver, b::AbstractVecOrMat; tol=0)
This function solves the linear system represented in solver::LinSolver
with a right-hand side b
. The tol
kwarg is controlling how accurate the linear system needs to be solved. A NEP-algorithm will call this solver every time a linear system associated with M(λ)
needs to be solved.
This function must be overloaded if a user wants to define their own way of solving linear systems. See LinSolver
for examples.
create_linsolver(creator::LinSovlerCreator,nep,λ)
Creates a LinSolver
instance for the nep
corresponding which is evaluated in λ
. The type of the output is decided by dispatch and the type of the LinSolverCreator
.
See also: LinSolver
, FactorizeLinSolverCreator
, BackslashLinSolverCreator
, DefaultLinSolverCreator
, GMRESLinSolverCreator
.
Standard eigenvalue problems
Some NEP-algorithms need to solve an associated linear eigenvalue problem, associated with M(λ)
. We provide the possibility to use Julia-native eigenvalue solvers, and an interface which allows you to define your own solver. By default, DefaultEigSolver
is specified, which tries to determine an appropriate eigenvalue solver based on the NEP-type.
struct DefaultEigSolver <: EigSolver
A linear eigenvalueproblem solver that calls checks for sparsity and accordingly assigns an appropriate solver.
See also: EigSolver
, eig_solve
, EigenEigSolver
, ArnoldiEigSolver
struct EigenEigSolver <: EigSolver
A linear eigenvalueproblem solver that calls Julia's in-built eigen()
Constructed as EigenEigSolver(A, [B,])
, and solves the problem
The paramter B
is optional an default is indentity, for which a standard linear eigenproblem is solved.
struct ArnoldiEigSolver <: EigSolver
A linear eigenproblem solver for large and sparse problems that calls the Arnoldi method implemented in the Julia package ArnoldiMethod.jl.
Constructed as ArnoldiEigSolver(A, [B,])
, and solves the problem
The paramter B
is optional an default is indentity, for which a standard linear eigenproblem is solved.
abstract type EigSolver
Structs inheriting from this type are able to solve linear eigenvalue problems arising in certain methods, such as, e.g., mslp
, sgiter
, and polyeig
.
The EigSolver
objects are passed as types to the NEP-algorithms, which uses it to dispatch the correct version of the function eig_solve
.
Example
The most common usecase is that you do not want to specify anything in particular, since the DefaultEigSolver
will use a dense or a sparse method depending on you problem. However, this example shows how you can force mslp
to use the sparse solver.
julia> nep=nep_gallery("qdep0");
julia> λ,v = mslp(nep, eigsolvertype=ArnoldiEigSolver);
julia> norm(compute_Mlincomb(nep,λ,v))
9.323110647141726e-16
Example
The EigSolver
s are constructed for extendability. As an illustartion this example creates a naive EigSolver
which casts the problem to a standard linear eigenproblem and calls the built-in function to solve it.
Create the types and a creator.
julia> struct MyEigSolver <: EigSolver
A
E
function MyEigSolver(A,E)
return new(A,E)
end
end
julia> import NonlinearEigenproblems.LinSolvers.eig_solve;
julia> function eig_solve(solver::MyEigSolver;nev = 1, target = 0)
M = solver.E \ solver.A
eig = eigen(M)
i = argmin(abs.(eig.values))
return eig.values[i], eig.vectors[:,i]
end
julia> nep=nep_gallery("dep0", 50);
julia> λ,v = mslp(nep, eigsolvertype=MyEigSolver, tol=1e-5);
julia> norm(compute_Mlincomb(nep,λ,v))
3.0777795031319117e-10
See also: eig_solve
, DefaultEigSolver
, EigenEigSolver
, ArnoldiEigSolver
, eig_solve
NonlinearEigenproblems.LinSolvers.eig_solve
— Function.eig_solve(solver::EigSolver; [nev,] [target,])
This function solves the linear eigenvalue problem represented in solver::EigSolver
. The nev
kwarg is controlling the number of eigenvalues aimed for, and target
specifies around which point the eigenvalues are computed. The former has a defalut value equalt to the seize of the problem, and the latter has a defalut value 0.
Return values are of the form (Vector, Matrix) where the former contains the eigenvalues and the latter the eigenvectors.
This function must be overloaded if a user wants to define their own way of solving linear eigenvalue problems. See EigSolver
for examples.