{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs #-}
module Numeric.LAPACK.Matrix.Array.Hermitian (
   Semidefinite,
   AnyHermitian,
   AnyHermitianP,
   assureFullRank,
   assureAnyRank,
   relaxSemidefinite,
   relaxIndefinite,
   assurePositiveDefiniteness,
   relaxDefiniteness,
   asUnknownDefiniteness,
   ) where

import qualified Numeric.LAPACK.Matrix.Shape.Omni as Omni
import Numeric.LAPACK.Matrix.Array (Matrix(Array), Quadratic)
import Numeric.LAPACK.Matrix.Layout.Private (Packed)

import qualified Type.Data.Bool as TBool
import Type.Data.Bool (False, True)

import qualified Data.Array.Comfort.Storable.Unchecked as Array
import Data.Function.HT (Id)


class (TBool.C neg, TBool.C pos) => Semidefinite neg pos where
instance Semidefinite False True where
instance Semidefinite True False where

type AnyHermitian neg zero pos bands sh =
      AnyHermitianP Packed neg zero pos bands sh
type AnyHermitianP pack neg zero pos bands sh =
      Quadratic pack (Omni.Hermitian neg zero pos) bands bands sh

{-
If a semidefinite matrix has full rank, then it is definite.
You can verify this by watching the eigenvalue decomposition of the matrix.
-}
assureFullRank ::
   (Semidefinite neg pos, TBool.C zero) =>
   AnyHermitianP pack neg zero pos bands sh a ->
   AnyHermitianP pack neg False pos bands sh a
assureFullRank :: AnyHermitianP pack neg zero pos bands sh a
-> AnyHermitianP pack neg False pos bands sh a
assureFullRank = AnyHermitianP pack neg zero pos bands sh a
-> AnyHermitianP pack neg False pos bands sh a
forall negA zeroA posA negB zeroB posB pack bands sh a.
(C negA, C zeroA, C posA, C negB, C zeroB, C posB) =>
AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness

assureAnyRank ::
   (Semidefinite neg pos, TBool.C zero) =>
   AnyHermitianP pack neg True pos bands sh a ->
   AnyHermitianP pack neg zero pos bands sh a
assureAnyRank :: AnyHermitianP pack neg True pos bands sh a
-> AnyHermitianP pack neg zero pos bands sh a
assureAnyRank = AnyHermitianP pack neg True pos bands sh a
-> AnyHermitianP pack neg zero pos bands sh a
forall negA zeroA posA negB zeroB posB pack bands sh a.
(C negA, C zeroA, C posA, C negB, C zeroB, C posB) =>
AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness

relaxSemidefinite ::
   (TBool.C neg, TBool.C zero, TBool.C pos) =>
   AnyHermitianP pack neg False pos bands sh a ->
   AnyHermitianP pack neg zero pos bands sh a
relaxSemidefinite :: AnyHermitianP pack neg False pos bands sh a
-> AnyHermitianP pack neg zero pos bands sh a
relaxSemidefinite = AnyHermitianP pack neg False pos bands sh a
-> AnyHermitianP pack neg zero pos bands sh a
forall negA zeroA posA negB zeroB posB pack bands sh a.
(C negA, C zeroA, C posA, C negB, C zeroB, C posB) =>
AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness

relaxIndefinite ::
   (TBool.C neg, TBool.C zero, TBool.C pos) =>
   AnyHermitianP pack neg zero pos bands sh a ->
   Quadratic pack Omni.HermitianUnknownDefiniteness bands bands sh a
relaxIndefinite :: AnyHermitianP pack neg zero pos bands sh a
-> Quadratic pack HermitianUnknownDefiniteness bands bands sh a
relaxIndefinite = AnyHermitianP pack neg zero pos bands sh a
-> Quadratic pack HermitianUnknownDefiniteness bands bands sh a
forall negA zeroA posA negB zeroB posB pack bands sh a.
(C negA, C zeroA, C posA, C negB, C zeroB, C posB) =>
AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness

assurePositiveDefiniteness ::
   (TBool.C neg, TBool.C zero, TBool.C pos) =>
   AnyHermitianP pack neg zero pos bands sh a ->
   Quadratic pack Omni.HermitianPositiveDefinite bands bands sh a
assurePositiveDefiniteness :: AnyHermitianP pack neg zero pos bands sh a
-> Quadratic pack HermitianPositiveDefinite bands bands sh a
assurePositiveDefiniteness = AnyHermitianP pack neg zero pos bands sh a
-> Quadratic pack HermitianPositiveDefinite bands bands sh a
forall negA zeroA posA negB zeroB posB pack bands sh a.
(C negA, C zeroA, C posA, C negB, C zeroB, C posB) =>
AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness

relaxDefiniteness ::
   (TBool.C neg, TBool.C zero, TBool.C pos) =>
   Quadratic pack Omni.HermitianPositiveDefinite bands bands sh a ->
   AnyHermitianP pack neg zero pos bands sh a
relaxDefiniteness :: Quadratic pack HermitianPositiveDefinite bands bands sh a
-> AnyHermitianP pack neg zero pos bands sh a
relaxDefiniteness = Quadratic pack HermitianPositiveDefinite bands bands sh a
-> AnyHermitianP pack neg zero pos bands sh a
forall negA zeroA posA negB zeroB posB pack bands sh a.
(C negA, C zeroA, C posA, C negB, C zeroB, C posB) =>
AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness

alterDefiniteness ::
   (TBool.C negA, TBool.C zeroA, TBool.C posA,
    TBool.C negB, TBool.C zeroB, TBool.C posB) =>
   AnyHermitianP pack negA zeroA posA bands sh a ->
   AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness :: AnyHermitianP pack negA zeroA posA bands sh a
-> AnyHermitianP pack negB zeroB posB bands sh a
alterDefiniteness (Array a) =
   OmniArray
  pack
  (Hermitian negB zeroB posB)
  bands
  bands
  Shape
  Small
  Small
  sh
  sh
  a
-> AnyHermitianP pack negB zeroB posB bands sh a
forall pack prop lower upper meas vert horiz height width a.
OmniArray pack prop lower upper meas vert horiz height width a
-> Matrix
     (Array pack prop) () () lower upper meas vert horiz height width a
Array (OmniArray
   pack
   (Hermitian negB zeroB posB)
   bands
   bands
   Shape
   Small
   Small
   sh
   sh
   a
 -> AnyHermitianP pack negB zeroB posB bands sh a)
-> OmniArray
     pack
     (Hermitian negB zeroB posB)
     bands
     bands
     Shape
     Small
     Small
     sh
     sh
     a
-> AnyHermitianP pack negB zeroB posB bands sh a
forall a b. (a -> b) -> a -> b
$ ((Omni
    pack
    (Hermitian negA zeroA posA)
    bands
    bands
    Shape
    Small
    Small
    sh
    sh
  -> Omni
       pack
       (Hermitian negB zeroB posB)
       bands
       bands
       Shape
       Small
       Small
       sh
       sh)
 -> Array
      (Omni
         pack
         (Hermitian negA zeroA posA)
         bands
         bands
         Shape
         Small
         Small
         sh
         sh)
      a
 -> OmniArray
      pack
      (Hermitian negB zeroB posB)
      bands
      bands
      Shape
      Small
      Small
      sh
      sh
      a)
-> Array
     (Omni
        pack
        (Hermitian negA zeroA posA)
        bands
        bands
        Shape
        Small
        Small
        sh
        sh)
     a
-> (Omni
      pack
      (Hermitian negA zeroA posA)
      bands
      bands
      Shape
      Small
      Small
      sh
      sh
    -> Omni
         pack
         (Hermitian negB zeroB posB)
         bands
         bands
         Shape
         Small
         Small
         sh
         sh)
-> OmniArray
     pack
     (Hermitian negB zeroB posB)
     bands
     bands
     Shape
     Small
     Small
     sh
     sh
     a
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Omni
   pack
   (Hermitian negA zeroA posA)
   bands
   bands
   Shape
   Small
   Small
   sh
   sh
 -> Omni
      pack
      (Hermitian negB zeroB posB)
      bands
      bands
      Shape
      Small
      Small
      sh
      sh)
