# GenericSchur

GenericSchur is a Julia package for eigen-analysis of dense
real and complex matrices of generic numeric type, i.e. those
not supported by the LAPACK-based routines in the standard LinearAlgebra
library. Examples are `BigFloat`, `Float128`, and `DoubleFloat`.

Normally, the `schur!`, `eigvals!`, `eigen!`, and `ordschur!` functions
in the `LinearAlgebra`
standard library are overloaded here, and may be accessed through the usual
`schur`, `eigvals`, `eigen`, and `ordschur` wrappers.

!!! note "Type piracy"
	Most users will enjoy the convenience of the functions from `LinearAlgebra`,
	but these piratical methods may be omitted; see the [Preferences](@ref) section
	for details.

## Complex Schur decomposition

The Schur decomposition is the workhorse for eigensystem analysis of
dense non-symmetric matrices.

This package provides a full Schur decomposition of complex square matrices:
```julia
A::StridedMatrix{C} where {C <: Complex} == Z * T * adjoint(Z)
```
where `T` is upper-triangular and `Z` is unitary, both with the same element
type as `A`.

```julia
A = your_matrix_generator() .+ 0im # in case you start with a real matrix
S = schur(A)
```
The result `S` is a `LinearAlgebra.Schur` object, with the properties `T`,
`Z=vectors`, and `values`.

The unexported [`GenericSchur.gschur`](@ref) and [`GenericSchur.gschur!`](@ref)
functions are available
for use when type piracy is suppressed, and for types
normally handled by the LAPACK wrappers in `LinearAlgebra`.

The algorithm is essentially the unblocked, serial, single-shift Francis (QR)
scheme used in the complex LAPACK routines. Scaling is enabled for balancing,
but currently permutation (which would reduce the work) is not.

## Hermitian matrices

The Schur decomposition of a Hermitian (or real symmetric) matrix is identical to
diagonalization, i.e.
the upper-triangular factor is diagonal. This package provides such decompositions
for real-symmetric and complex-Hermitian matrices via `eigen!`
(and [`GenericSchur.geigen!`](@ref)) etc.
In these cases, an `alg` argument
may be used to select a `LinearAlgebra.QRIteration` or `LinearAlgebra.DivideAndConquer`
algorithm. The divide-and-conquer scheme takes a long time to compile, but execution
is significantly faster than QR iteration for large matrices.

## Real decompositions

A quasi-triangular "real Schur" decomposition of real matrices is also
provided:
```julia
A::StridedMatrix{R} where {R <: Real} == Z * T * transpose(Z)
```
where `T` is quasi-upper-triangular and `Z` is orthogonal, both with the
same element type as `A`.  This is what you get by invoking the above-mentioned
functions with matrix arguments whose element type `T <: Real`.
By default, the result is in standard form, so
pair-blocks (and therefore rank-2 invariant subspaces) should be fully resolved.
(This differs from the original version in GenericLinearAlgebra.jl.)

If the optional keyword `standardized` is set to `false` in `gschur`, a
non-standard (but less expensive) form is produced.

## Eigenvectors

Right and left eigenvectors are available from Schur factorizations,
using

```julia
S = schur(A)
VR = eigvecs(S)
VL = eigvecs(S,left=true)
```
or [`GenericSchur.geigvecs`](@ref).
The results are currently unreliable if the Frobenius norm of `A` is extremely
small or large, so scale if necessary (also see Balancing, below).

## Balancing

The accuracy of eigenvalues and eigenvectors may be improved for some
matrices by use of a similarity transform which reduces the matrix
norm.  This is done by default in the `eigen!` method, and may also be
handled explicitly via the [`balance!`](@ref) function provided here:
```julia
Ab, B = balance!(copy(A))
S = schur(Ab)
v = eigvecs(S)
lmul!(B, v) # to get the eigenvectors of A
```
More details are in the function docstring. Although the balancing function
also does permutations to isolate trivial subspaces, the Schur routines do not
yet exploit this opportunity for reduced workload.

## Generalized problems

The generalized Schur decomposition of matrix pencils is provided via `schur(A,B)`, or
[`GenericSchur.ggschur!(A,B)`](@ref), for real and complex element types. No specific
implementations are currently provided for Hermitian/Symmetric problems.

Note that although many nearly singular matrix pencils can be factored and reordered
with our implementations, accuracy may suffer; for such problems it is best to
extract the regular part with a Kronecker-like decomposition (see the `MatrixPencils`
package).

Right and left eigenvectors are available for generalized problems, via
`eigvecs(S::GeneralizedSchur)` and `geigvecs(S::GeneralizedSchur)`.

## Reordering
An invariant (viz. deflating) subspace may be extracted via methods of the
`LinearAlgebra.ordschur` function; see the documentation in the LinearAlgebra stdlib.
(The [`GenericSchur.gordschur!`](@ref) function may also be used, especially if type
piracy is disabled.)  This package provides reordering methods for ordinary and
generalized Schur factorizations, both real and complex element types.

## Preferences
The runtime behavior can be adjusted by use of the
[Preferences](https://github.com/JuliaPackaging/Preferences.jl) package.

The `piracy` preference may be set to "true" (the default) or "false" to determine
whether methods are added to functions such as `LinearAlgebra.schur!`.

## Acknowledgements

This package includes translations from [LAPACK](http://www.netlib.org/lapack/index.html)
code, and incorporates or elaborates several methods from Andreas Noack's
[GenericLinearAlgebra.jl](http://github.com/JuliaLinearAlgebra/GenericLinearAlgebra.jl)
package.



