{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE GADTs #-} module Numeric.LAPACK.Matrix.Layout.Private ( module Numeric.LAPACK.Matrix.Layout.Private, module Numeric.BLAS.Matrix.Layout, ) where import qualified Numeric.LAPACK.Matrix.Extent.Private as Extent import Numeric.LAPACK.Matrix.Extent.Private (Extent) import Numeric.BLAS.Matrix.Layout (Order(..), flipOrder, transposeFromOrder) import qualified Type.Data.Num.Unary.Literal as TypeNum import qualified Type.Data.Num.Unary.Proof as Proof import qualified Type.Data.Num.Unary as Unary import Type.Data.Num.Unary (unary, (:+:)) import Type.Data.Num (integralFromProxy) import Type.Base.Proxy (Proxy(Proxy)) import qualified Data.Array.Comfort.Shape as Shape import Data.Array.Comfort.Shape (triangleSize, triangleRoot) import Control.DeepSeq (NFData, rnf) import Control.Applicative ((<$>)) import Data.List (tails) import Data.Tuple.HT (mapSnd, swap) import Data.Bool.HT (if') swapOnRowMajor :: Order -> (a,a) -> (a,a) swapOnRowMajor order = case order of RowMajor -> swap ColumnMajor -> id sideSwapFromOrder :: Order -> (a,a) -> (Char, (a,a)) sideSwapFromOrder order (m0,n0) = let ((side,m), (_,n)) = swapOnRowMajor order (('L', m0), ('R', n0)) in (side,(m,n)) mapChecked :: (Shape.C sha, Shape.C shb) => String -> (sha -> shb) -> sha -> shb mapChecked name f sizeA = let sizeB = f sizeA in if Shape.size sizeA == Shape.size sizeB then sizeB else error $ name ++ ": sizes mismatch" data Full meas vert horiz height width = Full { fullOrder :: Order, fullExtent :: Extent meas vert horiz height width } deriving (Eq, Show) instance (Extent.Measure meas, Extent.C vert, Extent.C horiz, NFData height, NFData width) => NFData (Full meas vert horiz height width) where rnf (Full order extent) = rnf (order, extent) instance (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width) => Shape.C (Full meas vert horiz height width) where size (Full _ extent) = Shape.size (Extent.dimensions extent) instance (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.Indexed height, Shape.Indexed width) => Shape.Indexed (Full meas vert horiz height width) where type Index (Full meas vert horiz height width) = (Shape.Index height, Shape.Index width) indices (Full order extent) = fullIndices order extent unifiedOffset (Full RowMajor extent) = Shape.unifiedOffset (Extent.dimensions extent) unifiedOffset (Full ColumnMajor extent) = Shape.unifiedOffset (swap $ Extent.dimensions extent) . swap unifiedSizeOffset (Full RowMajor extent) = Shape.unifiedSizeOffset (Extent.dimensions extent) unifiedSizeOffset (Full ColumnMajor extent) = mapSnd (.swap) $ Shape.unifiedSizeOffset (swap $ Extent.dimensions extent) inBounds (Full _ extent) = Shape.inBounds (Extent.dimensions extent) instance (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.InvIndexed height, Shape.InvIndexed width) => Shape.InvIndexed (Full meas vert horiz height width) where unifiedIndexFromOffset (Full order extent) = fullIndexFromOffset order extent transpose :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Full meas vert horiz height width -> Full meas horiz vert width height transpose (Full order extent) = Full (flipOrder order) (Extent.transpose extent) inverse :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Full meas vert horiz height width -> Full meas horiz vert width height inverse (Full order extent) = Full order (Extent.transpose extent) dimensions :: (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width) => Full meas vert horiz height width -> (Int, Int) dimensions (Full order extent) = swapOnRowMajor order (Shape.size $ Extent.height extent, Shape.size $ Extent.width extent) fullHeight :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Full meas vert horiz height width -> height fullHeight = Extent.height . fullExtent fullWidth :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Full meas vert horiz height width -> width fullWidth = Extent.width . fullExtent fullIndices :: (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.Indexed a, Shape.Indexed b) => Order -> Extent meas vert horiz a b -> [(Shape.Index a, Shape.Index b)] fullIndices order extent = case order of RowMajor -> Shape.indices $ Extent.dimensions extent ColumnMajor -> map swap $ Shape.indices $ swap $ Extent.dimensions extent fullIndexFromOffset :: (Shape.Checking check, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.InvIndexed a, Shape.InvIndexed b) => Order -> Extent meas vert horiz a b -> Int -> Shape.Result check (Shape.Index a, Shape.Index b) fullIndexFromOffset order extent = case order of RowMajor -> Shape.unifiedIndexFromOffset (Extent.dimensions extent) ColumnMajor -> fmap swap . Shape.unifiedIndexFromOffset (swap $ Extent.dimensions extent) type General height width = Full Extent.Size Extent.Big Extent.Big height width type Tall height width = Full Extent.Size Extent.Big Extent.Small height width type Wide height width = Full Extent.Size Extent.Small Extent.Big height width type LiberalSquare height width = SquareMeas Extent.Size height width type Square size = SquareMeas Extent.Shape size size type SquareMeas meas height width = Full meas Extent.Small Extent.Small height width fullMapExtent :: Extent.Map measA vertA horizA measB vertB horizB height width -> Full measA vertA horizA height width -> Full measB vertB horizB height width fullMapExtent f (Full order extent) = Full order $ f extent general :: Order -> height -> width -> General height width general order height width = Full order $ Extent.general height width tall :: (Shape.C height, Shape.C width) => Order -> height -> width -> Tall height width tall order height width = if Shape.size height >= Shape.size width then Full order $ Extent.tall height width else error "Layout.tall: height smaller than width" wide :: (Shape.C height, Shape.C width) => Order -> height -> width -> Wide height width wide order height width = if Shape.size height <= Shape.size width then Full order $ Extent.wide height width else error "Layout.wide: width smaller than height" liberalSquare :: (Shape.C height, Shape.C width) => Order -> height -> width -> LiberalSquare height width liberalSquare order height width = if Shape.size height == Shape.size width then Full order $ Extent.liberalSquare height width else error "Layout.liberalSquare: height and width sizes differ" square :: Order -> sh -> Square sh square order sh = Full order $ Extent.square sh caseTallWide :: (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width) => Full meas vert horiz height width -> Either (Tall height width) (Wide height width) caseTallWide (Full order extent) = either (Left . Full order) (Right . Full order) $ Extent.caseTallWide (\h w -> Shape.size h >= Shape.size w) extent data Split lower meas vert horiz height width = Split { splitLower :: lower, splitOrder :: Order, splitExtent :: Extent meas vert horiz height width } deriving (Eq, Show) splitHeight :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Split lower meas vert horiz height width -> height splitHeight = Extent.height . splitExtent splitWidth :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Split lower meas vert horiz height width -> width splitWidth = Extent.width . splitExtent splitMapExtent :: Extent.Map measA vertA horizA measB vertB horizB height width -> Split lower measA vertA horizA height width -> Split lower measB vertB horizB height width splitMapExtent f (Split lowerPart order extent) = Split lowerPart order $ f extent caseTallWideSplit :: (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width) => Split lower meas vert horiz height width -> Either (Split lower Extent.Size Extent.Big Extent.Small height width) (Split lower Extent.Size Extent.Small Extent.Big height width) caseTallWideSplit (Split lowerPart order extent) = either (Left . Split lowerPart order) (Right . Split lowerPart order) $ Extent.caseTallWide (\h w -> Shape.size h >= Shape.size w) extent data Reflector = Reflector deriving (Eq, Show) data Triangle = Triangle deriving (Eq, Show) instance NFData Reflector where rnf Reflector = () instance NFData Triangle where rnf Triangle = () splitPart :: (Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.Indexed height, Shape.Indexed width) => Split lower meas vert horiz height width -> (Shape.Index height, Shape.Index width) -> Either lower Triangle splitPart (Split lowerPart _ extent) (r,c) = if Shape.offset (Extent.height extent) r > Shape.offset (Extent.width extent) c then Left lowerPart else Right Triangle instance (NFData lower, Extent.Measure meas, Extent.C vert, Extent.C horiz, NFData height, NFData width) => NFData (Split lower meas vert horiz height width) where rnf (Split lowerPart order extent) = rnf (lowerPart, order, extent) instance (Eq lower, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width) => Shape.C (Split lower meas vert horiz height width) where size (Split _ _ extent) = Shape.size (Extent.dimensions extent) instance (Eq lower, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.Indexed height, Shape.Indexed width) => Shape.Indexed (Split lower meas vert horiz height width) where type Index (Split lower meas vert horiz height width) = (Either lower Triangle, (Shape.Index height, Shape.Index width)) indices sh@(Split _ order extent) = map (\ix -> (splitPart sh ix, ix)) $ fullIndices order extent unifiedOffset sh@(Split _ order extent) (part,ix) = do Shape.assert "Shape.Split.offset: wrong matrix part" $ part == splitPart sh ix case order of RowMajor -> Shape.unifiedOffset (Extent.dimensions extent) ix ColumnMajor -> Shape.unifiedOffset (swap $ Extent.dimensions extent) (swap ix) unifiedSizeOffset sh@(Split _ order extent) = let check (part,ix) a = do Shape.assert "Shape.Split.sizeOffset: wrong matrix part" $ part == splitPart sh ix return a in case order of RowMajor -> mapSnd (\getOffset (part,ix) -> check (part,ix) =<< getOffset ix) $ Shape.unifiedSizeOffset (Extent.dimensions extent) ColumnMajor -> mapSnd (\getOffset (part,ix) -> check (part,ix) =<< getOffset (swap ix)) $ Shape.unifiedSizeOffset (swap $ Extent.dimensions extent) inBounds sh@(Split _ _ extent) (part,ix) = Shape.inBounds (Extent.dimensions extent) ix && part == splitPart sh ix instance (Eq lower, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.InvIndexed height, Shape.InvIndexed width) => Shape.InvIndexed (Split lower meas vert horiz height width) where unifiedIndexFromOffset sh@(Split _ order extent) k = do ix <- fullIndexFromOffset order extent k return (splitPart sh ix, ix) data Mosaic pack mirror uplo size = Mosaic { mosaicPack :: PackingSingleton pack, mosaicMirror :: MirrorSingleton mirror, mosaicUplo :: UpLoSingleton uplo, mosaicOrder :: Order, mosaicSize :: size } deriving (Eq, Show) data Packed data Unpacked data PackingSingleton pack where Packed :: PackingSingleton Packed Unpacked :: PackingSingleton Unpacked deriving instance Eq (PackingSingleton pack) deriving instance Show (PackingSingleton pack) instance NFData (PackingSingleton pack) where rnf Packed = () rnf Unpacked = () class Packing pack where autoPacking :: PackingSingleton pack instance Packing Unpacked where autoPacking = Unpacked instance Packing Packed where autoPacking = Packed squareFromMosaic :: Mosaic Unpacked mirror uplo size -> Square size squareFromMosaic (Mosaic {mosaicOrder = order, mosaicSize = size}) = square order size mosaicFromSquare :: (Mirror mirror, UpLo uplo) => Square size -> Mosaic Unpacked mirror uplo size mosaicFromSquare (Full {fullOrder = order, fullExtent = extent}) = Mosaic { mosaicPack = Unpacked, mosaicMirror = autoMirror, mosaicUplo = autoUplo, mosaicOrder = order, mosaicSize = Extent.squareSize extent } data NoMirror data SimpleMirror data ConjugateMirror data MirrorSingleton mirror where NoMirror :: MirrorSingleton NoMirror SimpleMirror :: MirrorSingleton SimpleMirror ConjugateMirror :: MirrorSingleton ConjugateMirror deriving instance Eq (MirrorSingleton mirror) deriving instance Show (MirrorSingleton mirror) instance NFData (MirrorSingleton mirror) where rnf NoMirror = () rnf SimpleMirror = () rnf ConjugateMirror = () class Mirror mirror where autoMirror :: MirrorSingleton mirror instance Mirror NoMirror where autoMirror = NoMirror instance Mirror SimpleMirror where autoMirror = SimpleMirror instance Mirror ConjugateMirror where autoMirror = ConjugateMirror type TriangularP pack = Mosaic pack NoMirror type Triangular = TriangularP Packed type LowerTriangularP pack = TriangularP pack Shape.Lower type LowerTriangular = Triangular Shape.Lower type UpperTriangularP pack = TriangularP pack Shape.Upper type UpperTriangular = Triangular Shape.Upper triangular :: UpLoSingleton uplo -> Order -> size -> Triangular uplo size triangular = Mosaic Packed NoMirror upperTriangular :: Order -> size -> UpperTriangular size upperTriangular = triangular Upper lowerTriangular :: Order -> size -> LowerTriangular size lowerTriangular = triangular Lower triangularP :: PackingSingleton pack -> UpLoSingleton uplo -> Order -> size -> TriangularP pack uplo size triangularP pack = Mosaic pack NoMirror upperTriangularP :: PackingSingleton pack -> Order -> size -> UpperTriangularP pack size upperTriangularP pack = triangularP pack Upper lowerTriangularP :: PackingSingleton pack -> Order -> size -> LowerTriangularP pack size lowerTriangularP pack = triangularP pack Lower type SymmetricP pack = Mosaic pack SimpleMirror Shape.Upper type Symmetric = SymmetricP Packed symmetric :: Order -> size -> Symmetric size symmetric = symmetricP Packed symmetricP :: PackingSingleton pack -> Order -> size -> SymmetricP pack size symmetricP pack = Mosaic pack SimpleMirror Upper symmetricFromHermitian :: HermitianP pack size -> SymmetricP pack size symmetricFromHermitian (Mosaic pack ConjugateMirror upper order size) = Mosaic pack SimpleMirror upper order size type HermitianP pack = Mosaic pack ConjugateMirror Shape.Upper type Hermitian = HermitianP Packed hermitian :: Order -> size -> Hermitian size hermitian = hermitianP Packed hermitianP :: PackingSingleton pack -> Order -> size -> HermitianP pack size hermitianP pack = Mosaic pack ConjugateMirror Upper hermitianFromSymmetric :: SymmetricP pack size -> HermitianP pack size hermitianFromSymmetric (Mosaic pack SimpleMirror upper order size) = Mosaic pack ConjugateMirror upper order size uploFromOrder :: Order -> Char uploFromOrder RowMajor = 'L' uploFromOrder ColumnMajor = 'U' newtype Bands offDiag = Bands (UnaryProxy offDiag) deriving (Eq, Show) type family GetBands strip type instance GetBands (Bands offDiag) = offDiag type Empty = Bands TypeNum.U0 data Filled = Filled deriving (Eq, Show) u0 :: UnaryProxy TypeNum.U0 u0 = unary TypeNum.u0 empty :: Empty empty = Bands u0 type family TriTransposed uplo type instance TriTransposed Shape.Lower = Shape.Upper type instance TriTransposed Shape.Upper = Shape.Lower triangularTranspose :: (UpLo uplo) => Mosaic pack mirror uplo sh -> Mosaic pack mirror (TriTransposed uplo) sh triangularTranspose (Mosaic pack mirror uplo order size) = Mosaic pack mirror (case uplo of Lower -> Upper Upper -> Lower) (flipOrder order) size autoUplo :: (UpLo uplo) => UpLoSingleton uplo autoUplo = switchUpLo Upper Lower uploOrder :: UpLoSingleton uplo -> Order -> Order uploOrder uplo = case uplo of Lower -> flipOrder; Upper -> id class UpLo uplo where switchUpLo :: f Shape.Upper -> f Shape.Lower -> f uplo instance UpLo Shape.Upper where switchUpLo f _ = f instance UpLo Shape.Lower where switchUpLo _ f = f data UpLoSingleton uplo where Lower :: UpLoSingleton Shape.Lower Upper :: UpLoSingleton Shape.Upper instance Eq (UpLoSingleton uplo) where Lower == Lower = True Upper == Upper = True instance Show (UpLoSingleton uplo) where show Lower = "Lower" show Upper = "Upper" instance NFData (UpLoSingleton uplo) where rnf Lower = () rnf Upper = () uploChar :: UpLoSingleton uplo -> Char uploChar Lower = 'L' uploChar Upper = 'U' instance (UpLo uplo, NFData size) => NFData (Mosaic pack mirror uplo size) where rnf (Mosaic pack mirror uplo order size) = rnf (pack, mirror, uplo, order, size) instance (UpLo uplo, Shape.C size) => Shape.C (Mosaic pack mirror uplo size) where size (Mosaic pack _mirror _uplo order size) = case pack of Packed -> triangleSize $ Shape.size size Unpacked -> Shape.size $ square order size instance (UpLo uplo, Shape.Indexed size) => Shape.Indexed (Mosaic pack mirror uplo size) where type Index (Mosaic pack mirror uplo size) = (Shape.Index size, Shape.Index size) indices (Mosaic pack _mirror uplo order size) = case (pack,uplo) of (Unpacked,_) -> Shape.indices $ square order size (Packed,Upper) -> triangleIndices order size (Packed,Lower) -> map swap $ triangleIndices (flipOrder order) size unifiedOffset (Mosaic pack _mirror uplo order size) = case (pack,uplo) of (Unpacked,_) -> Shape.unifiedOffset $ square order size (Packed,Upper) -> triangleOffset order size (Packed,Lower) -> triangleOffset (flipOrder order) size . swap unifiedSizeOffset (Mosaic pack _mirror uplo order size) = case (pack,uplo) of (Unpacked,_) -> Shape.unifiedSizeOffset $ square order size (Packed,Upper) -> triangleSizeOffset order size (Packed,Lower) -> mapSnd (.swap) $ triangleSizeOffset (flipOrder order) size inBounds (Mosaic pack _mirror uplo _ size) ix@(r,c) = Shape.inBounds (size,size) ix && case (pack,uplo) of (Unpacked,_) -> True (Packed,Upper) -> Shape.offset size r <= Shape.offset size c (Packed,Lower) -> Shape.offset size r >= Shape.offset size c instance (UpLo uplo, Shape.InvIndexed size) => Shape.InvIndexed (Mosaic pack mirror uplo size) where unifiedIndexFromOffset (Mosaic pack _mirror uplo order size) k = case (pack,uplo) of (Unpacked,_) -> Shape.unifiedIndexFromOffset (square order size) k (Packed,Upper) -> triangleIndexFromOffset order size k (Packed,Lower) -> swap <$> triangleIndexFromOffset (flipOrder order) size k squareRootDouble :: Int -> Double squareRootDouble = sqrt . fromIntegral squareExtent :: String -> Int -> Int squareExtent name size = let n = round $ squareRootDouble size in if size == n*n then n else error (name ++ ": no square number of elements") triangleRootDouble :: Int -> Double triangleRootDouble = triangleRoot . fromIntegral triangleExtent :: String -> Int -> Int triangleExtent name size = let n = round $ triangleRootDouble size in if size == triangleSize n then n else error (name ++ ": no triangular number of elements") triangleIndices :: (Shape.Indexed sh) => Order -> sh -> [(Shape.Index sh, Shape.Index sh)] triangleIndices RowMajor = Shape.indices . Shape.upperTriangular triangleIndices ColumnMajor = map swap . Shape.indices . Shape.lowerTriangular triangleOffset :: (Shape.Checking check, Shape.Indexed sh) => Order -> sh -> (Shape.Index sh, Shape.Index sh) -> Shape.Result check Int triangleOffset order size = case order of RowMajor -> Shape.unifiedOffset (Shape.upperTriangular size) ColumnMajor -> Shape.unifiedOffset (Shape.lowerTriangular size) . swap triangleSizeOffset :: (Shape.Checking check, Shape.Indexed sh) => Order -> sh -> (Int, (Shape.Index sh, Shape.Index sh) -> Shape.Result check Int) triangleSizeOffset order size = case order of RowMajor -> Shape.unifiedSizeOffset (Shape.upperTriangular size) ColumnMajor -> mapSnd (.swap) $ Shape.unifiedSizeOffset (Shape.lowerTriangular size) triangleIndexFromOffset :: (Shape.Checking check, Shape.InvIndexed sh) => Order -> sh -> Int -> Shape.Result check (Shape.Index sh, Shape.Index sh) triangleIndexFromOffset order size = case order of RowMajor -> Shape.unifiedIndexFromOffset (Shape.upperTriangular size) ColumnMajor -> fmap swap . Shape.unifiedIndexFromOffset (Shape.lowerTriangular size) type UnaryProxy a = Proxy (Unary.Un a) data Banded sub super meas vert horiz height width = Banded { bandedOffDiagonals :: (UnaryProxy sub, UnaryProxy super), bandedOrder :: Order, bandedExtent :: Extent meas vert horiz height width } deriving (Eq, Show) type BandedGeneral sub super = Banded sub super Extent.Size Extent.Big Extent.Big type BandedSquareMeas sub super meas height width = Banded sub super meas Extent.Small Extent.Small height width type BandedSquare sub super size = BandedSquareMeas sub super Extent.Shape size size type BandedLowerTriangular sub size = BandedSquare sub TypeNum.U0 size type BandedUpperTriangular super size = BandedSquare TypeNum.U0 super size type Diagonal size = BandedSquare TypeNum.U0 TypeNum.U0 size type RectangularDiagonal = Banded TypeNum.U0 TypeNum.U0 bandedHeight :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Banded sub super meas vert horiz height width -> height bandedHeight = Extent.height . bandedExtent bandedWidth :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Banded sub super meas vert horiz height width -> width bandedWidth = Extent.width . bandedExtent bandedMapExtent :: Extent.Map measA vertA horizA measB vertB horizB height width -> Banded sub super measA vertA horizA height width -> Banded sub super measB vertB horizB height width bandedMapExtent f (Banded offDiag order extent) = Banded offDiag order $ f extent bandedBreadth :: (Unary.Natural sub, Unary.Natural super) => (UnaryProxy sub, UnaryProxy super) -> Int bandedBreadth (sub,super) = integralFromProxy sub + 1 + integralFromProxy super numOffDiagonals :: (Unary.Natural sub, Unary.Natural super) => Order -> (UnaryProxy sub, UnaryProxy super) -> (Int,Int) numOffDiagonals order (sub,super) = swapOnRowMajor order (integralFromProxy sub, integralFromProxy super) natFromProxy :: (Unary.Natural n) => UnaryProxy n -> Proof.Nat n natFromProxy Proxy = Proof.Nat addOffDiagonals :: (Unary.Natural subA, Unary.Natural superA, Unary.Natural subB, Unary.Natural superB, (subA :+: subB) ~ subC, (superA :+: superB) ~ superC) => (UnaryProxy subA, UnaryProxy superA) -> (UnaryProxy subB, UnaryProxy superB) -> ((Proof.Nat subC, Proof.Nat superC), (UnaryProxy subC, UnaryProxy superC)) addOffDiagonals (subA,superA) (subB,superB) = ((Proof.addNat (natFromProxy subA) (natFromProxy subB), Proof.addNat (natFromProxy superA) (natFromProxy superB)), (Proxy,Proxy)) bandedTranspose :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => Banded sub super meas vert horiz height width -> Banded super sub meas horiz vert width height bandedTranspose (Banded (sub,super) order extent) = Banded (super,sub) (flipOrder order) (Extent.transpose extent) diagonalInverse :: (Extent.Measure meas) => BandedSquareMeas TypeNum.U0 TypeNum.U0 meas height width -> BandedSquareMeas TypeNum.U0 TypeNum.U0 meas width height diagonalInverse (Banded (sub,super) order extent) = Banded (super,sub) order (Extent.transpose extent) bandedGeneral :: (UnaryProxy sub, UnaryProxy super) -> Order -> height -> width -> BandedGeneral sub super height width bandedGeneral offDiag order height width = Banded offDiag order (Extent.general height width) bandedSquare :: (UnaryProxy sub, UnaryProxy super) -> Order -> size -> BandedSquare sub super size bandedSquare offDiag order = Banded offDiag order . Extent.square rectangularDiagonal :: (Extent.Measure meas, Extent.C vert, Extent.C horiz) => (Shape.C height, Shape.C width) => Extent meas vert horiz height width -> (Int, RectangularDiagonal meas vert horiz height width) rectangularDiagonal extent = let m = Shape.size $ Extent.height extent n = Shape.size $ Extent.width extent order = if m <= n then RowMajor else ColumnMajor in (min m n, Banded (u0,u0) order extent) data BandedIndex row column = InsideBox row column | VertOutsideBox Int column | HorizOutsideBox row Int deriving (Eq, Show) instance (Unary.Natural sub, Unary.Natural super, Extent.Measure meas, Extent.C vert, Extent.C horiz, NFData height, NFData width) => NFData (Banded sub super meas vert horiz height width) where rnf (Banded (Proxy,Proxy) order extent) = rnf (order, extent) instance (Unary.Natural sub, Unary.Natural super, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.C height, Shape.C width) => Shape.C (Banded sub super meas vert horiz height width) where size (Banded offDiag order extent) = bandedBreadth offDiag * case order of RowMajor -> Shape.size (Extent.height extent) ColumnMajor -> Shape.size (Extent.width extent) instance (Unary.Natural sub, Unary.Natural super, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.Indexed height, Shape.Indexed width) => Shape.Indexed (Banded sub super meas vert horiz height width) where type Index (Banded sub super meas vert horiz height width) = BandedIndex (Shape.Index height) (Shape.Index width) indices (Banded (sub,super) order extent) = let (height,width) = Extent.dimensions extent in case order of RowMajor -> map (\(r,c) -> either (HorizOutsideBox r) (InsideBox r) c) $ bandedIndicesRowMajor (sub,super) (height,width) ColumnMajor -> map (\(c,r) -> either (flip VertOutsideBox c) (flip InsideBox c) r) $ bandedIndicesRowMajor (super,sub) (width,height) unifiedOffset shape@(Banded (sub,super) order extent) ix = do Shape.assert "Banded.offset: index outside band" $ Shape.inBounds shape ix let (height,width) = Extent.dimensions extent kl = integralFromProxy sub ku = integralFromProxy super return $ bandedOffset (kl,ku) order (height,width) ix inBounds (Banded (sub,super) order extent) ix = let (height,width) = Extent.dimensions extent kl = integralFromProxy sub ku = integralFromProxy super insideBand r c = Shape.inBounds (Shape.Range (-kl) ku) (c-r) in case (order,ix) of (_, InsideBox r c) -> Shape.inBounds (height,width) (r,c) && insideBand (Shape.offset height r) (Shape.offset width c) (RowMajor, HorizOutsideBox r c) -> Shape.inBounds height r && insideBand (Shape.offset height r) (outsideOffset width c) (ColumnMajor, VertOutsideBox r c) -> Shape.inBounds width c && insideBand (outsideOffset height r) (Shape.offset width c) _ -> False instance (Unary.Natural sub, Unary.Natural super, Extent.Measure meas, Extent.C vert, Extent.C horiz, Shape.InvIndexed height, Shape.InvIndexed width) => Shape.InvIndexed (Banded sub super meas vert horiz height width) where unifiedIndexFromOffset (Banded (sub,super) order extent) j = bandedIndexFromOffset (integralFromProxy sub, integralFromProxy super) order (Extent.dimensions extent) j outsideOffset :: Shape.C sh => sh -> Int -> Int outsideOffset size k = if k<0 then k else Shape.size size + k bandedOffset :: (Shape.Indexed height, Shape.Indexed width) => (Int, Int) -> Order -> (height, width) -> BandedIndex (Shape.Index height) (Shape.Index width) -> Int bandedOffset (kl,ku) order (height,width) ix = let k = kl+ku in case ix of InsideBox r c -> let i = Shape.uncheckedOffset height r j = Shape.uncheckedOffset width c in case order of RowMajor -> k*i + kl+j ColumnMajor -> k*j + ku+i VertOutsideBox r c -> let i = outsideOffset height r j = Shape.uncheckedOffset width c in k*j + ku+i HorizOutsideBox r c -> let i = Shape.uncheckedOffset height r j = outsideOffset width c in k*i + kl+j bandedIndicesRowMajor :: (Unary.Natural sub, Unary.Natural super, Shape.Indexed height, Shape.Indexed width) => (UnaryProxy sub, UnaryProxy super) -> (height, width) -> [(Shape.Index height, Either Int (Shape.Index width))] bandedIndicesRowMajor (sub,super) (height,width) = let kl = integralFromProxy sub ku = integralFromProxy super in concat $ zipWith (\r -> map ((,) r)) (Shape.indices height) $ map (take (kl+1+ku)) $ tails $ (map Left $ take kl $ iterate (1+) (-kl)) ++ (map Right $ Shape.indices width) ++ (map Left $ iterate (1+) 0) bandedIndexFromOffset :: (Shape.Checking check, Shape.InvIndexed height, Shape.InvIndexed width) => (Int,Int) -> Order -> (height,width) -> Int -> Shape.Result check (BandedIndex (Shape.Index height) (Shape.Index width)) bandedIndexFromOffset (kl,ku) order (height,width) = case order of RowMajor -> let n = Shape.size width in \j -> do let (rb,cb) = divMod j (kl+1+ku) r <- Shape.unifiedIndexFromOffset height rb let ci = rb+cb-kl if' (ci<0) (return $ HorizOutsideBox r ci) $ if' (ci>=n) (return $ HorizOutsideBox r (ci-n)) $ (InsideBox r <$> Shape.unifiedIndexFromOffset width ci) ColumnMajor -> \j -> do let m = Shape.size height let (cb,rb) = divMod j (kl+1+ku) c <- Shape.unifiedIndexFromOffset width cb let ri = rb+cb-ku if' (ri<0) (return $ VertOutsideBox ri c) $ if' (ri>=m) (return $ VertOutsideBox (ri-m) c) $ (flip InsideBox c <$> Shape.unifiedIndexFromOffset height ri) data BandedHermitian off size = BandedHermitian { bandedHermitianOffDiagonals :: UnaryProxy off, bandedHermitianOrder :: Order, bandedHermitianSize :: size } deriving (Eq, Show) instance (Unary.Natural off, NFData size) => NFData (BandedHermitian off size) where rnf (BandedHermitian Proxy order size) = rnf (order, size) instance (Unary.Natural off, Shape.C size) => Shape.C (BandedHermitian off size) where size (BandedHermitian offDiag _order size) = (1 + integralFromProxy offDiag) * Shape.size size instance (Unary.Natural off, Shape.Indexed size) => Shape.Indexed (BandedHermitian off size) where type Index (BandedHermitian off size) = BandedIndex (Shape.Index size) (Shape.Index size) indices (BandedHermitian offDiag order size) = case order of RowMajor -> map (\(r,c) -> either (HorizOutsideBox r) (InsideBox r) c) $ bandedIndicesRowMajor (u0, offDiag) (size,size) ColumnMajor -> map (\(c,r) -> either (flip VertOutsideBox c) (flip InsideBox c) r) $ bandedIndicesRowMajor (offDiag, u0) (size,size) unifiedOffset shape@(BandedHermitian offDiag order size) ix = do Shape.assert "BandedHermitian.offset: index outside band" $ Shape.inBounds shape ix let k = integralFromProxy offDiag return $ bandedOffset (0,k) order (size,size) ix inBounds (BandedHermitian offDiag order size) ix = let ku = integralFromProxy offDiag insideBand r c = Shape.inBounds (Shape.Range 0 ku) (c-r) in case (order,ix) of (_, InsideBox r c) -> Shape.inBounds (size,size) (r,c) && insideBand (Shape.offset size r) (Shape.offset size c) (RowMajor, HorizOutsideBox r c) -> Shape.inBounds size r && insideBand (Shape.offset size r) (outsideOffset size c) (ColumnMajor, VertOutsideBox r c) -> Shape.inBounds size c && insideBand (outsideOffset size r) (Shape.offset size c) _ -> False instance (Unary.Natural off, Shape.InvIndexed size) => Shape.InvIndexed (BandedHermitian off size) where unifiedIndexFromOffset (BandedHermitian offDiag order size) j = bandedHermitianIndexFromOffset (integralFromProxy offDiag) order size j bandedHermitianIndexFromOffset :: (Shape.Checking check, Shape.InvIndexed sh, Shape.Index sh ~ ix) => Int -> Order -> sh -> Int -> Shape.Result check (BandedIndex ix ix) bandedHermitianIndexFromOffset k order size = case order of RowMajor -> let n = Shape.size size in \j -> do let (rb,cb) = divMod j (k+1) r <- Shape.unifiedIndexFromOffset size rb let ci = rb+cb if ci Shape.unifiedIndexFromOffset size ci else return $ HorizOutsideBox r (ci-n) ColumnMajor -> \j -> do let (cb,rb) = divMod j (k+1) c <- Shape.unifiedIndexFromOffset size cb let ri = rb+cb-k if ri>=0 then flip InsideBox c <$> Shape.unifiedIndexFromOffset size ri else return $ VertOutsideBox ri c