-> Array
     (Omni
        pack
        (Hermitian negA zeroA posA)
        bands
        bands
        Shape
        Small
        Small
        sh
        sh)
     a
-> OmniArray
     pack
     (Hermitian negB zeroB posB)
     bands
     bands
     Shape
     Small
     Small
     sh
     sh
     a
forall sh0 sh1 a. (sh0 -> sh1) -> Array sh0 a -> Array sh1 a
Array.mapShape Array
  (Omni
     pack
     (Hermitian negA zeroA posA)
     bands
     bands
     Shape
     Small
     Small
     sh
     sh)
  a
a ((Omni
    pack
    (Hermitian negA zeroA posA)
    bands
    bands
    Shape
    Small
    Small
    sh
    sh
  -> Omni
       pack
       (Hermitian negB zeroB posB)
       bands
       bands
       Shape
       Small
       Small
       sh
       sh)
 -> OmniArray
      pack
      (Hermitian negB zeroB posB)
      bands
      bands
      Shape
      Small
      Small
      sh
      sh
      a)
-> (Omni
      pack
      (Hermitian negA zeroA posA)
      bands
      bands
      Shape
      Small
      Small
      sh
      sh
    -> Omni
         pack
         (Hermitian negB zeroB posB)
         bands
         bands
         Shape
         Small
         Small
         sh
         sh)
