)abbrev package IEP InnerEigenPackage
++ Author: P. Gianni
++ Description:
++  This is a package for the exact computation of eigenvalues and
++  eigenvectors.  This package works for matrices with coefficients from
++  a field over which we can factor polynomials.  Eigenvalues in base
++  field are always explicitly computed while the other are expressed
++  in terms of their minimal polynomial.
InnerEigenPackage(F : Field) : Exports == Implementation
 where
   UP   ==> SparseUnivariatePolynomial(F)
   M     ==> Matrix(F)
   NNI   ==> NonNegativeInteger
   AV    ==> Vector(UP)

   Eigenvalue  ==> Union(F, UP)
   EigenForm ==> Record(eigval : Eigenvalue, eigmult : NNI, eigvec : List AV)
   GenEigen  ==> Record(eigval : Eigenvalue, geneigvec : List AV)

   Exports == with

     characteristicPolynomial :  M ->  UP
       ++ characteristicPolynomial(m) returns the characteristic
       ++ polynomial of the matrix m

     eigenvalues : (M, UP -> Factored(UP)) ->  List Eigenvalue
       ++ eigenvalues(m, fac) returns the eigenvalues of the
       ++ matrix m.  Eigenvalues in base field are given
       ++ explicitly, other are represented by minimal polynomial.
       ++ fac is a factorizer for polynomials over F.

     eigenvector : (Eigenvalue, M)  ->  List AV
       ++ eigenvector(eigval, m) returns the
       ++ eigenvectors belonging to the eigenvalue eigval
       ++ for the matrix m.

     generalizedEigenvector : (Eigenvalue, M, NNI, NNI) -> List AV
       ++ generalizedEigenvector(alpha, m, k, g)
       ++ returns the generalized eigenvectors
       ++ of the matrix relative to the eigenvalue alpha.
       ++ The integers k and g are respectively the algebraic and the
       ++ geometric multiplicity of the eigenvalue alpha.

     generalizedEigenvector  : (EigenForm, M) -> List AV
       ++ generalizedEigenvector(eigen, m)
       ++ returns the generalized eigenvectors
       ++ of the matrix relative to the eigenvalue eigen, as
       ++ returned by the function eigenvectors.

     generalizedEigenvectors : (M, UP -> Factored(UP)) -> List GenEigen
       ++ generalizedEigenvectors(m, fac) returns the generalized
       ++ eigenvectors of the matrix m.
       ++ fac is a factorizer for polynomials over F.

     eigenvectors : (M, UP -> Factored(UP)) ->  List(EigenForm)
       ++ eigenvectors(m, fac) returns the eigenvalues and eigenvectors
       ++ for the matrix m.
       ++ The eigenvalues in base field and corresponding eigenvectors
       ++ are explicitly computed, while the other eigenvalues
       ++ are given via their minimal polynomial and the corresponding
       ++ eigenvectors are expressed in terms of a "generic" root of
       ++ such a polynomial.
       ++ fac is a factorizer for polynomials over F.

     if F has PolynomialFactorizationExplicit then

       eigenvalues : M -> List Eigenvalue
         ++ eigenvalues(m) returns the eigenvalues of the matrix m.
       eigenvectors : M ->  List(EigenForm)
         ++ eigenvectors(m) returns the eigenvalues and eigenvectors
         ++ for the matrix m.
         ++ The eigenvalues in base field and corresponding eigenvectors
         ++ are explicitly computed, while the non rational ones
         ++ are given via their minimal polynomial and the corresponding
         ++ eigenvectors are expressed in terms of a "generic" root of
         ++ such a polynomial.
       generalizedEigenvectors  : M -> List GenEigen
         ++ generalizedEigenvectors(m) returns the generalized
         ++ eigenvectors of the matrix m.

   Implementation == add

     if F has PolynomialFactorizationExplicit then

         eigenvalues(m) == eigenvalues(m, factorPolynomial$F)

         eigenvectors(m) == eigenvectors(m, factorPolynomial$F)

         generalizedEigenvectors(m) ==
             generalizedEigenvectors(m, factorPolynomial$F)

     -- local functions
     intRatEig : (F, M, NNI) -> List AV
     intAlgEig : (UP, M, NNI) -> List AV
     genEigForm : (EigenForm, M) -> GenEigen

     ---- next functions needed for defining  ModularField ----
     reduction(u : UP, p : UP) : UP == u rem p

     merge(p : UP, q : UP) : Union(UP, "failed") ==
         p = q => p
         p = 0 => q
         q = 0 => p
         "failed"

     exactquo(u : UP, v : UP, p : UP) : Union(UP, "failed") ==
         val := extendedEuclidean(v, p, u)
         val case "failed" => "failed"
         val.coef1

     -- generalized eigenvectors associated to a given eigenvalue
     genEigForm(eigen : EigenForm, A : M) : GenEigen ==
         alpha := eigen.eigval
         k := eigen.eigmult
         g := #(eigen.eigvec)
         k = g  => [alpha, eigen.eigvec]
         [alpha, generalizedEigenvector(alpha, A, k, g)]

     if F has FiniteFieldCategory then

         characteristicPolynomial(A : M) : UP ==
              char_pol(A)$CharacteristicPolynomial2(F)

     else

         characteristicPolynomial(A : M) : UP ==
              char_pol_via_berkovitz(A)$CharacteristicPolynomial4(F)

     eigenvalues(A : M, fac : UP -> Factored(UP)) : List Eigenvalue ==
         pol := characteristicPolynomial(A)
         lrat : List F := empty()
         lsym : List UP := empty()
         fp := fac(pol)
         for fr in factorList(fp) repeat
             f1 := fr.factor
             degree(f1) = 1 =>
                 rv := -coefficient(f1, 0)/leadingCoefficient(f1)
                 lrat := cons(rv, lrat)
             lsym := cons(f1, lsym)
         append([lr::Eigenvalue for lr in lrat],
                [ls::Eigenvalue for ls in lsym])

     eigenvector(alpha : Eigenvalue, A : M) : List AV  ==
         alpha case F => intRatEig(alpha, A, 1$NNI)
         intAlgEig(alpha, A, 1$NNI)

     -- Eigenvectors belonging to a given eigenvalue from base field.
     intRatEig(alpha : F, A : M, m : NNI) : List AV  ==
         n := nrows A
         B : M := zero(n, n)$M
         for i in 1..n repeat
             for j in 1..n repeat B(i, j) := A(i, j)
             B(i, i) := B(i, i) - alpha
         sol : List(AV) := []
         for v in nullSpace(B^m) repeat
             w : AV := new(n, 0)
             for i in 1..n repeat w(i) := v(i)::UP
             sol := cons(w, sol)
         sol

     --  Eigenvectors belonging to a given algebraic eigenvalue.
     intAlgEig(alpha : UP, A : M, m : NNI) : List AV  ==
         n := nrows A
         MM := ModularField(UP, UP, reduction, merge, exactquo)
         AM := Matrix MM
         pol : UP := unitCanonical alpha
         alg : MM := reduce(monomial(1, 1), pol)
         B : AM := zero(n, n)
         for i in 1..n repeat
             for j in 1..n repeat B(i, j) := reduce(A(i, j)::UP, pol)
             B(i, i) := B(i, i) - alg
         sol : List AV := empty()
         for vec in nullSpace(B^m) repeat
             w : AV := new(n, 0)
             for i in 1..n repeat w(i) := vec(i)::UP
             sol := cons(w, sol)
         sol

     generalizedEigenvector(alpha : Eigenvalue, A : M, k : NNI, g : NNI
                           ) : List AV ==
         alpha case F => intRatEig(alpha, A, (1+k-g)::NNI)
         intAlgEig(alpha, A, (1+k-g)::NNI)

     generalizedEigenvector(ei : EigenForm, A : M) : List AV  ==
         generalizedEigenvector(ei.eigval, A, ei.eigmult, # ei.eigvec)

     generalizedEigenvectors(A : M, fac : UP -> Factored(UP)
                            ) : List GenEigen  ==
         leig := eigenvectors(A, fac)
         [genEigForm(leg, A) for leg in leig]

     eigenvectors(A : M, fac : UP -> Factored(UP)) : List(EigenForm) ==
         p := characteristicPolynomial(A)
         ratSol : List EigenForm := empty()
         algSol : List EigenForm := empty()
         lff := factorList fac p
         for fact in lff repeat
             pol := fact.factor
             degree(pol) = 1 =>
                 vec : F := -coefficient(pol, 0)/leadingCoefficient(pol)
                 ratSol := cons([vec, fact.exponent,
                                 intRatEig(vec, A, 1$NNI)]$EigenForm, ratSol)
             alpha : UP := pol
             algSol := cons([alpha, fact.exponent,
                             intAlgEig(alpha, A, 1$NNI)]$EigenForm, algSol)
         append(ratSol, algSol)


)abbrev package EP EigenPackage
++ Author: P. Gianni
++ Related Constructors: NumericRealEigenPackage,  NumericComplexEigenPackage,
++  RadicalEigenPackage, InnerEigenPackage
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++  This is a package for the exact computation of eigenvalues and
++  eigenvectors.  This package works for matrices with coefficients which
++  are rational functions over a ring where we can factor polynomials.
++  Eigenvalues not in base field are represented by their minimal
++  polynomial.
EigenPackage(R) : Exports == Implementation where
   R     : GcdDomain
   P     ==> Polynomial R
   F     ==> Fraction P
   SY    ==> Symbol()
   M     ==> Matrix(F)
   NNI   ==> NonNegativeInteger
   ST    ==> SuchThat(SY, P)

   Eigenvalue  ==> Union(F, ST)
   EigenForm   ==> Record(eigval : Eigenvalue, eigmult : NNI, eigvec : List M)
   GenEigen    ==> Record(eigval : Eigenvalue, geneigvec : List M)

   Exports == with
     characteristicPolynomial :  (M, SY)  ->  P
       ++ characteristicPolynomial(m, var) returns the
       ++ characteristicPolynomial of the matrix m using
       ++ the symbol var as the main variable.

     characteristicPolynomial :      M       ->  P
       ++ characteristicPolynomial(m) returns the
       ++ characteristicPolynomial of the matrix m using
       ++ a new generated symbol symbol as the main variable.

     eigenvector       :   (Eigenvalue, M)  ->  List M
       ++ eigenvector(eigval, m) returns the eigenvectors
       ++ belonging to the eigenvalue eigval for the matrix m.

     generalizedEigenvector  : (Eigenvalue, M, NNI, NNI) -> List M
       ++ generalizedEigenvector(alpha, m, k, g)
       ++ returns the generalized eigenvectors
       ++ of the matrix relative to the eigenvalue alpha.
       ++ The integers k and g are respectively the algebraic and the
       ++ geometric multiplicity of the eigenvalue alpha.

     generalizedEigenvector  : (EigenForm, M) -> List M
       ++ generalizedEigenvector(eigen, m) returns the generalized
       ++ eigenvectors of the matrix relative to the eigenvalue
       ++ eigen, as returned by the function eigenvectors.

     if R has PolynomialFactorizationExplicit then

         eigenvalues       :    M        ->  List Eigenvalue
           ++ eigenvalues(m) returns the eigenvalues of the matrix m.

         generalizedEigenvectors  : M -> List GenEigen
           ++ generalizedEigenvectors(m) returns the generalized
           ++ returns the generalized eigenvectors of the matrix m.

         eigenvectors      :    M        ->  List(EigenForm)
           ++ eigenvectors(m) returns the eigenvalues and eigenvectors
           ++ for the matrix m.
           ++ The eigenvalues in base field and the corresponding eigenvectors
           ++ are explicitly computed, while the other ones are given
           ++ via their minimal polynomial and the corresponding
           ++ eigenvectors are expressed in terms of a "generic" root of
           ++ such a polynomial.

   Implementation == add

      IEP ==> InnerEigenPackage(F)

      UP ==> SparseUnivariatePolynomial(F)

      AV ==> Vector(UP)

      SUP ==> SparseUnivariatePolynomial(P)

      Ei_to_EiF(a : Eigenvalue) : Union(F, UP) ==
          a case F => a
          map(coerce, univariate(rhs a, lhs a)
             )$UnivariatePolynomialCategoryFunctions2(P, SUP, F, UP)

      dummy : SY := new()$SY

      get_x(a : Eigenvalue) : SY ==
          a case F => dummy
          lhs a

      UP_to_F(p : UP, x : SY) : F == p(x::P::F)

      AV_to_M(v : AV, x : SY) : M ==
          matrix([[UP_to_F(v(i), x)] for i in 1..#v])

      characteristicPolynomial(m : M, x : SY) ==
          up := char_pol_via_berkovitz(m)$CharacteristicPolynomial4(F)
          numer(up(x::P::F))

      characteristicPolynomial(m : M) : P ==
          characteristicPolynomial(m, new()$SY)

      eigenvector(a, m) ==
          x := get_x(a)
          res1 := eigenvector(Ei_to_EiF(a), m)$IEP
          [AV_to_M(v, x) for v in res1]

      generalizedEigenvector(a, m, k, g) ==
          x := get_x(a)
          res1 := generalizedEigenvector(Ei_to_EiF(a), m, k, g)$IEP
          [AV_to_M(v, x) for v in res1]

      generalizedEigenvector(eif, m) ==
          k := eif.eigmult
          g := #(eif.eigvec)
          k = g => eif.eigvec
          generalizedEigenvector(eif.eigval, m, k, g)

      if F has PolynomialFactorizationExplicit then

          EiF_to_Ei(a : Union(F, UP), x : SY) : Eigenvalue ==
              a case F => a
              [x, numer((a::UP)(x::F))]

          eigenvalues(m) ==
              x := new()$SY
              res1 := eigenvalues(m)$IEP
              [EiF_to_Ei(a, x) for a in res1]

          eigenvectors(m) ==
              x := new()$SY
              res1 := eigenvectors(m)$IEP
              [[EiF_to_Ei(ri.eigval, x), ri.eigmult,
                [AV_to_M(v, x) for v in ri.eigvec]] for ri in res1]

          generalizedEigenvectors(m) ==
              x := new()$SY
              res1 := generalizedEigenvectors(m)$IEP
              [[EiF_to_Ei(ri.eigval, x),
                [AV_to_M(v, x) for v in ri.geneigvec]] for ri in res1]


)abbrev package CHARPOL CharacteristicPolynomialPackage
++ Author: Barry Trager
++ Basic Functions:
++ Related Constructors:
++ Also See:
++ AMS Classifications:
++ Keywords:
++ References:
++ Description:
++ This package provides a characteristicPolynomial function
++ for any matrix over a commutative ring.

CharacteristicPolynomialPackage(R : CommutativeRing) : C == T where
   M ==> Matrix R
   C == with
      characteristicPolynomial : (M, R) -> R
        ++ characteristicPolynomial(m, r) computes the characteristic
        ++ polynomial of the matrix m evaluated at the point r.
        ++ In particular, if r is the polynomial 'x, then it returns
        ++ the characteristic polynomial expressed as a polynomial in 'x.
   T == add

           ---- characteristic polynomial  ----
     characteristicPolynomial(A : M, v : R) : R ==
         up := char_pol_via_berkovitz(A)$CharacteristicPolynomial4(R)
         up(v)

--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