-> OmniArray
     pack
     (Hermitian negB zeroB posB)
     bands
     bands
     Shape
     Small
     Small
     sh
     sh
     a
forall a b. (a -> b) -> a -> b
$ \Omni
  pack
  (Hermitian negA zeroA posA)
  bands
  bands
  Shape
  Small
  Small
  sh
  sh
omni ->
      case Omni
  pack
  (Hermitian negA zeroA posA)
  bands
  bands
  Shape
  Small
  Small
  sh
  sh
omni of
         Omni.Full Full Shape Small Small sh sh
sh -> Full Shape Small Small sh sh
-> Omni
     Unpacked
     (Hermitian negB zeroB posB)
     bands
     bands
     Shape
     Small
     Small
     sh
     sh
forall property lower upper meas vert horiz height width.
(Property property, Strip lower, Strip upper) =>
Full meas vert horiz height width
-> Omni Unpacked property lower upper meas vert horiz height width
Omni.Full Full Shape Small Small sh sh
sh
         Omni.Hermitian Hermitian sh
sh -> Hermitian sh
-> Omni
     Packed
     (Hermitian negB zeroB posB)
     Filled
     Filled
     Shape
     Small
     Small
     sh
     sh
forall neg zero pos size.
(C neg, C zero, C pos) =>
Hermitian size
-> Omni
     Packed
     (Hermitian neg zero pos)
     Filled
     Filled
     Shape
     Small
     Small
     size
     size
Omni.Hermitian Hermitian sh
sh
         Omni.BandedHermitian BandedHermitian offDiag sh
sh -> BandedHermitian offDiag sh
-> Omni
     Packed
     (Hermitian negB zeroB posB)
     (Bands offDiag)
     (Bands offDiag)
     Shape
     Small
     Small
     sh
     sh
forall neg zero pos offDiag size.
(C neg, C zero, C pos, Natural offDiag) =>
BandedHermitian offDiag size
-> Omni
     Packed
     (Hermitian neg zero pos)
     (Bands offDiag)
     (Bands offDiag)
     Shape
     Small
     Small
     size
     size
Omni.BandedHermitian BandedHermitian offDiag sh
sh


asUnknownDefiniteness ::
   Id (Quadratic pack Omni.HermitianUnknownDefiniteness bands bands sh a)
asUnknownDefiniteness :: Id (Quadratic pack HermitianUnknownDefiniteness bands bands sh a)
asUnknownDefiniteness = Id (Quadratic pack HermitianUnknownDefiniteness bands bands sh a)
forall a. a -> a
id