packages feed

easytensor 2.0.1.0 → 2.1.0.0

raw patch · 61 files changed

+8508/−3074 lines, 61 filesdep ~constraints-derivingbuild-type:Customsetup-changedPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: constraints-deriving

API changes (from Hackage documentation)

- Numeric.DataFrame.Contraction: instance (Data.Type.List.ConcatList as bs asbs, Numeric.Dimensions.Dim.Dimensions as, Numeric.Dimensions.Dim.Dimensions bs, GHC.Num.Num t) => Numeric.DataFrame.Contraction.Contraction t as bs asbs
- Numeric.DataFrame.IO: data family IODataFrame (t :: Type) (ns :: [k])
- Numeric.DataFrame.Internal.Backend: type DFBackend (t :: Type) (ds :: [Nat]) = Backend I t ds (BackendFamily t ds)
- Numeric.DataFrame.Internal.Backend: type KnownBackend (t :: Type) (ds :: [Nat]) = KnownBackend t ds (BackendFamily t ds)
- Numeric.DataFrame.Internal.PrimArray: arrayContent# :: PrimArray t a => a -> (# t | (# CumulDims, Int#, ByteArray# #) #)
- Numeric.DataFrame.ST: data family STDataFrame s (t :: Type) (ns :: [k])
- Numeric.DataFrame.SubSpace: (!) :: SubSpace t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) => DataFrame t asbs -> Idxs as -> DataFrame t bs
- Numeric.DataFrame.SubSpace: indexOffset# :: SubSpace t as bs asbs => Int# -> DataFrame t asbs -> DataFrame t bs
- Numeric.DataFrame.SubSpace: instance (Data.Type.List.ConcatList as bs asbs, Numeric.Dimensions.Dim.Dimensions as, Numeric.Dimensions.Dim.Dimensions bs, Numeric.Dimensions.Dim.Dimensions asbs, Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t bs), Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t asbs), Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Type.DataFrame t bs), Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Type.DataFrame t asbs)) => Numeric.DataFrame.SubSpace.SubSpace t as bs asbs
- Numeric.DataFrame.SubSpace: updateOffset# :: SubSpace t as bs asbs => Int# -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs
- Numeric.DataFrame.Type: instance (Data.Type.List.All GHC.Read.Read ts, Data.Type.List.All Numeric.PrimBytes.PrimBytes ts, Numeric.TypedList.RepresentableList ts, Numeric.Dimensions.Dim.BoundedDims ds, Data.Type.List.All Numeric.Dimensions.Dim.KnownXNatType ds) => GHC.Read.Read (Numeric.DataFrame.Type.DataFrame ts ds)
- Numeric.DataFrame.Type: instance (GHC.Classes.Ord (Numeric.ProductOrd.Partial.ProductOrd (Numeric.DataFrame.Internal.Backend.DFBackend t ds)), GHC.Classes.Eq (Numeric.DataFrame.Internal.Backend.DFBackend t ds)) => GHC.Classes.Ord (Numeric.ProductOrd.Partial.ProductOrd (Numeric.DataFrame.Type.DataFrame t ds))
- Numeric.DataFrame.Type: instance (GHC.Read.Read t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.BoundedDims ds, Data.Type.List.All Numeric.Dimensions.Dim.KnownXNatType ds) => GHC.Read.Read (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance (Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Internal.Backend.DFBackend t ds), Numeric.PrimBytes.PrimBytes t) => Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Classes.Eq (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Classes.Eq (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Classes.Ord (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Classes.Ord (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Classes.Ord (Numeric.ProductOrd.NonTransitive.ProductOrd (Numeric.DataFrame.Internal.Backend.DFBackend t ds)) => GHC.Classes.Ord (Numeric.ProductOrd.NonTransitive.ProductOrd (Numeric.DataFrame.Type.DataFrame t ds))
- Numeric.DataFrame.Type: instance GHC.Enum.Bounded (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Enum.Bounded (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Enum.Enum (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Enum.Enum (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Float.Floating (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Float.Floating (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Float.RealFloat (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Float.RealFloat (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Num.Num (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Num.Num (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Real.Fractional (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Real.Fractional (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Real.Integral (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Real.Integral (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Real.Real (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Real.Real (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance GHC.Real.RealFrac (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => GHC.Real.RealFrac (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: instance Numeric.ProductOrd.ProductOrder (Numeric.DataFrame.Internal.Backend.DFBackend t ds) => Numeric.ProductOrd.ProductOrder (Numeric.DataFrame.Type.DataFrame t ds)
- Numeric.DataFrame.Type: type KnownBackend t (ds :: [Nat]) = KnownBackend t ds BackendFamily t ds
- Numeric.Matrix: LUFact :: Matrix t n n -> Matrix t n n -> Matrix t n n -> Scalar t -> LUFact t n
- Numeric.Matrix: [luLower] :: LUFact t n -> Matrix t n n
- Numeric.Matrix: [luPermSign] :: LUFact t n -> Scalar t
- Numeric.Matrix: [luPerm] :: LUFact t n -> Matrix t n n
- Numeric.Matrix: [luUpper] :: LUFact t n -> Matrix t n n
- Numeric.Matrix: class MatrixLU t (n :: Nat)
- Numeric.Matrix: data LUFact t n
- Numeric.Matrix: lu :: MatrixLU t n => Matrix t n n -> LUFact t n
- Numeric.Matrix: luSolve :: forall (t :: Type) (n :: Nat). (KnownDim n, Fractional t, PrimArray t (Matrix t n n), PrimArray t (Vector t n)) => LUFact t n -> Vector t n -> Vector t n
- Numeric.Matrix: pivotMat :: forall (t :: Type) (n :: Nat). (KnownDim n, PrimArray t (Matrix t n n), Ord t, Num t) => Matrix t n n -> (Matrix t n n, Matrix t n n, Scalar t)
+ Numeric.Basics: class (Eq a, Floating a) => Epsilon a
+ Numeric.Basics: class (Real a, PrimBytes a) => RealExtras a
+ Numeric.Basics: class (Epsilon a, RealExtras a, RealFloat a) => RealFloatExtras a
+ Numeric.Basics: copysign :: RealExtras a => a -> a -> a
+ Numeric.Basics: data TooManyIterations
+ Numeric.Basics: epsilon :: Epsilon a => a
+ Numeric.Basics: hypot :: RealFloatExtras a => a -> a -> a
+ Numeric.Basics: instance GHC.Classes.Eq Numeric.Basics.TooManyIterations
+ Numeric.Basics: instance GHC.Classes.Ord Numeric.Basics.TooManyIterations
+ Numeric.Basics: instance GHC.Exception.Type.Exception Numeric.Basics.TooManyIterations
+ Numeric.Basics: instance GHC.Show.Show Numeric.Basics.TooManyIterations
+ Numeric.Basics: instance Numeric.Basics.Epsilon GHC.Types.Double
+ Numeric.Basics: instance Numeric.Basics.Epsilon GHC.Types.Float
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Int.Int16
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Int.Int32
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Int.Int64
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Int.Int8
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Types.Double
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Types.Float
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Types.Int
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Types.Word
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Word.Word16
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Word.Word32
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Word.Word64
+ Numeric.Basics: instance Numeric.Basics.RealExtras GHC.Word.Word8
+ Numeric.Basics: instance Numeric.Basics.RealFloatExtras GHC.Types.Double
+ Numeric.Basics: instance Numeric.Basics.RealFloatExtras GHC.Types.Float
+ Numeric.Basics: maxFinite :: RealFloatExtras a => a
+ Numeric.Basics: negateUnless :: Num t => Bool -> t -> t
+ Numeric.Basics: pattern M_EPS :: Epsilon a => a
+ Numeric.Basics: tooManyIterations :: IterativeMethod => String -> a
+ Numeric.Basics: type IterativeMethod = HasCallStack
+ Numeric.DataFrame: sort :: forall (t :: Type) n ns. (SortableDataFrame t (n : ns), Ord t, SortBy n) => DataFrame t (n : ns) -> DataFrame t (n : ns)
+ Numeric.DataFrame: sortBy :: forall (t :: Type) n ns. (SortableDataFrame t (n : ns), SortBy n) => (DataFrame t ns -> DataFrame t ns -> Ordering) -> DataFrame t (n : ns) -> DataFrame t (n : ns)
+ Numeric.DataFrame.Contraction: instance (Data.Type.List.Classes.ConcatList as bs asbs, Numeric.Dimensions.Dim.Dimensions as, Numeric.Dimensions.Dim.Dimensions bs, GHC.Num.Num t) => Numeric.DataFrame.Contraction.Contraction t as bs asbs
+ Numeric.DataFrame.IO: castDataFrame :: forall (t :: Type) (xns :: [XNat]) (ns :: [Nat]). FixedDims xns ns => IODataFrame t ns -> IODataFrame t xns
+ Numeric.DataFrame.IO: copyDataFrameOff :: forall (t :: Type) as bs asbs. (Dimensions bs, PrimArray t (DataFrame t bs), ConcatList as bs asbs) => Int -> DataFrame t bs -> IODataFrame t asbs -> IO ()
+ Numeric.DataFrame.IO: copyMutableDataFrameOff :: forall (t :: Type) as bs asbs. (ExactDims bs, PrimBytes t, ConcatList as bs asbs) => Int -> IODataFrame t bs -> IODataFrame t asbs -> IO ()
+ Numeric.DataFrame.IO: data IODataFrame (t :: Type) (ns :: [k])
+ Numeric.DataFrame.IO: getDataFrameSteps :: forall (t :: Type) ns. IODataFrame t ns -> CumulDims
+ Numeric.DataFrame.IO: oneMoreDataFrame :: forall (t :: Type) ns. IODataFrame t ns -> IO (IODataFrame t ns)
+ Numeric.DataFrame.IO: pattern XIOFrame :: forall (t :: Type) (xns :: [XNat]). () => forall (ns :: [Nat]). (FixedDims xns ns, Dimensions ns) => IODataFrame t ns -> IODataFrame t xns
+ Numeric.DataFrame.IO: subDataFrameView :: forall (t :: Type) b bi bd as bs asbs. (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> IODataFrame t asbs -> IODataFrame t (bd :+ bs)
+ Numeric.DataFrame.IO: subDataFrameView' :: forall (t :: Type) as bs asbs. ConcatList as bs asbs => Idxs as -> IODataFrame t asbs -> IODataFrame t bs
+ Numeric.DataFrame.IO: withThawDataFrame :: forall (t :: Type) ns r. PrimArray t (DataFrame t ns) => (t -> IO r) -> (IODataFrame t ns -> IO r) -> DataFrame t ns -> IO r
+ Numeric.DataFrame.Internal.Backend: class KnownBackend t ds (BackendFamily t ds) => KnownBackend (t :: Type) (ds :: [Nat])
+ Numeric.DataFrame.Internal.Backend: instance Numeric.DataFrame.Internal.Backend.Family.KnownBackend t ds (Numeric.DataFrame.Internal.Backend.Family.BackendFamily t ds) => Numeric.DataFrame.Internal.Backend.KnownBackend t ds
+ Numeric.DataFrame.Internal.Mutable: castDataFrame# :: forall (t :: Type) (xns :: [XNat]) (ns :: [Nat]) s. FixedDims xns ns => MDataFrame s t ns -> MDataFrame s t xns
+ Numeric.DataFrame.Internal.Mutable: copyDataFrameOff# :: forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (Dimensions bs, PrimArray t (DataFrame t bs), ConcatList as bs asbs) => Int -> DataFrame t bs -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: copyMDataFrameOff# :: forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (ExactDims bs, PrimBytes t, ConcatList as bs asbs) => Int -> MDataFrame s t bs -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: getDataFrameSteps# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. MDataFrame s t ns -> CumulDims
+ Numeric.DataFrame.Internal.Mutable: oneMoreDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. MDataFrame s t ns -> State# s -> (# State# s, MDataFrame s t ns #)
+ Numeric.DataFrame.Internal.Mutable: subDataFrameView# :: forall (t :: Type) (k :: Type) (b :: k) (bi :: k) (bd :: k) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> MDataFrame s t asbs -> MDataFrame s t (bd :+ bs)
+ Numeric.DataFrame.Internal.Mutable: subDataFrameView'# :: forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. ConcatList as bs asbs => Idxs as -> MDataFrame s t asbs -> MDataFrame s t bs
+ Numeric.DataFrame.Internal.Mutable: withThawDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) (r :: Type) s. PrimArray t (DataFrame t ns) => (t -> State# s -> (# State# s, r #)) -> (MDataFrame s t ns -> State# s -> (# State# s, r #)) -> DataFrame t ns -> State# s -> (# State# s, r #)
+ Numeric.DataFrame.Internal.PrimArray: broadcast# :: PrimArray t a => t -> a
+ Numeric.DataFrame.Internal.PrimArray: cdIxM :: CumulDims -> Idxs ns -> Maybe Int
+ Numeric.DataFrame.Internal.PrimArray: cdIxSub :: CumulDims -> Idxs (ns +: idxN) -> Dim subN -> Int
+ Numeric.DataFrame.Internal.PrimArray: fromElems# :: PrimArray t a => CumulDims -> Int# -> ByteArray# -> a
+ Numeric.DataFrame.Internal.PrimArray: getOffAndSteps :: Int -> CumulDims -> Idxs ns -> (Int, CumulDims)
+ Numeric.DataFrame.Internal.PrimArray: getOffAndStepsM :: Int -> CumulDims -> Idxs ns -> Maybe (Int, CumulDims)
+ Numeric.DataFrame.Internal.PrimArray: getOffAndStepsSub :: Int -> CumulDims -> Idxs (ns +: idxN) -> Dim subN -> (Int, CumulDims)
+ Numeric.DataFrame.Internal.PrimArray: getOffAndStepsSubM :: Int -> CumulDims -> Idxs (ns +: idxN) -> Dim subN -> Maybe (Int, CumulDims)
+ Numeric.DataFrame.Internal.PrimArray: instance GHC.Show.Show Numeric.DataFrame.Internal.PrimArray.CumulDims
+ Numeric.DataFrame.Internal.PrimArray: withArrayContent :: forall (t :: Type) (a :: Type) (rep :: RuntimeRep) (r :: TYPE rep). PrimArray t a => (t -> r) -> (CumulDims -> Int# -> ByteArray# -> r) -> a -> r
+ Numeric.DataFrame.Internal.PrimArray: withArrayContent# :: forall (rep :: RuntimeRep) (r :: TYPE rep). PrimArray t a => (t -> r) -> (CumulDims -> Int# -> ByteArray# -> r) -> a -> r
+ Numeric.DataFrame.ST: castDataFrame :: forall (t :: Type) (xns :: [XNat]) (ns :: [Nat]) s. FixedDims xns ns => STDataFrame s t ns -> STDataFrame s t xns
+ Numeric.DataFrame.ST: copyDataFrameOff :: forall (t :: Type) as bs asbs s. (Dimensions bs, PrimArray t (DataFrame t bs), ConcatList as bs asbs) => Int -> DataFrame t bs -> STDataFrame s t asbs -> ST s ()
+ Numeric.DataFrame.ST: copyMutableDataFrameOff :: forall (t :: Type) as bs asbs s. (ExactDims bs, PrimBytes t, ConcatList as bs asbs) => Int -> STDataFrame s t bs -> STDataFrame s t asbs -> ST s ()
+ Numeric.DataFrame.ST: data STDataFrame s (t :: Type) (ns :: [k])
+ Numeric.DataFrame.ST: getDataFrameSteps :: forall (t :: Type) ns s. STDataFrame s t ns -> CumulDims
+ Numeric.DataFrame.ST: oneMoreDataFrame :: forall (t :: Type) ns s. STDataFrame s t ns -> ST s (STDataFrame s t ns)
+ Numeric.DataFrame.ST: pattern XSTFrame :: forall s (t :: Type) (xns :: [XNat]). () => forall (ns :: [Nat]). (FixedDims xns ns, Dimensions ns) => STDataFrame s t ns -> STDataFrame s t xns
+ Numeric.DataFrame.ST: subDataFrameView :: forall (t :: Type) b bi bd as bs asbs s. (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> STDataFrame s t asbs -> STDataFrame s t (bd :+ bs)
+ Numeric.DataFrame.ST: subDataFrameView' :: forall (t :: Type) as bs asbs s. ConcatList as bs asbs => Idxs as -> STDataFrame s t asbs -> STDataFrame s t bs
+ Numeric.DataFrame.ST: withThawDataFrame :: forall (t :: Type) ns r s. PrimArray t (DataFrame t ns) => (t -> ST s r) -> (STDataFrame s t ns -> ST s r) -> DataFrame t ns -> ST s r
+ Numeric.DataFrame.SubSpace: (.!) :: forall t a bs. SubSpace t '[a] bs (a :+ bs) => DataFrame t (a :+ bs) -> Idx a -> DataFrame t bs
+ Numeric.DataFrame.SubSpace: ewfoldl' :: forall t as bs asbs b. SubSpace t as bs asbs => (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: ewfoldr' :: forall t as bs asbs b. SubSpace t as bs asbs => (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: indexOffset :: forall t as bs asbs. SubSpace t as bs asbs => Int -> DataFrame t asbs -> DataFrame t bs
+ Numeric.DataFrame.SubSpace: instance (Data.Type.List.Classes.ConcatList as bs asbs, Numeric.DataFrame.SubSpace.SubSpaceCtx t as bs asbs) => Numeric.DataFrame.SubSpace.SubSpace t as bs asbs
+ Numeric.DataFrame.SubSpace: iwfoldl' :: forall t as bs asbs b. SubSpace t as bs asbs => (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: iwfoldr' :: forall t as bs asbs b. SubSpace t as bs asbs => (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: joinDataFrame :: forall t as bs asbs. (SubSpace t as bs asbs, PrimBytes (DataFrame t bs)) => DataFrame (DataFrame t bs) as -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: lookup :: forall t (as :: [XNat]) (bs :: [XNat]) (asbs :: [XNat]). (ConcatList as bs asbs, All KnownDimType bs, PrimBytes t) => Idxs as -> DataFrame t asbs -> Maybe (DataFrame t bs)
+ Numeric.DataFrame.SubSpace: selement :: forall t a bs f. (SubSpace t '[a] bs (a :+ bs), Applicative f) => Idx a -> (DataFrame t bs -> f (DataFrame t bs)) -> DataFrame t (a :+ bs) -> f (DataFrame t (a :+ bs))
+ Numeric.DataFrame.SubSpace: selementWise :: forall t a bs s bs' f. (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs'), Applicative f) => (DataFrame s bs' -> f (DataFrame t bs)) -> DataFrame s (a :+ bs') -> f (DataFrame t (a :+ bs))
+ Numeric.DataFrame.SubSpace: selementWise_ :: forall t a bs f b. (SubSpace t '[a] bs (a :+ bs), Applicative f) => (DataFrame t bs -> f b) -> DataFrame t (a :+ bs) -> f ()
+ Numeric.DataFrame.SubSpace: sewfoldMap :: forall t a bs m. (SubSpace t '[a] bs (a :+ bs), Monoid m) => (DataFrame t bs -> m) -> DataFrame t (a :+ bs) -> m
+ Numeric.DataFrame.SubSpace: sewfoldl :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: sewfoldl' :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: sewfoldr :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: sewfoldr' :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: sewgen :: forall t a bs. (SubSpace t '[a] bs (a :+ bs), Dimensions '[a]) => DataFrame t bs -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: sewmap :: forall t a bs s bs'. (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs')) => (DataFrame s bs' -> DataFrame t bs) -> DataFrame s (a :+ bs') -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: sewzip :: forall t a bs l bsL r bsR. (SubSpace t '[a] bs (a :+ bs), SubSpace l '[a] bsL (a :+ bsL), SubSpace r '[a] bsR (a :+ bsR)) => (DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs) -> DataFrame l (a :+ bsL) -> DataFrame r (a :+ bsR) -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: sindexOffset :: forall t a bs. SubSpace t '[a] bs (a :+ bs) => Int -> DataFrame t (a :+ bs) -> DataFrame t bs
+ Numeric.DataFrame.SubSpace: sindexWise :: forall t a bs s bs' f. (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs'), Applicative f) => (Idx a -> DataFrame s bs' -> f (DataFrame t bs)) -> DataFrame s (a :+ bs') -> f (DataFrame t (a :+ bs))
+ Numeric.DataFrame.SubSpace: sindexWise_ :: forall t a bs f b. (SubSpace t '[a] bs (a :+ bs), Applicative f) => (Idx a -> DataFrame t bs -> f b) -> DataFrame t (a :+ bs) -> f ()
+ Numeric.DataFrame.SubSpace: siwfoldMap :: forall t a bs m. (SubSpace t '[a] bs (a :+ bs), Monoid m) => (Idx a -> DataFrame t bs -> m) -> DataFrame t (a :+ bs) -> m
+ Numeric.DataFrame.SubSpace: siwfoldl :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (Idx a -> b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: siwfoldl' :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (Idx a -> b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: siwfoldr :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (Idx a -> DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: siwfoldr' :: forall t a bs b. SubSpace t '[a] bs (a :+ bs) => (Idx a -> DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b
+ Numeric.DataFrame.SubSpace: siwgen :: forall t a bs. (SubSpace t '[a] bs (a :+ bs), Dimensions '[a]) => (Idx a -> DataFrame t bs) -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: siwmap :: forall t a bs s bs'. (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs')) => (Idx a -> DataFrame s bs' -> DataFrame t bs) -> DataFrame s (a :+ bs') -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: siwzip :: forall t a bs l bsL r bsR. (SubSpace t '[a] bs (a :+ bs), SubSpace l '[a] bsL (a :+ bsL), SubSpace r '[a] bsR (a :+ bsR)) => (Idx a -> DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs) -> DataFrame l (a :+ bsL) -> DataFrame r (a :+ bsR) -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: sliceMaybe :: forall (t :: Type) (b :: XNat) bi bd as bs asbs. (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs, All KnownDimType bs, PrimBytes t) => Idxs (as +: bi) -> DataFrame t asbs -> Maybe (DataFrame t (bd :+ bs))
+ Numeric.DataFrame.SubSpace: slookup :: forall t (a :: XNat) (bs :: [XNat]). (All KnownDimType bs, PrimBytes t) => Idx a -> DataFrame t (a :+ bs) -> Maybe (DataFrame t bs)
+ Numeric.DataFrame.SubSpace: sslice :: forall t b bi bd bs. (KnownDimKind (KindOfEl bs), CanSlice t (b :+ bs), SubFrameIndexCtx b bi bd, KnownDim bd, PrimArray t (DataFrame t (bd :+ bs))) => Idx bi -> DataFrame t (b :+ bs) -> DataFrame t (bd :+ bs)
+ Numeric.DataFrame.SubSpace: ssliceMaybe :: forall (t :: Type) (b :: XNat) (bi :: XNat) (bd :: XNat) (bs :: [XNat]). (SubFrameIndexCtx b bi bd, KnownDim bd, All KnownDimType bs, PrimBytes t) => Idx bi -> DataFrame t (b :+ bs) -> Maybe (DataFrame t (bd :+ bs))
+ Numeric.DataFrame.SubSpace: supdate :: forall t a bs. SubSpace t '[a] bs (a :+ bs) => Idx a -> DataFrame t bs -> DataFrame t (a :+ bs) -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: supdateOffset :: forall t a bs. SubSpace t '[a] bs (a :+ bs) => Int -> DataFrame t bs -> DataFrame t (a :+ bs) -> DataFrame t (a :+ bs)
+ Numeric.DataFrame.SubSpace: supdateSlice :: forall t b bi bd bs. (KnownDimKind (KindOfEl bs), CanSlice t (b :+ bs), SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs, PrimArray t (DataFrame t (bd :+ bs))) => Idx bi -> DataFrame t (bd :+ bs) -> DataFrame t (b :+ bs) -> DataFrame t (b :+ bs)
+ Numeric.DataFrame.SubSpace: type family CanSlice (t :: Type) (asbs :: [k]) :: Constraint
+ Numeric.DataFrame.SubSpace: updateOffset :: forall t as bs asbs. SubSpace t as bs asbs => Int -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: }
+ Numeric.DataFrame.Type: (!) :: IndexFrame t d ds => DataFrame t (d : ds) -> Word -> DataFrame t ds
+ Numeric.DataFrame.Type: asDiag :: forall (n :: Nat) (m :: Nat) (ds :: [Nat]) (t :: Type). (Dimensions ds, KnownDim n, KnownDim m, KnownBackend t (Min n m :+ ds), KnownBackend t (n :+ (m :+ ds)), PrimBytes t) => DataFrame t (Min n m :+ ds) -> DataFrame t (n :+ (m :+ ds))
+ Numeric.DataFrame.Type: class IndexFrame t d ds
+ Numeric.DataFrame.Type: class KnownBackend t ds BackendFamily t ds => KnownBackend t (ds :: [Nat])
+ Numeric.DataFrame.Type: data Nat
+ Numeric.DataFrame.Type: instance (Data.Type.List.All GHC.Read.Read ts, Data.Type.List.All Numeric.PrimBytes.PrimBytes ts, Numeric.TypedList.RepresentableList ts, Numeric.Dimensions.Dim.BoundedDims ds, Data.Type.List.All Numeric.Dimensions.Dim.KnownDimType ds) => GHC.Read.Read (Numeric.DataFrame.Type.DataFrame ts ds)
+ Numeric.DataFrame.Type: instance (GHC.Classes.Ord (Numeric.ProductOrd.Partial.ProductOrd (Numeric.DataFrame.Internal.BackendI.DFBackend t ds)), GHC.Classes.Eq (Numeric.DataFrame.Internal.BackendI.DFBackend t ds)) => GHC.Classes.Ord (Numeric.ProductOrd.Partial.ProductOrd (Numeric.DataFrame.Type.DataFrame t ds))
+ Numeric.DataFrame.Type: instance (GHC.Float.RealFloat (Numeric.DataFrame.Type.DataFrame t '[]), Numeric.DataFrame.Internal.Backend.KnownBackend t '[], GHC.Classes.Eq t) => GHC.Float.RealFloat (Numeric.DataFrame.Type.DataFrame t '[])
+ Numeric.DataFrame.Type: instance (GHC.Read.Read t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.BoundedDims ds, Data.Type.List.All Numeric.Dimensions.Dim.KnownDimType ds) => GHC.Read.Read (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance (GHC.Real.RealFrac (Numeric.DataFrame.Type.DataFrame t '[]), Numeric.DataFrame.Internal.Backend.KnownBackend t '[], GHC.Classes.Eq t) => GHC.Real.RealFrac (Numeric.DataFrame.Type.DataFrame t '[])
+ Numeric.DataFrame.Type: instance (Numeric.Basics.RealExtras (Numeric.DataFrame.Type.DataFrame t '[]), Numeric.DataFrame.Internal.Backend.KnownBackend t '[], GHC.Classes.Eq t) => Numeric.Basics.RealExtras (Numeric.DataFrame.Type.DataFrame t '[])
+ Numeric.DataFrame.Type: instance (Numeric.Basics.RealFloatExtras (Numeric.DataFrame.Type.DataFrame t '[]), Numeric.DataFrame.Internal.Backend.KnownBackend t '[], GHC.Classes.Eq t) => Numeric.Basics.RealFloatExtras (Numeric.DataFrame.Type.DataFrame t '[])
+ Numeric.DataFrame.Type: instance (Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Internal.BackendI.DFBackend t ds), Numeric.PrimBytes.PrimBytes t) => Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance (Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t '[d]), Numeric.Dimensions.Dim.KnownDim d) => Numeric.DataFrame.Type.IndexFrame t d '[]
+ Numeric.DataFrame.Type: instance (Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t (d : ds)), Numeric.Dimensions.Dim.KnownDim d, Numeric.DataFrame.Internal.Backend.KnownBackend t ds) => Numeric.DataFrame.Type.IndexFrame t d ds
+ Numeric.DataFrame.Type: instance (Numeric.DataFrame.Type.AllFrames GHC.Classes.Eq ts ds, Numeric.DataFrame.Type.AllFrames GHC.Classes.Ord ts ds) => GHC.Classes.Ord (Numeric.DataFrame.Type.DataFrame ts ds)
+ Numeric.DataFrame.Type: instance (Numeric.DataFrame.Type.IndexFrame t d ds, Numeric.DataFrame.Type.IndexFrame ts d ds) => Numeric.DataFrame.Type.IndexFrame (t : ts) d ds
+ Numeric.DataFrame.Type: instance (Numeric.Dimensions.Dim.Dimensions xns, Numeric.DataFrame.Internal.Backend.KnownBackend t (Numeric.Dimensions.Dim.DimsBound xns), Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t (Numeric.Dimensions.Dim.DimsBound xns)), Numeric.PrimBytes.PrimBytes t) => Numeric.DataFrame.Internal.PrimArray.PrimArray t (Numeric.DataFrame.Type.DataFrame t xns)
+ Numeric.DataFrame.Type: instance (Numeric.TypedList.RepresentableList ts, Data.Type.List.All Numeric.PrimBytes.PrimBytes ts) => Numeric.DataFrame.Type.IndexFrame ts xd xds
+ Numeric.DataFrame.Type: instance GHC.Classes.Eq (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Classes.Eq (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Classes.Ord (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Classes.Ord (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Classes.Ord (Numeric.ProductOrd.NonTransitive.ProductOrd (Numeric.DataFrame.Internal.BackendI.DFBackend t ds)) => GHC.Classes.Ord (Numeric.ProductOrd.NonTransitive.ProductOrd (Numeric.DataFrame.Type.DataFrame t ds))
+ Numeric.DataFrame.Type: instance GHC.Enum.Bounded (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Enum.Bounded (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Enum.Enum (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Enum.Enum (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Float.Floating (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Float.Floating (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Float.RealFloat (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Float.RealFloat (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Num.Num (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Num.Num (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Real.Fractional (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Real.Fractional (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Real.Integral (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Real.Integral (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Real.Real (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Real.Real (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance GHC.Real.RealFrac (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => GHC.Real.RealFrac (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance Numeric.Basics.Epsilon (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => Numeric.Basics.Epsilon (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance Numeric.Basics.RealExtras (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => Numeric.Basics.RealExtras (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance Numeric.Basics.RealFloatExtras (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => Numeric.Basics.RealFloatExtras (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance Numeric.DataFrame.Type.IndexFrame '[] d ds
+ Numeric.DataFrame.Type: instance Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance Numeric.PrimBytes.PrimBytes t => Numeric.DataFrame.Type.IndexFrame t xd xds
+ Numeric.DataFrame.Type: instance Numeric.ProductOrd.ProductOrder (Numeric.DataFrame.Internal.BackendI.DFBackend t ds) => Numeric.ProductOrd.ProductOrder (Numeric.DataFrame.Type.DataFrame t ds)
+ Numeric.DataFrame.Type: instance forall l (ts :: l). (GHC.Enum.Enum (Numeric.DataFrame.Type.DataFrame ts '[]), Numeric.DataFrame.Type.KnownBackends ts '[]) => GHC.Enum.Enum (Numeric.DataFrame.Type.DataFrame ts '[])
+ Numeric.DataFrame.Type: instance forall l (ts :: l). (GHC.Real.Integral (Numeric.DataFrame.Type.DataFrame ts '[]), Numeric.DataFrame.Type.KnownBackends ts '[], GHC.Classes.Eq (Numeric.DataFrame.Type.DataFrame ts '[])) => GHC.Real.Integral (Numeric.DataFrame.Type.DataFrame ts '[])
+ Numeric.DataFrame.Type: instance forall l (ts :: l). (GHC.Real.Real (Numeric.DataFrame.Type.DataFrame ts '[]), Numeric.DataFrame.Type.KnownBackends ts '[], GHC.Classes.Eq (Numeric.DataFrame.Type.DataFrame ts '[])) => GHC.Real.Real (Numeric.DataFrame.Type.DataFrame ts '[])
+ Numeric.DataFrame.Type: instance forall l (ts :: l). (Numeric.Basics.Epsilon (Numeric.DataFrame.Type.DataFrame ts '[]), Numeric.DataFrame.Type.KnownBackends ts '[], GHC.Classes.Eq (Numeric.DataFrame.Type.DataFrame ts '[])) => Numeric.Basics.Epsilon (Numeric.DataFrame.Type.DataFrame ts '[])
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (Numeric.Dimensions.Dim.Dimensions xns, Numeric.DataFrame.Type.KnownBackends ts (Numeric.Dimensions.Dim.DimsBound xns), GHC.Enum.Bounded (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => GHC.Enum.Bounded (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (Numeric.Dimensions.Dim.Dimensions xns, Numeric.DataFrame.Type.KnownBackends ts (Numeric.Dimensions.Dim.DimsBound xns), GHC.Float.Floating (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => GHC.Float.Floating (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (Numeric.Dimensions.Dim.Dimensions xns, Numeric.DataFrame.Type.KnownBackends ts (Numeric.Dimensions.Dim.DimsBound xns), GHC.Num.Num (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => GHC.Num.Num (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (Numeric.Dimensions.Dim.Dimensions xns, Numeric.DataFrame.Type.KnownBackends ts (Numeric.Dimensions.Dim.DimsBound xns), GHC.Real.Fractional (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => GHC.Real.Fractional (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (Numeric.Dimensions.Dim.Dimensions xns, Numeric.DataFrame.Type.KnownBackends ts (Numeric.Dimensions.Dim.DimsBound xns), Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => Numeric.PrimBytes.PrimBytes (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (xns Data.Type.Equality.~ Data.Type.List.Map 'Numeric.Dimensions.Dim.N (Numeric.Dimensions.Dim.DimsBound xns), GHC.Classes.Eq (Numeric.DataFrame.Type.DataFrame ts xns), GHC.Classes.Ord (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => GHC.Classes.Ord (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: instance forall l (xns :: [Numeric.Dimensions.Dim.XNat]) (ts :: l). (xns Data.Type.Equality.~ Data.Type.List.Map 'Numeric.Dimensions.Dim.N (Numeric.Dimensions.Dim.DimsBound xns), Numeric.ProductOrd.ProductOrder (Numeric.DataFrame.Type.DataFrame ts (Numeric.Dimensions.Dim.DimsBound xns))) => Numeric.ProductOrd.ProductOrder (Numeric.DataFrame.Type.DataFrame ts xns)
+ Numeric.DataFrame.Type: pattern XIdxs :: forall (ds :: [XNat]) (ns :: [Nat]). (FixedDims ds ns, Dimensions ns) => () => Idxs ns -> Idxs ds
+ Numeric.DataFrame.Type: scalar :: t -> DataFrame t ('[] :: [Nat])
+ Numeric.DataFrame.Type: unScalar :: DataFrame t ('[] :: [Nat]) -> t
+ Numeric.Matrix.Bidiagonal: BiDiag :: Matrix t n n -> Scalar t -> Vector t (Min n m) -> Vector t (Min n m) -> Matrix t m m -> Scalar t -> BiDiag
+ Numeric.Matrix.Bidiagonal: [bdAlpha] :: BiDiag -> Vector t (Min n m)
+ Numeric.Matrix.Bidiagonal: [bdBeta] :: BiDiag -> Vector t (Min n m)
+ Numeric.Matrix.Bidiagonal: [bdUDet] :: BiDiag -> Scalar t
+ Numeric.Matrix.Bidiagonal: [bdU] :: BiDiag -> Matrix t n n
+ Numeric.Matrix.Bidiagonal: [bdVDet] :: BiDiag -> Scalar t
+ Numeric.Matrix.Bidiagonal: [bdV] :: BiDiag -> Matrix t m m
+ Numeric.Matrix.Bidiagonal: biDiag :: forall (t :: Type) (n :: Nat) (m :: Nat). (PrimBytes t, Num t) => Dims '[n, m] -> Vector t (Min n m) -> Vector t (Min n m) -> Matrix t n m
+ Numeric.Matrix.Bidiagonal: bidiagonalHouseholder :: forall (t :: Type) (n :: Nat) (m :: Nat). (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m) => Matrix t n m -> BiDiag t n m
+ Numeric.Matrix.Bidiagonal: data BiDiag (t :: Type) (n :: Nat) (m :: Nat)
+ Numeric.Matrix.Bidiagonal: instance (GHC.Classes.Eq t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m, Numeric.Dimensions.Dim.KnownDim (Data.Type.Lits.Min n m), Numeric.DataFrame.Internal.Backend.KnownBackend t '[Data.Type.Lits.Min n m]) => GHC.Classes.Eq (Numeric.Matrix.Bidiagonal.BiDiag t n m)
+ Numeric.Matrix.Bidiagonal: instance (GHC.Show.Show t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m, Numeric.Dimensions.Dim.KnownDim (Data.Type.Lits.Min n m)) => GHC.Show.Show (Numeric.Matrix.Bidiagonal.BiDiag t n m)
+ Numeric.Matrix.LU: LU :: Matrix t n n -> Matrix t n n -> Matrix t n n -> Scalar t -> LU
+ Numeric.Matrix.LU: [luLower] :: LU -> Matrix t n n
+ Numeric.Matrix.LU: [luPermDet] :: LU -> Scalar t
+ Numeric.Matrix.LU: [luPerm] :: LU -> Matrix t n n
+ Numeric.Matrix.LU: [luUpper] :: LU -> Matrix t n n
+ Numeric.Matrix.LU: class (KnownDim n, Ord t, Fractional t, PrimBytes t, KnownBackend t '[n, n]) => MatrixLU t (n :: Nat)
+ Numeric.Matrix.LU: data LU (t :: Type) (n :: Nat)
+ Numeric.Matrix.LU: detViaLU :: forall (t :: Type) (n :: Nat). MatrixLU t n => Matrix t n n -> Scalar t
+ Numeric.Matrix.LU: instance (GHC.Classes.Eq (Numeric.Matrix.Internal.Matrix t n n), GHC.Classes.Eq t) => GHC.Classes.Eq (Numeric.Matrix.LU.LU t n)
+ Numeric.Matrix.LU: instance (GHC.Show.Show t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n) => GHC.Show.Show (Numeric.Matrix.LU.LU t n)
+ Numeric.Matrix.LU: instance (Numeric.Dimensions.Dim.KnownDim n, GHC.Classes.Ord t, GHC.Real.Fractional t, Numeric.PrimBytes.PrimBytes t, Numeric.DataFrame.Internal.Backend.KnownBackend t '[n, n]) => Numeric.Matrix.LU.MatrixLU t n
+ Numeric.Matrix.LU: inverseViaLU :: forall (t :: Type) (n :: Nat). MatrixLU t n => Matrix t n n -> Matrix t n n
+ Numeric.Matrix.LU: lu :: MatrixLU t n => Matrix t n n -> LU t n
+ Numeric.Matrix.LU: luSolveL :: forall t (n :: Nat) (ds :: [Nat]). (MatrixLU t n, Dimensions ds) => LU t n -> DataFrame t (ds +: n) -> DataFrame t (ds +: n)
+ Numeric.Matrix.LU: luSolveR :: forall t (n :: Nat) (ds :: [Nat]). (MatrixLU t n, Dimensions ds) => LU t n -> DataFrame t (n :+ ds) -> DataFrame t (n :+ ds)
+ Numeric.Matrix.QR: LQ :: Matrix t n m -> Matrix t m m -> Scalar t -> LQ
+ Numeric.Matrix.QR: QR :: Matrix t n n -> Scalar t -> Matrix t n m -> QR
+ Numeric.Matrix.QR: [lqL] :: LQ -> Matrix t n m
+ Numeric.Matrix.QR: [lqQDet] :: LQ -> Scalar t
+ Numeric.Matrix.QR: [lqQ] :: LQ -> Matrix t m m
+ Numeric.Matrix.QR: [qrQDet] :: QR -> Scalar t
+ Numeric.Matrix.QR: [qrQ] :: QR -> Matrix t n n
+ Numeric.Matrix.QR: [qrR] :: QR -> Matrix t n m
+ Numeric.Matrix.QR: class (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m) => MatrixQR t (n :: Nat) (m :: Nat)
+ Numeric.Matrix.QR: data LQ (t :: Type) (n :: Nat) (m :: Nat)
+ Numeric.Matrix.QR: data QR (t :: Type) (n :: Nat) (m :: Nat)
+ Numeric.Matrix.QR: detViaQR :: forall t n. MatrixQR t n n => Matrix t n n -> Scalar t
+ Numeric.Matrix.QR: instance (GHC.Classes.Eq t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m) => GHC.Classes.Eq (Numeric.Matrix.QR.LQ t n m)
+ Numeric.Matrix.QR: instance (GHC.Classes.Eq t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m) => GHC.Classes.Eq (Numeric.Matrix.QR.QR t n m)
+ Numeric.Matrix.QR: instance (GHC.Show.Show t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m) => GHC.Show.Show (Numeric.Matrix.QR.LQ t n m)
+ Numeric.Matrix.QR: instance (GHC.Show.Show t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m) => GHC.Show.Show (Numeric.Matrix.QR.QR t n m)
+ Numeric.Matrix.QR: instance (Numeric.PrimBytes.PrimBytes t, GHC.Classes.Ord t, Numeric.Basics.Epsilon t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m) => Numeric.Matrix.QR.MatrixQR t n m
+ Numeric.Matrix.QR: inverseViaQR :: forall t n. MatrixQR t n n => Matrix t n n -> Matrix t n n
+ Numeric.Matrix.QR: lq :: MatrixQR t n m => Matrix t n m -> LQ t n m
+ Numeric.Matrix.QR: qr :: MatrixQR t n m => Matrix t n m -> QR t n m
+ Numeric.Matrix.QR: qrSolveL :: forall t (n :: Nat) (m :: Nat) (ds :: [Nat]). (MatrixQR t n m, Dimensions ds) => Matrix t n m -> DataFrame t (ds +: m) -> DataFrame t (ds +: n)
+ Numeric.Matrix.QR: qrSolveR :: forall t (n :: Nat) (m :: Nat) (ds :: [Nat]). (MatrixQR t n m, Dimensions ds) => Matrix t n m -> DataFrame t (n :+ ds) -> DataFrame t (m :+ ds)
+ Numeric.Matrix.SVD: SVD :: Matrix t n n -> Vector t (Min n m) -> Matrix t m m -> SVD
+ Numeric.Matrix.SVD: [svdS] :: SVD -> Vector t (Min n m)
+ Numeric.Matrix.SVD: [svdU] :: SVD -> Matrix t n n
+ Numeric.Matrix.SVD: [svdV] :: SVD -> Matrix t m m
+ Numeric.Matrix.SVD: class RealFloatExtras t => MatrixSVD (t :: Type) (n :: Nat) (m :: Nat)
+ Numeric.Matrix.SVD: data SVD (t :: Type) (n :: Nat) (m :: Nat)
+ Numeric.Matrix.SVD: instance (GHC.Classes.Eq (Numeric.Matrix.Internal.Matrix t n n), GHC.Classes.Eq (Numeric.Matrix.Internal.Matrix t m m), GHC.Classes.Eq (Numeric.Vector.Internal.Vector t (Data.Type.Lits.Min n m))) => GHC.Classes.Eq (Numeric.Matrix.SVD.SVD t n m)
+ Numeric.Matrix.SVD: instance (GHC.Show.Show t, Numeric.PrimBytes.PrimBytes t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m, Numeric.Dimensions.Dim.KnownDim (Data.Type.Lits.Min n m)) => GHC.Show.Show (Numeric.Matrix.SVD.SVD t n m)
+ Numeric.Matrix.SVD: instance (Numeric.Basics.RealFloatExtras t, Numeric.Dimensions.Dim.KnownDim n, Numeric.Dimensions.Dim.KnownDim m) => Numeric.Matrix.SVD.MatrixSVD t n m
+ Numeric.Matrix.SVD: instance (Numeric.Basics.RealFloatExtras t, Numeric.Quaternion.Internal.Quaternion t) => Numeric.Matrix.SVD.MatrixSVD t 3 3
+ Numeric.Matrix.SVD: instance Numeric.Basics.RealFloatExtras t => Numeric.Matrix.SVD.MatrixSVD t 1 1
+ Numeric.Matrix.SVD: instance Numeric.Basics.RealFloatExtras t => Numeric.Matrix.SVD.MatrixSVD t 2 2
+ Numeric.Matrix.SVD: svd :: (MatrixSVD t n m, IterativeMethod) => Matrix t n m -> SVD t n m
+ Numeric.Matrix.SVD: svd1 :: (PrimBytes t, Num t, Eq t) => Matrix t 1 1 -> SVD t 1 1
+ Numeric.Matrix.SVD: svd2 :: forall t. RealFloatExtras t => Matrix t 2 2 -> SVD t 2 2
+ Numeric.Matrix.SVD: svd3 :: forall t. (Quaternion t, RealFloatExtras t) => Matrix t 3 3 -> SVD t 3 3
+ Numeric.Matrix.SVD: svd3q :: forall t. (Quaternion t, RealFloatExtras t) => Matrix t 3 3 -> (Quater t, Vector t 3, Quater t)
+ Numeric.Subroutine.Householder: householderReflectionInplaceL :: forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat). (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m) => STDataFrame s t '[n] -> STDataFrame s t '[n, n] -> STDataFrame s t '[n, m] -> Idxs '[n, m] -> ST s Bool
+ Numeric.Subroutine.Householder: householderReflectionInplaceR :: forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat). (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m) => STDataFrame s t '[m] -> STDataFrame s t '[m, m] -> STDataFrame s t '[n, m] -> Idxs '[n, m] -> ST s Bool
+ Numeric.Subroutine.SolveTriangular: solveLowerTriangularL :: forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat]). (PrimBytes t, Fractional t, Eq t, KnownDim n, KnownDim m, n <= m) => STDataFrame s t (ds +: m) -> DataFrame t '[n, m] -> ST s ()
+ Numeric.Subroutine.SolveTriangular: solveLowerTriangularR :: forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat]). (PrimBytes t, Fractional t, Eq t, KnownDim n, KnownDim m, n <= m) => DataFrame t '[n, m] -> STDataFrame s t (n :+ ds) -> ST s ()
+ Numeric.Subroutine.SolveTriangular: solveUpperTriangularL :: forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat]). (PrimBytes t, Fractional t, Eq t, KnownDim m, m <= n) => STDataFrame s t (ds +: m) -> DataFrame t '[n, m] -> ST s ()
+ Numeric.Subroutine.SolveTriangular: solveUpperTriangularR :: forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat]). (PrimBytes t, Fractional t, Eq t, KnownDim m, m <= n) => DataFrame t '[n, m] -> STDataFrame s t (m :+ ds) -> ST s ()
+ Numeric.Subroutine.Sort: class BoundedDim n => SortBy n
+ Numeric.Subroutine.Sort: instance Numeric.Dimensions.Dim.BoundedDim xn => Numeric.Subroutine.Sort.SortBy xn
+ Numeric.Subroutine.Sort: instance Numeric.Dimensions.Dim.KnownDim n => Numeric.Subroutine.Sort.SortBy n
+ Numeric.Subroutine.Sort: instance Numeric.Subroutine.Sort.SortBy 0
+ Numeric.Subroutine.Sort: instance Numeric.Subroutine.Sort.SortBy 1
+ Numeric.Subroutine.Sort: instance Numeric.Subroutine.Sort.SortBy 2
+ Numeric.Subroutine.Sort: instance Numeric.Subroutine.Sort.SortBy 3
+ Numeric.Subroutine.Sort: instance Numeric.Subroutine.Sort.SortBy 4
+ Numeric.Subroutine.Sort: sort :: forall (t :: Type) n ns. (SortableDataFrame t (n : ns), Ord t, SortBy n) => DataFrame t (n : ns) -> DataFrame t (n : ns)
+ Numeric.Subroutine.Sort: sortBy :: forall (t :: Type) n ns. (SortableDataFrame t (n : ns), SortBy n) => (DataFrame t ns -> DataFrame t ns -> Ordering) -> DataFrame t (n : ns) -> DataFrame t (n : ns)
+ Numeric.Subroutine.Sort: sortByInplace :: (SortBy n, PrimBytes t) => (STDataFrame s t ns -> STDataFrame s t ns -> ST s Ordering) -> STDataFrame s t (n : ns) -> ST s ()
+ Numeric.Subroutine.Sort: type family SortableDataFrame (t :: Type) (ns :: [k]) :: Constraint
- Numeric.DataFrame.IO: copyDataFrame :: forall (t :: Type) (b :: Nat) (bi :: Nat) (bd :: Nat) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]). (b ~ ((bi + bd) - 1), PrimBytes t, PrimBytes (DataFrame t (bd :+ bs)), ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> IODataFrame t asbs -> IO ()
+ Numeric.DataFrame.IO: copyDataFrame :: forall (t :: Type) b bi bd as bs asbs. (SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs, PrimArray t (DataFrame t (bd :+ bs)), ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> IODataFrame t asbs -> IO ()
- Numeric.DataFrame.IO: copyDataFrame' :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]). (PrimBytes t, PrimBytes (DataFrame t bs), ConcatList as bs asbs) => Idxs as -> DataFrame t bs -> IODataFrame t asbs -> IO ()
+ Numeric.DataFrame.IO: copyDataFrame' :: forall (t :: Type) as bs asbs. (ExactDims bs, PrimArray t (DataFrame t bs), ConcatList as bs asbs) => Idxs as -> DataFrame t bs -> IODataFrame t asbs -> IO ()
- Numeric.DataFrame.IO: copyMutableDataFrame :: forall (t :: Type) (b :: Nat) (bi :: Nat) (bd :: Nat) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]). (b ~ ((bi + bd) - 1), PrimBytes t, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> IODataFrame t (bd :+ bs) -> IODataFrame t asbs -> IO ()
+ Numeric.DataFrame.IO: copyMutableDataFrame :: forall (t :: Type) b bi bd as bs asbs. (SubFrameIndexCtx b bi bd, ExactDims bs, PrimBytes t, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> IODataFrame t (bd :+ bs) -> IODataFrame t asbs -> IO ()
- Numeric.DataFrame.IO: copyMutableDataFrame' :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]). (PrimBytes t, ConcatList as bs asbs) => Idxs as -> IODataFrame t bs -> IODataFrame t asbs -> IO ()
+ Numeric.DataFrame.IO: copyMutableDataFrame' :: forall (t :: Type) as bs asbs. (ExactDims bs, PrimBytes t, ConcatList as bs asbs) => Idxs as -> IODataFrame t bs -> IODataFrame t asbs -> IO ()
- Numeric.DataFrame.IO: freezeDataFrame :: forall (t :: Type) (ns :: [Nat]). PrimArray t (DataFrame t ns) => IODataFrame t ns -> IO (DataFrame t ns)
+ Numeric.DataFrame.IO: freezeDataFrame :: forall (t :: Type) ns. PrimArray t (DataFrame t ns) => IODataFrame t ns -> IO (DataFrame t ns)
- Numeric.DataFrame.IO: isDataFramePinned :: forall (k :: Type) (t :: Type) (ns :: [k]). KnownDimKind k => IODataFrame t ns -> Bool
+ Numeric.DataFrame.IO: isDataFramePinned :: forall (t :: Type) ns. IODataFrame t ns -> Bool
- Numeric.DataFrame.IO: newDataFrame :: forall t (ns :: [Nat]). (PrimBytes t, Dimensions ns) => IO (IODataFrame t ns)
+ Numeric.DataFrame.IO: newDataFrame :: forall (t :: Type) ns. (PrimBytes t, Dimensions ns) => IO (IODataFrame t ns)
- Numeric.DataFrame.IO: newPinnedDataFrame :: forall t (ns :: [Nat]). (PrimBytes t, Dimensions ns) => IO (IODataFrame t ns)
+ Numeric.DataFrame.IO: newPinnedDataFrame :: forall (t :: Type) ns. (PrimBytes t, Dimensions ns) => IO (IODataFrame t ns)
- Numeric.DataFrame.IO: readDataFrame :: forall (t :: Type) (ns :: [Nat]). PrimBytes t => IODataFrame t ns -> Idxs ns -> IO (DataFrame t ('[] :: [Nat]))
+ Numeric.DataFrame.IO: readDataFrame :: forall (t :: Type) ns. PrimBytes (DataFrame t ('[] :: KindOf ns)) => IODataFrame t ns -> Idxs ns -> IO (DataFrame t ('[] :: KindOf ns))
- Numeric.DataFrame.IO: readDataFrameOff :: forall (t :: Type) (ns :: [Nat]). PrimBytes t => IODataFrame t ns -> Int -> IO (DataFrame t ('[] :: [Nat]))
+ Numeric.DataFrame.IO: readDataFrameOff :: forall (t :: Type) ns. PrimBytes (DataFrame t ('[] :: KindOf ns)) => IODataFrame t ns -> Int -> IO (DataFrame t ('[] :: KindOf ns))
- Numeric.DataFrame.IO: thawDataFrame :: forall (t :: Type) (ns :: [Nat]). (Dimensions ns, PrimBytes (DataFrame t ns)) => DataFrame t ns -> IO (IODataFrame t ns)
+ Numeric.DataFrame.IO: thawDataFrame :: forall (t :: Type) ns. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> IO (IODataFrame t ns)
- Numeric.DataFrame.IO: thawPinDataFrame :: forall (t :: Type) (ns :: [Nat]). (Dimensions ns, PrimBytes (DataFrame t ns)) => DataFrame t ns -> IO (IODataFrame t ns)
+ Numeric.DataFrame.IO: thawPinDataFrame :: forall (t :: Type) ns. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> IO (IODataFrame t ns)
- Numeric.DataFrame.IO: unsafeFreezeDataFrame :: forall (t :: Type) (ns :: [Nat]). PrimArray t (DataFrame t ns) => IODataFrame t ns -> IO (DataFrame t ns)
+ Numeric.DataFrame.IO: unsafeFreezeDataFrame :: forall (t :: Type) ns. PrimArray t (DataFrame t ns) => IODataFrame t ns -> IO (DataFrame t ns)
- Numeric.DataFrame.IO: unsafeThawDataFrame :: forall (t :: Type) (ns :: [Nat]). (Dimensions ns, PrimBytes (DataFrame t ns), PrimBytes t) => DataFrame t ns -> IO (IODataFrame t ns)
+ Numeric.DataFrame.IO: unsafeThawDataFrame :: forall (t :: Type) ns. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> IO (IODataFrame t ns)
- Numeric.DataFrame.IO: withDataFramePtr :: forall (k :: Type) (t :: Type) (ns :: [k]) (r :: Type). (PrimBytes t, KnownDimKind k) => IODataFrame t ns -> (Ptr t -> IO r) -> IO r
+ Numeric.DataFrame.IO: withDataFramePtr :: forall (t :: Type) ns (r :: Type). PrimBytes t => IODataFrame t ns -> (Ptr t -> IO r) -> IO r
- Numeric.DataFrame.IO: writeDataFrame :: forall t (ns :: [Nat]). PrimBytes t => IODataFrame t ns -> Idxs ns -> DataFrame t ('[] :: [Nat]) -> IO ()
+ Numeric.DataFrame.IO: writeDataFrame :: forall (t :: Type) ns. PrimBytes (DataFrame t ('[] :: KindOf ns)) => IODataFrame t ns -> Idxs ns -> DataFrame t ('[] :: KindOf ns) -> IO ()
- Numeric.DataFrame.IO: writeDataFrameOff :: forall (t :: Type) (ns :: [Nat]). PrimBytes t => IODataFrame t ns -> Int -> DataFrame t ('[] :: [Nat]) -> IO ()
+ Numeric.DataFrame.IO: writeDataFrameOff :: forall (t :: Type) ns. PrimBytes (DataFrame t ('[] :: KindOf ns)) => IODataFrame t ns -> Int -> DataFrame t ('[] :: KindOf ns) -> IO ()
- Numeric.DataFrame.Internal.Backend: inferBounded :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Bounded t, KnownBackend t ds b) => Dict (Bounded (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferBounded :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Bounded t, KnownBackend t ds b) => Dict (Bounded (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferEq :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Eq t, KnownBackend t ds b) => Dict (Eq (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferEq :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Eq t, KnownBackend t ds b) => Dict (Eq (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferFloating :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Floating t, KnownBackend t ds b) => Dict (Floating (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferFloating :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Floating t, KnownBackend t ds b) => Dict (Floating (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferFractional :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Fractional t, KnownBackend t ds b) => Dict (Fractional (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferFractional :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Fractional t, KnownBackend t ds b) => Dict (Fractional (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferNum :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Num t, KnownBackend t ds b) => Dict (Num (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferNum :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Num t, KnownBackend t ds b) => Dict (Num (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferOrd :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Ord t, KnownBackend t ds b) => Dict (Ord (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferOrd :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Ord t, KnownBackend t ds b) => Dict (Ord (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferPONonTransitive :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Ord t, KnownBackend t ds b) => Dict (Ord (ProductOrd (Backend I t ds b)))
+ Numeric.DataFrame.Internal.Backend: inferPONonTransitive :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Ord t, KnownBackend t ds b) => Dict (Ord (ProductOrd (Backend i t ds b)))
- Numeric.DataFrame.Internal.Backend: inferPOPartial :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Ord t, KnownBackend t ds b) => Dict (Ord (ProductOrd (Backend I t ds b)))
+ Numeric.DataFrame.Internal.Backend: inferPOPartial :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Ord t, KnownBackend t ds b) => Dict (Ord (ProductOrd (Backend i t ds b)))
- Numeric.DataFrame.Internal.Backend: inferPrimArray :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (PrimBytes t, KnownBackend t ds b) => Dict (PrimArray t (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferPrimArray :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (PrimBytes t, KnownBackend t ds b) => Dict (PrimArray t (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferPrimBytes :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (PrimBytes t, Dimensions ds, KnownBackend t ds b) => Dict (PrimBytes (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferPrimBytes :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (PrimBytes t, Dimensions ds, KnownBackend t ds b) => Dict (PrimBytes (Backend i t ds b))
- Numeric.DataFrame.Internal.Backend: inferPrimElem :: forall (t :: Type) (d :: Nat) (ds :: [Nat]). KnownBackend t (d : ds) => DFBackend t (d : ds) -> Dict (PrimBytes t)
+ Numeric.DataFrame.Internal.Backend: inferPrimElem :: forall (t :: Type) (d :: Nat) (ds :: [Nat]) (i :: Type). KnownBackend t (d : ds) => Backend i t (d : ds) (BackendFamily t (d : ds)) -> Dict (PrimBytes t)
- Numeric.DataFrame.Internal.Backend: inferProductOrder :: forall (t :: Type) (ds :: [Nat]) (b :: Type). (Ord t, KnownBackend t ds b) => Dict (ProductOrder (Backend I t ds b))
+ Numeric.DataFrame.Internal.Backend: inferProductOrder :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type). (Ord t, KnownBackend t ds b) => Dict (ProductOrder (Backend i t ds b))
- Numeric.DataFrame.Internal.Mutable: copyDataFrame# :: forall (t :: Type) (b :: Nat) (bi :: Nat) (bd :: Nat) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (b ~ ((bi + bd) - 1), PrimBytes t, PrimBytes (DataFrame t (bd :+ bs)), ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: copyDataFrame# :: forall (t :: Type) (k :: Type) (b :: k) (bi :: k) (bd :: k) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs, PrimArray t (DataFrame t (bd :+ bs)), ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
- Numeric.DataFrame.Internal.Mutable: copyDataFrame'# :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (PrimBytes t, PrimBytes (DataFrame t bs), ConcatList as bs asbs) => Idxs as -> DataFrame t bs -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: copyDataFrame'# :: forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (ExactDims bs, PrimArray t (DataFrame t bs), ConcatList as bs asbs) => Idxs as -> DataFrame t bs -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
- Numeric.DataFrame.Internal.Mutable: copyMDataFrame# :: forall (t :: Type) (b :: Nat) (bi :: Nat) (bd :: Nat) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (b ~ ((bi + bd) - 1), PrimBytes t, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> MDataFrame s t (bd :+ bs) -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: copyMDataFrame# :: forall (t :: Type) (k :: Type) (b :: k) (bi :: k) (bd :: k) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (SubFrameIndexCtx b bi bd, ExactDims bs, PrimBytes t, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> MDataFrame s t (bd :+ bs) -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
- Numeric.DataFrame.Internal.Mutable: copyMDataFrame'# :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (PrimBytes t, ConcatList as bs asbs) => Idxs as -> MDataFrame s t bs -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: copyMDataFrame'# :: forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s. (ExactDims bs, PrimBytes t, ConcatList as bs asbs) => Idxs as -> MDataFrame s t bs -> MDataFrame s t asbs -> State# s -> (# State# s, () #)
- Numeric.DataFrame.Internal.Mutable: data MDataFrame s t (ns :: [Nat])
+ Numeric.DataFrame.Internal.Mutable: data MDataFrame s t (ns :: [k])
- Numeric.DataFrame.Internal.Mutable: freezeDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. PrimArray t (DataFrame t ns) => MDataFrame s t ns -> State# s -> (# State# s, DataFrame t ns #)
+ Numeric.DataFrame.Internal.Mutable: freezeDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. PrimArray t (DataFrame t ns) => MDataFrame s t ns -> State# s -> (# State# s, DataFrame t ns #)
- Numeric.DataFrame.Internal.Mutable: isDataFramePinned# :: forall (t :: Type) (ns :: [Nat]) s. MDataFrame s t ns -> Bool
+ Numeric.DataFrame.Internal.Mutable: isDataFramePinned# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. MDataFrame s t ns -> Bool
- Numeric.DataFrame.Internal.Mutable: newDataFrame# :: forall t (ns :: [Nat]) s. (PrimBytes t, Dimensions ns) => State# s -> (# State# s, MDataFrame s t ns #)
+ Numeric.DataFrame.Internal.Mutable: newDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. (PrimBytes t, Dimensions ns) => State# s -> (# State# s, MDataFrame s t ns #)
- Numeric.DataFrame.Internal.Mutable: newPinnedDataFrame# :: forall t (ns :: [Nat]) s. (PrimBytes t, Dimensions ns) => State# s -> (# State# s, MDataFrame s t ns #)
+ Numeric.DataFrame.Internal.Mutable: newPinnedDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. (PrimBytes t, Dimensions ns) => State# s -> (# State# s, MDataFrame s t ns #)
- Numeric.DataFrame.Internal.Mutable: readDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => MDataFrame s t ns -> Idxs ns -> State# s -> (# State# s, t #)
+ Numeric.DataFrame.Internal.Mutable: readDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. PrimBytes (DataFrame t ('[] :: [k])) => MDataFrame s t ns -> Idxs ns -> State# s -> (# State# s, DataFrame t ('[] :: [k]) #)
- Numeric.DataFrame.Internal.Mutable: readDataFrameOff# :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => MDataFrame s t ns -> Int# -> State# s -> (# State# s, t #)
+ Numeric.DataFrame.Internal.Mutable: readDataFrameOff# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. PrimBytes (DataFrame t ('[] :: [k])) => MDataFrame s t ns -> Int -> State# s -> (# State# s, DataFrame t ('[] :: [k]) #)
- Numeric.DataFrame.Internal.Mutable: thawDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. (Dimensions ns, PrimBytes (DataFrame t ns)) => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)
+ Numeric.DataFrame.Internal.Mutable: thawDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)
- Numeric.DataFrame.Internal.Mutable: thawPinDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. (Dimensions ns, PrimBytes (DataFrame t ns)) => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)
+ Numeric.DataFrame.Internal.Mutable: thawPinDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)
- Numeric.DataFrame.Internal.Mutable: unsafeFreezeDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. PrimArray t (DataFrame t ns) => MDataFrame s t ns -> State# s -> (# State# s, DataFrame t ns #)
+ Numeric.DataFrame.Internal.Mutable: unsafeFreezeDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. PrimArray t (DataFrame t ns) => MDataFrame s t ns -> State# s -> (# State# s, DataFrame t ns #)
- Numeric.DataFrame.Internal.Mutable: unsafeThawDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. (Dimensions ns, PrimBytes (DataFrame t ns), PrimBytes t) => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)
+ Numeric.DataFrame.Internal.Mutable: unsafeThawDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)
- Numeric.DataFrame.Internal.Mutable: withDataFramePtr# :: forall (t :: Type) (ns :: [Nat]) (r :: Type). PrimBytes t => MDataFrame RealWorld t ns -> (Addr# -> State# RealWorld -> (# State# RealWorld, r #)) -> State# RealWorld -> (# State# RealWorld, r #)
+ Numeric.DataFrame.Internal.Mutable: withDataFramePtr# :: forall (t :: Type) (k :: Type) (ns :: [k]) (r :: Type). PrimBytes t => MDataFrame RealWorld t ns -> (Addr# -> State# RealWorld -> (# State# RealWorld, r #)) -> State# RealWorld -> (# State# RealWorld, r #)
- Numeric.DataFrame.Internal.Mutable: writeDataFrame# :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => MDataFrame s t ns -> Idxs ns -> t -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: writeDataFrame# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. PrimBytes (DataFrame t ('[] :: [k])) => MDataFrame s t ns -> Idxs ns -> DataFrame t ('[] :: [k]) -> State# s -> (# State# s, () #)
- Numeric.DataFrame.Internal.Mutable: writeDataFrameOff# :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => MDataFrame s t ns -> Int# -> t -> State# s -> (# State# s, () #)
+ Numeric.DataFrame.Internal.Mutable: writeDataFrameOff# :: forall (t :: Type) (k :: Type) (ns :: [k]) s. PrimBytes (DataFrame t ('[] :: [k])) => MDataFrame s t ns -> Int -> DataFrame t ('[] :: [k]) -> State# s -> (# State# s, () #)
- Numeric.DataFrame.Internal.PrimArray: broadcast :: PrimArray t a => t -> a
+ Numeric.DataFrame.Internal.PrimArray: broadcast :: forall (t :: Type) (a :: Type). PrimArray t a => t -> a
- Numeric.DataFrame.Internal.PrimArray: fromElems :: PrimArray t a => CumulDims -> Int# -> ByteArray# -> a
+ Numeric.DataFrame.Internal.PrimArray: fromElems :: forall (t :: Type) (a :: Type). PrimArray t a => CumulDims -> Int# -> ByteArray# -> a
- Numeric.DataFrame.ST: copyDataFrame :: forall (t :: Type) (b :: Nat) (bi :: Nat) (bd :: Nat) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (b ~ ((bi + bd) - 1), PrimBytes t, PrimBytes (DataFrame t (bd :+ bs)), ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> STDataFrame s t asbs -> ST s ()
+ Numeric.DataFrame.ST: copyDataFrame :: forall (t :: Type) b bi bd as bs asbs s. (SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs, PrimArray t (DataFrame t (bd :+ bs)), ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> STDataFrame s t asbs -> ST s ()
- Numeric.DataFrame.ST: copyDataFrame' :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (PrimBytes t, PrimBytes (DataFrame t bs), ConcatList as bs asbs) => Idxs as -> DataFrame t bs -> STDataFrame s t asbs -> ST s ()
+ Numeric.DataFrame.ST: copyDataFrame' :: forall (t :: Type) as bs asbs s. (ExactDims bs, PrimArray t (DataFrame t bs), ConcatList as bs asbs) => Idxs as -> DataFrame t bs -> STDataFrame s t asbs -> ST s ()
- Numeric.DataFrame.ST: copyMutableDataFrame :: forall (t :: Type) (b :: Nat) (bi :: Nat) (bd :: Nat) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (b ~ ((bi + bd) - 1), PrimBytes t, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> STDataFrame s t (bd :+ bs) -> STDataFrame s t asbs -> ST s ()
+ Numeric.DataFrame.ST: copyMutableDataFrame :: forall (t :: Type) b bi bd as bs asbs s. (SubFrameIndexCtx b bi bd, ExactDims bs, PrimBytes t, ConcatList as (b :+ bs) asbs) => Idxs (as +: bi) -> STDataFrame s t (bd :+ bs) -> STDataFrame s t asbs -> ST s ()
- Numeric.DataFrame.ST: copyMutableDataFrame' :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s. (PrimBytes t, ConcatList as bs asbs) => Idxs as -> STDataFrame s t bs -> STDataFrame s t asbs -> ST s ()
+ Numeric.DataFrame.ST: copyMutableDataFrame' :: forall (t :: Type) as bs asbs s. (ExactDims bs, PrimBytes t, ConcatList as bs asbs) => Idxs as -> STDataFrame s t bs -> STDataFrame s t asbs -> ST s ()
- Numeric.DataFrame.ST: freezeDataFrame :: forall (t :: Type) (ns :: [Nat]) s. PrimArray t (DataFrame t ns) => STDataFrame s t ns -> ST s (DataFrame t ns)
+ Numeric.DataFrame.ST: freezeDataFrame :: forall (t :: Type) ns s. PrimArray t (DataFrame t ns) => STDataFrame s t ns -> ST s (DataFrame t ns)
- Numeric.DataFrame.ST: isDataFramePinned :: forall (k :: Type) (t :: Type) (ns :: [k]) s. KnownDimKind k => STDataFrame s t ns -> Bool
+ Numeric.DataFrame.ST: isDataFramePinned :: forall (t :: Type) ns s. STDataFrame s t ns -> Bool
- Numeric.DataFrame.ST: newDataFrame :: forall t (ns :: [Nat]) s. (PrimBytes t, Dimensions ns) => ST s (STDataFrame s t ns)
+ Numeric.DataFrame.ST: newDataFrame :: forall (t :: Type) ns s. (PrimBytes t, Dimensions ns) => ST s (STDataFrame s t ns)
- Numeric.DataFrame.ST: newPinnedDataFrame :: forall t (ns :: [Nat]) s. (PrimBytes t, Dimensions ns) => ST s (STDataFrame s t ns)
+ Numeric.DataFrame.ST: newPinnedDataFrame :: forall (t :: Type) ns s. (PrimBytes t, Dimensions ns) => ST s (STDataFrame s t ns)
- Numeric.DataFrame.ST: readDataFrame :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => STDataFrame s t ns -> Idxs ns -> ST s (DataFrame t ('[] :: [Nat]))
+ Numeric.DataFrame.ST: readDataFrame :: forall (t :: Type) ns s. PrimBytes (DataFrame t ('[] :: KindOf ns)) => STDataFrame s t ns -> Idxs ns -> ST s (DataFrame t ('[] :: KindOf ns))
- Numeric.DataFrame.ST: readDataFrameOff :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => STDataFrame s t ns -> Int -> ST s (DataFrame t ('[] :: [Nat]))
+ Numeric.DataFrame.ST: readDataFrameOff :: forall (t :: Type) ns s. PrimBytes (DataFrame t ('[] :: KindOf ns)) => STDataFrame s t ns -> Int -> ST s (DataFrame t ('[] :: KindOf ns))
- Numeric.DataFrame.ST: thawDataFrame :: forall (t :: Type) (ns :: [Nat]) s. (Dimensions ns, PrimBytes (DataFrame t ns)) => DataFrame t ns -> ST s (STDataFrame s t ns)
+ Numeric.DataFrame.ST: thawDataFrame :: forall (t :: Type) ns s. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> ST s (STDataFrame s t ns)
- Numeric.DataFrame.ST: thawPinDataFrame :: forall (t :: Type) (ns :: [Nat]) s. (Dimensions ns, PrimBytes (DataFrame t ns)) => DataFrame t ns -> ST s (STDataFrame s t ns)
+ Numeric.DataFrame.ST: thawPinDataFrame :: forall (t :: Type) ns s. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> ST s (STDataFrame s t ns)
- Numeric.DataFrame.ST: unsafeFreezeDataFrame :: forall (t :: Type) (ns :: [Nat]) s. PrimArray t (DataFrame t ns) => STDataFrame s t ns -> ST s (DataFrame t ns)
+ Numeric.DataFrame.ST: unsafeFreezeDataFrame :: forall (t :: Type) ns s. PrimArray t (DataFrame t ns) => STDataFrame s t ns -> ST s (DataFrame t ns)
- Numeric.DataFrame.ST: unsafeThawDataFrame :: forall (t :: Type) (ns :: [Nat]) s. (Dimensions ns, PrimBytes (DataFrame t ns), PrimBytes t) => DataFrame t ns -> ST s (STDataFrame s t ns)
+ Numeric.DataFrame.ST: unsafeThawDataFrame :: forall (t :: Type) ns s. (Dimensions ns, PrimArray t (DataFrame t ns)) => DataFrame t ns -> ST s (STDataFrame s t ns)
- Numeric.DataFrame.ST: writeDataFrame :: forall t (ns :: [Nat]) s. PrimBytes t => STDataFrame s t ns -> Idxs ns -> DataFrame t ('[] :: [Nat]) -> ST s ()
+ Numeric.DataFrame.ST: writeDataFrame :: forall (t :: Type) ns s. PrimBytes (DataFrame t ('[] :: KindOf ns)) => STDataFrame s t ns -> Idxs ns -> DataFrame t ('[] :: KindOf ns) -> ST s ()
- Numeric.DataFrame.ST: writeDataFrameOff :: forall (t :: Type) (ns :: [Nat]) s. PrimBytes t => STDataFrame s t ns -> Int -> DataFrame t ('[] :: [Nat]) -> ST s ()
+ Numeric.DataFrame.ST: writeDataFrameOff :: forall (t :: Type) ns s. PrimBytes (DataFrame t ('[] :: KindOf ns)) => STDataFrame s t ns -> Int -> DataFrame t ('[] :: KindOf ns) -> ST s ()
- Numeric.DataFrame.SubSpace: class (ConcatList as bs asbs, Dimensions as, Dimensions bs, Dimensions asbs, PrimArray t (DataFrame t bs), PrimArray t (DataFrame t asbs), PrimBytes (DataFrame t bs), PrimBytes (DataFrame t asbs)) => SubSpace (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) | asbs as -> bs, asbs bs -> as, as bs -> asbs
+ Numeric.DataFrame.SubSpace: class (ConcatList as bs asbs, SubSpaceCtx t as bs asbs, PrimBytes t, KnownDimKind k) => SubSpace (t :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) | asbs as -> bs, asbs bs -> as, as bs -> asbs where {
- Numeric.DataFrame.SubSpace: element :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) f. (SubSpace t as bs asbs, Applicative f) => Idxs as -> (DataFrame t bs -> f (DataFrame t bs)) -> DataFrame t asbs -> f (DataFrame t asbs)
+ Numeric.DataFrame.SubSpace: element :: forall t as bs asbs f. (SubSpace t as bs asbs, Applicative f) => Idxs as -> (DataFrame t bs -> f (DataFrame t bs)) -> DataFrame t asbs -> f (DataFrame t asbs)
- Numeric.DataFrame.SubSpace: elementWise :: forall (s :: Type) (bs' :: [Nat]) (asbs' :: [Nat]) (f :: Type -> Type). (SubSpace t as bs asbs, Applicative f, SubSpace s as bs' asbs') => (DataFrame s bs' -> f (DataFrame t bs)) -> DataFrame s asbs' -> f (DataFrame t asbs)
+ Numeric.DataFrame.SubSpace: elementWise :: forall t as bs asbs s bs' asbs' f. (SubSpace t as bs asbs, SubSpace s as bs' asbs', Applicative f) => (DataFrame s bs' -> f (DataFrame t bs)) -> DataFrame s asbs' -> f (DataFrame t asbs)
- Numeric.DataFrame.SubSpace: ewfoldMap :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) m. (Monoid m, SubSpace t as bs asbs) => (DataFrame t bs -> m) -> DataFrame t asbs -> m
+ Numeric.DataFrame.SubSpace: ewfoldMap :: forall t as bs asbs m. (SubSpace t as bs asbs, Monoid m) => (DataFrame t bs -> m) -> DataFrame t asbs -> m
- Numeric.DataFrame.SubSpace: ewfoldl :: SubSpace t as bs asbs => (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: ewfoldl :: forall t as bs asbs b. SubSpace t as bs asbs => (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b
- Numeric.DataFrame.SubSpace: ewfoldr :: SubSpace t as bs asbs => (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: ewfoldr :: forall t as bs asbs b. SubSpace t as bs asbs => (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b
- Numeric.DataFrame.SubSpace: ewgen :: SubSpace t as bs asbs => DataFrame t bs -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: ewgen :: forall t as bs asbs. (SubSpace t as bs asbs, Dimensions as) => DataFrame t bs -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: ewmap :: forall s (bs' :: [Nat]) (asbs' :: [Nat]). (SubSpace t as bs asbs, SubSpace s as bs' asbs') => (DataFrame s bs' -> DataFrame t bs) -> DataFrame s asbs' -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: ewmap :: forall t as bs asbs s bs' asbs'. (SubSpace t as bs asbs, SubSpace s as bs' asbs') => (DataFrame s bs' -> DataFrame t bs) -> DataFrame s asbs' -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: ewzip :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s (bs' :: [Nat]) (asbs' :: [Nat]) r (bs'' :: [Nat]) (asbs'' :: [Nat]). (SubSpace t as bs asbs, SubSpace s as bs' asbs', SubSpace r as bs'' asbs'') => (DataFrame t bs -> DataFrame s bs' -> DataFrame r bs'') -> DataFrame t asbs -> DataFrame s asbs' -> DataFrame r asbs''
+ Numeric.DataFrame.SubSpace: ewzip :: forall t as bs asbs l bsL asbsL r bsR asbsR. (SubSpace t as bs asbs, SubSpace l as bsL asbsL, SubSpace r as bsR asbsR) => (DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs) -> DataFrame l asbsL -> DataFrame r asbsR -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: index :: SubSpace t as bs asbs => Idxs as -> DataFrame t asbs -> DataFrame t bs
+ Numeric.DataFrame.SubSpace: index :: forall t as bs asbs. SubSpace t as bs asbs => Idxs as -> DataFrame t asbs -> DataFrame t bs
- Numeric.DataFrame.SubSpace: indexWise :: forall (s :: Type) (bs' :: [Nat]) (asbs' :: [Nat]) (f :: Type -> Type). (SubSpace t as bs asbs, Applicative f, SubSpace s as bs' asbs') => (Idxs as -> DataFrame s bs' -> f (DataFrame t bs)) -> DataFrame s asbs' -> f (DataFrame t asbs)
+ Numeric.DataFrame.SubSpace: indexWise :: forall t as bs asbs s bs' asbs' f. (SubSpace t as bs asbs, SubSpace s as bs' asbs', Applicative f) => (Idxs as -> DataFrame s bs' -> f (DataFrame t bs)) -> DataFrame s asbs' -> f (DataFrame t asbs)
- Numeric.DataFrame.SubSpace: infixl 4 !
+ Numeric.DataFrame.SubSpace: infixl 4 .!
- Numeric.DataFrame.SubSpace: iwfoldMap :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) m. (Monoid m, SubSpace t as bs asbs) => (Idxs as -> DataFrame t bs -> m) -> DataFrame t asbs -> m
+ Numeric.DataFrame.SubSpace: iwfoldMap :: forall t as bs asbs m. (SubSpace t as bs asbs, Monoid m) => (Idxs as -> DataFrame t bs -> m) -> DataFrame t asbs -> m
- Numeric.DataFrame.SubSpace: iwfoldl :: SubSpace t as bs asbs => (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: iwfoldl :: forall t as bs asbs b. SubSpace t as bs asbs => (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b
- Numeric.DataFrame.SubSpace: iwfoldr :: SubSpace t as bs asbs => (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b
+ Numeric.DataFrame.SubSpace: iwfoldr :: forall t as bs asbs b. SubSpace t as bs asbs => (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b
- Numeric.DataFrame.SubSpace: iwgen :: SubSpace t as bs asbs => (Idxs as -> DataFrame t bs) -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: iwgen :: forall t as bs asbs. (SubSpace t as bs asbs, Dimensions as) => (Idxs as -> DataFrame t bs) -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: iwmap :: forall s (bs' :: [Nat]) (asbs' :: [Nat]). (SubSpace t as bs asbs, SubSpace s as bs' asbs') => (Idxs as -> DataFrame s bs' -> DataFrame t bs) -> DataFrame s asbs' -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: iwmap :: forall t as bs asbs s bs' asbs'. (SubSpace t as bs asbs, SubSpace s as bs' asbs') => (Idxs as -> DataFrame s bs' -> DataFrame t bs) -> DataFrame s asbs' -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: iwzip :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s (bs' :: [Nat]) (asbs' :: [Nat]) r (bs'' :: [Nat]) (asbs'' :: [Nat]). (SubSpace t as bs asbs, SubSpace s as bs' asbs', SubSpace r as bs'' asbs'') => (Idxs as -> DataFrame t bs -> DataFrame s bs' -> DataFrame r bs'') -> DataFrame t asbs -> DataFrame s asbs' -> DataFrame r asbs''
+ Numeric.DataFrame.SubSpace: iwzip :: forall t as bs asbs l bsL asbsL r bsR asbsR. (SubSpace t as bs asbs, SubSpace l as bsL asbsL, SubSpace r as bsR asbsR) => (Idxs as -> DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs) -> DataFrame l asbsL -> DataFrame r asbsR -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: slice :: forall (bi :: Nat) (bd :: Nat) (b' :: Nat) (bs' :: [Nat]). (SubSpace t as bs asbs, b' ~ ((bi + bd) - 1), bs ~ (b' :+ bs'), KnownDim bd) => Idxs (as +: bi) -> DataFrame t asbs -> DataFrame t (bd :+ bs')
+ Numeric.DataFrame.SubSpace: slice :: forall (t :: Type) b bi bd as bs asbs. (KnownDimKind (KindOfEl asbs), CanSlice t asbs, SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs, PrimArray t (DataFrame t (bd :+ bs))) => Idxs (as +: bi) -> DataFrame t asbs -> DataFrame t (bd :+ bs)
- Numeric.DataFrame.SubSpace: update :: SubSpace t as bs asbs => Idxs as -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: update :: forall t as bs asbs. SubSpace t as bs asbs => Idxs as -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs
- Numeric.DataFrame.SubSpace: updateSlice :: forall (bi :: Nat) (bd :: Nat) (b' :: Nat) (bs' :: [Nat]). (SubSpace t as bs asbs, b' ~ ((bi + bd) - 1), bs ~ (b' :+ bs'), KnownDim bd) => Idxs (as +: bi) -> DataFrame t (bd :+ bs') -> DataFrame t asbs -> DataFrame t asbs
+ Numeric.DataFrame.SubSpace: updateSlice :: forall (t :: Type) b bi bd as bs asbs. (KnownDimKind (KindOfEl asbs), CanSlice t asbs, SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs, ConcatList as (b :+ bs) asbs, PrimArray t (DataFrame t (bd :+ bs))) => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> DataFrame t asbs -> DataFrame t asbs
- Numeric.DataFrame.Type: class InferKnownBackend (t :: k) ds
+ Numeric.DataFrame.Type: class InferKnownBackend t (ds :: [Nat])
- Numeric.DataFrame.Type: constrainDF :: forall (ds :: [XNat]) (ys :: [XNat]) (l :: Type) (ts :: l). (BoundedDims ds, All KnownXNatType ds) => DataFrame ts ys -> Maybe (DataFrame ts ds)
+ Numeric.DataFrame.Type: constrainDF :: forall (ds :: [XNat]) (ys :: [XNat]) t. (BoundedDims ds, All KnownDimType ds) => DataFrame t ys -> Maybe (DataFrame t ds)
- Numeric.DataFrame.Type: fromList :: forall (t :: Type) (ds :: [Nat]). (PrimBytes t, Dimensions ds) => [DataFrame t ds] -> DataFrame t (XN 0 : AsXDims ds)
+ Numeric.DataFrame.Type: fromList :: forall (t :: Type) (ds :: [Nat]) (xds :: [XNat]). (PrimBytes t, Dimensions ds, xds ~ Map N ds, ds ~ UnMap N xds) => [DataFrame t ds] -> DataFrame t (XN 0 : xds)
- Numeric.DataFrame.Type: pattern Dn :: forall (xn :: XNat). KnownXNatType xn => forall (n :: Nat). (KnownDim n, xn ~ N n) => Dim n -> Dim xn
+ Numeric.DataFrame.Type: pattern Dn :: forall (d :: XNat). KnownDimType d => forall (n :: Nat). (KindOf d ~ XNat, d ~ N n) => Dim n -> Dim d
- Numeric.DataFrame.Type: pattern KnownDims :: forall (ds :: [Nat]). () => (All KnownDim ds, All (BoundedDim :: Nat -> Constraint) ds, RepresentableList ds, Dimensions ds) => Dims ds
+ Numeric.DataFrame.Type: pattern XDims :: forall (ds :: [XNat]). KnownDimKind (KindOfEl ds) => forall (ns :: [Nat]). (KindOfEl ds ~ XNat, FixedDims ds ns) => Dims ns -> Dims ds
- Numeric.DataFrame.Type: type DFBackend t (ds :: [Nat]) = Backend I t ds BackendFamily t ds
+ Numeric.DataFrame.Type: type DFBackend (t :: Type) (ds :: [Nat]) = Backend I t ds (BackendFamily t ds)
- Numeric.DataFrame.Type: type Dims (xs :: [k]) = TypedList (Dim :: k -> Type) xs
+ Numeric.DataFrame.Type: type Dims = TypedList (Dim :: k -> Type)
- Numeric.DataFrame.Type: type Idxs (xs :: [k]) = TypedList (Idx :: k -> Type) xs
+ Numeric.DataFrame.Type: type Idxs = TypedList (Idx :: k -> Type)
- Numeric.DataFrame.Type: type N (n :: Nat) = N n
+ Numeric.DataFrame.Type: type N = N
- Numeric.DataFrame.Type: type XN (n :: Nat) = XN n
+ Numeric.DataFrame.Type: type XN = XN
- Numeric.Quaternion: class Quaternion t where {
+ Numeric.Quaternion: class (Floating (Quater t), Floating t, Ord t, PrimBytes t, KnownBackend t '[3], KnownBackend t '[4], KnownBackend t '[3, 3], KnownBackend t '[4, 4]) => Quaternion t where {
- Numeric.Scalar: fromScalar :: SubSpace t ds '[] ds => Scalar t -> DataFrame t ds
+ Numeric.Scalar: fromScalar :: PrimArray t (DataFrame t ds) => Scalar t -> DataFrame t (ds :: [Nat])
- Numeric.Scalar: scalar :: t -> Scalar t
+ Numeric.Scalar: scalar :: t -> DataFrame t ('[] :: [Nat])
- Numeric.Scalar: unScalar :: Scalar t -> t
+ Numeric.Scalar: unScalar :: DataFrame t ('[] :: [Nat]) -> t
- Numeric.Vector: (.*.) :: (Num t, Num (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t n -> Vector t n -> Vector t n
+ Numeric.Vector: (.*.) :: (Num t, Num (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t (n :: Nat) -> Vector t n -> Vector t n
- Numeric.Vector: (·) :: (Num t, Num (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t n -> Vector t n -> Scalar t
+ Numeric.Vector: (·) :: (Num t, Num (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t (n :: Nat) -> Vector t n -> Scalar t
- Numeric.Vector: cross :: (Num t, SubSpace t '[3] '[] '[3]) => Vector t 3 -> Vector t 3 -> Vector t 3
+ Numeric.Vector: cross :: (Num t, PrimBytes t) => Vector t 3 -> Vector t 3 -> Vector t 3
- Numeric.Vector: det2 :: (Num t, SubSpace t '[2] '[] '[2]) => Vector t 2 -> Vector t 2 -> Scalar t
+ Numeric.Vector: det2 :: (Num t, PrimBytes t) => Vector t 2 -> Vector t 2 -> Scalar t
- Numeric.Vector: dot :: (Num t, Num (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t n -> Vector t n -> Scalar t
+ Numeric.Vector: dot :: (Num t, Num (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t (n :: Nat) -> Vector t n -> Scalar t
- Numeric.Vector: normL1 :: (Num t, SubSpace t '[n] '[] '[n]) => Vector t n -> Scalar t
+ Numeric.Vector: normL1 :: (Num (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n]) => Vector t (n :: k) -> DataFrame t ('[] :: [k])
- Numeric.Vector: normL2 :: (Floating t, SubSpace t '[n] '[] '[n]) => Vector t n -> Scalar t
+ Numeric.Vector: normL2 :: (Floating (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n]) => Vector t (n :: k) -> DataFrame t ('[] :: [k])
- Numeric.Vector: normLNInf :: (Ord t, Num t, SubSpace t '[n] '[] '[n]) => Vector t n -> Scalar t
+ Numeric.Vector: normLNInf :: (Ord (DataFrame t ('[] :: [k])), Num (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n]) => Vector t (n :: k) -> DataFrame t ('[] :: [k])
- Numeric.Vector: normLP :: (Floating t, SubSpace t '[n] '[] '[n]) => Int -> Vector t n -> Scalar t
+ Numeric.Vector: normLP :: (Floating (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n]) => Int -> Vector t (n :: k) -> DataFrame t ('[] :: [k])
- Numeric.Vector: normLPInf :: (Ord t, Num t, SubSpace t '[n] '[] '[n]) => Vector t n -> Scalar t
+ Numeric.Vector: normLPInf :: (Ord (DataFrame t ('[] :: [k])), Num (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n]) => Vector t (n :: k) -> DataFrame t ('[] :: [k])
- Numeric.Vector: normalized :: (Floating t, Fractional (Vector t n), SubSpace t '[n] '[] '[n]) => Vector t n -> Vector t n
+ Numeric.Vector: normalized :: forall (k :: Type) (t :: Type) (n :: k). (Floating (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n]) => Vector t n -> Vector t n

Files

Setup.hs view
@@ -1,2 +1,32 @@+{-+Disable some errors and warnings during the haddock pass+  (caused by compiler plugins and hs-boot)+ -}+{-# OPTIONS_GHC -Wall #-}+module Main (main) where+ import Distribution.Simple-main = defaultMain+import Distribution.Simple.Setup++main :: IO ()+main = defaultMainWithHooks simpleUserHooks+  { confHook = \a -> confHook simpleUserHooks a . tweakFlags }++tweakFlags :: ConfigFlags -> ConfigFlags+tweakFlags flags = flags+  { configProgramArgs = addHaddockArgs (configProgramArgs flags) }++addHaddockArgs :: [(String, [String])] -> [(String, [String])]+addHaddockArgs []+  = [("haddock", newHaddockGhcArgs)]+addHaddockArgs (("haddock", args):otherProgsArgs)+  = ("haddock", args ++ newHaddockGhcArgs) : otherProgsArgs+addHaddockArgs (progArgs:otherProgsArgs)+  = progArgs : addHaddockArgs otherProgsArgs++newHaddockGhcArgs :: [String]+newHaddockGhcArgs =+  [ "--optghc=-fdefer-type-errors"+  , "--optghc=-fno-warn-deferred-type-errors"+  , "--optghc=-fno-warn-missing-home-modules"+  ]
bench/subspacefolds.hs view
@@ -23,47 +23,47 @@     seq t1 putStrLn $ "Created DataFrame, elapsed time is " ++ show (diffUTCTime t1 t0)      putStrLn "\nRunning a ewfoldl on scalar elements..."-    let rezEwf = ewfoldl @Float @DList @'[] (\a x -> return $! fromMaybe x a + fromMaybe 0 a / (x+1)) (Just 1)  df+    let rezEwf = ewfoldl' @Float @DList @'[] (\a x -> return $! fromMaybe x a + fromMaybe 0 a / (x+1)) (Just 1)  df     t2 <- rezEwf `seq` getCurrentTime     seq t2 putStrLn $ "Done; elapsed time = " ++ show (diffUTCTime t2 t1)     print rezEwf      putStrLn "\nRunning a iwfoldl on scalar elements (not using idx)..."-    let rezIwf = iwfoldl @Float  @DList @'[] (\_ a x -> a +  a / (x+1)) 1 df+    let rezIwf = iwfoldl' @Float  @DList @'[] (\_ a x -> a +  a / (x+1)) 1 df     t3 <- rezIwf `seq` getCurrentTime     seq t3 putStrLn $ "Done; elapsed time = " ++ show (diffUTCTime t3 t2)     print rezIwf      putStrLn "\nRunning a iwfoldr on scalar elements (using fromEnum idx)..."-    let rezIwf2 = iwfoldr @Float @DList @'[] (\i x a -> return $! fromMaybe 0 a + x / ((1+) . fromIntegral $ fromEnum i)) (Just 0) df+    let rezIwf2 = iwfoldr' @Float @DList @'[] (\i x a -> return $! fromMaybe 0 a + x / ((1+) . fromIntegral $ fromEnum i)) (Just 0) df     t4 <- rezIwf2 `seq` getCurrentTime     seq t4 putStrLn $ "Done; elapsed time = " ++ show (diffUTCTime t4 t3)     print rezIwf2      putStrLn "\nRunning a iwfoldl on scalar elements (enforcing idx)..."-    let rezIwf3 = iwfoldl @Float @DList @'[] (\i a x -> i `seq` return $! fromMaybe 0 a + fromMaybe x a / (x+1)) (Just 1) df+    let rezIwf3 = iwfoldl' @Float @DList @'[] (\i a x -> i `seq` return $! fromMaybe 0 a + fromMaybe x a / (x+1)) (Just 1) df     t5 <- rezIwf3 `seq` getCurrentTime     seq t5 putStrLn $ "Done; elapsed time = " ++ show (diffUTCTime t5 t4)     print rezIwf3      putStrLn "\nRunning a ewfoldl on vector4 elements..."-    let rezEwv1 = ewfoldl @Float @(Init DList) @'[Last DList]-                          (\a x -> return $! fromMaybe 2 a + fromMaybe 0 a / (1 + iwgen @_ @_ @'[] (\(Idx i:*U) -> x ! Idx (i+1) :* U )) )+    let rezEwv1 = ewfoldl' @Float @(Init DList) @'[Last DList]+                          (\a x -> return $! fromMaybe 2 a + fromMaybe 0 a / (1 + iwgen @_ @_ @'[] (\(Idx i:*U) -> x ! (i+1) )) )                           (Just (3 :: DataFrame Float '[4])) df     t6 <- rezEwv1 `seq` getCurrentTime     seq t6 putStrLn $ "Done; elapsed time = " ++ show (diffUTCTime t6 t5)     print rezEwv1      putStrLn "\nRunning a ewfoldr on vector3 elements..."-    let rezEwv2 = ewfoldr @Float @(Init DList) @'[Last DList]-                          (\x a -> return $! fromMaybe 2 a + fromMaybe 1 a / (1 + iwgen @_ @_ @'[] (\(Idx i:*U) -> x ! Idx (i+1):* U )))+    let rezEwv2 = ewfoldr' @Float @(Init DList) @'[Last DList]+                          (\x a -> return $! fromMaybe 2 a + fromMaybe 1 a / (1 + iwgen @_ @_ @'[] (\(Idx i:*U) -> x ! (i+1) )))                           (Just (3 :: DataFrame Float '[3])) df     t7 <- rezEwv2 `seq` getCurrentTime     seq t7 putStrLn $ "Done; elapsed time = " ++ show (diffUTCTime t7 t6)     print rezEwv2      putStrLn "\nRunning a ewfoldr with matrix products..."-    let rezEwm = ewfoldr @Float @(Take 3 DList) @(Drop 3 DList)+    let rezEwm = ewfoldr' @Float @(Take 3 DList) @(Drop 3 DList)                           (\x a ->  a + x %* (DF5 1 0.5 0.1 0.01 0.001)  )                           (1 :: DataFrame Float (Init (Drop 3 DList) +: 3)) df     t8 <- rezEwm `seq` getCurrentTime@@ -74,4 +74,4 @@       putStrLn "Checking indexes"-    print $ df ! (2:*1:*1:*3:*1:*U :: Idxs (Take 5 DList))+    print $ df.!2.!1.!1.!3.!1
easytensor.cabal view
@@ -1,11 +1,13 @@--- This file has been generated from package.yaml by hpack version 0.28.2.+cabal-version: 1.24++-- This file has been generated from package.yaml by hpack version 0.31.1. -- -- see: https://github.com/sol/hpack ----- hash: c1b3d6ebe751438aebdd514a166566c79aa2a98083755f019015772fc95cb34e+-- hash: 75fa5546720cb775f5ce9a26382fcd60253bba851441e469156242ee52655f97  name:           easytensor-version:        2.0.1.0+version:        2.1.0.0 synopsis:       Pure, type-indexed haskell vector, matrix, and tensor library. description:    Pure, type-indexed haskell vector, matrix, and tensor library. Features dimensionality type-checking for all operations. Generic n-dimensional versions are implemented using low-level prim ops. Allows ad-hoc replacement with fixed low-dimensionality vectors and matrices without changing user interface. Please see the README on GitHub at <https://github.com/achirkin/easytensor#readme> category:       math, geometry@@ -16,14 +18,18 @@ copyright:      Copyright: (c) 2019 Artem Chirkin license:        BSD3 license-file:   LICENSE-build-type:     Simple-cabal-version:  >= 1.10+build-type:     Custom  source-repository head   type: git   location: https://github.com/achirkin/easytensor   subdir: easytensor +custom-setup+  setup-depends:+      Cabal+    , base+ flag unsafeindices   description: Disable bound checks when accessing elements of a tensor, matrix, or vector.   manual: True@@ -31,6 +37,7 @@  library   exposed-modules:+      Numeric.Basics       Numeric.DataFrame       Numeric.DataFrame.Contraction       Numeric.DataFrame.Internal.Backend@@ -41,17 +48,24 @@       Numeric.DataFrame.SubSpace       Numeric.DataFrame.Type       Numeric.Matrix+      Numeric.Matrix.Bidiagonal+      Numeric.Matrix.LU+      Numeric.Matrix.QR+      Numeric.Matrix.SVD       Numeric.PrimBytes       Numeric.ProductOrd       Numeric.ProductOrd.NonTransitive       Numeric.ProductOrd.Partial       Numeric.Quaternion       Numeric.Scalar+      Numeric.Subroutine.Householder+      Numeric.Subroutine.SolveTriangular+      Numeric.Subroutine.Sort       Numeric.Vector   other-modules:       Numeric.Matrix.Internal-      Numeric.Matrix.Internal.Mat44d-      Numeric.Matrix.Internal.Mat44f+      Numeric.Matrix.Internal.Double+      Numeric.Matrix.Internal.Float       Numeric.Scalar.Internal       Numeric.Vector.Internal       Numeric.Quaternion.Internal@@ -73,7 +87,7 @@   ghc-options: -Wall -Wcompat -Wtabs -Wmonomorphism-restriction -Wmissing-local-signatures -Wmissing-home-modules -Widentities -Wredundant-constraints   build-depends:       base >=4.11 && <5-    , constraints-deriving >=1.0.4.0 && <2+    , constraints-deriving >=1.1.1.0 && <2     , dimensions >=2 && <3   if flag(unsafeindices)     cpp-options: -DUNSAFE_INDICES@@ -83,14 +97,19 @@   type: exitcode-stdio-1.0   main-is: Spec.hs   other-modules:-      Numeric.DataFrame.Arbitraries+      Numeric.Arbitraries       Numeric.DataFrame.BasicTest       Numeric.DataFrame.SubSpaceTest+      Numeric.Matrix.BidiagonalTest+      Numeric.Matrix.LUTest+      Numeric.Matrix.QRTest+      Numeric.Matrix.SVDTest       Numeric.MatrixDoubleTest       Numeric.MatrixFloatTest       Numeric.PrimBytesTest       Numeric.QuaterDoubleTest       Numeric.QuaterFloatTest+      Numeric.Subroutine.SolveTriangularTest       Spec.Util       Paths_easytensor   hs-source-dirs:@@ -100,7 +119,7 @@       Cabal     , QuickCheck     , base >=4.11 && <5-    , constraints-deriving >=1.0.4.0 && <2+    , constraints-deriving >=1.1.1.0 && <2     , dimensions >=2 && <3     , easytensor     , template-haskell@@ -116,7 +135,7 @@   ghc-options: -Wall -Wcompat -Wtabs -Wmonomorphism-restriction -Wmissing-local-signatures -Wmissing-home-modules -Widentities -Wredundant-constraints   build-depends:       base >=4.11 && <5-    , constraints-deriving >=1.0.4.0 && <2+    , constraints-deriving >=1.1.1.0 && <2     , dimensions >=2 && <3     , easytensor   default-language: Haskell2010@@ -131,7 +150,7 @@   ghc-options: -Wall -Wcompat -Wtabs -Wmonomorphism-restriction -Wmissing-local-signatures -Wmissing-home-modules -Widentities -Wredundant-constraints   build-depends:       base >=4.11 && <5-    , constraints-deriving >=1.0.4.0 && <2+    , constraints-deriving >=1.1.1.0 && <2     , dimensions >=2 && <3     , easytensor     , time
src-base/Numeric/DataFrame/Internal/Backend/Family.hs view
@@ -14,6 +14,8 @@ {-# LANGUAGE TypeFamilyDependencies #-} {-# LANGUAGE TypeInType             #-} {-# LANGUAGE TypeOperators          #-}+-- Combined GADT patterns are a bit of a trouble+{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-} -- Constraints @b ~ BackendFamily t ds@ is not redundant; they allows to avoid AllowAmbigousTypes. {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} {- |@@ -66,10 +68,6 @@     BackendFamily Double '[4]   = DoubleX4     BackendFamily t       ds    = ArrayBase t ds --- | Promise that we are sure the backend is ArrayBase.-unsafeDefault :: forall t ds . Dict (BackendFamily t ds ~ ArrayBase t ds)-unsafeDefault = unsafeCoerce# (Dict @(ArrayBase t ds ~ ArrayBase t ds))- -- | Singleton type used to determine the currently used DataFrame backend; --   establishes a good bijection @b <~> t ds@ (better than just using @BackendFamily@ everywhere). data BackendSing (t :: Type) (ds :: [Nat]) (backend :: Type) where@@ -99,33 +97,41 @@ #if defined(__HADDOCK__) || defined(__HADDOCK_VERSION__) instance KnownBackend t ds b where bSing = undefined #else-instance KnownBackend t      '[]  (ScalarBase t)   where bSing = BSC-instance KnownBackend Float  '[2]  FloatX2         where bSing = BF2-instance KnownBackend Float  '[3]  FloatX3         where bSing = BF3-instance KnownBackend Float  '[4]  FloatX4         where bSing = BF4-instance KnownBackend Double '[2]  DoubleX2        where bSing = BD2-instance KnownBackend Double '[3]  DoubleX3        where bSing = BD3-instance KnownBackend Double '[4]  DoubleX4        where bSing = BD4+instance KnownBackend t      '[]  (ScalarBase t)   where bSing = BSC; {-# INLINE bSing #-}+instance KnownBackend Float  '[2]  FloatX2         where bSing = BF2; {-# INLINE bSing #-}+instance KnownBackend Float  '[3]  FloatX3         where bSing = BF3; {-# INLINE bSing #-}+instance KnownBackend Float  '[4]  FloatX4         where bSing = BF4; {-# INLINE bSing #-}+instance KnownBackend Double '[2]  DoubleX2        where bSing = BD2; {-# INLINE bSing #-}+instance KnownBackend Double '[3]  DoubleX3        where bSing = BD3; {-# INLINE bSing #-}+instance KnownBackend Double '[4]  DoubleX4        where bSing = BD4; {-# INLINE bSing #-} instance PrimBytes t       => KnownBackend t       ds  (ArrayBase t ds) where     bSing = case unsafeDefault @t @ds of Dict -> BPB+    {-# INLINE bSing #-}+instance {-# INCOHERENT #-}+         (PrimBytes t, Dimensions ds, b ~ BackendFamily t ds)+      => KnownBackend t ds b where+    bSing = case (dims @ds, primTag @t undefined) of+      (U, _)                -> BSC+      (D2 :* U, PTagFloat)  -> BF2+      (D3 :* U, PTagFloat)  -> BF3+      (D4 :* U, PTagFloat)  -> BF4+      (D2 :* U, PTagDouble) -> BD2+      (D3 :* U, PTagDouble) -> BD3+      (D4 :* U, PTagDouble) -> BD4+      _                     -> case unsafeDefault @t @ds of Dict -> BPB+    {-# INLINE bSing #-}++-- | Promise that we are sure the backend is ArrayBase.+unsafeDefault :: forall t ds . Dict (BackendFamily t ds ~ ArrayBase t ds)+unsafeDefault = unsafeCoerce# (Dict @(ArrayBase t ds ~ ArrayBase t ds)) #endif  -- | Find an instance of `KnownBackend` class using `PrimBytes` and `Dimensions`. inferKnownBackend :: forall t ds b                   . (PrimBytes t, Dimensions ds, b ~ BackendFamily t ds)                   => Dict (KnownBackend t ds b)-inferKnownBackend = case (dims @ds, primTag @t undefined) of-  (U, _) -> Dict-  (d :* U, PTagFloat)-      | Just Dict <- sameDim (D @2) d -> Dict-      | Just Dict <- sameDim (D @3) d -> Dict-      | Just Dict <- sameDim (D @4) d -> Dict-  (d :* U, PTagDouble)-      | Just Dict <- sameDim (D @2) d -> Dict-      | Just Dict <- sameDim (D @3) d -> Dict-      | Just Dict <- sameDim (D @4) d -> Dict-  _ -> case unsafeDefault @t @ds of Dict -> Dict+inferKnownBackend = Dict {-# INLINE inferKnownBackend #-}  
src-base/Numeric/DataFrame/Internal/Backend/Family/ArrayBase.hs view
@@ -1,9 +1,9 @@+{-# LANGUAGE AllowAmbiguousTypes       #-} {-# LANGUAGE ConstraintKinds           #-} {-# LANGUAGE DataKinds                 #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE FlexibleInstances         #-}-{-# LANGUAGE GADTs                     #-} {-# LANGUAGE MagicHash                 #-} {-# LANGUAGE MultiParamTypeClasses     #-} {-# LANGUAGE PolyKinds                 #-}@@ -24,6 +24,7 @@ import           Data.Int import           Data.Word import           GHC.Base                             hiding (foldr)+import           GHC.Exts                             (TYPE) import           Numeric.DataFrame.Internal.PrimArray import           Numeric.Dimensions import           Numeric.PrimBytes@@ -40,24 +41,23 @@     (# t --  Same value for each element;          --  this is the cheapest way to initialize an array.          --  It is also used for Num instances to avoid dependency on Dimensions.-     | (# Int#  -- Offset in Content array (measured in elements)+     | (# CumulDims  -- Steps array; [Word]+                     -- similar to steps in OpenCV::Mat, but counted in elements+                     --        rather than in bytes.+                     -- e.g. 0th element is the size of the content in elements+                     --      (data must be contiguous)+                     --      1th element is the size of subspace data minus outer dim.+        , Int#  -- Offset in Content array (measured in elements)         , ByteArray# -- Content;                      -- elements are stored row-by-row, plane-by-plane;                      -- (C-style, rather than Fortran-style);                      -- similar to C, OpenCV, etc.                      -- The data must be contiguous!                      -- (i.e. stride must be the same size as the element size).-        , CumulDims  -- Steps array; [Word]-                     -- similar to steps in OpenCV::Mat, but counted in elements-                     --        rather than in bytes.-                     -- e.g. 0th element is the size of the content in elements-                     --      (data must be contiguous)-                     --      1th element is the size of subspace data minus outer dim.         , Dict (PrimBytes t)         #)      #) - instance (PrimBytes t, Dimensions ds) => PrimBytes (ArrayBase t ds) where     {-# SPECIALIZE instance Dimensions ds => PrimBytes (ArrayBase Float ds)  #-}     {-# SPECIALIZE instance Dimensions ds => PrimBytes (ArrayBase Double ds) #-}@@ -72,16 +72,13 @@     {-# SPECIALIZE instance Dimensions ds => PrimBytes (ArrayBase Word32 ds) #-}     {-# SPECIALIZE instance Dimensions ds => PrimBytes (ArrayBase Word64 ds) #-} -    getBytes (ArrayBase a ) = case a of-        (# t | #)-          | W# nw <- totalDim' @ds-          , n <- word2Int# nw-          , tbs <- byteSize t -> go tbs (tbs *# n) t-        (# | (# _, arr, _, _ #) #) ->-          -- very weird trick with touch# allows to workaround GHC bug-          --  "internal error: ARR_WORDS object entered!"-          -- TODO: report this-          case runRW# (\s -> (# touch# arr s, arr #)) of (# _, ba #) -> ba+    getBytes = withArrayContent'+      (\t -> let tbs = byteSize t+             in go tbs (tbs *# totalDim# @ds) t)+      -- very weird trick with touch# allows to workaround GHC bug+      --  "internal error: ARR_WORDS object entered!"+      -- TODO: report this+      (\_ _ arr -> case runRW# (\s -> (# touch# arr s, arr #)) of (# _, ba #) -> ba)       where         go :: Int# -> Int# -> t -> ByteArray#         go tbs bsize t = case runRW#@@ -89,34 +86,29 @@              (# s1, mba #) -> unsafeFreezeByteArray# mba                ( loop# 0# tbs bsize (\i -> writeBytes mba i t) s1 )          ) of (# _, ba #) -> ba-        {-# NOINLINE go #-}     {-# INLINE getBytes #-} -    getBytesPinned (ArrayBase a) = case a of-        (# t | #)-          | W# nw <- totalDim' @ds-          , n <- word2Int# nw-          , tbs <- byteSize t -> go tbs (tbs *# n) t-        (# | (# off, arr, _, _ #) #) ->-          if isTrue# (isByteArrayPinned# arr)-          then case runRW# (\s -> (# touch# arr s, arr #)) of (# _, ba #) -> ba-          else case runRW#-           ( \s0 -> case (# sizeofByteArray# arr-                          , byteAlign @t undefined-                          #) of-               (# bsize, tba #)-                 | (# s1, mba #) <- newAlignedPinnedByteArray# bsize tba s0-                 , s2 <- copyByteArray# arr off mba off bsize s1-                   -> unsafeFreezeByteArray# mba s2-           ) of (# _, ba #) -> ba+    getBytesPinned = withArrayContent' f+      (const $ \off arr -> case runRW# (g off arr) of (# _, ba #) -> ba)       where-        go :: Int# -> Int# -> t -> ByteArray#-        go tbs bsize t = case runRW#-         ( \s0 -> case newAlignedPinnedByteArray# bsize (byteAlign t) s0 of-             (# s1, mba #) -> unsafeFreezeByteArray# mba-               ( loop# 0# tbs bsize (\i -> writeBytes mba i t) s1 )-         ) of (# _, ba #) -> ba-        {-# NOINLINE go #-}+        g :: Int# -> ByteArray# -> State# RealWorld -> (# State# RealWorld, ByteArray# #)+        g off arr s0+          | isTrue# (isByteArrayPinned# arr)+            = (# touch# arr s0, arr #)+          | tba <- byteAlign @t undefined+          , bsize <- sizeofByteArray# arr+          , (# s1, mba #) <- newAlignedPinnedByteArray# bsize tba s0+          , s2 <- copyByteArray# arr off mba off bsize s1+            = unsafeFreezeByteArray# mba s2+        f :: t -> ByteArray#+        f t+          | tbs <- byteSize t+          , bsize <- totalDim# @ds *# tbs+            = case runRW#+             ( \s0 -> case newAlignedPinnedByteArray# bsize (byteAlign t) s0 of+                 (# s1, mba #) -> unsafeFreezeByteArray# mba+                   ( loop# 0# tbs bsize (\i -> writeBytes mba i t) s1 )+             ) of (# _, ba #) -> ba     {-# INLINE getBytesPinned #-}  @@ -124,7 +116,7 @@       | tbs <- byteSize (undefined :: t)       , (# offN, offRem #) <- quotRemInt# bOff tbs       = case offRem of-          0# -> ArrayBase (# | (#  offN, ba, steps, Dict #) #)+          0# -> fromElems' steps offN ba           _  -> case cdTotalDim# steps of n -> go (tbs *# n)       where         steps = cumulDims $ dims @ds@@ -137,8 +129,7 @@                   of             (# s1, mba #) -> unsafeFreezeByteArray# mba                               (copyByteArray# ba bOff mba 0# bsize s1)-         ) of (# _, r #) -> ArrayBase (# | (# 0#, r, steps, Dict #) #)-        {-# NOINLINE go #-}+         ) of (# _, r #) -> fromElems' steps 0# r     {-# INLINE fromBytes #-}      readBytes mba bOff s0@@ -149,16 +140,17 @@       = case newByteArray# bsize s0 of          (# s1, mba1 #) -> case unsafeFreezeByteArray# mba1                                 (copyMutableByteArray# mba bOff mba1 0# bsize s1) of-           (# s2, ba #) -> (# s2, ArrayBase (# | (# 0#, ba, steps, Dict #) #) #)+           (# s2, ba #) -> (# s2, fromElems' steps 0# ba #)     {-# INLINE readBytes #-} -    writeBytes mba bOff (ArrayBase c)-      | tbs <- byteSize (undefined :: t) = case c of-        (# t | #) | W# n <- totalDim' @ds ->-          loop# bOff tbs (bOff +# word2Int# n *# tbs) (\i -> writeBytes mba i t)-        (# | (# offContent, arrContent, steps, _ #) #)-           | n <- cdTotalDim# steps->-          copyByteArray# arrContent (offContent *# tbs) mba bOff (n *# tbs)+    writeBytes mba bOff+      | tbs <- byteSize (undefined :: t) = withArrayContent'+        (\t -> loop# bOff tbs+          (bOff +# totalDim# @ds *# tbs)+          (\i -> writeBytes mba i t))+        (\steps offContent arrContent ->+          copyByteArray# arrContent (offContent *# tbs)+                         mba bOff (cdTotalDim# steps *# tbs))     {-# INLINE writeBytes #-}      readAddr addr s0@@ -169,29 +161,28 @@       = case newByteArray# bsize s0 of          (# s1, mba1 #) -> case unsafeFreezeByteArray# mba1                                 (copyAddrToByteArray# addr mba1 0# bsize s1) of-           (# s2, ba #) -> (# s2, ArrayBase (# | (# 0# , ba, steps, Dict #) #) #)+           (# s2, ba #) -> (# s2, fromElems' steps 0# ba #)     {-# INLINE readAddr #-} -    writeAddr (ArrayBase c) addr-      | tbs <- byteSize (undefined :: t) = case c of-        (# t | #) | W# n <- totalDim' @ds ->-          loop# 0# tbs (word2Int# n *# tbs) (\i -> writeAddr t (plusAddr# addr i))-        (# | (# offContent, arrContent, steps, _ #) #)-           | n <- cdTotalDim# steps ->-          copyByteArrayToAddr# arrContent (offContent *# tbs) addr (n *# tbs)+    writeAddr a addr+      | tbs <- byteSize (undefined :: t) = withArrayContent'+        (\t -> loop# 0# tbs+          (totalDim# @ds *# tbs)+          (\i -> writeAddr t (plusAddr# addr i)))+        (\steps offContent arrContent ->+          copyByteArrayToAddr# arrContent (offContent *# tbs)+                               addr (cdTotalDim# steps *# tbs)) a     {-# INLINE writeAddr #-}  -    byteSize  _ = case totalDim' @ds of -- WARNING: slow!-      W# n -> byteSize (undefined :: t) *# word2Int# n+    byteSize _ = byteSize @t undefined *# totalDim# @ds -- WARNING: slow!     {-# INLINE byteSize #-} -    byteAlign _ = byteAlign (undefined :: t)+    byteAlign _ = byteAlign @t undefined     {-# INLINE byteAlign #-} -    byteOffset (ArrayBase a) = case a of-      (# _ | #)                  -> 0#-      (# | (# off, _, _, _ #) #) -> off *# byteSize (undefined :: t)+    byteOffset = withArrayContent'+      (\_ -> 0#) (\_ off _ -> off *# byteSize @t undefined)     {-# INLINE byteOffset #-}      byteFieldOffset _ _ = negateInt# 1#@@ -199,8 +190,7 @@      indexArray ba off       | steps <- cumulDims $ dims @ds-      , n <- cdTotalDim# steps-      = ArrayBase (# | (# off *# n, ba, steps, Dict #) #)+      = fromElems' steps (off *# cdTotalDim# steps) ba     {-# INLINE indexArray #-}  @@ -222,17 +212,17 @@   (ArrayBase (# b | #))     = comb x (f a b) accumV2Idempotent x f comb-  a@(ArrayBase (# | (# _, _, steps, Dict #) #))+  a@(ArrayBase (# | (# steps, _, _, Dict #) #))   b@(ArrayBase (# | _ #))     = foldr (comb . (\i -> f (ixOff i a) (ixOff i b))) x                           [0 .. fromIntegral (cdTotalDim steps) - 1] accumV2Idempotent x f comb     (ArrayBase (# a | #))-  b@(ArrayBase (# | (# _, _, steps, Dict #) #))+  b@(ArrayBase (# | (# steps, _, _, Dict #) #))     = foldr (comb . (\i -> f a (ixOff i b))) x                           [0 .. fromIntegral (cdTotalDim steps) - 1] accumV2Idempotent x f comb-  a@(ArrayBase (# | (# _, _, steps, Dict #) #))+  a@(ArrayBase (# | (# steps, _, _, Dict #) #))     (ArrayBase (# b | #))     = foldr (comb . (\i -> f (ixOff i a) b)) x                           [0 .. fromIntegral (cdTotalDim steps) - 1]@@ -242,7 +232,7 @@ mapV :: (t -> t) -> ArrayBase t ds -> ArrayBase t ds mapV f (ArrayBase (# t | #))     = ArrayBase (# f t | #)-mapV f x@(ArrayBase (# | (# offN, ba, steps, Dict #) #))+mapV f x@(ArrayBase (# | (# steps, offN, ba, Dict #) #))     | tbs <- byteSize (undefEl x)     , n <- cdTotalDim# steps     = case runRW#@@ -251,7 +241,7 @@            ( loop1# n                (\i -> writeArray mba i (f (indexArray ba (offN +# i)))) s1            )-     ) of (# _, r #) -> ArrayBase (# | (# 0#, r, steps, Dict #) #)+     ) of (# _, r #) -> fromElems' steps 0# r {-# INLINE mapV #-}  @@ -259,8 +249,8 @@      -> ArrayBase t ds -> ArrayBase t ds -> ArrayBase t ds zipV f (ArrayBase (# x | #)) b = mapV (f x) b zipV f a (ArrayBase (# y | #)) = mapV (`f` y) a-zipV f a@(ArrayBase (# | (# oa, ba, steps, Dict #) #))-         (ArrayBase (# | (# ob, bb, _, _ #) #))+zipV f a@(ArrayBase (# | (# steps, oa, ba, Dict #) #))+         (ArrayBase (# | (# _,    ob, bb, _ #) #))     | n <- cdTotalDim# steps     = case runRW#      ( \s0 -> case newByteArray# (byteSize (undefEl a) *# n) s0 of@@ -272,7 +262,7 @@                         )                ) s1            )-     ) of (# _, r #) -> ArrayBase (# | (# 0#, r, steps, Dict #) #)+     ) of (# _, r #) -> fromElems' steps 0# r {-# INLINE zipV #-}  @@ -397,8 +387,8 @@     {-# SPECIALIZE instance Bounded (ArrayBase Word16 ds) #-}     {-# SPECIALIZE instance Bounded (ArrayBase Word32 ds) #-}     {-# SPECIALIZE instance Bounded (ArrayBase Word64 ds) #-}-    maxBound = ArrayBase (# maxBound | #)-    minBound = ArrayBase (# minBound | #)+    maxBound = broadcast' maxBound+    minBound = broadcast' minBound  instance Num t => Num (ArrayBase t ds)  where     {-# SPECIALIZE instance Num (ArrayBase Float ds)  #-}@@ -425,7 +415,7 @@     {-# INLINE abs #-}     signum = mapV signum     {-# INLINE signum #-}-    fromInteger i = ArrayBase (# fromInteger i | #)+    fromInteger = broadcast' . fromInteger     {-# INLINE fromInteger #-}  instance Fractional t => Fractional (ArrayBase t ds)  where@@ -435,14 +425,14 @@     {-# INLINE (/) #-}     recip = mapV recip     {-# INLINE recip #-}-    fromRational r = ArrayBase (# fromRational r | #)+    fromRational = broadcast' . fromRational     {-# INLINE fromRational #-}   instance Floating t => Floating (ArrayBase t ds) where     {-# SPECIALIZE instance Floating (ArrayBase Float ds)  #-}     {-# SPECIALIZE instance Floating (ArrayBase Double ds) #-}-    pi = ArrayBase (# pi | #)+    pi = broadcast' pi     {-# INLINE pi #-}     exp = mapV exp     {-# INLINE exp #-}@@ -480,26 +470,9 @@     {-# INLINE atanh #-}  instance PrimBytes t => PrimArray t (ArrayBase t ds) where-    {-# SPECIALIZE instance PrimArray Float  (ArrayBase Float ds)  #-}-    {-# SPECIALIZE instance PrimArray Double (ArrayBase Double ds) #-}-    {-# SPECIALIZE instance PrimArray Int    (ArrayBase Int ds)    #-}-    {-# SPECIALIZE instance PrimArray Word   (ArrayBase Word ds)   #-}-    {-# SPECIALIZE instance PrimArray Int8   (ArrayBase Int8 ds)   #-}-    {-# SPECIALIZE instance PrimArray Int16  (ArrayBase Int16 ds)  #-}-    {-# SPECIALIZE instance PrimArray Int32  (ArrayBase Int32 ds)  #-}-    {-# SPECIALIZE instance PrimArray Int64  (ArrayBase Int64 ds)  #-}-    {-# SPECIALIZE instance PrimArray Word8  (ArrayBase Word8 ds)  #-}-    {-# SPECIALIZE instance PrimArray Word16 (ArrayBase Word16 ds) #-}-    {-# SPECIALIZE instance PrimArray Word32 (ArrayBase Word32 ds) #-}-    {-# SPECIALIZE instance PrimArray Word64 (ArrayBase Word64 ds) #-} -    broadcast t = ArrayBase (# t | #)-    {-# INLINE broadcast #-}--    ix# i (ArrayBase a) = case a of-      (# t | #)                    -> t-      (# | (# off, arr, _, _ #) #) -> indexArray arr (off +# i)-    {-# INLINE ix# #-}+    broadcast# t = ArrayBase (# t | #)+    {-# INLINE broadcast# #-}      gen# steps f z0 = go (byteSize @t undefined *# n)       where@@ -510,57 +483,63 @@                (# s2, z1 #) -> case unsafeFreezeByteArray# mba s2 of                  (# s3, ba #) -> (# s3, (# z1, ba #) #)          ) of (# _, (# z1, ba #) #)-                   -> (# z1, ArrayBase (# | (# 0# , ba, steps, Dict #) #) #)-        {-# NOINLINE go #-}+                   -> (# z1, fromElems' steps 0# ba #)         loop0 mba i z s           | isTrue# (i ==# n) = (# s, z #)           | otherwise = case f z of               (# z', x #) -> loop0 mba (i +# 1#) z' (writeArray mba i x s)     {-# INLINE gen# #-} -    upd# steps i x (ArrayBase (# a | #)) = go (byteSize x)-      where-        n = cdTotalDim# steps-        go tbs = case runRW#-         ( \s0 -> case newByteArray# (tbs *# n) s0 of-             (# s1, mba #) -> unsafeFreezeByteArray# mba-               (writeArray mba i x-                 (loop1# n (\j -> writeArray mba j a) s1)-               )-         ) of (# _, r #) -> ArrayBase (# |  (# 0# , r, steps, Dict #) #)-        {-# NOINLINE go #-}-    upd# _ i x (ArrayBase (# | (# offN, ba, steps, Dict #) #))-        = go (byteSize x)+    upd# steps i x = withArrayContent' f g       where         n = cdTotalDim# steps-        go tbs = case runRW#-         ( \s0 -> case newByteArray# (tbs *# n) s0 of-             (# s1, mba #) -> unsafeFreezeByteArray# mba-               (writeArray mba i x-                 (copyByteArray# ba (offN *# tbs) mba 0# (tbs *# n) s1)-               )-         ) of (# _, r #) -> ArrayBase (# | (# 0#, r, steps, Dict #) #)-        {-# NOINLINE go #-}+        f a = go (byteSize x)+          where+            go tbs = case runRW#+             ( \s0 -> case newByteArray# (tbs *# n) s0 of+                 (# s1, mba #) -> unsafeFreezeByteArray# mba+                   (writeArray mba i x+                     (loop1# n (\j -> writeArray mba j a) s1)+                   )+             ) of (# _, r #) -> fromElems' steps 0# r+        g _ offN ba = go (byteSize x)+          where+            go tbs = case runRW#+             ( \s0 -> case newByteArray# (tbs *# n) s0 of+                 (# s1, mba #) -> unsafeFreezeByteArray# mba+                   (writeArray mba i x+                     (copyByteArray# ba (offN *# tbs) mba 0# (tbs *# n) s1)+                   )+             ) of (# _, r #) -> fromElems' steps 0# r     {-# INLINE upd# #-} -    arrayContent# (ArrayBase a) = case a of-      (# x | #)                     -> (# x | #)-      (# | (# off, arr, cd, _ #) #) -> (# | (# cd, off, arr #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# = withArrayContent'+    {-# INLINE withArrayContent# #-} -    offsetElems (ArrayBase a) = case a of-      (# _ | #)                  -> 0#-      (# | (# off, _, _, _ #) #) -> off-    {-# INLINE offsetElems #-}+    fromElems# = fromElems'+    {-# INLINE fromElems# #-} -    uniqueOrCumulDims (ArrayBase a) = case a of-      (# t | #)                    -> Left t-      (# | (# _, _, steps, _ #) #) -> Right steps-    {-# INLINE uniqueOrCumulDims #-}+withArrayContent' ::+       forall (t :: Type) (ds :: [Nat]) (rep :: RuntimeRep) (r :: TYPE rep)+     . (t -> r)+    -> (CumulDims -> Int# -> ByteArray# -> r)+    -> ArrayBase t ds -> r+withArrayContent' f _ (ArrayBase (# e | #)) = f e+withArrayContent' _ g (ArrayBase (# | (# steps, off, ba, _ #) #)) = g steps off ba+{-# INLINE withArrayContent' #-} -    fromElems steps off ba = ArrayBase (# | (# off, ba, steps, Dict #) #)-    {-# INLINE fromElems #-}+fromElems' :: forall (t :: Type) (ds :: [Nat])+            . PrimBytes t => CumulDims -> Int# -> ByteArray# -> ArrayBase t ds+fromElems' steps off ba = ArrayBase (# | (# steps, off, ba, Dict #) #)+{-# INLINE fromElems' #-} +broadcast' :: t -> ArrayBase t ds+broadcast' t = ArrayBase (# t | #)+{-# INLINE broadcast' #-}++totalDim# :: forall (ds :: [Nat]) . Dimensions ds => Int#+totalDim# = case totalDim' @ds of W# n -> word2Int# n+{-# INLINE totalDim# #-}  loop# :: Int# -- ^ initial value       -> Int# -- ^ step
src-base/Numeric/DataFrame/Internal/Backend/Family/DoubleX2.hs view
@@ -4,12 +4,10 @@ {-# LANGUAGE MagicHash             #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE UnboxedSums           #-} {-# LANGUAGE UnboxedTuples         #-} {-# LANGUAGE UndecidableInstances  #-} module Numeric.DataFrame.Internal.Backend.Family.DoubleX2 (DoubleX2 (..)) where - import           GHC.Base import           Numeric.DataFrame.Internal.PrimArray import           Numeric.PrimBytes@@ -368,8 +366,8 @@  instance PrimArray Double DoubleX2 where -    broadcast (D# x) = DoubleX2# x x-    {-# INLINE broadcast #-}+    broadcast# (D# x) = DoubleX2# x x+    {-# INLINE broadcast# #-}      ix# 0# (DoubleX2# a1 _) = D# a1     ix# 1# (DoubleX2# _ a2) = D# a2@@ -386,8 +384,8 @@     upd# _ _ _ x                     = x     {-# INLINE upd# #-} -    arrayContent# x = (# | (# CumulDims [ELEM_N, 1], 0#, getBytes x #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x)+    {-# INLINE withArrayContent# #-}      offsetElems _ = 0#     {-# INLINE offsetElems #-}@@ -395,7 +393,7 @@     uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1])     {-# INLINE uniqueOrCumulDims #-} -    fromElems _ off ba = DoubleX2#+    fromElems# _ off ba = DoubleX2#       (indexDoubleArray# ba off)       (indexDoubleArray# ba (off +# 1#))-    {-# INLINE fromElems #-}+    {-# INLINE fromElems# #-}
src-base/Numeric/DataFrame/Internal/Backend/Family/DoubleX3.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE MagicHash             #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE UnboxedSums           #-} {-# LANGUAGE UnboxedTuples         #-} {-# LANGUAGE UndecidableInstances  #-} module Numeric.DataFrame.Internal.Backend.Family.DoubleX3 (DoubleX3 (..)) where@@ -399,8 +398,8 @@  instance PrimArray Double DoubleX3 where -    broadcast (D# x) = DoubleX3# x x x-    {-# INLINE broadcast #-}+    broadcast# (D# x) = DoubleX3# x x x+    {-# INLINE broadcast# #-}      ix# 0# (DoubleX3# a1 _ _) = D# a1     ix# 1# (DoubleX3# _ a2 _) = D# a2@@ -420,8 +419,8 @@     upd# _ _ _ x                       = x     {-# INLINE upd# #-} -    arrayContent# x = (# | (# CumulDims [ELEM_N, 1], 0#, getBytes x #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x)+    {-# INLINE withArrayContent# #-}      offsetElems _ = 0#     {-# INLINE offsetElems #-}@@ -429,8 +428,8 @@     uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1])     {-# INLINE uniqueOrCumulDims #-} -    fromElems _ off ba = DoubleX3#+    fromElems# _ off ba = DoubleX3#       (indexDoubleArray# ba off)       (indexDoubleArray# ba (off +# 1#))       (indexDoubleArray# ba (off +# 2#))-    {-# INLINE fromElems #-}+    {-# INLINE fromElems# #-}
src-base/Numeric/DataFrame/Internal/Backend/Family/DoubleX4.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE MagicHash             #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE UnboxedSums           #-} {-# LANGUAGE UnboxedTuples         #-} {-# LANGUAGE UndecidableInstances  #-} module Numeric.DataFrame.Internal.Backend.Family.DoubleX4 (DoubleX4 (..)) where@@ -426,8 +425,8 @@  instance PrimArray Double DoubleX4 where -    broadcast (D# x) = DoubleX4# x x x x-    {-# INLINE broadcast #-}+    broadcast# (D# x) = DoubleX4# x x x x+    {-# INLINE broadcast# #-}      ix# 0# (DoubleX4# a1 _ _ _) = D# a1     ix# 1# (DoubleX4# _ a2 _ _) = D# a2@@ -450,8 +449,8 @@     upd# _ _ _ x                         = x     {-# INLINE upd# #-} -    arrayContent# x = (# | (# CumulDims [ELEM_N, 1], 0#, getBytes x #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x)+    {-# INLINE withArrayContent# #-}      offsetElems _ = 0#     {-# INLINE offsetElems #-}@@ -459,9 +458,9 @@     uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1])     {-# INLINE uniqueOrCumulDims #-} -    fromElems _ off ba = DoubleX4#+    fromElems# _ off ba = DoubleX4#       (indexDoubleArray# ba off)       (indexDoubleArray# ba (off +# 1#))       (indexDoubleArray# ba (off +# 2#))       (indexDoubleArray# ba (off +# 3#))-    {-# INLINE fromElems #-}+    {-# INLINE fromElems# #-}
src-base/Numeric/DataFrame/Internal/Backend/Family/FloatX2.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE MagicHash             #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE UnboxedSums           #-} {-# LANGUAGE UnboxedTuples         #-} {-# LANGUAGE UndecidableInstances  #-} module Numeric.DataFrame.Internal.Backend.Family.FloatX2 (FloatX2 (..)) where@@ -368,8 +367,8 @@  instance PrimArray Float FloatX2 where -    broadcast (F# x) = FloatX2# x x-    {-# INLINE broadcast #-}+    broadcast# (F# x) = FloatX2# x x+    {-# INLINE broadcast# #-}      ix# 0# (FloatX2# a1 _) = F# a1     ix# 1# (FloatX2# _ a2) = F# a2@@ -386,8 +385,8 @@     upd# _ _ _ x                    = x     {-# INLINE upd# #-} -    arrayContent# x = (# | (# CumulDims [ELEM_N, 1], 0#, getBytes x #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x)+    {-# INLINE withArrayContent# #-}      offsetElems _ = 0#     {-# INLINE offsetElems #-}@@ -395,7 +394,7 @@     uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1])     {-# INLINE uniqueOrCumulDims #-} -    fromElems _ off ba = FloatX2#+    fromElems# _ off ba = FloatX2#       (indexFloatArray# ba off)       (indexFloatArray# ba (off +# 1#))-    {-# INLINE fromElems #-}+    {-# INLINE fromElems# #-}
src-base/Numeric/DataFrame/Internal/Backend/Family/FloatX3.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE MagicHash             #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE UnboxedSums           #-} {-# LANGUAGE UnboxedTuples         #-} {-# LANGUAGE UndecidableInstances  #-} module Numeric.DataFrame.Internal.Backend.Family.FloatX3 (FloatX3 (..)) where@@ -400,8 +399,8 @@  instance PrimArray Float FloatX3 where -    broadcast (F# x) = FloatX3# x x x-    {-# INLINE broadcast #-}+    broadcast# (F# x) = FloatX3# x x x+    {-# INLINE broadcast# #-}      ix# 0# (FloatX3# a1 _ _) = F# a1     ix# 1# (FloatX3# _ a2 _) = F# a2@@ -421,8 +420,8 @@     upd# _ _ _ x                      = x     {-# INLINE upd# #-} -    arrayContent# x = (# | (# CumulDims [ELEM_N, 1], 0#, getBytes x #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x)+    {-# INLINE withArrayContent# #-}      offsetElems _ = 0#     {-# INLINE offsetElems #-}@@ -430,8 +429,8 @@     uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1])     {-# INLINE uniqueOrCumulDims #-} -    fromElems _ off ba = FloatX3#+    fromElems# _ off ba = FloatX3#       (indexFloatArray# ba off)       (indexFloatArray# ba (off +# 1#))       (indexFloatArray# ba (off +# 2#))-    {-# INLINE fromElems #-}+    {-# INLINE fromElems# #-}
src-base/Numeric/DataFrame/Internal/Backend/Family/FloatX4.hs view
@@ -5,7 +5,6 @@ {-# LANGUAGE MagicHash             #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeApplications      #-}-{-# LANGUAGE UnboxedSums           #-} {-# LANGUAGE UnboxedTuples         #-} {-# LANGUAGE UndecidableInstances  #-} {-# OPTIONS_GHC -fno-warn-orphans  #-}@@ -20,6 +19,7 @@ import           Numeric.ProductOrd import qualified Numeric.ProductOrd.NonTransitive     as NonTransitive import qualified Numeric.ProductOrd.Partial           as Partial+import           Unsafe.Coerce                        (unsafeCoerce)   data FloatX4 = FloatX4# Float# Float# Float# Float#@@ -432,8 +432,8 @@  instance PrimArray Float FloatX4 where -    broadcast (F# x) = FloatX4# x x x x-    {-# INLINE broadcast #-}+    broadcast# (F# x) = FloatX4# x x x x+    {-# INLINE broadcast# #-}      ix# 0# (FloatX4# a1 _ _ _) = F# a1     ix# 1# (FloatX4# _ a2 _ _) = F# a2@@ -456,8 +456,8 @@     upd# _ _ _ x                        = x     {-# INLINE upd# #-} -    arrayContent# x = (# | (# CumulDims [ELEM_N, 1], 0#, getBytes x #) #)-    {-# INLINE arrayContent# #-}+    withArrayContent# _ g x = g (CumulDims [ELEM_N, 1]) 0# (getBytes x)+    {-# INLINE withArrayContent# #-}      offsetElems _ = 0#     {-# INLINE offsetElems #-}@@ -465,13 +465,12 @@     uniqueOrCumulDims _ = Right (CumulDims [ELEM_N, 1])     {-# INLINE uniqueOrCumulDims #-} -    fromElems _ off ba = FloatX4#+    fromElems# _ off ba = FloatX4#       (indexFloatArray# ba off)       (indexFloatArray# ba (off +# 1#))       (indexFloatArray# ba (off +# 2#))       (indexFloatArray# ba (off +# 3#))-    {-# INLINE fromElems #-}-+    {-# INLINE fromElems# #-}  -------------------------------------------------------------------------------- -- Rewrite rules to improve efficiency of algorithms@@ -485,14 +484,13 @@ --------------------------------------------------------------------------------  getIdxOffset :: Idxs '[4] -> Int#-getIdxOffset is = case unsafeCoerce# is of-  [W# i] -> word2Int# i-  _      -> 0#+getIdxOffset is = case unsafeCoerce is of+  ~[w] -> case w of W# i -> word2Int# i {-# INLINE getIdxOffset #-}   {-# RULES-"index/FloatX4" forall i . index @Float @'[4] i-  = unsafeCoerce# (ix# @Float @FloatX4 (getIdxOffset i))+"index/FloatX4" forall i . index @Float @'[4] @'[] @'[4] i+  = unsafeCoerce (ix# @Float @FloatX4 (getIdxOffset i))    #-}
src-base/Numeric/DataFrame/Internal/Backend/Family/ScalarBase.hs view
@@ -9,7 +9,8 @@ module Numeric.DataFrame.Internal.Backend.Family.ScalarBase (ScalarBase (..)) where  -import           GHC.Base+import           Data.Coerce+import           Numeric.Basics import           Numeric.DataFrame.Internal.PrimArray import           Numeric.PrimBytes import           Numeric.ProductOrd@@ -18,7 +19,7 @@  -- | Specialize ScalarBase type without any arrays newtype ScalarBase t = ScalarBase { _unScalarBase :: t }-  deriving ( Enum, Eq, Bounded, Integral+  deriving ( Enum, Eq, Bounded, Integral, Epsilon, RealExtras, RealFloatExtras            , Num, Fractional, Floating, Ord, Real, RealFrac, RealFloat            , PrimBytes) @@ -28,23 +29,23 @@ deriving instance Ord t => Ord (Partial.ProductOrd (ScalarBase t))  instance PrimBytes t => PrimArray t (ScalarBase t) where-  broadcast = unsafeCoerce#-  {-# INLINE broadcast #-}-  ix# _ = unsafeCoerce#+  broadcast# = coerce+  {-# INLINE broadcast# #-}+  ix# _ = coerce   {-# INLINE ix# #-}-  gen# _ = unsafeCoerce#+  gen# _ = coerce   {-# INLINE gen# #-}   upd# _ 0# = const . ScalarBase   upd# _ _  = const id   {-# INLINE upd# #-}-  arrayContent# x = (# _unScalarBase x | #)-  {-# INLINE arrayContent# #-}+  withArrayContent# f _ x = f (_unScalarBase x)+  {-# INLINE withArrayContent# #-}   offsetElems _ = 0#   {-# INLINE offsetElems #-}   uniqueOrCumulDims = Left . _unScalarBase   {-# INLINE uniqueOrCumulDims #-}-  fromElems _ off ba = indexArray ba off-  {-# INLINE fromElems #-}+  fromElems# _ off ba = indexArray ba off+  {-# INLINE fromElems# #-}  _suppressHlintUnboxedTuplesWarning :: () -> (# (), () #) _suppressHlintUnboxedTuplesWarning = undefined
+ src/Numeric/Basics.hs view
@@ -0,0 +1,238 @@+{-# LANGUAGE ConstraintKinds  #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE PatternSynonyms  #-}+{-# LANGUAGE ViewPatterns     #-}+module Numeric.Basics+  ( -- * Constants+    pattern M_E, pattern M_LOG2E, pattern M_LOG10E, pattern M_LN2, pattern M_LN10+  , pattern M_SQRT2, pattern M_SQRT1_2+  , pattern M_PI, pattern M_PI_2, pattern M_PI_3, pattern M_PI_4+  , pattern M_1_PI, pattern M_2_PI, pattern M_2_SQRTPI+  , Epsilon (..), pattern M_EPS+    -- * Functions+  , RealExtras (..), RealFloatExtras (..)+  , negateUnless+    -- * Exceptions+  , IterativeMethod, TooManyIterations, tooManyIterations+  ) where++import Data.Int+import Data.Word+import GHC.Exception+import GHC.Stack+import Numeric.PrimBytes++-- | \( e \)+pattern M_E :: (Eq a, Fractional a) => Fractional a => a+pattern M_E = 2.718281828459045235360287471352662498++-- | \( \log_2 e \)+pattern M_LOG2E :: (Eq a, Fractional a) => Fractional a => a+pattern M_LOG2E = 1.442695040888963407359924681001892137++-- | \( \log_{10} e \)+pattern M_LOG10E :: (Eq a, Fractional a) => Fractional a => a+pattern M_LOG10E = 0.434294481903251827651128918916605082++-- | \( \log_e 2 \)+pattern M_LN2 :: (Eq a, Fractional a) => Fractional a => a+pattern M_LN2 = 0.693147180559945309417232121458176568++-- | \( \log_e 10 \)+pattern M_LN10 :: (Eq a, Fractional a) => Fractional a => a+pattern M_LN10 = 2.302585092994045684017991454684364208++-- | \( \sqrt{2} \)+pattern M_SQRT2 :: (Eq a, Fractional a) => Fractional a => a+pattern M_SQRT2 = 1.414213562373095048801688724209698079++-- | \( \frac{1}{\sqrt{2}} \)+pattern M_SQRT1_2 :: (Eq a, Fractional a) => Fractional a => a+pattern M_SQRT1_2 = 0.707106781186547524400844362104849039++-- | \( \pi \)+pattern M_PI :: (Eq a, Fractional a) => Fractional a => a+pattern M_PI = 3.1415926535897932384626433832795028841971+-- | \( \frac{\pi}{2} \)+pattern M_PI_2 :: (Eq a, Fractional a) => Fractional a => a+pattern M_PI_2 = 1.570796326794896619231321691639751442++-- | \( \frac{\pi}{3} \)+pattern M_PI_3 :: (Eq a, Fractional a) => Fractional a => a+pattern M_PI_3 = 1.047197551196597746154214461093167628++-- | \( \frac{\pi}{4} \)+pattern M_PI_4 :: (Eq a, Fractional a) => Fractional a => a+pattern M_PI_4 = 0.785398163397448309615660845819875721++-- | \( \frac{1}{\pi} \)+pattern M_1_PI :: (Eq a, Fractional a) => Fractional a => a+pattern M_1_PI = 0.318309886183790671537767526745028724++-- | \( \frac{2}{\pi} \)+pattern M_2_PI :: (Eq a, Fractional a) => Fractional a => a+pattern M_2_PI = 0.636619772367581343075535053490057448++-- | \( \frac{2}{\sqrt{\pi}} \)+pattern M_2_SQRTPI :: (Eq a, Fractional a) => Fractional a => a+pattern M_2_SQRTPI = 1.128379167095512573896158903121545172++-- | Define a meaningful precision for complex floating-point operations.+class (Eq a, Floating a) => Epsilon a where+    -- | A small positive number that depends on the type of @a@.+    --   Compare your values to @epsilon@ to tell if they are near zero.+    epsilon :: a++instance Epsilon Double where+    epsilon = 1e-12++instance Epsilon Float where+    epsilon = 1e-6++-- | A small positive number that depends on the type of @a@.+pattern M_EPS :: Epsilon a => a+pattern M_EPS <- ((epsilon ==) -> True)+  where+    M_EPS = epsilon++-- | Negate if @False@.+--   This is a useful alternative to `signum`,+--     when @signum 0 == 0@ causing some troubles.+negateUnless :: Num t => Bool -> t -> t+negateUnless True  = id+negateUnless False = negate+{-# INLINE negateUnless #-}++-- | Extra functions for `Real` types.+class (Real a, PrimBytes a) => RealExtras a where+    -- | @copysign x y@ returns a value with the magnitude of x and the sign of y.+    --+    --   NB: in future, this function is to reimplemented using primops+    --       and should behave the same way as its C analogue.+    copysign :: a -> a -> a+    copysign x y+      | (x >= 0) == (y >= 0) = x+      | otherwise = negate x+    {-# INLINE copysign #-}++instance RealExtras Int+instance RealExtras Int8+instance RealExtras Int16+instance RealExtras Int32+instance RealExtras Int64+instance RealExtras Word+instance RealExtras Word8+instance RealExtras Word16+instance RealExtras Word32+instance RealExtras Word64++instance RealExtras Float where+    copysign = c'copysignf+    {-# INLINE copysign #-}++instance RealExtras Double where+    copysign = c'copysignd+    {-# INLINE copysign #-}++-- | Extra functions for `RealFrac` types.+class (Epsilon a, RealExtras a, RealFloat a) => RealFloatExtras a where+    -- | \( \sqrt{ x^2 + y^2 } \).+    --+    --   NB: in future, this function is to reimplemented using primops+    --       and should behave the same way as its C analogue.+    hypot :: a -> a -> a+    hypot x y = scaleFloat ea (sqrt (an*an + bn*bn))+      where+        x' = abs x+        y' = abs y+        (a,b) = if x' >= y' then (x', y') else (y', x')+        (_, ea) = decodeFloat a+        an = scaleFloat (negate ea) a+        bn = scaleFloat (negate ea) b+    {-# INLINE hypot #-}+    -- | Maximum finite number representable by this FP type.+    maxFinite :: a++instance RealFloatExtras Float where+    hypot = c'hypotf+    {-# INLINE hypot #-}+    maxFinite = 3.40282347e+38+    {-# INLINE maxFinite #-}+++instance RealFloatExtras Double where+    hypot = c'hypotd+    {-# INLINE hypot #-}+    maxFinite = 1.7976931348623157e+308+    {-# INLINE maxFinite #-}++foreign import ccall unsafe "hypot"  c'hypotd :: Double -> Double -> Double+foreign import ccall unsafe "hypotf" c'hypotf :: Float -> Float -> Float+foreign import ccall unsafe "copysign"  c'copysignd :: Double -> Double -> Double+foreign import ccall unsafe "copysignf" c'copysignf :: Float -> Float -> Float++{- |+This is just an alias for the `HasCallStack` constraint.+It servers two goals:++  1. Document functions that use iterative methods and can fail+     (supposedly in extremely rare cases).+  2. Provide a call stack in case of failure.++Use `tooManyIterations` function where necessary if you implement an iterative+algorithm and annotate your implementation function with `IterativeMethod` constraint.++ -}+type IterativeMethod = HasCallStack++-- | Throw a `TooManyIterations` exception.+tooManyIterations ::+       IterativeMethod+    => String  -- ^ Label (e.g. function name)+    -> a+tooManyIterations s+  = throw TooManyIterations+  { tmiUserInfo  = s+  , tmiCallStack = callStack+  }++{- |+Typically, this exception can occur in an iterative algorithm;+when the number of iterations exceeds a pre-defined limit, but the stop condition+is not fulfilled.++Use the `IterativeMethod` constraint to annotate functions that throw this exception.+ -}+data TooManyIterations+  = TooManyIterations+  { tmiUserInfo  :: String+    -- ^ Short description of the error, e.g. a function name.+  , tmiCallStack :: CallStack+    -- ^ Function call stack.+    --   Note, this field is ignored in the `Eq` and `Ord` instances.+  }++-- | Note, this instance ignores `oodCallStack`+instance Eq TooManyIterations where+  (==) a b = tmiUserInfo a == tmiUserInfo b++-- | Note, this instance ignores `oodCallStack`+instance Ord TooManyIterations where+  compare a b = compare (tmiUserInfo a) (tmiUserInfo b)++instance Show TooManyIterations where+  showsPrec p e = addLoc errStr+    where+      addLoc s+        = let someE = errorCallWithCallStackException s (tmiCallStack e)+              errc :: ErrorCall+              errc = case fromException someE of+                Nothing -> ErrorCall s+                Just ec -> ec+          in  showsPrec p errc+      errStr = unlines+        [ "An iterative method has exceeded the limit for the iteration number."+        , "User info: " ++ tmiUserInfo e+        ]++instance Exception TooManyIterations
src/Numeric/DataFrame.hs view
@@ -7,6 +7,8 @@     -- * Functionality   , module Numeric.DataFrame.SubSpace   , module Numeric.DataFrame.Contraction+  , module Numeric.Basics+  , module Numeric.Subroutine.Sort   ) where  import Numeric.DataFrame.Internal.Backend ()@@ -18,3 +20,7 @@ import Numeric.Matrix import Numeric.Scalar import Numeric.Vector++import Numeric.Basics++import Numeric.Subroutine.Sort (sort, sortBy)
src/Numeric/DataFrame/Contraction.hs view
@@ -1,16 +1,17 @@-{-# LANGUAGE DataKinds              #-}-{-# LANGUAGE FlexibleContexts       #-}-{-# LANGUAGE FlexibleInstances      #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE InstanceSigs           #-}-{-# LANGUAGE MagicHash              #-}-{-# LANGUAGE MultiParamTypeClasses  #-}-{-# LANGUAGE ScopedTypeVariables    #-}-{-# LANGUAGE TypeApplications       #-}-{-# LANGUAGE TypeFamilies           #-}-{-# LANGUAGE TypeOperators          #-}-{-# LANGUAGE UnboxedTuples          #-}-{-# LANGUAGE UndecidableInstances   #-}+{-# LANGUAGE DataKinds               #-}+{-# LANGUAGE FlexibleContexts        #-}+{-# LANGUAGE FlexibleInstances       #-}+{-# LANGUAGE FunctionalDependencies  #-}+{-# LANGUAGE InstanceSigs            #-}+{-# LANGUAGE MagicHash               #-}+{-# LANGUAGE MultiParamTypeClasses   #-}+{-# LANGUAGE ScopedTypeVariables     #-}+{-# LANGUAGE TypeApplications        #-}+{-# LANGUAGE TypeFamilies            #-}+{-# LANGUAGE TypeOperators           #-}+{-# LANGUAGE UnboxedTuples           #-}+{-# LANGUAGE UndecidableInstances    #-}+{-# LANGUAGE UndecidableSuperClasses #-} ----------------------------------------------------------------------------- -- | -- Module      :  Numeric.DataFrame.Contraction
src/Numeric/DataFrame/IO.hs view
@@ -2,14 +2,18 @@ {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE FlexibleInstances         #-}+{-# LANGUAGE InstanceSigs              #-} {-# LANGUAGE MagicHash                 #-} {-# LANGUAGE MultiParamTypeClasses     #-}+{-# LANGUAGE PatternSynonyms           #-} {-# LANGUAGE PolyKinds                 #-} {-# LANGUAGE ScopedTypeVariables       #-} {-# LANGUAGE TypeApplications          #-} {-# LANGUAGE TypeFamilies              #-} {-# LANGUAGE TypeInType                #-} {-# LANGUAGE TypeOperators             #-}+{-# LANGUAGE UndecidableInstances      #-}+{-# LANGUAGE ViewPatterns              #-} ----------------------------------------------------------------------------- -- | -- Module      :  Numeric.DataFrame.IO@@ -22,208 +26,348 @@  module Numeric.DataFrame.IO     ( IODataFrame (XIOFrame), SomeIODataFrame (..)-    , newDataFrame, newPinnedDataFrame+    , castDataFrame+    , newDataFrame, newPinnedDataFrame, oneMoreDataFrame+    , subDataFrameView, subDataFrameView'     , copyDataFrame, copyMutableDataFrame     , copyDataFrame', copyMutableDataFrame'+    , copyDataFrameOff, copyMutableDataFrameOff     , freezeDataFrame, unsafeFreezeDataFrame-    , thawDataFrame, thawPinDataFrame, unsafeThawDataFrame+    , thawDataFrame, thawPinDataFrame, unsafeThawDataFrame, withThawDataFrame     , writeDataFrame, writeDataFrameOff     , readDataFrame, readDataFrameOff-    , withDataFramePtr, isDataFramePinned+    , isDataFramePinned, getDataFrameSteps+    , withDataFramePtr     ) where  -import GHC.Base-import GHC.IO   (IO (..))-import GHC.Ptr  (Ptr (..))+import GHC.IO  (IO (..))+import GHC.Ptr (Ptr (..)) +import Control.Monad.ST                     (RealWorld)+import Data.Coerce+import Data.Kind import Numeric.DataFrame.Internal.Mutable import Numeric.DataFrame.Internal.PrimArray import Numeric.DataFrame.Type import Numeric.Dimensions+import Unsafe.Coerce   -- | Mutable DataFrame that lives in IO. --   Internal representation is always a MutableByteArray.-data family IODataFrame (t :: Type) (ns :: [k])---- | Pure wrapper on a mutable byte array-newtype instance IODataFrame t (ns :: [Nat]) = IODataFrame (MDataFrame RealWorld t (ns :: [Nat]))+newtype IODataFrame (t :: Type) (ns :: [k]) = IODataFrame (MDataFrame RealWorld t (ns :: [k]))  -- | Data frame with some dimensions missing at compile time. --   Pattern-match against its constructor to get a Nat-indexed mutable data frame.-data instance IODataFrame t (xs :: [XNat])-  = forall (ns :: [Nat]) . Dimensions ns-  => XIOFrame (IODataFrame t ns)+pattern XIOFrame :: forall (t :: Type) (xns :: [XNat]) . ()+                 => forall (ns :: [Nat]) . (FixedDims xns ns, Dimensions ns)+                 => IODataFrame t ns -> IODataFrame t xns+pattern XIOFrame df <- (mkXIOFramePat -> XIOFramePat df)+  where+    XIOFrame = castDataFrame+{-# COMPLETE XIOFrame #-} +data XIOFramePat (t :: Type) (xns :: [XNat])+  = forall (ns :: [Nat]) . (FixedDims xns ns, Dimensions ns)+  => XIOFramePat (IODataFrame t ns)++mkXIOFramePat :: forall (t :: Type) (xns :: [XNat])+               . IODataFrame t xns -> XIOFramePat t xns+mkXIOFramePat df+  | SomeDims ds <- fromSteps (getDataFrameSteps df)+  , XDims (Dims :: Dims ns) <- (unsafeCoerce ds) :: Dims xns+    = XIOFramePat @t @xns @ns (unsafeCoerce df)+  | otherwise+    = error "XIOFrame pattern: impossible args"+ -- | Mutable DataFrame of unknown dimensionality data SomeIODataFrame (t :: Type)   = forall (ns :: [Nat]) . Dimensions ns => SomeIODataFrame (IODataFrame t ns) +-- | Allow coercing between @XNat@-indexed and @Nat@-indexed Mutable DataFrames.+castDataFrame ::+       forall (t :: Type) (xns :: [XNat]) (ns :: [Nat])+     . FixedDims xns ns+    => IODataFrame t ns -> IODataFrame t xns+castDataFrame = coerce (castDataFrame# @t @xns @ns)+{-# INLINE castDataFrame #-}+ -- | Create a new mutable DataFrame.-newDataFrame :: forall t (ns :: [Nat])-              . ( PrimBytes t, Dimensions ns)-             => IO (IODataFrame t ns)-newDataFrame = IODataFrame <$> IO (newDataFrame# @t @ns)+newDataFrame ::+       forall (t :: Type) ns+     . (PrimBytes t, Dimensions ns) => IO (IODataFrame t ns)+newDataFrame = coerce (newDataFrame# @t @_ @ns) {-# INLINE newDataFrame #-} - -- | Create a new mutable DataFrame.-newPinnedDataFrame :: forall t (ns :: [Nat])-                    . ( PrimBytes t, Dimensions ns)-                   => IO (IODataFrame t ns)-newPinnedDataFrame = IODataFrame <$> IO (newPinnedDataFrame# @t @ns)+newPinnedDataFrame ::+       forall (t :: Type) ns+     . (PrimBytes t, Dimensions ns) => IO (IODataFrame t ns)+newPinnedDataFrame = coerce (newPinnedDataFrame# @t @_ @ns) {-# INLINE newPinnedDataFrame #-} +-- | Create a new mutable DataFrame of the same size.+oneMoreDataFrame ::+       forall (t :: Type) ns+     . IODataFrame t ns -> IO (IODataFrame t ns)+oneMoreDataFrame = coerce (oneMoreDataFrame# @t @_ @ns)+{-# INLINE oneMoreDataFrame #-} +-- | View a part of a DataFrame.+--+--   This function does not perform a copy.+--   All changes to a new DataFrame will be reflected in the original DataFrame as well.+--+--   If any of the dims in @as@ or @b@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+subDataFrameView ::+       forall (t :: Type) b bi bd as bs asbs+     . (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs)+    => Idxs (as +: bi) -> IODataFrame t asbs -> IODataFrame t (bd :+ bs)+subDataFrameView = coerce (subDataFrameView# @t @_ @b @bi @bd @as @bs @asbs)++-- | View a part of a DataFrame.+--+--   This function does not perform a copy.+--   All changes to a new DataFrame will be reflected in the original DataFrame as well.+--+--   This is a simpler version of @subDataFrameView@ that allows+--    to view over one index at a time.+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+subDataFrameView' ::+       forall (t :: Type) as bs asbs+     . ConcatList as bs asbs+    => Idxs as -> IODataFrame t asbs -> IODataFrame t bs+subDataFrameView' = coerce (subDataFrameView'# @t @_ @as @bs @asbs)+ -- | Copy one DataFrame into another mutable DataFrame at specified position. -----   In contrast to @copyMDataFrame'@, this function allows to copy over a range of contiguous---   indices over a single dimension.+--   In contrast to @copyDataFrame'@, this function allows to copy over a range+--    of contiguous indices over a single dimension. --   For example, you can write a 3x4 matrix into a 7x4 matrix, starting at indices 0..3.-copyDataFrame :: forall (t :: Type)-                        (b :: Nat) (bi :: Nat) (bd :: Nat)-                        (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-               . ( b ~ (bi + bd - 1)-                 , PrimBytes t-                 , PrimBytes (DataFrame t (bd :+ bs))-                 , ConcatList as (b :+ bs) asbs-                 )-              => Idxs (as +: bi) -> DataFrame t (bd :+ bs)-              -> IODataFrame t asbs -> IO ()-copyDataFrame ei df (IODataFrame mdf) = IO (copyDataFrame# ei df mdf)+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function copies only as+--   many elements as fits into the dataframe along this dimension (possibly none).+copyDataFrame ::+       forall (t :: Type) b bi bd as bs asbs+     . ( SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs+       , PrimArray t (DataFrame t (bd :+ bs))+       , ConcatList as (b :+ bs) asbs )+    => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> IODataFrame t asbs -> IO ()+copyDataFrame = coerce (copyDataFrame# @t @_ @b @bi @bd @as @bs @asbs) {-# INLINE copyDataFrame #-}  -- | Copy one mutable DataFrame into another mutable DataFrame at specified position. -----   In contrast to @copyMDataFrame'@, this function allows to copy over a range of contiguous---   indices over a single dimension.+--   In contrast to @copyMutableDataFrame'@, this function allows to copy over a range+--    of contiguous indices over a single dimension. --   For example, you can write a 3x4 matrix into a 7x4 matrix, starting at indices 0..3.-copyMutableDataFrame :: forall (t :: Type)-                               (b :: Nat) (bi :: Nat) (bd :: Nat)-                               (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-                      . ( b ~ (bi + bd - 1)-                        , PrimBytes t-                        , ConcatList as (b :+ bs) asbs-                        )-                     => Idxs (as +: bi) -> IODataFrame t (bd :+ bs)-                     -> IODataFrame t asbs -> IO ()-copyMutableDataFrame ei (IODataFrame mdfA) (IODataFrame mdfB)-    = IO (copyMDataFrame# ei mdfA mdfB)+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function copies only as+--   many elements as fits into the dataframe along this dimension (possibly none).+copyMutableDataFrame ::+       forall (t :: Type) b bi bd as bs asbs+     . ( SubFrameIndexCtx b bi bd+       , ExactDims bs+       , PrimBytes t+       , ConcatList as (b :+ bs) asbs )+    => Idxs (as +: bi) -> IODataFrame t (bd :+ bs) -> IODataFrame t asbs -> IO ()+copyMutableDataFrame = coerce (copyMDataFrame# @t @_ @b @bi @bd @as @bs @asbs) {-# INLINE copyMutableDataFrame #-}  -- | Copy one DataFrame into another mutable DataFrame at specified position. -----   This is a simpler version of @copyDataFrame@ that allows to copy over one index at a time.-copyDataFrame' :: forall (t :: Type)-                         (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-                . ( PrimBytes t-                  , PrimBytes (DataFrame t bs)-                  , ConcatList as bs asbs-                 )-               => Idxs as -> DataFrame t bs-               -> IODataFrame t asbs -> IO ()-copyDataFrame' ei df (IODataFrame mdf) = IO (copyDataFrame'# ei df mdf)+--   This is a simpler version of @copyDataFrame@ that allows+--     to copy over one index at a time.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+copyDataFrame' ::+       forall (t :: Type) as bs asbs+     . ( ExactDims bs+       , PrimArray t (DataFrame t bs)+       , ConcatList as bs asbs )+    => Idxs as -> DataFrame t bs -> IODataFrame t asbs -> IO ()+copyDataFrame' = coerce (copyDataFrame'# @t @_ @as @bs @asbs) {-# INLINE copyDataFrame' #-}  -- | Copy one mutable DataFrame into another mutable DataFrame at specified position. -----   This is a simpler version of @copyDataFrame@ that allows to copy over one index at a time.-copyMutableDataFrame' :: forall (t :: Type)-                                (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-                       . ( PrimBytes t-                         , ConcatList as bs asbs-                         )-                      => Idxs as -> IODataFrame t bs-                      -> IODataFrame t asbs -> IO ()-copyMutableDataFrame' ei (IODataFrame mdfA) (IODataFrame mdfB)-  = IO (copyMDataFrame'# ei mdfA mdfB)+--   This is a simpler version of @copyMutableDataFrame@ that allows+--     to copy over one index at a time.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+copyMutableDataFrame' ::+       forall (t :: Type) as bs asbs+     . (ExactDims bs, PrimBytes t, ConcatList as bs asbs)+    => Idxs as -> IODataFrame t bs -> IODataFrame t asbs -> IO ()+copyMutableDataFrame' = coerce (copyMDataFrame'# @t @_ @as @bs @asbs) {-# INLINE copyMutableDataFrame' #-} +-- | Copy one DataFrame into another mutable DataFrame by offset in+--   primitive elements.+--+--   This is a low-level copy function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+copyDataFrameOff ::+       forall (t :: Type) as bs asbs+     . ( Dimensions bs+       , PrimArray t (DataFrame t bs)+       , ConcatList as bs asbs )+    => Int -> DataFrame t bs -> IODataFrame t asbs -> IO ()+copyDataFrameOff = coerce (copyDataFrameOff# @t @_ @as @bs @asbs)+{-# INLINE copyDataFrameOff #-}++-- | Copy one mutable DataFrame into another mutable DataFrame by offset in+--   primitive elements.+--+--   This is a low-level copy function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds+copyMutableDataFrameOff ::+       forall (t :: Type) as bs asbs+     . (ExactDims bs, PrimBytes t, ConcatList as bs asbs)+    => Int -> IODataFrame t bs -> IODataFrame t asbs -> IO ()+copyMutableDataFrameOff = coerce (copyMDataFrameOff# @t @_ @as @bs @asbs)+{-# INLINE copyMutableDataFrameOff #-}+ -- | Make a mutable DataFrame immutable, without copying.-unsafeFreezeDataFrame :: forall (t :: Type) (ns :: [Nat])-                       . PrimArray t (DataFrame t ns)-                      => IODataFrame t ns -> IO (DataFrame t ns)-unsafeFreezeDataFrame (IODataFrame mdf) = IO (unsafeFreezeDataFrame# mdf)+unsafeFreezeDataFrame ::+       forall (t :: Type) ns+     . PrimArray t (DataFrame t ns)+    => IODataFrame t ns -> IO (DataFrame t ns)+unsafeFreezeDataFrame = coerce (unsafeFreezeDataFrame# @t @_ @ns) {-# INLINE unsafeFreezeDataFrame #-} - -- | Copy content of a mutable DataFrame into a new immutable DataFrame.-freezeDataFrame :: forall (t :: Type) (ns :: [Nat])-                 . PrimArray t (DataFrame t ns)-                => IODataFrame t ns -> IO (DataFrame t ns)-freezeDataFrame (IODataFrame mdf) = IO (freezeDataFrame# mdf)+freezeDataFrame ::+       forall (t :: Type) ns+     . PrimArray t (DataFrame t ns)+    => IODataFrame t ns -> IO (DataFrame t ns)+freezeDataFrame = coerce (freezeDataFrame# @t @_ @ns) {-# INLINE freezeDataFrame #-}  -- | Create a new mutable DataFrame and copy content of immutable one in there.-thawDataFrame :: forall (t :: Type) (ns :: [Nat])-               . (Dimensions ns, PrimBytes (DataFrame t ns))-              => DataFrame t ns -> IO (IODataFrame t ns)-thawDataFrame df = IODataFrame <$> IO (thawDataFrame# df)+thawDataFrame ::+       forall (t :: Type) ns+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns -> IO (IODataFrame t ns)+thawDataFrame = coerce (thawDataFrame# @t @_ @ns) {-# INLINE thawDataFrame #-}  -- | Create a new mutable DataFrame and copy content of immutable one in there. --   The result array is pinned and aligned.-thawPinDataFrame :: forall (t :: Type) (ns :: [Nat])-                  . (Dimensions ns, PrimBytes (DataFrame t ns))-                 => DataFrame t ns -> IO (IODataFrame t ns)-thawPinDataFrame df = IODataFrame <$> IO (thawPinDataFrame# df)+thawPinDataFrame ::+       forall (t :: Type) ns+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns -> IO (IODataFrame t ns)+thawPinDataFrame = coerce (thawPinDataFrame# @t @_ @ns) {-# INLINE thawPinDataFrame #-}  -- | UnsafeCoerces an underlying byte array.-unsafeThawDataFrame :: forall (t :: Type) (ns :: [Nat])-                     . ( Dimensions ns-                       , PrimBytes (DataFrame t ns), PrimBytes t)-                    => DataFrame t ns -> IO (IODataFrame t ns)-unsafeThawDataFrame df = IODataFrame <$> IO (unsafeThawDataFrame# df)+unsafeThawDataFrame ::+       forall (t :: Type) ns+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns+    -> IO (IODataFrame t ns)+unsafeThawDataFrame = coerce (unsafeThawDataFrame# @t @_ @ns) {-# INLINE unsafeThawDataFrame #-} ---- | Write a single element at the specified index-writeDataFrame :: forall t (ns :: [Nat])-                . PrimBytes t-               => IODataFrame t ns -> Idxs ns -> DataFrame t ('[] :: [Nat]) -> IO ()-writeDataFrame (IODataFrame mdf) ei = IO . writeDataFrame# mdf ei . unsafeCoerce#-{-# INLINE writeDataFrame #-}----- | Read a single element at the specified index-readDataFrame :: forall (t :: Type) (ns :: [Nat])-               . PrimBytes t-              => IODataFrame t ns -> Idxs ns -> IO (DataFrame t ('[] :: [Nat]))-readDataFrame (IODataFrame mdf) = unsafeCoerce# . IO . readDataFrame# mdf-{-# INLINE readDataFrame #-}-+-- | Given two continuations @f@ and @g@.+--   If the input DataFrame is a single broadcast value, use it in @f@.+--   Otherwise, create a new mutable DataFrame and copy content of immutable one+--   in there; then use it in @g@.+--+--   This function is useful when @thawDataFrame@ cannot be used due to+--   @Dimensions ns@ constraint being not available.+withThawDataFrame ::+       forall (t :: Type) ns r+     . PrimArray t (DataFrame t ns)+    => (t -> IO r)+    -> (IODataFrame t ns -> IO r)+    -> DataFrame t ns -> IO r+withThawDataFrame = coerce (withThawDataFrame# @t @_ @ns @r) --- | Write a single element at the specified element offset-writeDataFrameOff :: forall (t :: Type) (ns :: [Nat])-                   . PrimBytes t-               => IODataFrame t ns -> Int -> DataFrame t ('[] :: [Nat])  -> IO ()-writeDataFrameOff (IODataFrame mdf) (I# i)-  = IO . writeDataFrameOff# mdf i . unsafeCoerce#+-- | Write a single element at the specified element offset.+--+--   This is a low-level write function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+writeDataFrameOff ::+       forall (t :: Type) ns+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => IODataFrame t ns -> Int -> DataFrame t ('[] :: KindOf ns) -> IO ()+writeDataFrameOff = coerce (writeDataFrameOff# @t @_ @ns) {-# INLINE writeDataFrameOff #-} +-- | Write a single element at the specified index.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+writeDataFrame ::+       forall (t :: Type) ns+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => IODataFrame t ns -> Idxs ns -> DataFrame t ('[] :: KindOf ns) -> IO ()+writeDataFrame = coerce (writeDataFrame# @t @_ @ns)+{-# INLINE writeDataFrame #-} --- | Read a single element at the specified element offset-readDataFrameOff :: forall (t :: Type) (ns :: [Nat])-                  . PrimBytes t-               => IODataFrame t ns -> Int -> IO (DataFrame t ('[] :: [Nat]))-readDataFrameOff (IODataFrame mdf) (I# i)-  = unsafeCoerce# (IO (readDataFrameOff# mdf i))+-- | Read a single element at the specified element offset.+--+--   This is a low-level read function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you read beyond the DataFrame bounds.+readDataFrameOff ::+       forall (t :: Type) ns+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => IODataFrame t ns -> Int -> IO (DataFrame t ('[] :: KindOf ns))+readDataFrameOff = coerce (readDataFrameOff# @t @_ @ns) {-# INLINE readDataFrameOff #-} +-- | Read a single element at the specified index.+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+readDataFrame ::+       forall (t :: Type) ns+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => IODataFrame t ns -> Idxs ns -> IO (DataFrame t ('[] :: KindOf ns))+readDataFrame = coerce (readDataFrame# @t @_ @ns)+{-# INLINE readDataFrame #-}  -- | Check if the byte array wrapped by this DataFrame is pinned, --   which means cannot be relocated by GC.-isDataFramePinned :: forall (k :: Type) (t :: Type) (ns :: [k])-                   . KnownDimKind k-                  => IODataFrame t ns -> Bool-isDataFramePinned df = case dimKind @k of-    DimNat -> case df of-      IODataFrame x -> isDataFramePinned# x-    DimXNat -> case df of-      XIOFrame (IODataFrame x) -> isDataFramePinned# x+isDataFramePinned ::+       forall (t :: Type) ns . IODataFrame t ns -> Bool+isDataFramePinned = coerce (isDataFramePinned# @t @_ @ns)+{-# INLINE isDataFramePinned #-} +-- | Get cumulative dimensions @ns@ of a @IODataFrame t ns@+getDataFrameSteps ::+       forall (t :: Type) ns . IODataFrame t ns -> CumulDims+getDataFrameSteps = coerce (getDataFrameSteps# @t @_ @ns)+{-# INLINE getDataFrameSteps #-}  -- | Allow arbitrary IO operations on a pointer to the beginning of the data --   keeping the data from garbage collecting until the arg function returns.@@ -233,15 +377,9 @@ -- --   Warning: use this function on a pinned DataFrame only; --            otherwise, the data may be relocated before the arg fun finishes.-withDataFramePtr :: forall (k :: Type) (t :: Type) (ns :: [k]) (r :: Type)-                  . (PrimBytes t, KnownDimKind k)-                 => IODataFrame t ns-                 -> ( Ptr t -> IO r )-                 -> IO r-withDataFramePtr df k = case dimKind @k of-    DimNat -> case df of-      IODataFrame x-        -> IO $ withDataFramePtr# x (\p -> case k (Ptr p) of IO f -> f)-    DimXNat -> case df of-      XIOFrame (IODataFrame x)-        -> IO $ withDataFramePtr# x (\p -> case k (Ptr p) of IO f -> f)+withDataFramePtr ::+       forall (t :: Type) ns (r :: Type)+     . PrimBytes t => IODataFrame t ns -> (Ptr t -> IO r) -> IO r+withDataFramePtr (IODataFrame x) k+  = IO (withDataFramePtr# x (\p -> case k (Ptr p) of IO f -> f))+{-# INLINE withDataFramePtr #-}
src/Numeric/DataFrame/Internal/Backend.hs view
@@ -2,6 +2,7 @@ {-# LANGUAGE ConstraintKinds       #-} {-# LANGUAGE DataKinds             #-} {-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE PolyKinds             #-} {-# LANGUAGE RoleAnnotations       #-}@@ -9,15 +10,39 @@ {-# LANGUAGE TypeApplications      #-} {-# LANGUAGE TypeFamilies          #-} {-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-} {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} #if defined(__HADDOCK__) || defined(__HADDOCK_VERSION__) {-# OPTIONS_GHC -fno-warn-simplifiable-class-constraints #-} #else {-# OPTIONS_GHC -fplugin Data.Constraint.Deriving #-} #endif+{-+This module contains all generic and specific instances for all backend+(implementation) types. Its hs-boot counterpart provides only generic instances+(that do not depend on BackendFamily).+Import this module only at the root of the module hierarchy, where the specific+implementation-dependent modules do not need to depend on it.+But do not forget to import this module in the places that will be imported by+the user (such as Numeric.DataFrame). So that the user can benefit from the+compile-time knowledge of the specific backend implementation. +By design the import chain is as follows:++NDI.Backend.Family.hs-boot            NDI.Backend.Family+         \                                   |+    NDI.Backend.hs-boot               NDI.Backend (instances only)+          \                                 /+     NDI.BackendI                          /+            \                             /+    Numeric.DataFrame.Type               /+                    \                   /+                     \                 /+                     Numeric.DataFrame++ -} module Numeric.DataFrame.Internal.Backend-  ( DFBackend, Backend (..), BackendFamily, KnownBackend ()+  ( Backend (..), BackendFamily, KnownBackend ()   , inferKnownBackend, inferPrimElem     -- * Auto-deriving instances   , inferEq, inferOrd@@ -47,15 +72,15 @@                                                                     inferKnownBackend,                                                                     inferPrimArray,                                                                     inferPrimElem)-import           Numeric.DataFrame.Internal.BackendI       (I) --- | Implementation behind the DataFrame-type DFBackend (t :: Type) (ds :: [Nat]) = Backend I t ds (BackendFamily t ds)  -- | Backend resolver: --   Use this constraint to find any class instances defined for all DataFrame implementations, --   e.g. @Num@, @PrimBytes@, etc.-type KnownBackend (t :: Type) (ds :: [Nat]) = Impl.KnownBackend t ds (BackendFamily t ds)+class Impl.KnownBackend t ds (BackendFamily t ds)+   => KnownBackend (t :: Type) (ds :: [Nat])+instance Impl.KnownBackend t ds (BackendFamily t ds)+   => KnownBackend (t :: Type) (ds :: [Nat])  -- | A newtype wrapper for all DataFrame implementations. --   I need two layers of wrappers to provide default overlappable instances to@@ -65,12 +90,12 @@ newtype Backend (i :: Type) (t :: Type) (ds :: [Nat]) (backend :: Type)     = Backend { _getBackend :: backend } type role Backend phantom phantom phantom representational-type instance DeriveContext (Backend I t ds b) = b ~ BackendFamily t ds--- When typechecker knows what the third parameter @b@ is, no instances overlap,+type instance DeriveContext (Backend i t ds b) = b ~ BackendFamily t ds+-- When typechecker knows what the fourth parameter @b@ is, no instances overlap, -- because @b@ is always always a concrete type. -- The "dynamic instances" derived via ToInstance have to be incoherent, -- because @BackendFamily t ds@ as a type family (before resolving it)---  is no more conrete than just @b@.+--  is no more concrete than just @b@. {-# ANN type Backend (DeriveAll' NoOverlap ["KnownBackend"]) #-}  @@ -80,47 +105,48 @@    . (PrimBytes t, Dimensions ds)   => Dict (KnownBackend t ds) inferKnownBackend-  = Impl.inferKnownBackend @t @ds @(BackendFamily t ds)+  = case Impl.inferKnownBackend @t @ds @(BackendFamily t ds) of+      Dict -> Dict  inferPrimElem-  :: forall (t :: Type) (d :: Nat) (ds :: [Nat])+  :: forall (t :: Type) (d :: Nat) (ds :: [Nat]) (i :: Type)    . KnownBackend t (d ': ds)-  => DFBackend t (d ': ds) -> Dict (PrimBytes t)+  => Backend i t (d ': ds) (BackendFamily t (d ': ds)) -> Dict (PrimBytes t) inferPrimElem = Impl.inferPrimElem @t @d @ds . _getBackend    inferEq-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Eq t, Impl.KnownBackend t ds b)-  => Dict (Eq (Backend I t ds b))+  => Dict (Eq (Backend i t ds b)) inferEq     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))     $ inferDeriveContext @t @ds @b undefined  inferOrd-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (Ord (Backend I t ds b))+  => Dict (Ord (Backend i t ds b)) inferOrd     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))     $ inferDeriveContext @t @ds @b undefined  inferProductOrder-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (ProductOrder (Backend I t ds b))+  => Dict (ProductOrder (Backend i t ds b)) inferProductOrder     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))     $ inferDeriveContext @t @ds @b undefined  inferPONonTransitive-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (Ord (NonTransitive.ProductOrd (Backend I t ds b)))+  => Dict (Ord (NonTransitive.ProductOrd (Backend i t ds b))) inferPONonTransitive     = mapDict (unsafeDerive NonTransitive.ProductOrd)     . mapDict toBackend@@ -128,9 +154,9 @@     $ inferDeriveContext @t @ds @b undefined  inferPOPartial-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (Ord (Partial.ProductOrd (Backend I t ds b)))+  => Dict (Ord (Partial.ProductOrd (Backend i t ds b))) inferPOPartial     = mapDict (unsafeDerive Partial.ProductOrd)     . mapDict toBackend@@ -138,9 +164,9 @@     $ inferDeriveContext @t @ds @b undefined  inferBounded-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Bounded t, Impl.KnownBackend t ds b)-  => Dict (Bounded (Backend I t ds b))+  => Dict (Bounded (Backend i t ds b)) inferBounded     -- Here is an ugly trick:     --  We don't have instance of @Bounded Float@ and @Bounded Double@.@@ -160,27 +186,27 @@     $ inferDeriveContext @t @ds @b undefined  inferNum-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Num t, Impl.KnownBackend t ds b)-  => Dict (Num (Backend I t ds b))+  => Dict (Num (Backend i t ds b)) inferNum     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))     $ inferDeriveContext @t @ds @b undefined  inferFractional-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Fractional t, Impl.KnownBackend t ds b)-  => Dict (Fractional (Backend I t ds b))+  => Dict (Fractional (Backend i t ds b)) inferFractional     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))     $ inferDeriveContext @t @ds @b undefined  inferFloating-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Floating t, Impl.KnownBackend t ds b)-  => Dict (Floating (Backend I t ds b))+  => Dict (Floating (Backend i t ds b)) inferFloating     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))@@ -188,18 +214,18 @@   inferPrimBytes-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (PrimBytes t, Dimensions ds, Impl.KnownBackend t ds b)-  => Dict (PrimBytes (Backend I t ds b))+  => Dict (PrimBytes (Backend i t ds b)) inferPrimBytes     = mapDict toBackend     . mapDict (Sub (Impl.inferBackendInstance @t @ds))     $ inferDeriveContext @t @ds @b undefined  inferPrimArray-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (PrimBytes t, Impl.KnownBackend t ds b)-  => Dict (PrimArray t (Backend I t ds b))+  => Dict (PrimArray t (Backend i t ds b)) inferPrimArray     = mapDict toBackend     . mapDict (Sub (Impl.inferPrimArray @t @ds))@@ -208,14 +234,14 @@  -- This is the rule that cannot be encoded in the type system, but enforced -- as an invariant: Backend t ds b implies DeriveContext t ds b-inferDeriveContext :: forall (t :: Type) (ds :: [Nat]) (b :: Type)-                    . Backend I t ds b-                   -> Dict (DeriveContext (Backend I t ds b))+inferDeriveContext :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)+                    . Backend i t ds b+                   -> Dict (DeriveContext (Backend i t ds b)) inferDeriveContext _ = unsafeCoerce (Dict :: Dict (b ~ b)) {-# INLINE inferDeriveContext #-}  -- Backend is the newtype wrapper over b. -- It has the same represenation and I expect it to have the same instance behavior.-toBackend :: forall c t ds b . c b :- c (Backend I t ds b)+toBackend :: forall c t ds b i . c b :- c (Backend i t ds b) toBackend = unsafeDerive Backend {-# INLINE toBackend #-}
src/Numeric/DataFrame/Internal/Backend.hs-boot view
@@ -1,17 +1,22 @@-{-# LANGUAGE CPP              #-}-{-# LANGUAGE ConstraintKinds  #-}-{-# LANGUAGE DataKinds        #-}-{-# LANGUAGE ExplicitForAll   #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE PolyKinds        #-}-{-# LANGUAGE RoleAnnotations  #-}-{-# LANGUAGE TypeOperators    #-}+{-# LANGUAGE CPP                   #-}+{-# LANGUAGE ConstraintKinds       #-}+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE ExplicitForAll        #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RoleAnnotations       #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-} #if defined(__HADDOCK__) || defined(__HADDOCK_VERSION__) {-# OPTIONS_GHC -fno-warn-simplifiable-class-constraints #-} #endif  module Numeric.DataFrame.Internal.Backend-  ( DFBackend, Backend (..), BackendFamily, KnownBackend ()+  ( Backend (..), BackendFamily, KnownBackend ()   , inferKnownBackend, inferPrimElem     -- * Auto-deriving instances   , inferEq, inferOrd@@ -32,21 +37,12 @@ import {-# SOURCE #-} Numeric.DataFrame.Internal.Backend.Family (BackendFamily) import {-# SOURCE #-} qualified Numeric.DataFrame.Internal.Backend.Family as Impl                                                                                    (KnownBackend)-import {-# SOURCE #-} Numeric.DataFrame.Internal.BackendI       (I) --- | Implementation behind the DataFrame-type DFBackend (t :: Type) (ds :: [Nat]) = Backend I t ds (BackendFamily t ds)---- | Backend resolver:---   Use this constraint to find any class instances defined for all DataFrame implementations,---   e.g. @Num@, @PrimBytes@, etc.-type KnownBackend (t :: Type) (ds :: [Nat]) = Impl.KnownBackend t ds (BackendFamily t ds)+class Impl.KnownBackend t ds (BackendFamily t ds)+   => KnownBackend (t :: Type) (ds :: [Nat])+instance Impl.KnownBackend t ds (BackendFamily t ds)+   => KnownBackend (t :: Type) (ds :: [Nat]) --- | A newtype wrapper for all DataFrame implementations.---   I need two layers of wrappers to provide default overlappable instances to---   all type classes using KnownBackend mechanics.---   Type arguments are redundant here;---   nevertheless, they improve readability of error messages. newtype Backend (i :: Type) (t :: Type) (ds :: [Nat]) (backend :: Type)     = Backend { _getBackend :: backend } type role Backend phantom phantom phantom representational@@ -57,61 +53,61 @@   => Dict (KnownBackend t ds)  inferPrimElem-  :: forall (t :: Type) (d :: Nat) (ds :: [Nat])+  :: forall (t :: Type) (d :: Nat) (ds :: [Nat]) (i :: Type)    . KnownBackend t (d ': ds)-  => DFBackend t (d ': ds) -> Dict (PrimBytes t)+  => Backend i t (d ': ds) (BackendFamily t (d ': ds)) -> Dict (PrimBytes t)  inferEq-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Eq t, Impl.KnownBackend t ds b)-  => Dict (Eq (Backend I t ds b))+  => Dict (Eq (Backend i t ds b))  inferOrd-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (Ord (Backend I t ds b))+  => Dict (Ord (Backend i t ds b))  inferProductOrder-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (ProductOrder (Backend I t ds b))+  => Dict (ProductOrder (Backend i t ds b))  inferPONonTransitive-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (Ord (NonTransitive.ProductOrd (Backend I t ds b)))+  => Dict (Ord (NonTransitive.ProductOrd (Backend i t ds b)))  inferPOPartial-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Ord t, Impl.KnownBackend t ds b)-  => Dict (Ord (Partial.ProductOrd (Backend I t ds b)))+  => Dict (Ord (Partial.ProductOrd (Backend i t ds b)))  inferBounded-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Bounded t, Impl.KnownBackend t ds b)-  => Dict (Bounded (Backend I t ds b))+  => Dict (Bounded (Backend i t ds b))  inferNum-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Num t, Impl.KnownBackend t ds b)-  => Dict (Num (Backend I t ds b))+  => Dict (Num (Backend i t ds b))  inferFractional-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Fractional t, Impl.KnownBackend t ds b)-  => Dict (Fractional (Backend I t ds b))+  => Dict (Fractional (Backend i t ds b))  inferFloating-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (Floating t, Impl.KnownBackend t ds b)-  => Dict (Floating (Backend I t ds b))+  => Dict (Floating (Backend i t ds b))  inferPrimBytes-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (PrimBytes t, Dimensions ds, Impl.KnownBackend t ds b)-  => Dict (PrimBytes (Backend I t ds b))+  => Dict (PrimBytes (Backend i t ds b))  inferPrimArray-  :: forall (t :: Type) (ds :: [Nat]) (b :: Type)+  :: forall (t :: Type) (ds :: [Nat]) (b :: Type) (i :: Type)    . (PrimBytes t, Impl.KnownBackend t ds b)-  => Dict (PrimArray t (Backend I t ds b))+  => Dict (PrimArray t (Backend i t ds b))
src/Numeric/DataFrame/Internal/BackendI.hs view
@@ -7,31 +7,54 @@ {-# LANGUAGE TypeApplications      #-} #if defined(__HADDOCK__) || defined(__HADDOCK_VERSION__) {-# LANGUAGE FlexibleInstances     #-}-{-# OPTIONS_GHC -fdefer-type-errors #-}-{-# OPTIONS_GHC -fno-warn-deferred-type-errors #-} {-# OPTIONS_GHC -fno-warn-missing-methods #-} {-# OPTIONS_GHC -fno-warn-redundant-constraints #-} {-# OPTIONS_GHC -fno-warn-simplifiable-class-constraints #-} #else {-# OPTIONS_GHC -fplugin Data.Constraint.Deriving #-} #endif+{-+The purpose of this module is to provide incoherent instances of common type classes+for the type @Backend@.+It imports @Backend.hs-boot@ module and thus does not depend on the actual+implementation of @BackendFamily@.+Import this module instead of @Backend.hs-boot@ in the places that must not depend+on @BackendFamily@, such as @Numeric.DataFrame.Type@. +By design the import chain is as follows:++NDI.Backend.Family.hs-boot            NDI.Backend.Family+         \                                   |+    NDI.Backend.hs-boot               NDI.Backend (instances only)+          \                                 /+     NDI.BackendI                          /+            \                             /+    Numeric.DataFrame.Type               /+                    \                   /+                     \                 /+                     Numeric.DataFrame++ -} module Numeric.DataFrame.Internal.BackendI-  ( I+  ( DFBackend, Backend (..), Backend.BackendFamily, Backend.KnownBackend ()+  , Backend.inferKnownBackend, Backend.inferPrimElem+#if !defined(__HADDOCK__) && !defined(__HADDOCK_VERSION__)   , inferEq, inferOrd   , inferProductOrder, inferPONonTransitive, inferPOPartial   , inferBounded, inferNum   , inferFractional, inferFloating   , inferPrimBytes, inferPrimArray+#endif   ) where  --import           Data.Constraint.Deriving             (OverlapMode (..),-                                                       ToInstance (..))+#if !defined(__HADDOCK__) && !defined(__HADDOCK_VERSION__)+import Data.Constraint          (Dict)+import Data.Constraint.Deriving (OverlapMode (..), ToInstance (..))+#endif import           Data.Kind                            (Type) import           Numeric.DataFrame.Internal.PrimArray (PrimArray)-import           Numeric.Dimensions                   (Dict, Dimensions, Nat)+import           Numeric.Dimensions                   (Dimensions, Nat) import           Numeric.PrimBytes                    (PrimBytes) import           Numeric.ProductOrd                   (ProductOrder) import qualified Numeric.ProductOrd.NonTransitive     as NonTransitive@@ -43,6 +66,9 @@   +-- | Implementation behind the DataFrame+type DFBackend (t :: Type) (ds :: [Nat]) = Backend I t ds (Impl.BackendFamily t ds)+ {- | The instance keeper for the `Backend` type.    Using this data as a tag to the `Backend` type allows to define `Backend` instances@@ -52,6 +78,10 @@ data I  ++-- The instances below are bumb stubs needed only to compile haddock+#if !defined(__HADDOCK__) && !defined(__HADDOCK_VERSION__)+ {-# ANN inferEq (ToInstance Incoherent) #-} inferEq   :: forall (t :: Type) (ds :: [Nat]) (b :: Type)@@ -129,10 +159,7 @@   => Dict (PrimArray t (Backend I t ds b)) inferPrimArray = Backend.inferPrimArray @t @ds @b ----- The instances below are bumb stubs needed only to compile haddock-#if defined(__HADDOCK__) || defined(__HADDOCK_VERSION__)+#else  instance     forall (t :: Type) (ds :: [Nat]) (b :: Type)
− src/Numeric/DataFrame/Internal/BackendI.hs-boot
@@ -1,9 +0,0 @@-module Numeric.DataFrame.Internal.BackendI (I) where--{- | The instance keeper for the `Backend` type.--  Using this data as a tag to the `Backend` type allows to define `Backend` instances-  in two different modules without any orphans.-- -}-data I
src/Numeric/DataFrame/Internal/Mutable.hs view
@@ -8,6 +8,7 @@ {-# LANGUAGE ScopedTypeVariables       #-} {-# LANGUAGE TypeApplications          #-} {-# LANGUAGE TypeFamilies              #-}+{-# LANGUAGE TypeInType                #-} {-# LANGUAGE TypeOperators             #-} {-# LANGUAGE UnboxedTuples             #-} {-# OPTIONS_GHC -fno-warn-redundant-constraints #-}@@ -17,264 +18,511 @@ -- Copyright   :  (c) Artem Chirkin -- License     :  BSD3 ----- Maintainer  :  chirkin@arch.ethz.ch ----- Interfrace to perform primitive stateful operations on mutable frames.+-- Interface to perform primitive stateful operations on mutable frames. -- -----------------------------------------------------------------------------  module Numeric.DataFrame.Internal.Mutable     ( MDataFrame ()+    , castDataFrame#     , newDataFrame#, newPinnedDataFrame#+    , oneMoreDataFrame#+    , subDataFrameView#, subDataFrameView'#     , copyDataFrame#, copyMDataFrame#     , copyDataFrame'#, copyMDataFrame'#+    , copyDataFrameOff#, copyMDataFrameOff#     , freezeDataFrame#, unsafeFreezeDataFrame#-    , thawDataFrame#, thawPinDataFrame#, unsafeThawDataFrame#+    , thawDataFrame#, thawPinDataFrame#, unsafeThawDataFrame#, withThawDataFrame#     , writeDataFrame#, writeDataFrameOff#     , readDataFrame#, readDataFrameOff#     , withDataFramePtr#, isDataFramePinned#+    , getDataFrameSteps#     ) where - import GHC.Base import Numeric.DataFrame.Internal.PrimArray import Numeric.DataFrame.Type import Numeric.Dimensions import Numeric.PrimBytes - -- | Mutable DataFrame type. --   Keeps element offset, number of elements, and a mutable byte storage-data MDataFrame s t (ns :: [Nat])+data MDataFrame s t (ns :: [k])   = MDataFrame# Int# CumulDims (MutableByteArray# s) +-- | Allow coercing between @XNat@-indexed and @Nat@-indexed Mutable DataFrames.+castDataFrame# ::+       forall (t :: Type) (xns :: [XNat]) (ns :: [Nat]) s+     . FixedDims xns ns+    => MDataFrame s t ns -> MDataFrame s t xns+castDataFrame# (MDataFrame# o c a) = MDataFrame# o c a+{-# INLINE castDataFrame# #-}  -- | Create a new mutable DataFrame.-newDataFrame# :: forall t (ns :: [Nat]) s-               . ( PrimBytes t, Dimensions ns)-              => State# s -> (# State# s, MDataFrame s t ns #)-newDataFrame# s0+newDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . (PrimBytes t, Dimensions ns)+    => State# s -> (# State# s, MDataFrame s t ns #)+newDataFrame#     | steps <- cumulDims $ dims @ns     , n <- cdTotalDim# steps-    , (# s1, mba #) <- newByteArray# (n *# byteSize @t undefined) s0-    = (# s1,  MDataFrame# 0# steps mba #)+      = if isTrue# (n ==# 0#)+        then \s0 -> (# s0, error "Empty DataFrame (DF0)" #)+        else \s0 -> case newByteArray# (n *# byteSize @t undefined) s0 of+                          (# s1, mba #) -> (# s1,  MDataFrame# 0# steps mba #) {-# INLINE newDataFrame# #-}  -- | Create a new mutable DataFrame.-newPinnedDataFrame# :: forall t (ns :: [Nat]) s-                     . ( PrimBytes t, Dimensions ns)-                    => State# s -> (# State# s, MDataFrame s t ns #)-newPinnedDataFrame# s0+newPinnedDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . (PrimBytes t, Dimensions ns)+    => State# s -> (# State# s, MDataFrame s t ns #)+newPinnedDataFrame#     | steps <- cumulDims $ dims @ns     , n <- cdTotalDim# steps-    , (# s1, mba #)  <- newAlignedPinnedByteArray#-        (n *# byteSize @t undefined)-        (byteAlign @t undefined) s0-    = (# s1,  MDataFrame# 0# steps mba #)+      = if isTrue# (n ==# 0#)+        then \s0 -> (# s0, error "Empty DataFrame (DF0)" #)+        else \s0 -> case newAlignedPinnedByteArray#+                          (n *# byteSize @t undefined)+                          (byteAlign @t undefined) s0 of+                          (# s1, mba #) -> (# s1,  MDataFrame# 0# steps mba #) {-# INLINE newPinnedDataFrame# #-} +-- | Create a new mutable DataFrame of the same size.+oneMoreDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . MDataFrame s t ns -> State# s -> (# State# s, MDataFrame s t ns #)+oneMoreDataFrame# mdf@(MDataFrame# off steps mba) s0+    | 0# <- cdTotalDim# steps = (# s0, mdf #)+    | (# s1, bs #) <- getSizeofMutableByteArray# mba s0+    , (# s2, mba' #) <- newByteArray# (bs -# off) s1+      = (# s2,  MDataFrame# 0# steps mba' #)+{-# INLINE oneMoreDataFrame# #-}++-- | View a part of a DataFrame.+--+--   This function does not perform a copy.+--   All changes to a new DataFrame will be reflected in the original DataFrame as well.+--+--   If any of the dims in @as@ or @b@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+subDataFrameView# ::+       forall (t :: Type) (k :: Type)+              (b :: k) (bi :: k) (bd :: k)+              (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs)+    => Idxs (as +: bi) -> MDataFrame s t asbs -> MDataFrame s t (bd :+ bs)+subDataFrameView# ei (MDataFrame# offM stepsM arr)+    = MDataFrame# (case offA of I# i -> i) stepsA arr+  where+    (offA, stepsA) = getOffAndStepsSub (I# offM) stepsM ei (dim @bd)++-- | View a part of a DataFrame.+--+--   This function does not perform a copy.+--   All changes to a new DataFrame will be reflected in the original DataFrame as well.+--+--   This is a simpler version of @subDataFrameView@ that allows+--    to view over one index at a time.+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+subDataFrameView'# ::+       forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . ConcatList as bs asbs+    => Idxs as -> MDataFrame s t asbs -> MDataFrame s t bs+subDataFrameView'# ei (MDataFrame# offM stepsM arr)+    = MDataFrame# (case offA of I# i -> i) stepsA arr+  where+    (offA, stepsA) = getOffAndSteps (I# offM) stepsM ei+ -- | Copy one DataFrame into another mutable DataFrame at specified position. -----   In contrast to @copyDataFrame'@, this function allows to copy over a range of contiguous---   indices over a single dimension.+--   In contrast to @copyDataFrame'@, this function allows to copy over a range+--    of contiguous indices over a single dimension. --   For example, you can write a 3x4 matrix into a 7x4 matrix, starting at indices 0..3.-copyDataFrame# :: forall (t :: Type)-                         (b :: Nat) (bi :: Nat) (bd :: Nat)-                         (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                . ( b ~ (bi + bd - 1)-                  , PrimBytes t-                  , PrimBytes (DataFrame t (bd :+ bs))-                  , ConcatList as (b :+ bs) asbs-                  )-               => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> MDataFrame s t asbs-               -> State# s -> (# State# s, () #)-copyDataFrame# ei df (MDataFrame# off steps mba) s-    | I# i <- cdIx steps ei-    = (# writeBytes mba ((off +# i) *# byteSize @t undefined) df s, () #)+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function copies only as+--   many elements as fits into the dataframe along this dimension (possibly none).+copyDataFrame# ::+       forall (t :: Type) (k :: Type)+              (b :: k) (bi :: k) (bd :: k)+              (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . ( SubFrameIndexCtx b bi bd, KnownDim bd+       , ExactDims bs+       , PrimArray t (DataFrame t (bd :+ bs))+       , ConcatList as (b :+ bs) asbs )+    => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> MDataFrame s t asbs+    -> State# s -> (# State# s, () #)+copyDataFrame# ei df (MDataFrame# offM stepsM arrDest)+    | elS <- byteSize @t undefined+    , Just (I# offDest, stepsB)+         <- getOffAndStepsSubM (I# offM) stepsM ei (dim @bd)+    , n <- cdTotalDim# stepsB+    , isTrue# (n ># 0#) -- is there enough space to write anything?+    = withArrayContent+      (\e s -> (# fillArray arrDest offDest n e s, () #))+      (\_ offSrc arrSrc s ->+        (# copyByteArray# arrSrc  (offSrc *# elS)+                          arrDest (offDest *# elS) (n *# elS) s, () #)) df+    | otherwise = \s -> (# s, () #) {-# INLINE copyDataFrame# #-} - {-# ANN copyMDataFrame# "HLint: ignore Use camelCase" #-} -- | Copy one mutable DataFrame into another mutable DataFrame at specified position. -----   In contrast to @copyMDataFrame'@, this function allows to copy over a range of contiguous---   indices over a single dimension.+--   In contrast to @copyMutableDataFrame'@, this function allows to copy over a range+--    of contiguous indices over a single dimension. --   For example, you can write a 3x4 matrix into a 7x4 matrix, starting at indices 0..3.-copyMDataFrame# :: forall (t :: Type)-                          (b :: Nat) (bi :: Nat) (bd :: Nat)-                          (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                 . ( b ~ (bi + bd - 1)-                   , PrimBytes t-                   , ConcatList as (b :+ bs) asbs-                   )-                => Idxs (as +: bi) -> MDataFrame s t (bd :+ bs) -> MDataFrame s t asbs-                -> State# s -> (# State# s, () #)-                     -- all information for copying in this case is taken from the inside-                     -- of the data types at the term level;-                     -- steps zips with indices just fine independently of their types-                     -- and length.-                     -- Thus, it's fine here to just unsafeCoerce# an index.-copyMDataFrame# ei df =-  copyMDataFrame'#-     (unsafeCoerce# ei :: Idxs as)-     (unsafeCoerce# df :: MDataFrame s t (b :+ bs))+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function copies only as+--   many elements as fits into the dataframe along this dimension (possibly none).+copyMDataFrame# ::+       forall (t :: Type) (k :: Type)+              (b :: k) (bi :: k) (bd :: k)+              (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . ( SubFrameIndexCtx b bi bd+       , ExactDims bs+       , PrimBytes t+       , ConcatList as (b :+ bs) asbs )+    => Idxs (as +: bi) -> MDataFrame s t (bd :+ bs) -> MDataFrame s t asbs+    -> State# s -> (# State# s, () #)+copyMDataFrame# ei (MDataFrame# offA (CumulDims ~(bb:b:_)) arrA)+                   (MDataFrame# offM stepsM arrM)+    | elS <- byteSize @t undefined+    , Just (I# offDest, stepsB)+         <- getOffAndStepsSubM (I# offM) stepsM ei (unsafeCoerce# (quot bb b))+    , n <- cdTotalDim# stepsB+    , isTrue# (n ># 0#) -- is there enough space to write anything?+    = \s -> (# copyMutableByteArray# arrA (offA *# elS)+                                     arrM (offDest *# elS) (n *# elS) s+             , () #)+    | otherwise = \s -> (# s, () #) {-# INLINE copyMDataFrame# #-}  {-# ANN copyDataFrame'# "HLint: ignore Use camelCase" #-} -- | Copy one DataFrame into another mutable DataFrame at specified position. -----   This is a simpler version of @copyDataFrame@ that allows to copy over one index at a time.-copyDataFrame'# :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                . ( PrimBytes t-                  , PrimBytes (DataFrame t bs)-                  , ConcatList as bs asbs-                  )-               => Idxs as -> DataFrame t bs -> MDataFrame s t asbs-               -> State# s -> (# State# s, () #)-copyDataFrame'# ei df (MDataFrame# off steps mba) s-    | I# i <- cdIx steps ei-    = (# writeBytes mba ((off +# i) *# byteSize @t undefined) df s, () #)+--   This is a simpler version of @copyDataFrame@ that allows+--     to copy over one index at a time.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+copyDataFrame'# ::+       forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . ( ExactDims bs+       , PrimArray t (DataFrame t bs)+       , ConcatList as bs asbs )+    => Idxs as -> DataFrame t bs -> MDataFrame s t asbs+    -> State# s -> (# State# s, () #)+copyDataFrame'# ei df (MDataFrame# offM stepsM arrDest)+    | elS <- byteSize @t undefined+    , Just (I# offDest, stepsA) <- getOffAndStepsM (I# offM) stepsM ei+    , n <- cdTotalDim# stepsA+    = withArrayContent+      (\e s -> (# fillArray arrDest offDest n e s, () #))+      (\_ offSrc arrSrc s ->+        (# copyByteArray# arrSrc  (offSrc *# elS)+                          arrDest (offDest *# elS) (n *# elS) s, () #)) df+    | otherwise = \s -> (# s, () #) {-# INLINE copyDataFrame'# #-}  {-# ANN copyMDataFrame'# "HLint: ignore Use camelCase" #-} -- | Copy one mutable DataFrame into another mutable DataFrame at specified position. -----   This is a simpler version of @copyMDataFrame@ that allows to copy over one index at a time.-copyMDataFrame'# :: forall (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                 . ( PrimBytes t-                   , ConcatList as bs asbs-                   )-                => Idxs as -> MDataFrame s t bs -> MDataFrame s t asbs-                -> State# s -> (# State# s, () #)-copyMDataFrame'# ei (MDataFrame# offA stepsA arrA) (MDataFrame# offM stepsM arrM) s+--   This is a simpler version of @copyMutableDataFrame@ that allows+--     to copy over one index at a time.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+copyMDataFrame'# ::+       forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . (ExactDims bs, PrimBytes t, ConcatList as bs asbs)+    => Idxs as -> MDataFrame s t bs -> MDataFrame s t asbs+    -> State# s -> (# State# s, () #)+copyMDataFrame'# ei (MDataFrame# offA stepsA arrA) (MDataFrame# offM stepsM arrM)     | elS <- byteSize @t undefined     , lenA <- cdTotalDim# stepsA-    , I# i <- cdIx stepsM ei-    = (# copyMutableByteArray# arrA (offA *# elS)-                               arrM ((offM +# i) *# elS) (lenA *# elS) s-       , () #)+    , Just (I# i) <- cdIxM stepsM ei+    = \s -> (# copyMutableByteArray#+                 arrA (offA *# elS)+                 arrM ((offM +# i) *# elS) (lenA *# elS) s, () #)+    | otherwise = \s -> (# s, () #) {-# INLINE copyMDataFrame'# #-} +-- | Copy one DataFrame into another mutable DataFrame by offset in+--   primitive elements.+--+--   This is a low-level copy function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+copyDataFrameOff# ::+       forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . ( Dimensions bs+       , PrimArray t (DataFrame t bs)+       , ConcatList as bs asbs )+    => Int -> DataFrame t bs -> MDataFrame s t asbs+    -> State# s -> (# State# s, () #)+copyDataFrameOff# (I# off) df (MDataFrame# offM _ arrDest)+    | elS <- byteSize @t undefined+    , offDest <- offM +# off+    = withArrayContent+      (\e s ->+        (# fillArray arrDest offDest+              (case totalDim (dims @bs) of W# n -> word2Int# n) e s, () #))+      (\steps offSrc arrSrc s ->+        (# copyByteArray# arrSrc  (offSrc *# elS)+                          arrDest (offDest *# elS)+                                  (cdTotalDim# steps *# elS) s, () #)) df+{-# INLINE copyDataFrameOff# #-}++-- | Copy one mutable DataFrame into another mutable DataFrame by offset in+--   primitive elements.+--+--   This is a low-level copy function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+copyMDataFrameOff# ::+       forall (t :: Type) (k :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k]) s+     . (ExactDims bs, PrimBytes t, ConcatList as bs asbs)+    => Int -> MDataFrame s t bs -> MDataFrame s t asbs+    -> State# s -> (# State# s, () #)+copyMDataFrameOff# (I# off) (MDataFrame# offA stepsA arrA)+                            (MDataFrame# offM _      arrM)+    | elS <- byteSize @t undefined+    , lenA <- cdTotalDim# stepsA+    = \s -> (# copyMutableByteArray#+                 arrA (offA *# elS)+                 arrM ((offM +# off) *# elS) (lenA *# elS) s, () #)+{-# INLINE copyMDataFrameOff# #-}+ -- | Make a mutable DataFrame immutable, without copying.-unsafeFreezeDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                        . PrimArray t (DataFrame t ns)-                       => MDataFrame s t ns-                       -> State# s -> (# State# s, DataFrame t ns #)-unsafeFreezeDataFrame# (MDataFrame# offM steps arrM) s1-    | (# s2, arrA #) <- unsafeFreezeByteArray# arrM s1-    = (# s2, fromElems steps offM arrA #)+unsafeFreezeDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . PrimArray t (DataFrame t ns)+    => MDataFrame s t ns+    -> State# s -> (# State# s, DataFrame t ns #)+unsafeFreezeDataFrame# (MDataFrame# offM steps arrM) s0+    | 0# <- cdTotalDim# steps+      = (# s0, error "Empty DataFrame (DF0)" #)+    | (# s1, arrA #) <- unsafeFreezeByteArray# arrM s0+      = (# s1, fromElems steps offM arrA #) {-# INLINE unsafeFreezeDataFrame# #-}  -- | Copy content of a mutable DataFrame into a new immutable DataFrame.-freezeDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                  . PrimArray t (DataFrame t ns)-                 => MDataFrame s t ns -> State# s -> (# State# s, DataFrame t ns #)+freezeDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . PrimArray t (DataFrame t ns)+    => MDataFrame s t ns -> State# s -> (# State# s, DataFrame t ns #) freezeDataFrame# (MDataFrame# offM steps arrM) s0+    | 0# <- cdTotalDim# steps+      = (# s0, error "Empty DataFrame (DF0)" #)     | elS  <- byteSize @t undefined     , n <- cdTotalDim# steps     , (# s1, mba #) <- newByteArray# (n *# elS) s0     , s2 <- copyMutableByteArray# arrM (offM *# elS) mba 0# (n *# elS) s1     , (# s3, arrA #) <- unsafeFreezeByteArray# mba s2-    = (# s3, fromElems steps 0# arrA #)+      = (# s3, fromElems steps 0# arrA #) {-# INLINE freezeDataFrame# #-}  -- | Create a new mutable DataFrame and copy content of immutable one in there.-thawDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                . ( Dimensions ns-                  , PrimBytes (DataFrame t ns))-               => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)+thawDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #) thawDataFrame# df s0-    | arrA  <- getBytes df-    , boff  <- byteOffset df-    , bsize <- byteSize df-    , steps <- cumulDims $ dims @ns-    , (# s1, arrM #) <- newByteArray# bsize s0-    , s2 <- copyByteArray# arrA boff arrM 0# bsize s1-    = (# s2, MDataFrame# 0# steps arrM #)+    | nw == 0+      = (# s0, error "Empty DataFrame (DF0)" #)+    | bSize <- case nw of W# w -> byteSize @t undefined *# word2Int# w+    , (# s1, arrM #) <- newByteArray# bSize s0+    , r <- MDataFrame# 0# steps arrM+    , (# s2, _ #) <- copyDataFrameOff# 0 df r s1+      = (# s2, r #)+  where+    nw = cdTotalDim steps+    steps = getSteps (dims @ns) df {-# INLINE thawDataFrame# #-}  -- | Create a new mutable DataFrame and copy content of immutable one in there. --   The result array is pinned and aligned.-thawPinDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                . ( Dimensions ns-                  , PrimBytes (DataFrame t ns))-               => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #)+thawPinDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns -> State# s -> (# State# s, MDataFrame s t ns #) thawPinDataFrame# df s0-    | arrA  <- getBytes df-    , boff  <- byteOffset df-    , bsize <- byteSize df-    , steps <- cumulDims $ dims @ns-    , (# s1, arrM #) <- newAlignedPinnedByteArray# bsize (byteAlign df) s0-    , s2 <- copyByteArray# arrA boff arrM 0# bsize s1-    = (# s2, MDataFrame# 0# steps arrM #)+    | nw == 0+      = (# s0, error "Empty DataFrame (DF0)" #)+    | bSize <- case nw of W# w -> byteSize @t undefined *# word2Int# w+    , (# s1, arrM #) <- newAlignedPinnedByteArray# bSize (byteAlign @t undefined) s0+    , r <- MDataFrame# 0# steps arrM+    , (# s2, _ #) <- copyDataFrameOff# 0 df r s1+      = (# s2, r #)+  where+    nw = cdTotalDim steps+    steps = getSteps (dims @ns) df {-# INLINE thawPinDataFrame# #-}  -- | UnsafeCoerces an underlying byte array.-unsafeThawDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                      . ( Dimensions ns-                        , PrimBytes (DataFrame t ns), PrimBytes t)-                     => DataFrame t ns-                     -> State# s -> (# State# s, MDataFrame s t ns #)-unsafeThawDataFrame# df s0-    | elS  <- byteSize @t undefined-    , arrA <- getBytes df-    , boff <- byteOffset df-    , steps <- cumulDims $ dims @ns-    = (# s0-       , MDataFrame# (quotInt# boff elS) steps (unsafeCoerce# arrA)-       #)+unsafeThawDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns+    -> State# s -> (# State# s, MDataFrame s t ns #)+unsafeThawDataFrame# = withArrayContent f g+  where+    f :: t -> State# s -> (# State# s, MDataFrame s t ns #)+    f e s0+      | steps <- cumulDims (dims @ns)+      , n <- cdTotalDim# steps+      , (# s1, arrM #) <- newByteArray# (n *# byteSize @t undefined) s0+      = (# fillArray arrM 0# n e s1, MDataFrame# 0# steps arrM #)+    g :: CumulDims -> Int# -> ByteArray# -> State# s -> (# State# s, MDataFrame s t ns #)+    g steps off ba s0+      = (# s0, MDataFrame# off steps (unsafeCoerce# ba) #) {-# INLINE unsafeThawDataFrame# #-} +-- | Given two continuations @f@ and @g@.+--   If the input DataFrame is a single broadcast value, use it in @f@.+--   Otherwise, create a new mutable DataFrame and copy content of immutable one+--   in there; then use it in @g@.+--+--   This function is useful when @thawDataFrame@ cannot be used due to+--   @Dimensions ns@ constraint being not available.+withThawDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) (r :: Type) s+     . PrimArray t (DataFrame t ns)+    => (t -> State# s -> (# State# s, r #)) -- ^ f+    -> (MDataFrame s t ns -> State# s -> (# State# s, r #)) -- ^ g+    -> DataFrame t ns+    -> State# s -> (# State# s, r #)+withThawDataFrame# f g = withArrayContent f g'+  where+    g' :: CumulDims -> Int# -> ByteArray# -> State# s -> (# State# s, r #)+    g' steps eOff arrA s0 = case cdTotalDim# steps of+      0# -> g (error "Empty DataFrame (DF0)") s0+      elems+       | elS <- byteSize @t undefined+       , bsize <- elS *# elems+       , (# s1, arrM #) <- newByteArray# bsize s0+       , s2 <- copyByteArray# arrA (eOff *# elS) arrM 0# bsize s1+         -> g (MDataFrame# 0# steps arrM) s2+{-# INLINE withThawDataFrame# #-} --- | Write a single element at the specified element offset-writeDataFrameOff# :: forall (t :: Type) (ns :: [Nat]) s-                    . PrimBytes t-                   => MDataFrame s t ns -> Int# -> t -> State# s -> (# State# s, () #)-writeDataFrameOff# (MDataFrame# off _ mba) i x s+-- | Write a single element at the specified element offset.+--+--   This is a low-level write function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+writeDataFrameOff# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . PrimBytes (DataFrame t ('[] :: [k]))+    => MDataFrame s t ns -> Int -> DataFrame t ('[] :: [k])+    -> State# s -> (# State# s, () #)+writeDataFrameOff# (MDataFrame# off _ mba) (I# i) x s   = (# writeArray mba (off +# i) x s, () #) {-# INLINE writeDataFrameOff# #-} --- | Write a single element at the specified index-writeDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                 . PrimBytes t-                => MDataFrame s t ns -> Idxs ns -> t -> State# s -> (# State# s, () #)+-- | Write a single element at the specified index.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+writeDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . PrimBytes (DataFrame t ('[] :: [k]))+    => MDataFrame s t ns -> Idxs ns -> DataFrame t ('[] :: [k])+    -> State# s -> (# State# s, () #) writeDataFrame# mdf@(MDataFrame# _ st _) ei-  | I# i <- cdIx st ei = writeDataFrameOff# mdf i+  | Just off <- (cdIxM st ei)+  = writeDataFrameOff# mdf off+  | otherwise = const (\s -> (# s, () #)) {-# INLINE writeDataFrame# #-} --- | Read a single element at the specified element offset-readDataFrameOff# :: forall (t :: Type) (ns :: [Nat]) s-                   . PrimBytes t-                  => MDataFrame s t ns -> Int# -> State# s -> (# State# s, t #)-readDataFrameOff# (MDataFrame# off _ mba) i = readArray mba (off +# i)+-- | Read a single element at the specified element offset.+--+--   This is a low-level read function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you read beyond the DataFrame bounds.+readDataFrameOff# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . PrimBytes (DataFrame t ('[] :: [k]))+    => MDataFrame s t ns -> Int+    -> State# s -> (# State# s, DataFrame t ('[] :: [k]) #)+readDataFrameOff# (MDataFrame# off _ mba) (I# i)+  = readArray @(DataFrame t ('[] :: [k])) mba (off +# i) {-# INLINE readDataFrameOff# #-} --- | Read a single element at the specified index-readDataFrame# :: forall (t :: Type) (ns :: [Nat]) s-                . PrimBytes t-               => MDataFrame s t ns -> Idxs ns -> State# s -> (# State# s, t #)+-- | Read a single element at the specified index.+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+readDataFrame# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . PrimBytes (DataFrame t ('[] :: [k]))+    => MDataFrame s t ns -> Idxs ns+    -> State# s -> (# State# s, DataFrame t ('[] :: [k]) #) readDataFrame# mdf@(MDataFrame# _ st _) ei-  | I# i <- cdIx st ei = readDataFrameOff# mdf i+  = readDataFrameOff# mdf (cdIx st ei) {-# INLINE readDataFrame# #-}  -- | Allow arbitrary operations on a pointer to the beginning of the data. --   Only possible with @RealWord@ state (thus, in @IO@) due to semantics of --   @touch#@ operation that keeps the data from being garbage collected.-withDataFramePtr# :: forall (t :: Type) (ns :: [Nat]) (r :: Type)-                   . PrimBytes t-                  => MDataFrame RealWorld t ns-                  -> ( Addr# -> State# RealWorld -> (# State# RealWorld, r #) )-                  -> State# RealWorld -> (# State# RealWorld, r #)+withDataFramePtr# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) (r :: Type)+     . PrimBytes t+    => MDataFrame RealWorld t ns+    -> (Addr# -> State# RealWorld -> (# State# RealWorld, r #))+    -> State# RealWorld -> (# State# RealWorld, r #) withDataFramePtr# (MDataFrame# off _ mba) k s0   | (# s1, a #) <- unsafeFreezeByteArray# mba s0   , (# s2, r #) <- k ( byteArrayContents# a                        `plusAddr#` (off *# byteSize @t undefined)                      ) s1-  = (# touch# mba s2, r #)+    = (# touch# mba s2, r #)+{-# INLINE withDataFramePtr# #-}  -- | Check if the byte array wrapped by this DataFrame is pinned, --   which means cannot be relocated by GC.-isDataFramePinned# :: forall (t :: Type) (ns :: [Nat]) s-                    . MDataFrame s t ns -> Bool+isDataFramePinned# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s . MDataFrame s t ns -> Bool isDataFramePinned# (MDataFrame# _ _ mba)   = isTrue# (isMutableByteArrayPinned# mba)++-- | Get cumulative dimensions @ns@ of a @MDataFrame s t ns@+getDataFrameSteps# ::+       forall (t :: Type) (k :: Type) (ns :: [k]) s+     . MDataFrame s t ns -> CumulDims+getDataFrameSteps# (MDataFrame# _ c _) = c+{-# INLINE getDataFrameSteps# #-}++-- | Fill a mutable byte array with the same single element+fillArray :: PrimBytes t+          => MutableByteArray# s+          -> Int# -- ^ Offset in elements+          -> Int# -- ^ Number of elements+          -> t+          -> State# s -> State# s+fillArray mba off n e+  = let lim = off +# n+        go i s | isTrue# (i >=# lim) = s+               | otherwise           = go (i +# 1#) (writeArray mba i e s)+    in  go off+{-# INLINE fillArray #-}
src/Numeric/DataFrame/Internal/PrimArray.hs view
@@ -1,27 +1,40 @@ {-# LANGUAGE CPP                    #-} {-# LANGUAGE DataKinds              #-}+{-# LANGUAGE ExplicitForAll         #-}+{-# LANGUAGE FlexibleInstances      #-} {-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE GADTs                  #-} {-# LANGUAGE MagicHash              #-} {-# LANGUAGE MultiParamTypeClasses  #-} {-# LANGUAGE PolyKinds              #-}+{-# LANGUAGE TypeOperators          #-} {-# LANGUAGE UnboxedTuples          #-} module Numeric.DataFrame.Internal.PrimArray   ( PrimArray (..), CumulDims (..)-  , cumulDims, cdTotalDim, cdTotalDim#, cdIx+  , cumulDims, cdTotalDim, cdTotalDim#+  , cdIx, cdIxSub, getOffAndSteps, getOffAndStepsSub+  , cdIxM, getOffAndStepsM, getOffAndStepsSubM   , ixOff, unsafeFromFlatList, getSteps, fromSteps+  , withArrayContent, fromElems, broadcast   ) where -import Data.Monoid        as Mon (Monoid (..))-import Data.Semigroup     as Sem (Semigroup (..))-import GHC.Base           (ByteArray#, Int (..), Int#, Word (..), word2Int#)+import Control.Arrow  ((***))+import Data.Monoid    as Mon (Monoid (..))+import Data.Semigroup as Sem (Semigroup (..))+import GHC.Base       hiding (foldr)+ -- (ByteArray#, Int (..), Int#, RuntimeRep (..), Type,+ --                           Word (..), inline, runRW#, touch#, word2Int#, (+#))+import GHC.Exts           (TYPE) import Numeric.Dimensions import Numeric.PrimBytes + -- | Given @Dims ns@, @CumulativeDims@ is a list of length @Length ns + 1@; --   which cumulative @totalDim@ accumulated on the right. --   In particular, its first element is @totalDim ds@, --   its last element is always is always @1@. newtype CumulDims = CumulDims { unCumulDims :: [Word] }+  deriving Show  instance Sem.Semigroup CumulDims where     CumulDims as <> CumulDims bs = CumulDims $ map (head bs *) (init as) ++ bs@@ -49,16 +62,128 @@ -- --   Note, you can take offset of subspace with CumulDims of larger space --     - very convenient!+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system. cdIx :: CumulDims -> Idxs ns -> Int-cdIx ~(CumulDims ~(_:steps))-  = fromIntegral . sum . zipWith (*) steps . listIdxs+cdIx steps+  = fromIntegral . fst . getOffAndSteps' 0 0 (unCumulDims steps) . listIdxs +-- | Calculate offset of an Idxs.+--+--   Also check if the last index plus dimVal of subN is not bigger than the+--   corresponding dim inside CumulDims; throw an `OutOfDimBounds` otherwise.+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+cdIxSub :: CumulDims -> Idxs (ns +: idxN) -> Dim subN -> Int+cdIxSub steps idxs d+  = fromIntegral+  . fst . getOffAndSteps' (dimVal d) 0 (unCumulDims steps) $ listIdxs idxs++-- | Calculate offset of an Idxs and return remaining CumulDims.+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+getOffAndSteps :: Int -- ^ Initial offset+               -> CumulDims -> Idxs ns -> (Int, CumulDims)+getOffAndSteps off0 steps+  = (fromIntegral *** CumulDims)+  . getOffAndSteps' 0 (fromIntegral off0) (unCumulDims steps) . listIdxs++-- | Calculate offset of an Idxs and return remaining CumulDims.+--+--   Also check if the last index plus dimVal of subN is not bigger than the+--   corresponding dim inside CumulDims; throw an `OutOfDimBounds` otherwise.+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+getOffAndStepsSub :: Int -- ^ Initial offset+                  -> CumulDims -> Idxs (ns +: idxN)+                  -> Dim subN -> (Int, CumulDims)+getOffAndStepsSub off0 steps idxs d+  = (fromIntegral *** CumulDims)+  . getOffAndSteps' (dimVal d) (fromIntegral off0) (unCumulDims steps)+  $ listIdxs idxs+++getOffAndSteps' :: Word -> Word -> [Word] -> [Word] -> (Word, [Word])+getOffAndSteps' sub0 off0 steps0 is0 = go sub0 off0 steps0 is0+  where+#ifndef UNSAFE_INDICES+    ds0 = case fromSteps (CumulDims steps0) of SomeDims x -> listDims x+#endif+    go :: Word -> Word -> [Word] -> [Word] -> (Word, [Word])+    go 0 off steps [] = (off, steps)+    go sub off ~(steps@(s:_)) [] = (off, sub*s : steps)+#ifndef UNSAFE_INDICES+    go sub _ ~(bs:(s:_)) [i]+      | b <- quot bs s+      , sub > 0 && i + sub > b+      = outOfDimBoundsNoCallStack+          "{Calculating SubDataFrame offset}"+          i b (Just sub) (Just (ds0, is0))+    go _ _ ~(bs:(s:_)) (i:_)+      | b <- quot bs s+      , i >= b+      = outOfDimBoundsNoCallStack+          "{Calculating SubDataFrame offset}"+          i b Nothing (Just (ds0, is0))+#endif+    go sub off ~(_:steps@(s:_)) (i:ixs)+      = go sub (off + i*s) steps ixs+{-# INLINE getOffAndSteps' #-}++++-- | Same as `cdIx`, but safe; returns @Nothing@ if out of bounds.+cdIxM :: CumulDims -> Idxs ns -> Maybe Int+cdIxM steps+  = fmap (fromIntegral . fst)+  . getOffAndStepsM' 0 0 (unCumulDims steps) . listIdxs++-- | Same as `getOffAndSteps`, but safe; returns @Nothing@ if out of bounds.+--   Trims the first (slicing) dimension of the returned CumulDims to fit+--   the original dataframe if necessary.+getOffAndStepsM :: Int -- ^ Initial offset+                -> CumulDims -> Idxs ns -> Maybe (Int, CumulDims)+getOffAndStepsM off0 steps+  = fmap (fromIntegral *** CumulDims)+  . getOffAndStepsM' 0 (fromIntegral off0) (unCumulDims steps) . listIdxs++-- | Same as `getOffAndStepsSub`, but safe; returns @Nothing@ if out of bounds.+--   Trims the first (slicing) dimension of the returned CumulDims to fit+--   the original dataframe if necessary.+getOffAndStepsSubM :: Int -- ^ Initial offset+                  -> CumulDims -> Idxs (ns +: idxN)+                  -> Dim subN -> Maybe (Int, CumulDims)+getOffAndStepsSubM off0 steps idxs d+  = fmap (fromIntegral *** CumulDims)+  . getOffAndStepsM' (dimVal d) (fromIntegral off0) (unCumulDims steps)+  $ listIdxs idxs++getOffAndStepsM' :: Word -> Word -> [Word] -> [Word] -> Maybe (Word, [Word])+getOffAndStepsM' = go+  where+    go :: Word -> Word -> [Word] -> [Word] -> Maybe (Word, [Word])+    go _   off steps [] = Just (off, steps)+    go sub off ~(bs:steps@(s:_)) (i:ixs)+      | is >= bs       = Nothing+      | not (null ixs) = go sub (off + is) steps ixs+      | sub == 0       = Just (off + is, steps)+      | otherwise      = Just (off + is, min (bs - is) (sub*s) : steps)+      where+        is = i*s+{-# INLINE getOffAndStepsM' #-}+ -- | Try to get @CumulDims@ from an array, --   and create it using @Dims@ if failed. getSteps :: PrimArray t a => Dims (ns :: [k]) -> a -> CumulDims-getSteps dds df = case uniqueOrCumulDims df of-   Left  _  -> cumulDims dds-   Right ds -> ds+getSteps dds = withArrayContent (const $ cumulDims dds) (\cd _ _ -> cd) {-# INLINE getSteps #-}  -- | Get @Dims@ by "de-accumulating" @CumulDims@.@@ -75,9 +200,14 @@  class PrimBytes t => PrimArray t a | a -> t where     -- | Broadcast element into array-    broadcast :: t -> a+    --+    --   Warning: do not use this function at the call site; use `broadcast`+    --            instead. Otherwise you will miss some rewrite rules.+    broadcast# :: t -> a     -- | Index an array given an offset     ix# :: Int# -> a -> t+    ix# i = withArrayContent id (\_ off arr -> indexArray arr (off +# i))+    {-# INLINE ix# #-}     -- | Generate an array using an accumulator funtion     gen# :: CumulDims             -- ^ Dimensionality of the result array;@@ -92,17 +222,26 @@             --   types and is not checked at runtime.          -> Int# -> t -> a -> a -    -- | If the array represented as a single broadcasted value,-    --   return this value.-    --   Otherwise, return full array content:+    -- | If the array is represented as a single broadcasted value, return this+    --   this value. Otherwise, return the full array content:     --    @CumulDims@, array offset (elements), byte array with the content.-    arrayContent# :: a -> (# t | (# CumulDims, Int#, ByteArray# #) #)+    --+    --   Warning: never use this function directly. Use `withArrayContent` instead.+    --            There is a bug in GHC 8.6, such that certain optimizations+    --            (probably, instance specialization/rewrite rules) break the code,+    --            which is only observable at runtime. The effect is that the+    --            content of a `ByteArray#` becomes a garbage. The workaround is+    --            to use a non-inlinable wrapper to disable these optimizations.+    --            In addition, the wrapper function has some rewrite rules, which+    --            can potentially improve performance with other GHC versions.+    withArrayContent# :: forall (rep :: RuntimeRep) (r :: TYPE rep)+                       . (t -> r)+                      -> (CumulDims -> Int# -> ByteArray# -> r)+                      -> a -> r      -- | Offset of an array as a number of elements     offsetElems :: a -> Int#-    offsetElems a = case arrayContent# a of-      (# _ | #)             -> 0#-      (# | (# _, o, _ #) #) -> o+    offsetElems a = withArrayContent (\_ f -> f 0#) (const $ \o _ f -> f o) a (\i -> i)     {-# INLINE offsetElems #-}      -- | Normally, this returns a cumulative @totalDim@s.@@ -114,18 +253,25 @@     --   Note, this function returns the only unique element only if it is     --   a such by construction (there is no equality checks involved).     uniqueOrCumulDims :: a -> Either t CumulDims-    uniqueOrCumulDims a = case arrayContent# a of-      (# x | #)              -> Left x-      (# | (# cd, _, _ #) #) -> Right cd+    uniqueOrCumulDims = withArrayContent Left (\cd _ _ -> Right cd)     {-# INLINE uniqueOrCumulDims #-} -    -- | Get array by its offset and cumulative dims in a ByteArray.+    -- | Define an array by its offset and cumulative dims in a ByteArray.     --   Both offset and dims are given in element number (not in bytes).     ---    --   It is better to use this function instead of @fromBytes@ to avoid-    --   recalculating @CumulDims@ for implementations that require it.-    fromElems :: CumulDims -> Int# -> ByteArray# -> a+    --   Warning: never use this function directly. Use `fromElems` instead.+    --            There is a bug in GHC 8.6, such that certain optimizations+    --            (probably, instance specialization/rewrite rules) break the code,+    --            which is only observable at runtime. The effect is that the+    --            content of a `ByteArray#` becomes a garbage. The workaround is+    --            to use a non-inlinable wrapper to disable these optimizations.+    --            In addition, the wrapper function has some rewrite rules, which+    --            can potentially improve performance with other GHC versions.+    fromElems# :: CumulDims -> Int# -> ByteArray# -> a +{-# WARNING fromElems# "Please, use fromElems instead." #-}+{-# WARNING withArrayContent# "Please, use withArrayContent instead." #-}+ -- | Index array by an integer offset (starting from 0). ixOff :: PrimArray t a => Int -> a -> t ixOff (I# i) = ix# i@@ -138,3 +284,51 @@   where     f []     = (# [], x0 #)     f (x:xs) = (# xs, x #)++-- | If the array is represented as a single broadcasted value, return this+--   this value. Otherwise, return the full array content:+--    @CumulDims@, array offset (elements), byte array with the content.+withArrayContent :: forall (t :: Type) (a :: Type)+                           (rep :: RuntimeRep) (r :: TYPE rep)+                  . PrimArray t a+                 => (t -> r)+                 -> (CumulDims -> Int# -> ByteArray# -> r)+                 -> a -> r+withArrayContent = withArrayContent#+#if __GLASGOW_HASKELL__ == 806+{-# NOINLINE withArrayContent #-}+#else+{-# INLINE[1] withArrayContent #-}+#endif++-- | Define an array by its offset and cumulative dims in a ByteArray.+--   Both offset and dims are given in element number (not in bytes).+--+--   It is better to use this function instead of @fromBytes@ to avoid+--   recalculating @CumulDims@ for implementations that require it.+fromElems :: forall (t :: Type) (a :: Type)+           . PrimArray t a => CumulDims -> Int# -> ByteArray# -> a+fromElems = fromElems#+#if __GLASGOW_HASKELL__ == 806+{-# NOINLINE fromElems #-}+#else+{-# INLINE[1] fromElems #-}+#endif++-- | Broadcast element into array+broadcast :: forall (t :: Type) (a :: Type)+           . PrimArray t a => t -> a+broadcast = broadcast#+{-# INLINE[1] broadcast #-}++{-# RULES++"withArrayContent/id"+  withArrayContent broadcast fromElems = id++"withArrayContent+fromElems" forall f g cd off ba .+  withArrayContent f g (fromElems cd off ba) = g cd off ba++"withArrayContent+broadcast" forall f g e .+  withArrayContent f g (broadcast e) = f e+  #-}
src/Numeric/DataFrame/ST.hs view
@@ -2,14 +2,18 @@ {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleContexts          #-} {-# LANGUAGE FlexibleInstances         #-}+{-# LANGUAGE InstanceSigs              #-} {-# LANGUAGE MagicHash                 #-} {-# LANGUAGE MultiParamTypeClasses     #-}+{-# LANGUAGE PatternSynonyms           #-} {-# LANGUAGE PolyKinds                 #-} {-# LANGUAGE ScopedTypeVariables       #-} {-# LANGUAGE TypeApplications          #-} {-# LANGUAGE TypeFamilies              #-} {-# LANGUAGE TypeInType                #-} {-# LANGUAGE TypeOperators             #-}+{-# LANGUAGE UndecidableInstances      #-}+{-# LANGUAGE ViewPatterns              #-} ----------------------------------------------------------------------------- -- | -- Module      :  Numeric.DataFrame.ST@@ -22,203 +26,344 @@  module Numeric.DataFrame.ST     ( STDataFrame (XSTFrame), SomeSTDataFrame (..)-    , newDataFrame, newPinnedDataFrame+    , castDataFrame+    , newDataFrame, newPinnedDataFrame, oneMoreDataFrame+    , subDataFrameView, subDataFrameView'     , copyDataFrame, copyMutableDataFrame     , copyDataFrame', copyMutableDataFrame'+    , copyDataFrameOff, copyMutableDataFrameOff     , freezeDataFrame, unsafeFreezeDataFrame-    , thawDataFrame, thawPinDataFrame, unsafeThawDataFrame+    , thawDataFrame, thawPinDataFrame, unsafeThawDataFrame, withThawDataFrame     , writeDataFrame, writeDataFrameOff     , readDataFrame, readDataFrameOff-    , isDataFramePinned+    , isDataFramePinned, getDataFrameSteps     ) where --import GHC.Base-import GHC.ST   (ST (..))+import GHC.ST (ST (..)) +import Data.Coerce+import Data.Kind import Numeric.DataFrame.Internal.Mutable import Numeric.DataFrame.Internal.PrimArray import Numeric.DataFrame.Type import Numeric.Dimensions+import Unsafe.Coerce   -- | Mutable DataFrame that lives in ST. --   Internal representation is always a MutableByteArray.-data family STDataFrame s (t :: Type) (ns :: [k])---- | Pure wrapper on a mutable byte array-newtype instance STDataFrame s t (ns :: [Nat]) = STDataFrame (MDataFrame s t (ns :: [Nat]))+newtype STDataFrame s (t :: Type) (ns :: [k]) = STDataFrame (MDataFrame s t (ns :: [k]))  -- | Data frame with some dimensions missing at compile time. --   Pattern-match against its constructor to get a Nat-indexed mutable data frame.-data instance STDataFrame s t (xs :: [XNat])-  = forall (ns :: [Nat]) . Dimensions ns-  => XSTFrame (STDataFrame s t ns)+pattern XSTFrame :: forall s  (t :: Type) (xns :: [XNat]) . ()+                 => forall (ns :: [Nat]) . (FixedDims xns ns, Dimensions ns)+                 => STDataFrame s t ns -> STDataFrame s t xns+pattern XSTFrame df <- (mkXSTFramePat -> XSTFramePat df)+  where+    XSTFrame = castDataFrame+{-# COMPLETE XSTFrame #-} +data XSTFramePat s (t :: Type) (xns :: [XNat])+  = forall (ns :: [Nat]) . (FixedDims xns ns, Dimensions ns)+  => XSTFramePat (STDataFrame s t ns)++mkXSTFramePat :: forall s  (t :: Type) (xns :: [XNat])+               . STDataFrame s t xns -> XSTFramePat s t xns+mkXSTFramePat df+  | SomeDims ds <- fromSteps (getDataFrameSteps df)+  , XDims (Dims :: Dims ns) <- (unsafeCoerce ds) :: Dims xns+    = XSTFramePat @s @t @xns @ns (unsafeCoerce df)+  | otherwise+    = error "XSTFrame pattern: impossible args"+ -- | Mutable DataFrame of unknown dimensionality data SomeSTDataFrame s (t :: Type)   = forall (ns :: [Nat]) . Dimensions ns => SomeSTDataFrame (STDataFrame s t ns) +-- | Allow coercing between @XNat@-indexed and @Nat@-indexed Mutable DataFrames.+castDataFrame ::+       forall (t :: Type) (xns :: [XNat]) (ns :: [Nat]) s+     . FixedDims xns ns+    => STDataFrame s t ns -> STDataFrame s t xns+castDataFrame = coerce (castDataFrame# @t @xns @ns)+{-# INLINE castDataFrame #-}+ -- | Create a new mutable DataFrame.-newDataFrame :: forall t (ns :: [Nat]) s-              . ( PrimBytes t, Dimensions ns)-             => ST s (STDataFrame s t ns)-newDataFrame = STDataFrame <$> ST (newDataFrame# @t @ns)+newDataFrame ::+       forall (t :: Type) ns s+     . (PrimBytes t, Dimensions ns) => ST s (STDataFrame s t ns)+newDataFrame = coerce (newDataFrame# @t @_ @ns) {-# INLINE newDataFrame #-} - -- | Create a new mutable DataFrame.-newPinnedDataFrame :: forall t (ns :: [Nat]) s-                    . ( PrimBytes t, Dimensions ns)-                   => ST s (STDataFrame s t ns)-newPinnedDataFrame = STDataFrame <$> ST (newPinnedDataFrame# @t @ns)+newPinnedDataFrame ::+       forall (t :: Type) ns s+     . (PrimBytes t, Dimensions ns) => ST s (STDataFrame s t ns)+newPinnedDataFrame = coerce (newPinnedDataFrame# @t @_ @ns) {-# INLINE newPinnedDataFrame #-} +-- | Create a new mutable DataFrame of the same size.+oneMoreDataFrame ::+       forall (t :: Type) ns s+     . STDataFrame s t ns -> ST s (STDataFrame s t ns)+oneMoreDataFrame = coerce (oneMoreDataFrame# @t @_ @ns)+{-# INLINE oneMoreDataFrame #-} +-- | View a part of a DataFrame.+--+--   This function does not perform a copy.+--   All changes to a new DataFrame will be reflected in the original DataFrame as well.+--+--   If any of the dims in @as@ or @b@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+subDataFrameView ::+       forall (t :: Type) b bi bd as bs asbs s+     . (SubFrameIndexCtx b bi bd, KnownDim bd, ConcatList as (b :+ bs) asbs)+    => Idxs (as +: bi) -> STDataFrame s t asbs -> STDataFrame s t (bd :+ bs)+subDataFrameView = coerce (subDataFrameView# @t @_ @b @bi @bd @as @bs @asbs)++-- | View a part of a DataFrame.+--+--   This function does not perform a copy.+--   All changes to a new DataFrame will be reflected in the original DataFrame as well.+--+--   This is a simpler version of @subDataFrameView@ that allows+--    to view over one index at a time.+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+subDataFrameView' ::+       forall (t :: Type) as bs asbs s+     . ConcatList as bs asbs+    => Idxs as -> STDataFrame s t asbs -> STDataFrame s t bs+subDataFrameView' = coerce (subDataFrameView'# @t @_ @as @bs @asbs)+ -- | Copy one DataFrame into another mutable DataFrame at specified position. -----   In contrast to @copyMDataFrame'@, this function allows to copy over a range of contiguous---   indices over a single dimension.+--   In contrast to @copyDataFrame'@, this function allows to copy over a range+--    of contiguous indices over a single dimension. --   For example, you can write a 3x4 matrix into a 7x4 matrix, starting at indices 0..3.-copyDataFrame :: forall (t :: Type)-                        (b :: Nat) (bi :: Nat) (bd :: Nat)-                        (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-               . ( b ~ (bi + bd - 1)-                 , PrimBytes t-                 , PrimBytes (DataFrame t (bd :+ bs))-                 , ConcatList as (b :+ bs) asbs-                 )-              => Idxs (as +: bi) -> DataFrame t (bd :+ bs)-              -> STDataFrame s t asbs -> ST s ()-copyDataFrame ei df (STDataFrame mdf) = ST (copyDataFrame# ei df mdf)+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function copies only as+--   many elements as fits into the dataframe along this dimension (possibly none).+copyDataFrame ::+       forall (t :: Type) b bi bd as bs asbs s+     . ( SubFrameIndexCtx b bi bd, KnownDim bd, ExactDims bs+       , PrimArray t (DataFrame t (bd :+ bs))+       , ConcatList as (b :+ bs) asbs )+    => Idxs (as +: bi) -> DataFrame t (bd :+ bs) -> STDataFrame s t asbs -> ST s ()+copyDataFrame = coerce (copyDataFrame# @t @_ @b @bi @bd @as @bs @asbs) {-# INLINE copyDataFrame #-}  -- | Copy one mutable DataFrame into another mutable DataFrame at specified position. -----   In contrast to @copyMDataFrame'@, this function allows to copy over a range of contiguous---   indices over a single dimension.+--   In contrast to @copyMutableDataFrame'@, this function allows to copy over a range+--    of contiguous indices over a single dimension. --   For example, you can write a 3x4 matrix into a 7x4 matrix, starting at indices 0..3.-copyMutableDataFrame :: forall (t :: Type)-                               (b :: Nat) (bi :: Nat) (bd :: Nat)-                               (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                      . ( b ~ (bi + bd - 1)-                        , PrimBytes t-                        , ConcatList as (b :+ bs) asbs-                        )-                     => Idxs (as +: bi) -> STDataFrame s t (bd :+ bs)-                     -> STDataFrame s t asbs -> ST s ()-copyMutableDataFrame ei (STDataFrame mdfA) (STDataFrame mdfB)-    = ST (copyMDataFrame# ei mdfA mdfB)+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function copies only as+--   many elements as fits into the dataframe along this dimension (possibly none).+copyMutableDataFrame ::+       forall (t :: Type) b bi bd as bs asbs s+     . ( SubFrameIndexCtx b bi bd+       , ExactDims bs+       , PrimBytes t+       , ConcatList as (b :+ bs) asbs )+    => Idxs (as +: bi) -> STDataFrame s t (bd :+ bs) -> STDataFrame s t asbs -> ST s ()+copyMutableDataFrame = coerce (copyMDataFrame# @t @_ @b @bi @bd @as @bs @asbs) {-# INLINE copyMutableDataFrame #-}  -- | Copy one DataFrame into another mutable DataFrame at specified position. -----   This is a simpler version of @copyDataFrame@ that allows to copy over one index at a time.-copyDataFrame' :: forall (t :: Type)-                         (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                . ( PrimBytes t-                  , PrimBytes (DataFrame t bs)-                  , ConcatList as bs asbs-                 )-               => Idxs as -> DataFrame t bs-               -> STDataFrame s t asbs -> ST s ()-copyDataFrame' ei df (STDataFrame mdf) = ST (copyDataFrame'# ei df mdf)+--   This is a simpler version of @copyDataFrame@ that allows+--     to copy over one index at a time.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+copyDataFrame' ::+       forall (t :: Type) as bs asbs s+     . ( ExactDims bs+       , PrimArray t (DataFrame t bs)+       , ConcatList as bs asbs )+    => Idxs as -> DataFrame t bs -> STDataFrame s t asbs -> ST s ()+copyDataFrame' = coerce (copyDataFrame'# @t @_ @as @bs @asbs) {-# INLINE copyDataFrame' #-}  -- | Copy one mutable DataFrame into another mutable DataFrame at specified position. -----   This is a simpler version of @copyDataFrame@ that allows to copy over one index at a time.-copyMutableDataFrame' :: forall (t :: Type)-                                (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) s-                       . ( PrimBytes t-                         , ConcatList as bs asbs-                         )-                      => Idxs as -> STDataFrame s t bs-                      -> STDataFrame s t asbs -> ST s ()-copyMutableDataFrame' ei (STDataFrame mdfA) (STDataFrame mdfB)-  = ST (copyMDataFrame'# ei mdfA mdfB)+--   This is a simpler version of @copyMutableDataFrame@ that allows+--     to copy over one index at a time.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+copyMutableDataFrame' ::+       forall (t :: Type) as bs asbs s+     . (ExactDims bs, PrimBytes t, ConcatList as bs asbs)+    => Idxs as -> STDataFrame s t bs -> STDataFrame s t asbs -> ST s ()+copyMutableDataFrame' = coerce (copyMDataFrame'# @t @_ @as @bs @asbs) {-# INLINE copyMutableDataFrame' #-} +-- | Copy one DataFrame into another mutable DataFrame by offset in+--   primitive elements.+--+--   This is a low-level copy function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+copyDataFrameOff ::+       forall (t :: Type) as bs asbs s+     . ( Dimensions bs+       , PrimArray t (DataFrame t bs)+       , ConcatList as bs asbs )+    => Int -> DataFrame t bs -> STDataFrame s t asbs -> ST s ()+copyDataFrameOff = coerce (copyDataFrameOff# @t @_ @as @bs @asbs)+{-# INLINE copyDataFrameOff #-}++-- | Copy one mutable DataFrame into another mutable DataFrame by offset in+--   primitive elements.+--+--   This is a low-level copy function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds+copyMutableDataFrameOff ::+       forall (t :: Type) as bs asbs s+     . (ExactDims bs, PrimBytes t, ConcatList as bs asbs)+    => Int -> STDataFrame s t bs -> STDataFrame s t asbs -> ST s ()+copyMutableDataFrameOff = coerce (copyMDataFrameOff# @t @_ @as @bs @asbs)+{-# INLINE copyMutableDataFrameOff #-}+ -- | Make a mutable DataFrame immutable, without copying.-unsafeFreezeDataFrame :: forall (t :: Type) (ns :: [Nat]) s-                       . PrimArray t (DataFrame t ns)-                      => STDataFrame s t ns -> ST s (DataFrame t ns)-unsafeFreezeDataFrame (STDataFrame mdf) = ST (unsafeFreezeDataFrame# mdf)+unsafeFreezeDataFrame ::+       forall (t :: Type) ns s+     . PrimArray t (DataFrame t ns)+    => STDataFrame s t ns -> ST s (DataFrame t ns)+unsafeFreezeDataFrame = coerce (unsafeFreezeDataFrame# @t @_ @ns) {-# INLINE unsafeFreezeDataFrame #-} - -- | Copy content of a mutable DataFrame into a new immutable DataFrame.-freezeDataFrame :: forall (t :: Type) (ns :: [Nat]) s-                 . PrimArray t (DataFrame t ns)-                => STDataFrame s t ns -> ST s (DataFrame t ns)-freezeDataFrame (STDataFrame mdf) = ST (freezeDataFrame# mdf)+freezeDataFrame ::+       forall (t :: Type) ns s+     . PrimArray t (DataFrame t ns)+    => STDataFrame s t ns -> ST s (DataFrame t ns)+freezeDataFrame = coerce (freezeDataFrame# @t @_ @ns) {-# INLINE freezeDataFrame #-}  -- | Create a new mutable DataFrame and copy content of immutable one in there.-thawDataFrame :: forall (t :: Type) (ns :: [Nat]) s-               . (Dimensions ns, PrimBytes (DataFrame t ns))-              => DataFrame t ns -> ST s (STDataFrame s t ns)-thawDataFrame df = STDataFrame <$> ST (thawDataFrame# df)+thawDataFrame ::+       forall (t :: Type) ns s+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns -> ST s (STDataFrame s t ns)+thawDataFrame = coerce (thawDataFrame# @t @_ @ns) {-# INLINE thawDataFrame #-}  -- | Create a new mutable DataFrame and copy content of immutable one in there. --   The result array is pinned and aligned.-thawPinDataFrame :: forall (t :: Type) (ns :: [Nat]) s-                  . (Dimensions ns, PrimBytes (DataFrame t ns))-                 => DataFrame t ns -> ST s (STDataFrame s t ns)-thawPinDataFrame df = STDataFrame <$> ST (thawPinDataFrame# df)+thawPinDataFrame ::+       forall (t :: Type) ns s+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns -> ST s (STDataFrame s t ns)+thawPinDataFrame = coerce (thawPinDataFrame# @t @_ @ns) {-# INLINE thawPinDataFrame #-}  -- | UnsafeCoerces an underlying byte array.-unsafeThawDataFrame :: forall (t :: Type) (ns :: [Nat]) s-                     . ( Dimensions ns-                       , PrimBytes (DataFrame t ns), PrimBytes t)-                    => DataFrame t ns -> ST s (STDataFrame s t ns)-unsafeThawDataFrame df = STDataFrame <$> ST (unsafeThawDataFrame# df)+unsafeThawDataFrame ::+       forall (t :: Type) ns s+     . (Dimensions ns, PrimArray t (DataFrame t ns))+    => DataFrame t ns+    -> ST s (STDataFrame s t ns)+unsafeThawDataFrame = coerce (unsafeThawDataFrame# @t @_ @ns) {-# INLINE unsafeThawDataFrame #-} ---- | Write a single element at the specified index-writeDataFrame :: forall t (ns :: [Nat]) s-                . PrimBytes t-               => STDataFrame s t ns -> Idxs ns -> DataFrame t ('[] :: [Nat]) -> ST s ()-writeDataFrame (STDataFrame mdf) ei = ST . writeDataFrame# mdf ei . unsafeCoerce#-{-# INLINE writeDataFrame #-}----- | Read a single element at the specified index-readDataFrame :: forall (t :: Type) (ns :: [Nat]) s-               . PrimBytes t-              => STDataFrame s t ns -> Idxs ns -> ST s (DataFrame t ('[] :: [Nat]))-readDataFrame (STDataFrame mdf) = unsafeCoerce# . ST . readDataFrame# mdf-{-# INLINE readDataFrame #-}-+-- | Given two continuations @f@ and @g@.+--   If the input DataFrame is a single broadcast value, use it in @f@.+--   Otherwise, create a new mutable DataFrame and copy content of immutable one+--   in there; then use it in @g@.+--+--   This function is useful when @thawDataFrame@ cannot be used due to+--   @Dimensions ns@ constraint being not available.+withThawDataFrame ::+       forall (t :: Type) ns r s+     . PrimArray t (DataFrame t ns)+    => (t -> ST s r)+    -> (STDataFrame s t ns -> ST s r)+    -> DataFrame t ns -> ST s r+withThawDataFrame = coerce (withThawDataFrame# @t @_ @ns @r) --- | Write a single element at the specified element offset-writeDataFrameOff :: forall (t :: Type) (ns :: [Nat]) s-                   . PrimBytes t-               => STDataFrame s t ns -> Int -> DataFrame t ('[] :: [Nat])  -> ST s ()-writeDataFrameOff (STDataFrame mdf) (I# i)-  = ST . writeDataFrameOff# mdf i . unsafeCoerce#+-- | Write a single element at the specified element offset.+--+--   This is a low-level write function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you write beyond the DataFrame bounds.+writeDataFrameOff ::+       forall (t :: Type) ns s+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => STDataFrame s t ns -> Int -> DataFrame t ('[] :: KindOf ns) -> ST s ()+writeDataFrameOff = coerce (writeDataFrameOff# @t @_ @ns) {-# INLINE writeDataFrameOff #-} +-- | Write a single element at the specified index.+--+--   This function is safe (no `OutOfDimBounds` exception possible).+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   you may happen to write data beyond dataframe bounds.+--   In this case, this function does nothing.+writeDataFrame ::+       forall (t :: Type) ns s+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => STDataFrame s t ns -> Idxs ns -> DataFrame t ('[] :: KindOf ns) -> ST s ()+writeDataFrame = coerce (writeDataFrame# @t @_ @ns)+{-# INLINE writeDataFrame #-} --- | Read a single element at the specified element offset-readDataFrameOff :: forall (t :: Type) (ns :: [Nat]) s-                  . PrimBytes t-               => STDataFrame s t ns -> Int -> ST s (DataFrame t ('[] :: [Nat]))-readDataFrameOff (STDataFrame mdf) (I# i)-  = unsafeCoerce# (ST (readDataFrameOff# mdf i))+-- | Read a single element at the specified element offset.+--+--   This is a low-level read function; you have to keep in mind the row-major+--   layout of Mutable DataFrames. Offset bounds are not checked.+--   You will get an undefined behavior if you read beyond the DataFrame bounds.+readDataFrameOff ::+       forall (t :: Type) ns s+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => STDataFrame s t ns -> Int -> ST s (DataFrame t ('[] :: KindOf ns))+readDataFrameOff = coerce (readDataFrameOff# @t @_ @ns) {-# INLINE readDataFrameOff #-} +-- | Read a single element at the specified index.+--+--   If any of the dims in @ns@ is unknown (@n ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+readDataFrame ::+       forall (t :: Type) ns s+     . PrimBytes (DataFrame t ('[] :: KindOf ns))+    => STDataFrame s t ns -> Idxs ns -> ST s (DataFrame t ('[] :: KindOf ns))+readDataFrame = coerce (readDataFrame# @t @_ @ns)+{-# INLINE readDataFrame #-}  -- | Check if the byte array wrapped by this DataFrame is pinned, --   which means cannot be relocated by GC.-isDataFramePinned :: forall (k :: Type) (t :: Type) (ns :: [k]) s-                   . KnownDimKind k-                  => STDataFrame s t ns -> Bool-isDataFramePinned df = case dimKind @k of-    DimNat -> case df of-      STDataFrame x -> isDataFramePinned# x-    DimXNat -> case df of-      XSTFrame (STDataFrame x) -> isDataFramePinned# x+isDataFramePinned ::+       forall (t :: Type) ns s . STDataFrame s t ns -> Bool+isDataFramePinned = coerce (isDataFramePinned# @t @_ @ns)+{-# INLINE isDataFramePinned #-}++-- | Get cumulative dimensions @ns@ of a @STDataFrame s t ns@+getDataFrameSteps ::+       forall (t :: Type) ns s . STDataFrame s t ns -> CumulDims+getDataFrameSteps = coerce (getDataFrameSteps# @t @_ @ns)+{-# INLINE getDataFrameSteps #-}++_unusedTopBind :: STDataFrame s t ns+_unusedTopBind = STDataFrame undefined
src/Numeric/DataFrame/SubSpace.hs view
@@ -1,503 +1,1265 @@-{-# LANGUAGE BangPatterns            #-}-{-# LANGUAGE DataKinds               #-}-{-# LANGUAGE FlexibleContexts        #-}-{-# LANGUAGE FlexibleInstances       #-}-{-# LANGUAGE FunctionalDependencies  #-}-{-# LANGUAGE MagicHash               #-}-{-# LANGUAGE MultiParamTypeClasses   #-}-{-# LANGUAGE ScopedTypeVariables     #-}-{-# LANGUAGE TypeApplications        #-}-{-# LANGUAGE TypeFamilies            #-}-{-# LANGUAGE TypeOperators           #-}-{-# LANGUAGE UnboxedTuples           #-}-{-# LANGUAGE UndecidableInstances    #-}-{-# LANGUAGE UndecidableSuperClasses #-}--------------------------------------------------------------------------------- |--- Module      :  Numeric.DataFrame.SubSpace--- Copyright   :  (c) Artem Chirkin--- License     :  BSD3--------------------------------------------------------------------------------------module Numeric.DataFrame.SubSpace-  ( SubSpace (..), (!), element-  , ewfoldMap, iwfoldMap-  , ewzip, iwzip-  , indexWise_, elementWise_-  ) where--import Data.Kind-import GHC.Exts--import Numeric.DataFrame.Internal.PrimArray-import Numeric.DataFrame.Type-import Numeric.Dimensions-import Numeric.PrimBytes----- | Operations on DataFrames------ @as@ is an indexing dimensionality------ @bs@ is an element dimensionality------ @t@ is an underlying data type (i.e. Float, Int, Double)----class ( ConcatList as bs asbs-      , Dimensions as-      , Dimensions bs-      , Dimensions asbs-      , PrimArray t (DataFrame t bs)-      , PrimArray t (DataFrame t asbs)-      , PrimBytes   (DataFrame t bs)-      , PrimBytes   (DataFrame t asbs)-      ) => SubSpace (t :: Type) (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-                    | asbs as -> bs, asbs bs -> as, as bs -> asbs where--    -- | Unsafely get a sub-dataframe by its primitive element offset.-    --   The offset is not checked to be aligned to the space structure or for bounds.-    --   Arguments are zero-based primitive element offset and subset ("bs" element)-    --   size (aka `totalDim` of sub dataframe)-    ---    --   Normal indexing can be expressed in terms of `indexOffset#`:-    ---    --   > index i = case (# dimVal (dim @bs), fromEnum i #) of (# I# n, I# j #) -> indexOffset# (n *# j)-    indexOffset# :: Int# -- ^ Prim element offset-                 -> DataFrame t asbs -> DataFrame t bs-    indexOffset# off df = case uniqueOrCumulDims df of-      Left a      -> broadcast a-      Right steps -> fromElems (dropPref (dims @as) steps) (offsetElems df +# off) (getBytes df)-    {-# INLINE [1] indexOffset# #-}--    -- | Unsafely update a sub-dataframe by its primitive element offset.-    --   The offset is not checked to be aligned to the space structure or for bounds.-    --   Arguments are zero-based primitive element offset and subset ("bs" element)-    --   size (aka `totalDim` of sub dataframe)-    ---    --   Normal updating can be expressed in terms of `indexOffset#`:-    ---    --   > update i = case (# dimVal (dim @bs), fromEnum i #) of (# I# n, I# j #) -> updateOffset# (n *# j)-    updateOffset# :: Int# -- ^ Prim element offset-                  -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs-    updateOffset# off x df-      | steps <- getSteps (dims @asbs) df-      , elemBS <- byteSize @t undefined = case runRW#-        ( \s0 -> case newByteArray# (cdTotalDim# steps *# elemBS) s0 of-          (# s1, mba #) -> unsafeFreezeByteArray# mba-            ( writeBytes mba (off *# elemBS) x-              ( writeBytes mba 0# df s1 )-            )-        ) of (# _, r #) -> fromElems steps 0# r-    {-# INLINE [1] updateOffset# #-}--    -- | Get an element by its index in the dataframe-    index :: Idxs as -> DataFrame t asbs -> DataFrame t bs-    index i df = case uniqueOrCumulDims df of-      Left a      -> broadcast a-      Right steps -> case cdIx steps i of-        I# off -> fromElems (dropPref (dims @as) steps) (offsetElems df +# off) (getBytes df)-    {-# INLINE [1] index #-}--    -- | Get a few contiguous elements.-    ---    --   In a sense, this is just a more complicated version of `index`.-    slice :: forall (bi :: Nat) (bd :: Nat) (b' :: Nat) (bs' :: [Nat])-           . ( b' ~ (bi + bd - 1), bs ~ (b' :+ bs'), KnownDim bd)-          => Idxs (as +: bi) -> DataFrame t asbs -> DataFrame t (bd :+ bs')-    slice  i df-      | _ :* Dims <- dims @bs-      , Dict <- inferKnownBackend @t @(bd ': bs')-        = case uniqueOrCumulDims df of-        Left a      -> broadcast a-        Right steps -> case cdIx steps i of-          I# off-            | bsteps <- repHead (dimVal' @bd) (dropPref (dims @as) steps)-              -> fromElems bsteps (offsetElems df +# off) (getBytes df)-      | otherwise = error "SubSpace/slice: impossible arguments"-      where-        repHead y (CumulDims (_:x:xs)) = CumulDims (y*x:x:xs)-        repHead _ steps                = steps--    -- | Set a new value to an element-    update :: Idxs as -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs-    update i x df-      | steps <- getSteps (dims @asbs) df-      , I# off <- cdIx steps i-      , elemBS <- byteSize @t undefined = case runRW#-        ( \s0 -> case newByteArray# (cdTotalDim# steps *# elemBS) s0 of-          (# s1, mba #) -> unsafeFreezeByteArray# mba-            ( writeBytes mba (off *# elemBS) x-              ( writeBytes mba 0# df s1 )-            )-        ) of (# _, r #) -> fromElems steps 0# r-    {-# INLINE [1] update #-}--    -- | Update a few contiguous elements-    ---    --   In a sense, this is just a more complicated version of `update`.-    updateSlice :: forall (bi :: Nat) (bd :: Nat) (b' :: Nat) (bs' :: [Nat])-           . ( b' ~ (bi + bd - 1), bs ~ (b' :+ bs'), KnownDim bd)-          => Idxs (as +: bi) -> DataFrame t (bd :+ bs') -> DataFrame t asbs -> DataFrame t asbs-    updateSlice i x df-      | _ :* Dims <- dims @bs-      , Dict <- inferKnownBackend @t @(bd ': bs')-      , steps <- getSteps (dims @asbs) df-      , I# off <- cdIx steps i-      , elemBS <- byteSize @t undefined = case runRW#-        ( \s0 -> case newByteArray# (cdTotalDim# steps *# elemBS) s0 of-          (# s1, mba #) -> unsafeFreezeByteArray# mba-            ( writeBytes mba (off *# elemBS) x-              ( writeBytes mba 0# df s1 )-            )-        ) of (# _, r #) -> fromElems steps 0# r-      | otherwise = error "SubSpace/updateSlice: impossible arguments"-    {-# INLINE [1] updateSlice #-}--    -- | Map a function over each element of DataFrame-    ewmap  :: forall s (bs' :: [Nat]) (asbs' :: [Nat])-            . SubSpace s as bs' asbs'-           => (DataFrame s bs' -> DataFrame t bs)-           -> DataFrame s asbs' -> DataFrame t asbs-    ewmap f df-      | bsizeT    <- byteSize @t undefined-      , stepsAS   <- cumulDims $ dims @as-      , stepsBS   <- cumulDims $ dims @bs-      , stepsBS'  <- cumulDims $ dims @bs'-      , stepsASBS <- stepsAS <> stepsBS-      , lenAS     <- cdTotalDim# stepsAS-      , lenBS     <- cdTotalDim# stepsBS-      , lenBS'    <- cdTotalDim# stepsBS'-      , lenBSB    <- lenBS *# bsizeT-      , lenASBSB  <- lenAS *# lenBSB-      = let go mba sourceOffE destOffB s-              | isTrue# (destOffB >=# lenASBSB)-                = s-              | otherwise-                = go mba (sourceOffE +# lenBS') (destOffB +# lenBSB)-                     (writeBytes mba destOffB (f (indexOffset# sourceOffE df)) s)-        in  case runRW#-          ( \s0 -> case newByteArray# lenASBSB s0 of-            (# s1, mba #) -> unsafeFreezeByteArray# mba ( go mba 0# 0# s1 )-          ) of (# _, r #) -> fromElems stepsASBS 0# r-    {-# INLINE [1] ewmap #-}--    -- | Map a function over each element with its index of DataFrame-    iwmap  :: forall s (bs' :: [Nat]) (asbs' :: [Nat])-            . SubSpace s as bs' asbs'-           => (Idxs as -> DataFrame s bs' -> DataFrame t bs)-           -> DataFrame s asbs' -> DataFrame t asbs-    iwmap f df-      | bsizeT    <- byteSize @t undefined-      , stepsAS   <- cumulDims $ dims @as-      , stepsBS   <- cumulDims $ dims @bs-      , stepsBS'  <- cumulDims $ dims @bs'-      , stepsASBS <- stepsAS <> stepsBS-      , lenAS     <- cdTotalDim# stepsAS-      , lenBS     <- cdTotalDim# stepsBS-      , lenBS'    <- cdTotalDim# stepsBS'-      , lenBSB    <- lenBS *# bsizeT-      , lenASBSB  <- lenAS *# lenBSB-      = let go _ [] _ _ s = s-            go mba (i:is) sourceOffE destOffB s-                = go mba is (sourceOffE +# lenBS') (destOffB +# lenBSB)-                     (writeBytes mba destOffB (f i (indexOffset# sourceOffE df)) s)-        in  case runRW#-          ( \s0 -> case newByteArray# lenASBSB s0 of-            (# s1, mba #) -> unsafeFreezeByteArray# mba ( go mba [minBound..maxBound] 0# 0# s1 )-          ) of (# _, r #) -> fromElems stepsASBS 0# r-    {-# INLINE [1] iwmap #-}--    -- | Generate a DataFrame by repeating an element-    ewgen :: DataFrame t bs -> DataFrame t asbs-    ewgen df = case uniqueOrCumulDims df of-      Left a -> broadcast a-      Right stepsBS-        | stepsAS <- cumulDims $ dims @as-        , stepsASBS <- stepsAS <> stepsBS-        , elS       <- byteSize @t undefined-        , lenBSB    <- cdTotalDim# stepsBS *# elS-        , lenASBSB  <- cdTotalDim# stepsASBS *# elS-          -> let go mba destOffB s-                   | isTrue# (destOffB >=# lenASBSB)-                     = s-                   | otherwise-                     = go mba (destOffB +# lenBSB)-                          (writeBytes mba destOffB df s)-             in  case runRW#-              ( \s0 -> case newByteArray# lenASBSB s0 of-                (# s1, mba #) -> unsafeFreezeByteArray# mba ( go mba 0# s1 )-              ) of (# _, r #) -> fromElems stepsASBS 0# r-    {-# INLINE [1] ewgen #-}--    -- | Generate a DataFrame by iterating a function (index -> element)-    iwgen :: (Idxs as -> DataFrame t bs) -> DataFrame t asbs-    iwgen f-        | stepsAS <- cumulDims $ dims @as-        , stepsBS <- cumulDims $ dims @bs-        , stepsASBS <- stepsAS <> stepsBS-        , elS       <- byteSize @t undefined-        , lenBSB    <- cdTotalDim# stepsBS *# elS-        , lenASBSB  <- cdTotalDim# stepsASBS *# elS-          = let go _ [] _ s = s-                go mba (i:is) destOffB s-                  = go mba is (destOffB +# lenBSB) (writeBytes mba destOffB (f i) s)-            in  case runRW#-              ( \s0 -> case newByteArray# lenASBSB s0 of-                (# s1, mba #) -> unsafeFreezeByteArray# mba ( go mba [minBound..maxBound] 0# s1 )-              ) of (# _, r #) -> fromElems stepsASBS 0# r-    {-# INLINE [1] iwgen #-}--    -- | Left-associative fold of a DataFrame.-    --   The fold is strict, so accumulater is evaluated to WHNF;-    --   but you'd better make sure that the function is strict enough to not-    --   produce memory leaks deeply inside the result data type.-    ewfoldl :: (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b-    ewfoldl f x0 df = case uniqueOrCumulDims df of-      Left a ->-        let b = broadcast a-            go 0 x = x-            go n x = go (n-1) $! f x b-        in  go (totalDim' @as) x0-      Right stepsASBS-        | stepsBS <- dropPref (dims @as) stepsASBS-        , lenBS   <- cdTotalDim# stepsBS-        , lenASBS <- cdTotalDim# stepsASBS-          -> let go sourceOffE x-                  | isTrue# (sourceOffE >=# lenASBS)-                    = x-                  | otherwise-                    = go (sourceOffE +# lenBS) $! f x (indexOffset# sourceOffE df)-             in  go 0# x0--    -- | Left-associative fold of a DataFrame with an index-    --   The fold is strict, so accumulater is evaluated to WHNF;-    --   but you'd better make sure that the function is strict enough to not-    --   produce memory leaks deeply inside the result data type.-    iwfoldl :: (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b-    iwfoldl f x0 df = case uniqueOrCumulDims df of-      Left a ->-        let b = broadcast a-            go [] x     = x-            go (i:is) x = go is $! f i x b-        in  go [minBound..maxBound] x0-      Right stepsASBS-        | stepsBS <- dropPref (dims @as) stepsASBS-        , lenBS   <- cdTotalDim# stepsBS-          -> let go [] _ x = x-                 go (i:is) sourceOffE x-                    = go is (sourceOffE +# lenBS) $! f i x (indexOffset# sourceOffE df)-             in  go [minBound..maxBound] 0# x0--    -- | Right-associative fold of a DataFrame-    --   The fold is strict, so accumulater is evaluated to WHNF;-    --   but you'd better make sure that the function is strict enough to not-    --   produce memory leaks deeply inside the result data type.-    ewfoldr :: (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b-    ewfoldr f x0 df = case uniqueOrCumulDims df of-      Left a ->-        let b = broadcast a-            go 0 x = x-            go n x = go (n-1) $! f b x-        in  go (totalDim' @as) x0-      Right stepsASBS-        | stepsBS <- dropPref (dims @as) stepsASBS-        , lenBS   <- cdTotalDim# stepsBS-        , lenASBS <- cdTotalDim# stepsASBS-          -> let go sourceOffE x-                  | isTrue# (sourceOffE <# 0#)-                    = x-                  | otherwise-                    = go (sourceOffE -# lenBS) $! f (indexOffset# sourceOffE df) x-             in  go (lenASBS -# lenBS) x0--    -- | Right-associative fold of a DataFrame with an index-    --   The fold is strict, so accumulater is evaluated to WHNF;-    --   but you'd better make sure that the function is strict enough to not-    --   produce memory leaks deeply inside the result data type.-    iwfoldr :: (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b-    iwfoldr f x0 df = case uniqueOrCumulDims df of-      Left a ->-        let b = broadcast a-            go [] x     = x-            go (i:is) x = go is $! f i b x-        in  go [maxBound, pred maxBound .. minBound] x0-      Right stepsASBS-        | stepsBS <- dropPref (dims @as) stepsASBS-        , lenBS   <- cdTotalDim# stepsBS-        , lenASBS <- cdTotalDim# stepsASBS-          -> let go [] _ x = x-                 go (i:is) sourceOffE x-                    = go is (sourceOffE -# lenBS) $! f i (indexOffset# sourceOffE df) x-             in  go [maxBound, pred maxBound .. minBound] (lenASBS -# lenBS) x0--    -- | Apply an applicative functor on each element (Lens-like traversal)-    elementWise :: forall (s :: Type) (bs' :: [Nat]) (asbs' :: [Nat]) (f :: Type -> Type)-                 . ( Applicative f-                   , SubSpace s as bs' asbs'-                   )-                => (DataFrame s bs' -> f (DataFrame t bs))-                -> DataFrame s asbs' -> f (DataFrame t asbs)-    elementWise = indexWise . const-    {-# INLINE [1] elementWise #-}--    -- | Apply an applicative functor on each element with its index-    --     (Lens-like indexed traversal)-    indexWise :: forall (s :: Type) (bs' :: [Nat]) (asbs' :: [Nat]) (f :: Type -> Type)-               . ( Applicative f-                 , SubSpace s as bs' asbs'-                 )-              => (Idxs as -> DataFrame s bs' -> f (DataFrame t bs))-              -> DataFrame s asbs' -> f (DataFrame t asbs)-    indexWise f df = runWithState <$> iwfoldl applyF (pure initialState) df-      where-        steps = cumulDims $ dims @asbs-        -- run a state-based continuation within RW-        runWithState :: ( State# RealWorld -> (# State# RealWorld, (# MutableByteArray# RealWorld, Int# #) #))-                     -> DataFrame t asbs-        runWithState g = case runRW#-                           ( \s0 -> case g s0 of-                                (# s1, (# marr, _ #) #) -> unsafeFreezeByteArray# marr s1-                           ) of (# _, arr #) -> fromElems steps 0# arr--        -- Prepare empty byte array for the result DataFrame and keep a current position counter-        -- Input: state-        -- Output: state +-        --     ( current mutable byte array + current write position )-        initialState :: State# RealWorld -> (# State# RealWorld, (# MutableByteArray# RealWorld, Int# #) #)-        initialState s0 = case newByteArray# (rezLength# *# rezElBSize#) s0 of-                            (# s1, marr #) -> (# s1, (# marr, 0# #) #)--        -- Given the result chunk, write it into a mutable array-        updateChunk :: (State# RealWorld -> (# State# RealWorld, (# MutableByteArray# RealWorld, Int# #) #))-                    -> DataFrame t bs-                    -> (State# RealWorld -> (# State# RealWorld, (# MutableByteArray# RealWorld, Int# #) #))-        updateChunk g dfChunk = case (# byteOffset dfChunk, getBytes dfChunk #) of-            (# off#, arr#  #) -> \s -> case g s of-                                        (# s1, (# marr#, pos# #) #) -> case-                                            copyByteArray# arr# (off# *# rezElBSize#)-                                                           marr# (pos# *# rezElBSize#)-                                                           (rezStepN# *# rezElBSize#) s1 of-                                          s2 -> (# s2, (# marr#, pos# +# rezStepN# #) #)--        -- Apply applicative functor on each chunk and update a state.-        applyF :: Idxs as-               -> f (State# RealWorld -> (# State# RealWorld, (# MutableByteArray# RealWorld, Int# #) #))-               -> DataFrame s bs'-               -> f (State# RealWorld -> (# State# RealWorld, (# MutableByteArray# RealWorld, Int# #) #))-        applyF idx s dfChunk = idx `seq` dfChunk `seq` updateChunk <$> s <*> f idx dfChunk--        -- Element byte size of the result DataFrame (byte size of s)-        rezElBSize# = byteSize @t undefined-        -- Number of primitive elements in the result DataFrame chunk-        !(I# rezStepN#) = fromIntegral $ totalDim' @bs-        -- Number of primitive elements in the result DataFrame-        rezLength# = cdTotalDim# steps------ | Apply an applicative functor on each element with its index---     (Lens-like indexed traversal)-indexWise_ :: forall t as bs asbs f b-            . (SubSpace t as bs asbs, Applicative f)-           => (Idxs as -> DataFrame t bs -> f b)-           -> DataFrame t asbs -> f ()-indexWise_ f = iwfoldr (\i -> (*>) . f i) (pure ())---- | Apply an applicative functor on each element (Lens-like traversal)-elementWise_ :: forall t as bs asbs f b-              . (SubSpace t as bs asbs, Applicative f)-             => (DataFrame t bs -> f b)-             -> DataFrame t asbs -> f ()-elementWise_ f = ewfoldr ((*>) . f) (pure ())----- | Apply a functor over a single element (simple lens)-element :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) f-         . (SubSpace t as bs asbs, Applicative f)-        => Idxs as-        -> (DataFrame t bs -> f (DataFrame t bs))-        -> DataFrame t asbs -> f (DataFrame t asbs)-element i f df = flip (update i) df <$> f (index i df)-{-# INLINE element #-}---- | Index an element (reverse arguments of `index`)-(!) :: SubSpace t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-    => DataFrame t asbs -> Idxs as -> DataFrame t bs-(!) = flip index-{-# INLINE (!) #-}-infixl 4 !----ewfoldMap :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) m-           . (Monoid m, SubSpace t as bs asbs)-          => (DataFrame t bs -> m) -> DataFrame t asbs -> m-ewfoldMap f = ewfoldl (\m b -> m `seq` (mappend m $! f b)) mempty-{-# INLINE ewfoldMap #-}--iwfoldMap :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) m-           . ( Monoid m, SubSpace t as bs asbs)-          => (Idxs as -> DataFrame t bs -> m) -> DataFrame t asbs -> m-iwfoldMap f = iwfoldl (\i m b -> m `seq` (mappend m $! f i b)) mempty-{-# INLINE iwfoldMap #-}------ | Zip two spaces on a specified subspace index-wise (with index)-iwzip :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-                s (bs' :: [Nat]) (asbs' :: [Nat])-                r (bs'' :: [Nat]) (asbs'' :: [Nat])-       . ( SubSpace t as bs asbs-         , SubSpace s as bs' asbs'-         , SubSpace r as bs'' asbs''-         )-      => (Idxs as -> DataFrame t bs -> DataFrame s bs' -> DataFrame r bs'')-      -> DataFrame t asbs-      -> DataFrame s asbs'-      -> DataFrame r asbs''-iwzip f dft dfs = iwmap g dft-  where-    g i dft' = f i dft' (index i dfs)-{-# INLINE iwzip #-}---- | Zip two spaces on a specified subspace element-wise (without index)-ewzip :: forall t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat])-                s (bs' :: [Nat]) (asbs' :: [Nat])-                r (bs'' :: [Nat]) (asbs'' :: [Nat])-       . ( SubSpace t as bs asbs-         , SubSpace s as bs' asbs'-         , SubSpace r as bs'' asbs''-         )-      => (DataFrame t bs -> DataFrame s bs' -> DataFrame r bs'')-      -> DataFrame t asbs-      -> DataFrame s asbs'-      -> DataFrame r asbs''-ewzip = iwzip . const-{-# INLINE ewzip #-}---instance ( ConcatList as bs asbs-         , Dimensions as-         , Dimensions bs-         , Dimensions asbs-         , PrimArray t (DataFrame t bs)-         , PrimArray t (DataFrame t asbs)-         , PrimBytes   (DataFrame t bs)-         , PrimBytes   (DataFrame t asbs)-         ) => SubSpace t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) where----dropPref :: Dims (ns :: [Nat]) -> CumulDims -> CumulDims-dropPref ds = CumulDims . drop (length $ listDims ds) . unCumulDims---unSc :: DataFrame (t :: Type) ('[] :: [Nat]) -> t-unSc = unsafeCoerce#--{-# RULES-"ewgen/broadcast" ewgen = broadcast . unSc--  #-}+{-# LANGUAGE AllowAmbiguousTypes     #-}+{-# LANGUAGE DataKinds               #-}+{-# LANGUAGE FlexibleContexts        #-}+{-# LANGUAGE FlexibleInstances       #-}+{-# LANGUAGE FunctionalDependencies  #-}+{-# LANGUAGE InstanceSigs            #-}+{-# LANGUAGE MagicHash               #-}+{-# LANGUAGE MultiParamTypeClasses   #-}+{-# LANGUAGE PolyKinds               #-}+{-# LANGUAGE RankNTypes              #-}+{-# LANGUAGE ScopedTypeVariables     #-}+{-# LANGUAGE TypeApplications        #-}+{-# LANGUAGE TypeFamilies            #-}+{-# LANGUAGE TypeOperators           #-}+{-# LANGUAGE UndecidableInstances    #-}+{-# LANGUAGE UndecidableSuperClasses #-}+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+{- |+Module      :  Numeric.DataFrame.SubSpace+Copyright   :  (c) Artem Chirkin+License     :  BSD3++This module provides a flexible interface to manipulate parts of a DataFrame.++==== A note on indexing and slicing++When you index or slice dataframes, the left part of the dimension list+(@as@ for indexing, plus @b@ for slicing) determines the mechanics of accessing+sub-dataframes.+If compiler knows all dimensions at compile time, it can guarantee that the+operation is safe (provided with valid indices).+Otherwise, you can get an `OutOfDimBounds` exception at runtime.++When all dimensions in the indexing subspace satisfy @d :: Nat@ or @d ~ N n@,+slicing functions are safe to use, but you need some type-level proof for GHC+that the indices align.++When any of the dimensions are unknown (@d ~ XN m@), these functions are unsafe+-- they can yield an `OutOfDimBounds` exception if you give a bad index.+But they are easy to use (no type-level proof needed).++ -}++module Numeric.DataFrame.SubSpace+  ( -- $indexingSafety+    -- * Class definition+    SubSpace (SubSpaceCtx), CanSlice+    -- * Simple interface+    --+    --   All functions in this section are named @sxxx@, where @s@ stands for+    --   "simple". These allow using all functions of `SubSpace` with indexing+    --   dimensionality @as@ fixed to a single dim @(as ~ '[a])@.+    --   Use these functions if you are tired of @TypeApplications@ or find the+    --   error messages too cryptic.+  , sindexOffset, supdateOffset+  , (.!), slookup, supdate, sslice, ssliceMaybe, supdateSlice+  , sewgen, siwgen, sewmap, siwmap, sewzip, siwzip+  , selement, selementWise, selementWise_, sindexWise, sindexWise_+  , sewfoldl, sewfoldl', sewfoldr, sewfoldr', sewfoldMap+  , siwfoldl, siwfoldl', siwfoldr, siwfoldr', siwfoldMap+    -- * Flexible interface+    --+    --   Functions in this section allow you pick, fold, iterate, or do whatever+    --   you want with arbitrary sub-dataframe dimensionalities:+    --   e.g. a DataFrame of rank 3 can be processed as an 1D array of matrices+    --   or a matrix of vectors, or a 3D array of scalars.+    --   Often, you would need @TypeApplications@ to specify explicitly at least+    --   the indexing subspace (parameter @as@).+  , joinDataFrame, indexOffset, updateOffset+  , index, Numeric.DataFrame.SubSpace.lookup+  , update, slice, sliceMaybe, updateSlice+  , ewgen, iwgen, ewmap, iwmap, ewzip, iwzip+  , element, elementWise, elementWise_, indexWise, indexWise_+  , ewfoldl, ewfoldl', ewfoldr, ewfoldr', ewfoldMap+  , iwfoldl, iwfoldl', iwfoldr, iwfoldr', iwfoldMap+  ) where++import           Control.Arrow                        (first)+import           Control.Monad+import           Control.Monad.ST+import           Data.Kind+import           GHC.Base                             (Int (..), (+#))+import           Numeric.DataFrame.Internal.PrimArray+import           Numeric.DataFrame.ST+import           Numeric.DataFrame.Type+import           Numeric.Dimensions+import qualified Numeric.TypedList                    as TL+import           Unsafe.Coerce++-- | Unsafely get a sub-dataframe by its primitive element offset.+--   The offset is not checked to be aligned to the space structure or for bounds.+--+--   Warning: this function is utterly unsafe -- it does not even throw an exception if+--            the offset is too big; you just get an undefined behavior.+sindexOffset ::+       forall t a bs+     . SubSpace t '[a] bs (a :+ bs)+    => Int -- ^ Prim element offset+    -> DataFrame t (a :+ bs) -> DataFrame t bs+sindexOffset = indexOffset @t @'[a] @bs @(a :+ bs)+{-# INLINE sindexOffset #-}++-- | Unsafely update a sub-dataframe by its primitive element offset.+--   The offset is not checked to be aligned to the space structure or for bounds.+--+--   Warning: this function is utterly unsafe -- it does not even throw an exception if+--            the offset is too big; you just get an undefined behavior.+supdateOffset ::+       forall t a bs+     . SubSpace t '[a] bs (a :+ bs)+    => Int -- ^ Prim element offset+    -> DataFrame t bs -> DataFrame t (a :+ bs) -> DataFrame t (a :+ bs)+supdateOffset = updateOffset @t @'[a] @bs @(a :+ bs)+{-# INLINE supdateOffset #-}++-- | Get an element by its index in the dataframe.+--+--   If (@a ~ XN m@) then this function is unsafe and can throw+--   an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+(.!) ::+       forall t a bs+     . SubSpace t '[a] bs (a :+ bs)+    => DataFrame t (a :+ bs) -> Idx a -> DataFrame t bs+(.!) x i = index @t @'[a] @bs @(a :+ bs) (i :* U) x+{-# INLINE (.!) #-}+infixl 4 .!++-- | Set a new value to an element.+--+--   If (@a ~ XN m@) and the index falls outside of the DataFrame dim,+--   then this function returns the original DataFrame.+supdate ::+       forall t a bs+     . SubSpace t '[a] bs (a :+ bs)+    => Idx a -> DataFrame t bs -> DataFrame t (a :+ bs) -> DataFrame t (a :+ bs)+supdate = update @t @'[a] @bs @(a :+ bs) . (:*U)+{-# INLINE[1] supdate #-}++-- | Map a function over each element of DataFrame.+sewmap ::+       forall t a bs s bs'+     . (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs'))+    => (DataFrame s bs' -> DataFrame t bs)+    -> DataFrame s (a :+ bs') -> DataFrame t (a :+ bs)+sewmap = ewmap @t @'[a] @bs @(a :+ bs) @s @bs' @(a :+ bs')+{-# INLINE sewmap #-}++-- | Map a function over each element with its index of DataFrame.+siwmap ::+       forall t a bs s bs'+     . (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs'))+    => (Idx a -> DataFrame s bs' -> DataFrame t bs)+    -> DataFrame s (a :+ bs') -> DataFrame t (a :+ bs)+siwmap f = iwmap @t @'[a] @bs @(a :+ bs) @s @bs' @(a :+ bs') (\(i :* U) -> f i)+{-# INLINE[1] siwmap #-}++-- | Generate a DataFrame by repeating an element.+sewgen ::+       forall t a bs+     . (SubSpace t '[a] bs (a :+ bs), Dimensions '[a])+    => DataFrame t bs -> DataFrame t (a :+ bs)+sewgen = ewgen @t @'[a] @bs @(a :+ bs)+{-# INLINE sewgen #-}++-- | Generate a DataFrame by iterating a function (index -> element).+siwgen ::+       forall t a bs+     . (SubSpace t '[a] bs (a :+ bs), Dimensions '[a])+    => (Idx a -> DataFrame t bs) -> DataFrame t (a :+ bs)+siwgen f = iwgen @t @'[a] @bs @(a :+ bs) (\(i :* U) -> f i)+{-# INLINE[1] siwgen #-}++-- | Left-associative lazy fold of a DataFrame.+--   Same rules apply as for `foldl`.+sewfoldl ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b+sewfoldl = ewfoldl @t @'[a] @bs @(a :+ bs) @b+{-# INLINE sewfoldl #-}++-- | Left-associative strict fold of a DataFrame.+--   Same rules apply as for `foldl'`.+sewfoldl' ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b+sewfoldl' = ewfoldl' @t @'[a] @bs @(a :+ bs) @b+{-# INLINE sewfoldl' #-}++-- | Left-associative lazy fold of a DataFrame with an index.+--   Same rules apply as for `foldl`.+siwfoldl ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (Idx a -> b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b+siwfoldl f = iwfoldl @t @'[a] @bs @(a :+ bs) @b (\(i :* U) -> f i)+{-# INLINE[1] siwfoldl #-}++-- | Left-associative strict fold of a DataFrame with an index.+--   Same rules apply as for `foldl'`.+siwfoldl' ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (Idx a -> b -> DataFrame t bs -> b) -> b -> DataFrame t (a :+ bs) -> b+siwfoldl' f = iwfoldl' @t @'[a] @bs @(a :+ bs) @b (\(i :* U) -> f i)+{-# INLINE[1] siwfoldl' #-}++-- | Right-associative lazy fold of a DataFrame.+--   Same rules apply as for `foldr`.+sewfoldr ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b+sewfoldr = ewfoldr @t @'[a] @bs @(a :+ bs) @b+{-# INLINE sewfoldr #-}++-- | Right-associative strict fold of a DataFrame.+--   Same rules apply as for `foldr'`.+sewfoldr' ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b+sewfoldr' = ewfoldr' @t @'[a] @bs @(a :+ bs) @b+{-# INLINE sewfoldr' #-}++-- | Right-associative lazy fold of a DataFrame with an index.+--   Same rules apply as for `foldr`.+siwfoldr ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (Idx a -> DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b+siwfoldr f = iwfoldr @t @'[a] @bs @(a :+ bs) @b (\(i :* U) -> f i)+{-# INLINE[1] siwfoldr #-}++-- | Right-associative strict fold of a DataFrame with an index.+--   Same rules apply as for `foldr'`.+siwfoldr' ::+       forall t a bs b+     . SubSpace t '[a] bs (a :+ bs)+    => (Idx a -> DataFrame t bs -> b -> b) -> b -> DataFrame t (a :+ bs) -> b+siwfoldr' f = iwfoldr' @t @'[a] @bs @(a :+ bs) @b (\(i :* U) -> f i)+{-# INLINE[1] siwfoldr' #-}++-- | Apply an applicative functor on each element (Lens-like traversal).+selementWise ::+       forall t a bs s bs' f+     . (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs'), Applicative f)+    => (DataFrame s bs' -> f (DataFrame t bs))+    -> DataFrame s (a :+ bs') -> f (DataFrame t (a :+ bs))+selementWise = elementWise @t @'[a] @bs @(a :+ bs) @s @bs' @(a :+ bs') @f+{-# INLINE selementWise #-}++-- | Apply an applicative functor on each element with its index+--     (Lens-like indexed traversal).+sindexWise ::+       forall t a bs s bs' f+     . (SubSpace t '[a] bs (a :+ bs), SubSpace s '[a] bs' (a :+ bs'), Applicative f)+    => (Idx a -> DataFrame s bs' -> f (DataFrame t bs))+    -> DataFrame s (a :+ bs') -> f (DataFrame t (a :+ bs))+sindexWise f = indexWise @t @'[a] @bs @(a :+ bs) @s @bs' @(a :+ bs') @f (\(i :* U) -> f i)+{-# INLINE[1] sindexWise #-}++-- | Apply an applicative functor on each element (Lens-like traversal)+selementWise_ ::+       forall t a bs f b+     . (SubSpace t '[a] bs (a :+ bs), Applicative f)+    => (DataFrame t bs -> f b) -> DataFrame t (a :+ bs) -> f ()+selementWise_ = elementWise_ @t @'[a] @bs @(a :+ bs) @f @b+{-# INLINE selementWise_ #-}++-- | Apply an applicative functor on each element with its index+--     (Lens-like indexed traversal)+sindexWise_ ::+       forall t a bs f b+    . (SubSpace t '[a] bs (a :+ bs), Applicative f)+   => (Idx a -> DataFrame t bs -> f b) -> DataFrame t (a :+ bs) -> f ()+sindexWise_ f = indexWise_ @t @'[a] @bs @(a :+ bs) @f @b (\(i :* U) -> f i)+{-# INLINE sindexWise_ #-}++-- | Apply a functor over a single element (simple lens)+--+--   If (@a ~ XN m@) and the index falls outside of the DataFrame Dim, the+--   argument Functor is not called and the result is @pure@ original DataFrame.+selement ::+       forall t a bs f+     . (SubSpace t '[a] bs (a :+ bs), Applicative f)+    => Idx a+    -> (DataFrame t bs -> f (DataFrame t bs))+    -> DataFrame t (a :+ bs) -> f (DataFrame t (a :+ bs))+selement = element @t @'[a] @bs @(a :+ bs) @f . (:* U)+{-# INLINE selement #-}++-- | Map each element of the DataFrame to a monoid,+--    and combine the results.+sewfoldMap ::+       forall t a bs m+     . (SubSpace t '[a] bs (a :+ bs), Monoid m)+    => (DataFrame t bs -> m) -> DataFrame t (a :+ bs) -> m+sewfoldMap = ewfoldMap @t @'[a] @bs @(a :+ bs) @m+{-# INLINE sewfoldMap #-}++-- | Map each element of the DataFrame and its index to a monoid,+--    and combine the results.+siwfoldMap ::+       forall t a bs m+     . (SubSpace t '[a] bs (a :+ bs), Monoid m)+    => (Idx a -> DataFrame t bs -> m) -> DataFrame t (a :+ bs) -> m+siwfoldMap f = iwfoldMap @t @'[a] @bs @(a :+ bs) @m (\(i :* U) -> f i)+{-# INLINE[1] siwfoldMap #-}++-- | Zip two spaces on a specified subspace element-wise (without index)+sewzip ::+       forall t a bs l bsL r bsR+     . (SubSpace t '[a] bs (a :+ bs), SubSpace l '[a] bsL (a :+ bsL), SubSpace r '[a] bsR (a :+ bsR))+    => (DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs)+    -> DataFrame l (a :+ bsL) -> DataFrame r (a :+ bsR) -> DataFrame t (a :+ bs)+sewzip = ewzip @t @'[a] @bs @(a :+ bs) @l @bsL @(a :+ bsL) @r @bsR @(a :+ bsR)+{-# INLINE sewzip #-}++-- | Zip two spaces on a specified subspace index-wise (with index)+siwzip ::+       forall t a bs l bsL r bsR+     . (SubSpace t '[a] bs (a :+ bs), SubSpace l '[a] bsL (a :+ bsL), SubSpace r '[a] bsR (a :+ bsR))+    => (Idx a -> DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs)+    -> DataFrame l (a :+ bsL) -> DataFrame r (a :+ bsR) -> DataFrame t (a :+ bs)+siwzip f = iwzip @t @'[a] @bs @(a :+ bs) @l @bsL @(a :+ bsL) @r @bsR @(a :+ bsR) (\(i :* U) -> f i)+{-# INLINE siwzip #-}++-- | Flatten a nested DataFrame, analogous to `Control.Monad.join`.+joinDataFrame ::+       forall t as bs asbs+     . (SubSpace t as bs asbs, PrimBytes (DataFrame t bs))+    => DataFrame (DataFrame t bs) as -> DataFrame t asbs+joinDataFrame = joinDataFrameI @_ @t @as @bs @asbs+{-# INLINE[1] joinDataFrame #-}++-- | Unsafely get a sub-dataframe by its primitive element offset.+--   The offset is not checked to be aligned to the space structure or for bounds.+--+--   Warning: this function is utterly unsafe -- it does not even throw an exception if+--            the offset is too big; you just get an undefined behavior.+indexOffset ::+       forall t as bs asbs+     . SubSpace t as bs asbs+    => Int -- ^ Prim element offset+    -> DataFrame t asbs -> DataFrame t bs+indexOffset = indexOffsetI @_ @t @as @bs @asbs+{-# INLINE[1] indexOffset #-}++-- | Unsafely update a sub-dataframe by its primitive element offset.+--   The offset is not checked to be aligned to the space structure or for bounds.+--+--   Warning: this function is utterly unsafe -- it does not even throw an exception if+--            the offset is too big; you just get an undefined behavior.+updateOffset ::+       forall t as bs asbs+     . SubSpace t as bs asbs+    => Int -- ^ Prim element offset+    -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs+updateOffset = updateOffsetI @_ @t @as @bs @asbs+{-# INLINE[1] updateOffset #-}++-- | Get an element by its index in the dataframe.+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+index ::+       forall t as bs asbs+     . SubSpace t as bs asbs+    => Idxs as -> DataFrame t asbs -> DataFrame t bs+index = indexI @_ @t @as @bs @asbs+{-# INLINE[1] index #-}++-- | Set a new value to an element.+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to update data beyond dataframe bounds.+--   In this case, the original DataFrame is returned.+update ::+       forall t as bs asbs+     . SubSpace t as bs asbs+    => Idxs as -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs+update = updateI @_ @t @as @bs @asbs+{-# INLINE[1] update #-}++-- | Map a function over each element of DataFrame.+ewmap ::+       forall t as bs asbs s bs' asbs'+     . (SubSpace t as bs asbs, SubSpace s as bs' asbs')+    => (DataFrame s bs' -> DataFrame t bs)+    -> DataFrame s asbs' -> DataFrame t asbs+ewmap = ewmapI @_ @t @as @bs @asbs @s @bs' @asbs'+{-# INLINE[1] ewmap #-}++-- | Map a function over each element with its index of DataFrame.+iwmap ::+       forall t as bs asbs s bs' asbs'+     . (SubSpace t as bs asbs, SubSpace s as bs' asbs')+    => (Idxs as -> DataFrame s bs' -> DataFrame t bs)+    -> DataFrame s asbs' -> DataFrame t asbs+iwmap = iwmapI @_ @t @as @bs @asbs @s @bs' @asbs'+{-# INLINE[1] iwmap #-}++-- | Generate a DataFrame by repeating an element.+ewgen ::+       forall t as bs asbs+     . (SubSpace t as bs asbs, Dimensions as)+    => DataFrame t bs -> DataFrame t asbs+ewgen = ewgenI @_ @t @as @bs @asbs+{-# INLINE[1] ewgen #-}++-- | Generate a DataFrame by iterating a function (index -> element).+iwgen ::+       forall t as bs asbs+     . (SubSpace t as bs asbs, Dimensions as)+    => (Idxs as -> DataFrame t bs) -> DataFrame t asbs+iwgen = iwgenI @_ @t @as @bs @asbs+{-# INLINE[1] iwgen #-}++-- | Left-associative lazy fold of a DataFrame.+--   Same rules apply as for `foldl`.+ewfoldl ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b+ewfoldl = ewfoldlI @_ @t @as @bs @asbs @b+{-# INLINE[1] ewfoldl #-}++-- | Left-associative strict fold of a DataFrame.+--   Same rules apply as for `foldl'`.+ewfoldl' ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b+ewfoldl' f z0 xs = ewfoldr f' id xs z0+  where+    f' x k z = k $! f z x+{-# INLINE ewfoldl' #-}++-- | Left-associative lazy fold of a DataFrame with an index.+--   Same rules apply as for `foldl`.+iwfoldl ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b+iwfoldl = iwfoldlI @_ @t @as @bs @asbs @b+{-# INLINE[1] iwfoldl #-}++-- | Left-associative strict fold of a DataFrame with an index.+--   Same rules apply as for `foldl'`.+iwfoldl' ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b+iwfoldl' f z0 xs = iwfoldr f' id xs z0+  where+    f' i x k z = k $! f i z x+{-# INLINE[1] iwfoldl' #-}++-- | Right-associative lazy fold of a DataFrame.+--   Same rules apply as for `foldr`.+ewfoldr ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b+ewfoldr = ewfoldrI @_ @t @as @bs @asbs @b+{-# INLINE[1] ewfoldr #-}++-- | Right-associative strict fold of a DataFrame.+--   Same rules apply as for `foldr'`.+ewfoldr' ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b+ewfoldr' f z0 xs = ewfoldl f' id xs z0+  where+    f' k x z = k $! f x z+{-# INLINE ewfoldr' #-}++-- | Right-associative lazy fold of a DataFrame with an index.+--   Same rules apply as for `foldr`.+iwfoldr ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b+iwfoldr = iwfoldrI @_ @t @as @bs @asbs @b+{-# INLINE[1] iwfoldr #-}++-- | Right-associative strict fold of a DataFrame with an index.+--   Same rules apply as for `foldr'`.+iwfoldr' ::+       forall t as bs asbs b+     . SubSpace t as bs asbs+    => (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b+iwfoldr' f z0 xs = iwfoldl f' id xs z0+  where+    f' i k x z = k $! f i x z+{-# INLINE[1] iwfoldr' #-}++-- | Apply an applicative functor on each element (Lens-like traversal).+elementWise ::+       forall t as bs asbs s bs' asbs' f+     . (SubSpace t as bs asbs, SubSpace s as bs' asbs', Applicative f)+    => (DataFrame s bs' -> f (DataFrame t bs))+    -> DataFrame s asbs' -> f (DataFrame t asbs)+elementWise = elementWiseI @_ @t @as @bs @asbs @s @bs' @asbs' @f+{-# INLINE[1] elementWise #-}++-- | Apply an applicative functor on each element with its index+--     (Lens-like indexed traversal).+indexWise ::+       forall t as bs asbs s bs' asbs' f+     . (SubSpace t as bs asbs, SubSpace s as bs' asbs', Applicative f)+    => (Idxs as -> DataFrame s bs' -> f (DataFrame t bs))+    -> DataFrame s asbs' -> f (DataFrame t asbs)+indexWise = indexWiseI @_ @t @as @bs @asbs @s @bs' @asbs' @f+{-# INLINE[1] indexWise #-}++-- | Apply an applicative functor on each element (Lens-like traversal)+elementWise_ ::+       forall t as bs asbs f b+     . (SubSpace t as bs asbs, Applicative f)+    => (DataFrame t bs -> f b) -> DataFrame t asbs -> f ()+elementWise_ f = ewfoldr ((*>) . f) (pure ())+{-# INLINE elementWise_ #-}++-- | Apply an applicative functor on each element with its index+--     (Lens-like indexed traversal)+indexWise_ ::+       forall t as bs asbs f b+    . (SubSpace t as bs asbs, Applicative f)+   => (Idxs as -> DataFrame t bs -> f b) -> DataFrame t asbs -> f ()+indexWise_ f = iwfoldr (\i -> (*>) . f i) (pure ())+{-# INLINE indexWise_ #-}++-- | Apply a functor over a single element (simple lens)+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@) and any of the+--   corresponding indices fall outside of the DataFrame Dims, then the+--   argument Functor is not called and the result is @pure@ original DataFrame.+element ::+       forall t as bs asbs f+     . (SubSpace t as bs asbs, Applicative f)+    => Idxs as+    -> (DataFrame t bs -> f (DataFrame t bs))+    -> DataFrame t asbs -> f (DataFrame t asbs)+element i f df = case dimKind @(KindOfEl asbs) of+  DimKNat -> flip (update i) df <$> f (index i df)+  DimKXNat+    | XFrame (dfN :: DataFrame t asbsN) <- df+    , Just off <- cdIxM (getSteps (dims @asbsN) dfN) i+      -> flip (updateOffset off) df <$> f (indexOffset off df)+    | otherwise+      -> pure df+{-# INLINE element #-}+++-- | Map each element of the DataFrame to a monoid,+--    and combine the results.+ewfoldMap ::+       forall t as bs asbs m+     . (SubSpace t as bs asbs, Monoid m)+    => (DataFrame t bs -> m) -> DataFrame t asbs -> m+ewfoldMap f = ewfoldr (mappend . f) mempty+{-# INLINE ewfoldMap #-}++-- | Map each element of the DataFrame and its index to a monoid,+--    and combine the results.+iwfoldMap ::+       forall t as bs asbs m+     . (SubSpace t as bs asbs, Monoid m)+    => (Idxs as -> DataFrame t bs -> m) -> DataFrame t asbs -> m+iwfoldMap f = iwfoldr (\i -> mappend . f i) mempty+{-# INLINE iwfoldMap #-}++-- | Zip two spaces on a specified subspace element-wise (without index)+ewzip :: forall t as bs asbs l bsL asbsL r bsR asbsR+     . (SubSpace t as bs asbs, SubSpace l as bsL asbsL, SubSpace r as bsR asbsR)+    => (DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs)+    -> DataFrame l asbsL -> DataFrame r asbsR -> DataFrame t asbs+ewzip = iwzip . const+{-# INLINE ewzip #-}++-- | Zip two spaces on a specified subspace index-wise (with index).+iwzip :: forall t as bs asbs l bsL asbsL r bsR asbsR+     . (SubSpace t as bs asbs, SubSpace l as bsL asbsL, SubSpace r as bsR asbsR)+    => (Idxs as -> DataFrame l bsL -> DataFrame r bsR -> DataFrame t bs)+    -> DataFrame l asbsL -> DataFrame r asbsR -> DataFrame t asbs+iwzip f dfl dfr = case dimKind @(KindOfEl asbs) of+  DimKNat -> iwmap (\i x -> f i x (index i dfr)) dfl+  DimKXNat+    | XFrame (_ :: DataFrame l asbsLN) <- dfl+    , XFrame (_ :: DataFrame r asbsRN) <- dfr+    , asbs <- unsafeCoerce -- minimum spans+        $ zipWith min (listDims $ dims @asbsLN) (listDims $ dims @asbsRN) :: Dims asbs+    , bs <- (dims :: Dims bs)+    , as <- (dropSufDims bs asbs :: Dims as)+      -> withLiftedConcatList @'Nothing @('Just (DimsBound bs)) @'Nothing as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) -> case () of+            _ | Dict <- inferKnownBackend @t @asbsn+              , Dict <- inferKnownBackend @t @bsn+             -> XFrame (iwgen @t @asn @bsn @asbsn+                         (\iN -> let i = liftIdxs iN+                                 in  unliftXFrame (f i (index i dfl) (index i dfr))+                         )+                       )+{-# INLINE iwzip #-}++-- | DataFrames indexed by Nats and XNats require slightly different sets of+--   constraints to be sliced.+--   This family hides the difference, so that I could write one function for+--   both kinds.+type family CanSlice (t :: Type) (asbs :: [k])  :: Constraint where+  CanSlice t (asbs :: [Nat])+    = ( PrimArray t (DataFrame t asbs), Dimensions asbs )+  CanSlice t (asbs :: [XNat])+    = ( )++-- | Get a few contiguous elements.+--+--   In a sense, this is just a more complicated version of `sindex`.+--+--   If (@b ~ XN m@) then this function is unsafe and can throw+--   an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+sslice ::+       forall t b bi bd bs+     . ( KnownDimKind (KindOfEl bs)+       , CanSlice t (b :+ bs)+       , SubFrameIndexCtx b bi bd, KnownDim bd+       , PrimArray t (DataFrame t (bd :+ bs)))+    => Idx bi -> DataFrame t (b :+ bs) -> DataFrame t (bd :+ bs)+sslice = slice @t @b @bi @bd @'[] @bs @(b :+ bs) . (:* U)+{-# INLINE[1] sslice #-}++-- | Update a few contiguous elements.+--+--   In a sense, this is just a more complicated version of `supdate`.+--+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function updates only as+--   many elements as fits into the dataframe along this dimension (possibly none).+supdateSlice ::+       forall t b bi bd bs+     . ( KnownDimKind (KindOfEl bs)+       , CanSlice t (b :+ bs)+       , SubFrameIndexCtx b bi bd+       , KnownDim bd, ExactDims bs+       , PrimArray t (DataFrame t (bd :+ bs)))+    => Idx bi -> DataFrame t (bd :+ bs)+    -> DataFrame t (b :+ bs) -> DataFrame t (b :+ bs)+supdateSlice = updateSlice @t @b @bi @bd @'[] @bs @(b :+ bs) . (:* U)+{-# INLINE[1] supdateSlice #-}++-- | Get a few contiguous elements.+--+--   In a sense, this is just a more complicated version of `index`.+--+--   If any of the dims in @as@ or @b@ is unknown (@a ~ XN m@),+--   then this function is unsafe and can throw an `OutOfDimBounds` exception.+--   Otherwise, its safety is guaranteed by the type system.+slice ::+       forall (t :: Type) b bi bd as bs asbs+     . ( KnownDimKind (KindOfEl asbs)+       , CanSlice t asbs+       , SubFrameIndexCtx b bi bd, KnownDim bd+       , ConcatList as (b :+ bs) asbs+       , PrimArray t (DataFrame t (bd :+ bs)))+    => Idxs (as +: bi) -> DataFrame t asbs -> DataFrame t (bd :+ bs)+slice i = case dimKind @(KindOfEl asbs) of+  DimKNat+    -> withArrayContent broadcast+    (\steps off0 ba ->+      let (off, bsteps) = getOffAndStepsSub (I# off0) steps i (dim @bd)+      in fromElems bsteps (case off of I# o -> o) ba+    )+  DimKXNat+    -> \(XFrame (df :: DataFrame t asbsN)) -> withArrayContent broadcast+    (\steps off0 ba ->+      let (off, bsteps) = getOffAndStepsSub (I# off0) steps i (dim @bd)+      in fromElems bsteps (case off of I# o -> o) ba+    ) df+{-# INLINE[1] slice #-}++-- | Update a few contiguous elements.+--+--   In a sense, this is just a more complicated version of `update`.+--+--   If any of the dims in @as@ is unknown (@a ~ XN m@),+--   you may happen to update data beyond dataframe bounds.+--   In this case, the original DataFrame is returned.+--   If (@b ~ XN m@) and (@Idx bi + Dim bd > Dim b@), this function updates only as+--   many elements as fits into the dataframe along this dimension (possibly none).+updateSlice ::+       forall (t :: Type) b bi bd as bs asbs+     . ( KnownDimKind (KindOfEl asbs)+       , CanSlice t asbs+       , SubFrameIndexCtx b bi bd+       , KnownDim bd, ExactDims bs+       , ConcatList as (b :+ bs) asbs+       , PrimArray t (DataFrame t (bd :+ bs)))+    => Idxs (as +: bi) -> DataFrame t (bd :+ bs)+    -> DataFrame t asbs -> DataFrame t asbs+updateSlice i bdbsDf asbsDf = case dimKind @(KindOfEl asbs) of+  DimKNat -> runST $ do+      asbsM <- thawDataFrame asbsDf+      copyDataFrame i bdbsDf asbsM+      unsafeFreezeDataFrame asbsM+  DimKXNat+    | (XFrame (asbsDfN :: DataFrame t asbsN)) <- asbsDf -> runST $ do+      asbsM <- thawDataFrame @t @asbsN asbsDfN+      copyDataFrame i bdbsDf (castDataFrame @t @asbs asbsM)+      XFrame <$> unsafeFreezeDataFrame asbsM+{-# INLINE[1] updateSlice #-}+++-- | Get an element by its index in the dataframe.+--   This is a safe alternative to `(.!)` function when the index dimension+--   is not known at compile time (@a ~ XN m@).+slookup ::+       forall t (a :: XNat) (bs :: [XNat])+     . (All KnownDimType bs, PrimBytes t)+    => Idx a -> DataFrame t (a :+ bs) -> Maybe (DataFrame t bs)+slookup = Numeric.DataFrame.SubSpace.lookup @t @'[a] @bs @(a :+ bs) . (:*U)+{-# INLINE slookup #-}++-- | Get an element by its index in the dataframe.+--   This is a safe alternative to `index` function when some of the dimensions+--   are not known at compile time (@d ~ XN m@).+lookup ::+       forall t (as :: [XNat]) (bs :: [XNat]) (asbs :: [XNat])+     . (ConcatList as bs asbs, All KnownDimType bs, PrimBytes t)+    => Idxs as -> DataFrame t asbs -> Maybe (DataFrame t bs)+lookup i (XFrame (df :: DataFrame t asbsN))+  | asbsN <- dims @asbsN+  , Just off <- cdIxM (getSteps asbsN df) i+  , asbs <- XDims asbsN :: Dims asbs+  , (as, bs) <- prefSufDims i asbs+    = withLiftedConcatList @'Nothing @'Nothing @('Just asbsN) as bs asbs $+        \(Dims :: Dims asn) (Dims :: Dims bsn) (_ :: Dims asbsn)+          -> case inferKnownBackend @t @bsn of+            Dict -> Just (XFrame (indexOffset @t @asn @bsn @asbsn off df))+  | otherwise = Nothing+{-# INLINE lookup #-}++-- | Get a few contiguous elements.+--+--   In a sense, this is just a more complicated version of `slookup`.+--+--   This is a safe alternative to `sslice` function when the slice dimension+--   is not known at compile time (@b ~ XN m@).+ssliceMaybe ::+       forall (t :: Type) (b :: XNat) (bi :: XNat) (bd :: XNat) (bs :: [XNat])+     . ( SubFrameIndexCtx b bi bd, KnownDim bd+       , All KnownDimType bs, PrimBytes t)+    => Idx bi -> DataFrame t (b :+ bs) -> Maybe (DataFrame t (bd :+ bs))+ssliceMaybe = sliceMaybe @t @b @bi @bd @'[] @bs @(b :+ bs) . (:* U)+{-# INLINE ssliceMaybe #-}+++-- | Get a few contiguous elements.+--+--   In a sense, this is just a more complicated version of `lookup`.+--+--   This is a safe alternative to `slice` function when some of the dimensions+--   are not known at compile time (@d ~ XN m@).+sliceMaybe ::+       forall (t :: Type) (b :: XNat) bi bd as bs asbs+     . ( SubFrameIndexCtx b bi bd, KnownDim bd+       , ConcatList as (b :+ bs) asbs+       , All KnownDimType bs, PrimBytes t)+    => Idxs (as +: bi) -> DataFrame t asbs -> Maybe (DataFrame t (bd :+ bs))+sliceMaybe i (XFrame (df :: DataFrame t asbsN))+  | asbsN <- dims @asbsN+  , bd <- dim @bd+  , Dict <- ( withKnownXDim @bd Dict+      :: Dict (KnownDim (DimBound bd), KnownDimType bd, FixedDim bd (DimBound bd)))+  , Just (I# off0, bsteps@(CumulDims (bbN:bN:_)))+      <- getOffAndStepsSubM 0 (getSteps asbsN df) i bd+  , bbN == bN * dimVal bd -- is there enough elements?+  , asbs <- XDims asbsN :: Dims asbs+  , XDims (Dims :: Dims bsN) <-+      unsafeCoerce (dropSome (listIdxs i) (listDims asbs)) :: Dims bs+  , Dict <- inferKnownBackend @t @(DimBound bd ': bsN)+    = Just $ XFrame @_ @t @(bd :+ bs) @(DimBound bd ': bsN)+              (withArrayContent broadcast+                (\_ off -> fromElems bsteps (off0 +# off)) df)+  | otherwise = Nothing+{-# INLINE sliceMaybe #-}+++-- | Operations on DataFrames+--+-- @as@ is an indexing dimensionality+--+-- @bs@ is an element dimensionality+--+-- @t@ is an underlying data type (i.e. Float, Int, Double)+--+class ( ConcatList as bs asbs+      , SubSpaceCtx t as bs asbs+      , PrimBytes t+      , KnownDimKind k+      ) => SubSpace (t :: Type) (as :: [k]) (bs :: [k]) (asbs :: [k])+                    | asbs as -> bs, asbs bs -> as, as bs -> asbs where+    type SubSpaceCtx t as bs asbs :: Constraint++    joinDataFrameI :: PrimBytes (DataFrame t bs)+                   => DataFrame (DataFrame t bs) as -> DataFrame t asbs+    indexOffsetI :: Int -> DataFrame t asbs -> DataFrame t bs+    updateOffsetI :: Int -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs+    indexI :: Idxs as -> DataFrame t asbs -> DataFrame t bs+    updateI :: Idxs as -> DataFrame t bs -> DataFrame t asbs -> DataFrame t asbs+    ewmapI  :: forall s (bs' :: [k]) (asbs' :: [k])+             . SubSpace s as bs' asbs'+            => (DataFrame s bs' -> DataFrame t bs)+            -> DataFrame s asbs' -> DataFrame t asbs+    iwmapI  :: forall s (bs' :: [k]) (asbs' :: [k])+             . SubSpace s as bs' asbs'+            => (Idxs as -> DataFrame s bs' -> DataFrame t bs)+            -> DataFrame s asbs' -> DataFrame t asbs+    ewgenI :: Dimensions as => DataFrame t bs -> DataFrame t asbs+    iwgenI :: Dimensions as => (Idxs as -> DataFrame t bs) -> DataFrame t asbs+    ewfoldlI :: (b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b+    iwfoldlI :: (Idxs as -> b -> DataFrame t bs -> b) -> b -> DataFrame t asbs -> b+    ewfoldrI :: (DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b+    iwfoldrI :: (Idxs as -> DataFrame t bs -> b -> b) -> b -> DataFrame t asbs -> b+    elementWiseI :: forall (s :: Type) (bs' :: [k]) (asbs' :: [k]) (f :: Type -> Type)+                  . (Applicative f, SubSpace s as bs' asbs')+                 => (DataFrame s bs' -> f (DataFrame t bs))+                 -> DataFrame s asbs' -> f (DataFrame t asbs)+    elementWiseI = indexWiseI . const+    {-# INLINE elementWiseI #-}+    indexWiseI :: forall (s :: Type) (bs' :: [k]) (asbs' :: [k]) (f :: Type -> Type)+                . (Applicative f, SubSpace s as bs' asbs')+               => (Idxs as -> DataFrame s bs' -> f (DataFrame t bs))+               -> DataFrame s asbs' -> f (DataFrame t asbs)++instance ( ConcatList as bs asbs+         , SubSpaceCtx t as bs asbs+         ) => SubSpace t (as :: [Nat]) (bs :: [Nat]) (asbs :: [Nat]) where+    type SubSpaceCtx t as bs asbs+      = ( Dimensions as, Dimensions bs, Dimensions asbs+        , PrimArray t (DataFrame t asbs), PrimArray t (DataFrame t bs))++    joinDataFrameI+      | Dict <- inferKnownBackend @(DataFrame t bs) @as+        = withArrayContent ewgenI+            (\steps -> fromElems (steps `mappend` cumulDims (dims @bs)))++    indexOffsetI (I# off) = withArrayContent broadcast+      (\steps off0 -> fromElems (dropPref (dims @as) steps) (off0 +# off))+    {-# INLINE indexOffsetI #-}++    updateOffsetI off bs asbs = runST $ do+        asbsM <- thawDataFrame asbs+        copyDataFrameOff off bs asbsM+        unsafeFreezeDataFrame asbsM+    {-# INLINE updateOffsetI #-}++    indexI i = withArrayContent broadcast+      (\steps off0 -> fromElems (dropPref (dims @as) steps)+         (case cdIx steps i of I# off -> off0 +# off))+    {-# INLINE indexI #-}++    updateI i bs asbs = runST $ do+        asbsM <- thawDataFrame asbs+        copyDataFrame' i bs asbsM+        unsafeFreezeDataFrame asbsM+    {-# INLINE updateI #-}++    ewmapI (f :: DataFrame s bs' -> DataFrame t bs) (asbs' :: DataFrame s asbs')+      = case uniqueOrCumulDims asbs' of+      Left e  -> ewgen (f (broadcast e))+      Right _ -> runST $ do+        let asTD  = fromIntegral (totalDim' @as ) :: Int+            bsTD  = fromIntegral (totalDim' @bs ) :: Int+            bs'TD = fromIntegral (totalDim' @bs') :: Int+        asbsM <- newDataFrame+        forM_ [0..asTD-1] $ \i ->+          copyDataFrameOff (i*bsTD) (f (indexOffset (i*bs'TD) asbs')) asbsM+        unsafeFreezeDataFrame asbsM+    {-# INLINE ewmapI #-}++    iwmapI f (asbs' :: DataFrame s asbs')+      = case uniqueOrCumulDims asbs' of+      Left e  -> iwgen (flip f (broadcast e))+      Right _ -> runST $ do+        asbsM <- newDataFrame+        forM_ [minBound..maxBound] $ \i ->+          copyDataFrame' i (f i (index i asbs')) asbsM+        unsafeFreezeDataFrame asbsM+    {-# INLINE iwmapI #-}++    ewgenI bs = case uniqueOrCumulDims bs of+      Left a -> broadcast a+      Right bsSteps -> runST $ do+        let asTD = fromIntegral (totalDim' @as) :: Int+            bsTD = fromIntegral (cdTotalDim bsSteps)+        asbsM <- newDataFrame+        forM_ [0, bsTD .. asTD * bsTD  - 1] $ \o -> copyDataFrameOff o bs asbsM+        unsafeFreezeDataFrame asbsM+    {-# INLINE ewgenI #-}++    iwgenI f = runST $ do+        asbsM <- newDataFrame+        forM_ [minBound..maxBound] $ \i -> copyDataFrame' i (f i) asbsM+        unsafeFreezeDataFrame asbsM+    {-# INLINE iwgenI #-}++    ewfoldlI f x0 asbs = case uniqueOrCumulDims asbs of+      Left a ->+        let b = broadcast a+            go i | i < 0     = x0+                 | otherwise = f (go (i-1)) b+        in  go (fromIntegral (totalDim' @as) - 1 :: Int)+      Right asbsSteps ->+        let bsSteps = dropPref (dims @as) asbsSteps+            bsLen   = max 1 (fromIntegral (cdTotalDim bsSteps)) :: Int+            asbsLen = fromIntegral (cdTotalDim asbsSteps) :: Int+            go i | i < 0     = x0+                 | otherwise = f (go (i - bsLen)) (indexOffset i asbs)+        in  go (asbsLen - bsLen)+    {-# INLINE ewfoldlI #-}++    iwfoldlI f x0 asbs+      | not (nonVoidDims (dims @as)) = x0+      | otherwise = case uniqueOrCumulDims asbs of+        Left a ->+          let b = broadcast a+              go i | i == minBound = f i x0 b+                   | otherwise     = f i (go (pred i)) b+          in  go maxBound+        Right _ ->+          let go i | i == minBound = f i x0 (index i asbs)+                   | otherwise     = f i (go (pred i)) (index i asbs)+          in  go maxBound+    {-# INLINE iwfoldlI #-}++    ewfoldrI f x0 asbs = case uniqueOrCumulDims asbs of+        Left a ->+          let b = broadcast a+              go i | i >= totalDim' @as = x0+                   | otherwise          = f b (go (i+1))+          in  go 0+        Right asbsSteps ->+          let bsSteps = dropPref (dims @as) asbsSteps+              bsLen   = max 1 (fromIntegral (cdTotalDim bsSteps)) :: Int+              asbsLen = fromIntegral (cdTotalDim asbsSteps) :: Int+              go i | i >= asbsLen = x0+                   | otherwise    = f (indexOffset i asbs) (go (i + bsLen))+          in  go 0+    {-# INLINE ewfoldrI #-}++    iwfoldrI f x0 asbs+      | not (nonVoidDims (dims @as)) = x0+      | otherwise = case uniqueOrCumulDims asbs of+        Left a ->+          let b = broadcast a+              go i | i == maxBound = f i b x0+                   | otherwise     = f i b (go (succ i))+          in  go minBound+        Right _ ->+          let go i | i == maxBound = f i (index i asbs) x0+                   | otherwise     = f i (index i asbs) (go (succ i))+          in  go minBound+    {-# INLINE iwfoldrI #-}++    indexWiseI (f :: Idxs as -> DataFrame s bs' -> f (DataFrame t bs))+        = fmap mkSTDF . iwfoldr fST (pure $ MakingDF (const (pure ())))+      where+        mkSTDF :: MakingDF t asbs -> DataFrame t asbs+        mkSTDF st = runST $ do+          df <- newDataFrame+          getMDF st df+          unsafeFreezeDataFrame df+        fST :: Idxs as -> DataFrame s bs'+            -> f (MakingDF t asbs) -> f (MakingDF t asbs)+        fST i bs' asbsSTF+          = (\r st -> MakingDF (\x -> copyDataFrame' i r x *> getMDF st x))+             <$> f i bs' <*> asbsSTF+    {-# INLINE indexWiseI #-}++-- | Hide ST monad state with a DataFrame in works inside a plain type.+newtype MakingDF t asbs+  = MakingDF { getMDF :: forall s . STDataFrame s t asbs -> ST s () }++-- | Checks if all of the dimensions are non-zero.+nonVoidDims :: Dims ns -> Bool+nonVoidDims = all (0 <) . listDims++dropPref :: Dims (ns :: [Nat]) -> CumulDims -> CumulDims+dropPref ds = CumulDims . dropSome (listDims ds) . unCumulDims++dropSome :: [Word] -> [Word] -> [Word]+dropSome []     xs = xs+dropSome (_:as) xs = dropSome as (tail xs)++instance ( ConcatList as bs asbs+         , SubSpaceCtx t as bs asbs+         ) => SubSpace t (as :: [XNat]) (bs :: [XNat]) (asbs :: [XNat]) where+    type SubSpaceCtx t as bs asbs+      = ( Dimensions bs, PrimBytes t, ExactDims bs+        , All KnownDimType as, All KnownDimType bs, All KnownDimType asbs)++    joinDataFrameI (XFrame (df :: DataFrame (DataFrame t bs) asN)) =+      let as   = XDims (dims @asN) :: Dims as+          bs   = dims :: Dims bs+          asbs = concatDims as bs :: Dims asbs+      in withLiftedConcatList @('Just asN) @('Just (DimsBound bs)) @'Nothing+                              as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) -> case () of+            _ | Dict <- inferKnownBackend @t @bsn+              , Dict <- inferKnownBackend @t @asbsn+                -> XFrame @_ @t @asbs @asbsn $ withArrayContent+                                                -- know for sure its DataFrame t bsn+                    (ewgen @t @asn @bsn @asbsn . unliftXFrame)+                    (\steps -> fromElems (steps `mappend` cumulDims (dims @bs)))+                    df+    {-# INLINE joinDataFrameI #-}++    indexOffsetI off (XFrame (df :: DataFrame t asbsN)) =+      let bs = dims :: Dims bs+          as = dropSufDims bs asbs :: Dims as+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @('Just (DimsBound bs)) @('Just asbsN)+                              as bs asbs $+           \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn)+             -> case inferKnownBackend @t @bsn of+               Dict -> XFrame (indexOffset @t @asn @bsn @asbsn off df)+    {-# INLINE indexOffsetI #-}++    updateOffsetI off (XFrame (bsDf :: DataFrame t bsN))+                      (XFrame (asbsDf :: DataFrame t asbsN)) =+      let bs = dims :: Dims bs+          as = dropSufDims bs asbs :: Dims as+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @('Just bsN) @('Just asbsN)+                              as bs asbs $+           \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn)+             -> XFrame (updateOffset @t @asn @bsn @asbsn off bsDf asbsDf)+    {-# INLINE updateOffsetI #-}++    indexI i (XFrame (df :: DataFrame t asbsN)) =+      let bs = dims :: Dims bs+          as = dropSufDims bs asbs :: Dims as+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN)+                              as bs asbs $+           \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn)+             -> case inferKnownBackend @t @bsn of+               Dict -> XFrame (index @t @asn @bsn @asbsn (unsafeUnliftIdxs i) df)+    {-# INLINE indexI #-}++    updateI i (XFrame (bsDf :: DataFrame t bsN))+              (XFrame (asbsDf :: DataFrame t asbsN)) =+      let bs = dims :: Dims bs+          as = dropSufDims bs asbs :: Dims as+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @('Just bsN) @('Just asbsN)+                              as bs asbs $+           \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn)+             -> XFrame (update @t @asn @bsn @asbsn (unsafeUnliftIdxs i) bsDf asbsDf)+    {-# INLINE updateI #-}++    ewmapI  :: forall s (bs' :: [XNat]) (asbs' :: [XNat])+             . SubSpace s as bs' asbs'+            => (DataFrame s bs' -> DataFrame t bs)+            -> DataFrame s asbs' -> DataFrame t asbs+    ewmapI f (XFrame (df :: DataFrame s asbsN')) =+      let bs    = dims :: Dims bs+          bs'   = dims :: Dims bs'+          as    = dropSufDims bs' asbs' :: Dims as+          asbs' = XDims (dims @asbsN') :: Dims asbs'+          asbs  = concatDims as bs :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN')+                              as bs' asbs' $+         \(Dims :: Dims asn) (Dims :: Dims bsn') (Dims :: Dims asbsn') ->+         withLiftedConcatList @('Just asn) @'Nothing @'Nothing+                                as bs asbs $+         \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) ->+           case inferKnownBackend @t @asbsn of+            Dict+             | Dict <- inferKnownBackend @t @bsn+             , Dict <- inferKnownBackend @s @bsn'+             -> XFrame (ewmap @t @asn @bsn @asbsn @s @bsn' @asbsn'+                        (unliftXFrame . f . XFrame) df)+    {-# INLINE ewmapI #-}++    iwmapI  :: forall s (bs' :: [XNat]) (asbs' :: [XNat])+             . SubSpace s as bs' asbs'+            => (Idxs as -> DataFrame s bs' -> DataFrame t bs)+            -> DataFrame s asbs' -> DataFrame t asbs+    iwmapI f (XFrame (df :: DataFrame s asbsN')) =+      let bs    = dims :: Dims bs+          bs'   = dims :: Dims bs'+          as    = dropSufDims bs' asbs' :: Dims as+          asbs' = XDims (dims @asbsN') :: Dims asbs'+          asbs  = concatDims as bs :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN')+                              as bs' asbs' $+         \(Dims :: Dims asn) (Dims :: Dims bsn') (Dims :: Dims asbsn') ->+         withLiftedConcatList @('Just asn) @'Nothing @'Nothing+                                as bs asbs $+         \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) -> case () of+           _ | Dict <- inferKnownBackend @t @asbsn+             , Dict <- inferKnownBackend @t @bsn+             , Dict <- inferKnownBackend @s @bsn'+               -> XFrame (iwmap @t @asn @bsn @asbsn @s @bsn' @asbsn'+                           (\i x -> unliftXFrame (f (liftIdxs i) (XFrame x))) df)+    {-# INLINE iwmapI #-}+++    ewgenI (XFrame (df :: DataFrame t bsN)) =+      let as   = dims :: Dims as+          bs   = dims :: Dims bs+          asbs = concatDims as bs :: Dims asbs+      in withLiftedConcatList @'Nothing @('Just bsN) @'Nothing as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) ->+            case inferKnownBackend @t @asbsn of+              Dict -> XFrame (ewgen @t @asn @bsn @asbsn df)+    {-# INLINE ewgenI #-}++    iwgenI f =+      let as   = dims :: Dims as+          bs   = dims :: Dims bs+          asbs = concatDims as bs :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @'Nothing as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) -> case () of+            _ | Dict <- inferKnownBackend @t @asbsn+              , Dict <- inferKnownBackend @t @bsn+                 -> XFrame (iwgen @t @asn @bsn @asbsn (unliftXFrame . f . liftIdxs))+    {-# INLINE iwgenI #-}++    ewfoldlI f x0 (XFrame (df :: DataFrame s asbsN)) =+      let as   = dropSufDims bs asbs :: Dims as+          bs   = dims :: Dims bs+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN) as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) ->+           case inferKnownBackend @t @bsn of+             Dict -> ewfoldl @t @asn @bsn @asbsn (\b x -> f b (XFrame x)) x0 df+    {-# INLINE ewfoldlI #-}++    iwfoldlI f x0 (XFrame (df :: DataFrame s asbsN)) =+      let as   = dropSufDims bs asbs :: Dims as+          bs   = dims :: Dims bs+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN) as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) ->+           case inferKnownBackend @t @bsn of+             Dict -> iwfoldl @t @asn @bsn @asbsn+                       (\i b x -> f (liftIdxs i) b (XFrame x)) x0 df+    {-# INLINE iwfoldlI #-}++    ewfoldrI f x0 (XFrame (df :: DataFrame s asbsN)) =+      let as   = dropSufDims bs asbs :: Dims as+          bs   = dims :: Dims bs+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN) as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) ->+           case inferKnownBackend @t @bsn of+             Dict -> ewfoldr @t @asn @bsn @asbsn (\x -> f (XFrame x)) x0 df+    {-# INLINE ewfoldrI #-}++    iwfoldrI f x0 (XFrame (df :: DataFrame s asbsN)) =+      let as   = dropSufDims bs asbs :: Dims as+          bs   = dims :: Dims bs+          asbs = XDims (dims @asbsN) :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN) as bs asbs $+          \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) ->+           case inferKnownBackend @t @bsn of+             Dict -> iwfoldr @t @asn @bsn @asbsn+                       (\i x -> f (liftIdxs i) (XFrame x)) x0 df+    {-# INLINE iwfoldrI #-}++    indexWiseI :: forall s (bs' :: [XNat]) (asbs' :: [XNat]) f+                . (Applicative f, SubSpace s as bs' asbs')+               => (Idxs as -> DataFrame s bs' -> f (DataFrame t bs))+               -> DataFrame s asbs' -> f (DataFrame t asbs)+    indexWiseI f (XFrame (df :: DataFrame s asbsN')) =+      let bs    = dims :: Dims bs+          bs'   = dims :: Dims bs'+          as    = dropSufDims bs' asbs' :: Dims as+          asbs' = XDims (dims @asbsN') :: Dims asbs'+          asbs  = concatDims as bs :: Dims asbs+      in withLiftedConcatList @'Nothing @'Nothing @('Just asbsN')+                              as bs' asbs' $+         \(Dims :: Dims asn) (Dims :: Dims bsn') (Dims :: Dims asbsn') ->+         withLiftedConcatList @('Just asn) @'Nothing @'Nothing+                                as bs asbs $+         \(Dims :: Dims asn) (Dims :: Dims bsn) (Dims :: Dims asbsn) -> case () of+           _ | Dict <- inferKnownBackend @t @asbsn+             , Dict <- inferKnownBackend @t @bsn+             , Dict <- inferKnownBackend @s @bsn'+               -> XFrame <$>+                         (indexWise @t @asn @bsn @asbsn @s @bsn' @asbsn'+                           (\i x -> unliftXFrame <$> f (liftIdxs i) (XFrame x)) df+                         )+    {-# INLINE indexWiseI #-}++dropSufDims :: ConcatList as bs asbs+            => Dims bs -> Dims asbs -> Dims as+dropSufDims = unsafeCoerce dropSuf+  where+    dropSuf :: [Word] -> [Word] -> [Word]+    dropSuf bs asbs = fst $ foldr f ([], bs) asbs+    f :: Word -> ([Word], [Word]) -> ([Word], [Word])+    f x (as, [])  = (x:as,[])+    f _ (_, _:rs) = ([], rs)++prefSufDims :: ConcatList as bs asbs+             => TypedList f as -> Dims asbs -> (Dims as, Dims bs)+prefSufDims = unsafeCoerce f+  where+    f :: [Word] -> [Word] -> ([Word], [Word])+    f  []      asbs   = ([], asbs)+    f (_:is) ~(a:sbs) = first (a:) (f is sbs)++concatDims :: ConcatList as bs asbs+           => Dims as -> Dims bs -> Dims asbs+concatDims = TL.concat++{-+A trick here is that both alternatives of 'MayEq' have the same representation+of a single equality constraint.+Thus, I can unsafeCoerce an equality later into MayEq to significantly+reduce amount of boilerplate.+ -}+type family MayEq (mns :: (Maybe [Nat])) (ns :: [Nat]) :: Constraint where+    MayEq 'Nothing   bs = bs ~ bs+    MayEq ('Just as) bs = as ~ bs++-- Very unsafe function, because it does not check the content of XDims at all.+withLiftedConcatList ::+       forall (asm :: Maybe [Nat]) (bsm :: Maybe [Nat]) (asbsm :: Maybe [Nat])+              (asx :: [XNat]) (bsx :: [XNat]) (asbsx :: [XNat]) r+     . -- (ConcatList asx bsx asbsx) =>+       Dims asx -> Dims bsx -> Dims asbsx+    -> ( forall (asn :: [Nat]) (bsn :: [Nat]) (asbsn :: [Nat])+          . ( ConcatList asn bsn asbsn+            , FixedDims asx asn, FixedDims bsx bsn, FixedDims asbsx asbsn+            , MayEq asm asn, MayEq bsm bsn, MayEq asbsm asbsn)+         => Dims asn -> Dims bsn -> Dims asbsn -> r+       ) -> r+withLiftedConcatList (XDims (asn :: Dims asn))+                     (XDims (bsn :: Dims bsn))+                     (XDims (asbsn :: Dims asbsn)) k+  | Dict <- unsafeEqTypes @_ @asbsn @(Concat asn bsn)+  , Dict <- unsafeCoerce (Dict @(asn ~ asn)) :: Dict (MayEq asm asn)+  , Dict <- unsafeCoerce (Dict @(bsn ~ bsn)) :: Dict (MayEq bsm bsn)+  , Dict <- unsafeCoerce (Dict @(asbsn ~ asbsn)) :: Dict (MayEq asbsm asbsn)+  , Dict <- inferConcat @asn @bsn @asbsn = k asn bsn asbsn++unliftXFrame :: forall (t :: Type) (xns :: [XNat]) (ns :: [Nat])+              . (ExactDims xns, FixedDims xns ns)+             => DataFrame t xns -> DataFrame t ns+unliftXFrame (XFrame x) = unsafeCoerce x+{-# INLINE unliftXFrame #-}++unsafeEqTypes :: forall k (a :: k) (b :: k)+               . Dict (a ~ b)+unsafeEqTypes = unsafeCoerce (Dict :: Dict (a ~ a))
src/Numeric/DataFrame/Type.hs view
@@ -12,6 +12,7 @@ {-# LANGUAGE MagicHash                  #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE PatternSynonyms            #-}+{-# LANGUAGE PolyKinds                  #-} {-# LANGUAGE RankNTypes                 #-} {-# LANGUAGE ScopedTypeVariables        #-} {-# LANGUAGE StandaloneDeriving         #-}@@ -22,7 +23,9 @@ {-# LANGUAGE UnboxedTuples              #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-}-+#ifdef UNSAFE_INDICES+{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}+#endif {- |   The core @easytensor@ types.  -}@@ -38,24 +41,29 @@   , DataFrame ( SingleFrame, MultiFrame, XFrame, (:*:), Z               , S, DF2, DF3, DF4, DF5, DF6, DF7, DF8, DF9) #endif+  , scalar, unScalar+  , IndexFrame (..), SubFrameIndexCtx     -- * Flexible assembling and disassembling   , PackDF, packDF, unpackDF   , appendDF, consDF, snocDF   , fromFlatList, fromListWithDefault, fromList-  , constrainDF+  , constrainDF, asDiag     -- * Infer type class instances   , KnownBackend (), DFBackend, KnownBackends   , InferKnownBackend (..), inferPrimElem     -- * Re-exports-  , Dim (..), Idx (), XNat (..), N, XN, Dims, Idxs, TypedList (..)+  , Dim (..), Idx (), Nat, XNat (..), N, XN, Dims, Idxs, TypedList (..)   , PrimBytes (), bSizeOf, bAlignOf, bFieldOffsetOf   , PrimArray (), ixOff   ) where  +#if !(MIN_VERSION_base(4,13,0))+import Data.Proxy (Proxy)+#endif+import           Control.Arrow                   (second, (***)) import           Data.Data-import           Data.Proxy                      (Proxy)-import           Data.Semigroup                  hiding (All)+import           Data.Semigroup                  hiding (All, Min) import           Data.Type.Lits import           Data.Void import           Foreign.Storable                (Storable (..))@@ -66,7 +74,9 @@ import qualified Text.ParserCombinators.ReadPrec as Read import qualified Text.Read                       as Read import qualified Text.Read.Lex                   as Read+import           Unsafe.Coerce +import           Numeric.Basics import           Numeric.DataFrame.Internal.PrimArray import           Numeric.Dimensions import           Numeric.PrimBytes@@ -75,12 +85,11 @@ import qualified Numeric.ProductOrd.Partial           as Partial import           Numeric.TypedList                    (typeables) -import {-# SOURCE #-} Numeric.DataFrame.Internal.Backend  (DFBackend,-                                                           KnownBackend)-import {-# SOURCE #-} qualified Numeric.DataFrame.Internal.Backend  as Backend-import           Numeric.DataFrame.Internal.BackendI ()+import           Numeric.DataFrame.Internal.BackendI (DFBackend, KnownBackend)+import qualified Numeric.DataFrame.Internal.BackendI as Backend  + -- | Keep data in a primitive data frame --    and maintain information about Dimensions in the type system data family DataFrame (t :: l) (xs :: [k])@@ -97,7 +106,7 @@ --   Pattern-match against its constructor to get a Nat-indexed data frame. data instance DataFrame (ts :: l) (xns :: [XNat])   = forall (ns :: [Nat])-  . (KnownXNatTypes xns, FixedDims xns ns, Dimensions ns, KnownBackends ts ns)+  . (All KnownDimType xns, FixedDims xns ns, Dimensions ns, KnownBackends ts ns)   => XFrame (DataFrame ts ns)  -- | Data frame that has an unknown dimensionality at compile time.@@ -113,21 +122,36 @@  {-# COMPLETE Z, (:*:) #-} +#define PLEASE_STYLISH_HASKELL \+  forall (xs :: [Type]) (ns :: [Nat])  . () => \+  forall (y :: Type)    (ys :: [Type]) . (xs ~ (y ': ys)) => \+  DataFrame y ns -> DataFrame ys ns -> DataFrame xs ns  -- | Constructing a @MultiFrame@ using DataFrame columns-pattern (:*:) :: forall (xs :: [Type]) (ns :: [Nat])  . ()-              => forall (y :: Type)    (ys :: [Type]) . (xs ~ (y ': ys))-              => DataFrame y ns -> DataFrame ys ns -> DataFrame xs ns+pattern (:*:) :: PLEASE_STYLISH_HASKELL pattern (:*:) x xs <- (MultiFrame (DataFrame' x :* (MultiFrame -> xs)))   where     (:*:) x (MultiFrame xs) = MultiFrame (DataFrame' x :* xs) infixr 6 :*:+#undef PLEASE_STYLISH_HASKELL  -- | Empty MultiFrame pattern Z :: forall (xs :: [Type]) (ns :: [Nat])            . () => (xs ~ '[]) => DataFrame xs ns pattern Z = MultiFrame U +-- | Convert a scalar back to an ordinary type+unScalar :: DataFrame t ('[] :: [Nat]) -> t+-- rely on that Scalar is just two times newtype alias to t+unScalar = unsafeCoerce+{-# INLINE unScalar #-}++-- | Convert any type to a scalar wrapper+scalar :: t -> DataFrame t ('[] :: [Nat])+-- rely on that Scalar is just two times newtype alias to t+scalar = unsafeCoerce+{-# INLINE scalar #-}+ -- | I use this kind-polymorphic constraint to generalize @XFrame@ and @SomeDataFrame@ --   over @SingleFrame@ and @MultiFrame@. type family KnownBackends (ts :: l) (ns :: [Nat]) :: Constraint where@@ -137,8 +161,8 @@       (KnownBackend t ns, KnownBackends ts ns)  -- | Allow inferring @KnownBackends@ if you know the dimensions and the element types.-class InferKnownBackend (t :: k) ds where-    -- Infer @KnownBackends@ if you know the dimensions and the element types.+class InferKnownBackend t (ds :: [Nat]) where+    -- | Infer @KnownBackends@ if you know the dimensions and the element types.     inferKnownBackend :: Dict (KnownBackends t ds)  instance (PrimBytes t, Dimensions ds) => InferKnownBackend (t :: Type) ds where@@ -146,15 +170,17 @@  instance (RepresentableList ts, All PrimBytes ts, Dimensions ds)       => InferKnownBackend (ts :: [Type]) ds where-    inferKnownBackend = go (tList @_ @ts)+    inferKnownBackend = go (tList @ts)       where-        go :: forall ss . All PrimBytes ss => TypeList ss -> Dict (KnownBackends ss ds)+        go :: forall ss . All PrimBytes ss+           => TypeList ss -> Dict (KnownBackends ss ds)         go U = Dict         go ((_ :: Proxy t) :* ts)              = case Backend.inferKnownBackend @t @ds of                  Dict -> case go ts of                    Dict -> Dict + -- | All component data frames must satisfy a given constraint. type family AllFrames (f :: Type -> Constraint) (ts :: [Type]) (ds :: [Nat])                                                              :: Constraint where@@ -162,6 +188,107 @@     AllFrames f (t ': ts) ds = (f (DataFrame t ds), AllFrames f ts ds)  +-- | Index one dimension deep into a @DataFrame@.+class IndexFrame t d ds where+    -- | Index one dimension deep into a @DataFrame@.+    --+    --   Note, this function does not provide indexing safety at the type level;+    --   it throws an `OutOfDimBounds` exception if an index is out of bounds+    --   (unless @unsafeindices@ package flag is enabled, which is even more dangerous).+    (!) :: DataFrame t (d ': ds) -> Word -> DataFrame t ds++instance (PrimArray t (DataFrame t '[d]), KnownDim d)+      => IndexFrame (t :: Type) (d :: Nat) '[] where+    {-# INLINE (!) #-}+    (!) df i+#ifndef UNSAFE_INDICES+      | i >= dimVal' @d = outOfDimBoundsNoCallStack "IndexFrame.(!)"+                            i (dimVal' @d) Nothing Nothing+      | otherwise+#endif+        = S (ixOff (fromIntegral i) df)++instance {-# INCOHERENT #-}+         ( PrimArray t (DataFrame t (d ': ds))+         , KnownDim d, KnownBackend t ds)+      => IndexFrame (t :: Type) (d :: Nat) ds where+    {-# INLINE (!) #-}+    (!) df i+#ifndef UNSAFE_INDICES+      | i >= dimVal' @d = outOfDimBoundsNoCallStack "IndexFrame.(!)"+                            i (dimVal' @d) Nothing Nothing+      | otherwise+#endif+        = withArrayContent broadcast+           (\(CumulDims ~(_:ss@(s:_))) off0 ->+               fromElems (CumulDims ss) (case s*i of W# off -> off0 +# word2Int# off)+           ) df+++instance IndexFrame ('[] :: [Type]) (d :: Nat) ds where+    {-# INLINE (!) #-}+    (!) Z _ = Z++instance (IndexFrame t d ds, IndexFrame ts d ds)+      => IndexFrame ((t ': ts) :: [Type]) (d :: Nat) ds where+    {-# INLINE (!) #-}+    (!) (df :*: dfs) i = df ! i :*: dfs ! i++instance PrimBytes t+      => IndexFrame (t :: Type) (xd :: XNat) xds where+    {-# INLINE (!) #-}+    (!) (XFrame df) i+      | D :* (Dims :: Dims ns) <- dims `inSpaceOf` df+      , Dict <- inferKnownBackend @t @ns+        = XFrame (df ! i)+    (!) _ _ = error "IndexFrame: impossible pattern"++instance (RepresentableList ts, All PrimBytes ts)+      => IndexFrame (ts :: [Type]) (xd :: XNat) xds where+    {-# INLINE (!) #-}+    (!) (XFrame df) i+      | (D :: Dim n) :* (Dims :: Dims ns) <- dims `inSpaceOf` df+      , Dict <- getTsEvs @ts @n @ns tList+        = XFrame (df ! i)+      where+        getTsEvs :: forall (as :: [Type]) (d :: Nat) (ds :: [Nat])+                  . ( All PrimBytes as, KnownBackends as (d ': ds)+                    , Dimensions ds, KnownDim d)+                 => TypeList as -> Dict (IndexFrame as d ds, KnownBackends as ds)+        getTsEvs U = Dict+        getTsEvs ((_ :: Proxy a) :* as')+          | Dict <- getTsEvs @_ @d @ds as'+          , Dict <- inferKnownBackend @a @ds = Dict+    (!) _ _ = error "IndexFrame: impossible pattern"++{- |+This type family describes two strategies for dealing with dimensions when+slicing a @DataFrame@.++If the original space dimension (@d@) is fixed at compile time+(@d :: Nat@ or @d ~ N n@), then we enforce the safety of a slicing operation+with types:+    the index space is bounded by the size of the original space+    minus the subframe size.++If the original space dimension (@d@) is not fixed (@d ~ XN m@), then we give up.+Just let the user do the slicing as easy as possible, and throw an `OutOfDimBounds`+exception at runtime if the index plus the sliced size is greater than the+original size of the DataFrame.+ -}+type family SubFrameIndexCtx (d :: k) (idxN :: k) (subN :: k) :: Constraint where+    SubFrameIndexCtx (n :: Nat) idxN subN+      = (n + 1) ~ (idxN + subN)+    SubFrameIndexCtx (N n) idxN subN+      = ( (n + 1) ~ (DimBound idxN + DimBound subN)+        , idxN ~ N (DimBound idxN)+        , subN ~ N (DimBound subN)+        )+    SubFrameIndexCtx (XN m) idxN subN+      = ( idxN ~ XN m+        , subN ~ N (DimBound subN)+        )+ deriving instance Typeable (DataFrame (t :: l) (xs :: [k])) deriving instance ( Data (DataFrame t xs)                   , Typeable t, Typeable xs, Typeable k, Typeable l)@@ -184,17 +311,24 @@                => Fractional (DataFrame t ds) deriving instance Floating (DFBackend t ds)                => Floating (DataFrame t ds)+deriving instance Epsilon (DFBackend t ds)+               => Epsilon (DataFrame t ds) deriving instance Real (DFBackend t ds)                => Real (DataFrame t ds)+deriving instance RealExtras (DFBackend t ds)+               => RealExtras (DataFrame t ds) deriving instance RealFrac (DFBackend t ds)                => RealFrac (DataFrame t ds) deriving instance RealFloat (DFBackend t ds)                => RealFloat (DataFrame t ds)+deriving instance RealFloatExtras (DFBackend t ds)+               => RealFloatExtras (DataFrame t ds) deriving instance PrimBytes (DFBackend t ds)                => PrimBytes (DataFrame t ds) deriving instance (PrimArray t (DFBackend t ds), PrimBytes t)                => PrimArray t (DataFrame t ds) + instance Ord (NonTransitive.ProductOrd (DFBackend t ds))       => Ord (NonTransitive.ProductOrd (DataFrame t ds)) where     (>) = coerce ((>) @(NonTransitive.ProductOrd (DFBackend t ds)))@@ -263,7 +397,7 @@          ) => Show (DataFrame (t :: Type) (ds :: [Nat])) where     showsPrec p x = case dims @ds of       U       -> showParen (p >= 10)-        $ showString "S " . showsPrec 10 (unsafeCoerce# x :: t)+        $ showString "S " . showsPrec 10 (unScalar x)       D0 :* _ -> showString "DF0"       d  :* _ -> showParen (p >= 10)         $ unpackDF' ( \Dict f ->@@ -310,24 +444,24 @@  instance (All Read ts, All PrimBytes ts, RepresentableList ts, Dimensions ds)       => Read (DataFrame (ts :: [Type]) (ds :: [Nat])) where-    readPrec = readFixedMultiDF (tList @Type @ts) (dims @ds)+    readPrec = readFixedMultiDF (tList @ts) (dims @ds)     readList = Read.readListDefault     readListPrec = Read.readListPrecDefault -instance (Read t, PrimBytes t, BoundedDims ds, All KnownXNatType ds)+instance (Read t, PrimBytes t, BoundedDims ds, All KnownDimType ds)       => Read (DataFrame (t :: Type) (ds :: [XNat])) where     readPrec = Read.parens . Read.prec 10 $ do       Read.lift . Read.expect $ Read.Ident "XFrame"-      Read.step $ readPrecBoundedDF (minDims @XNat @ds)+      Read.step $ readPrecBoundedDF (minimalDims @ds)     readList = Read.readListDefault     readListPrec = Read.readListPrecDefault  instance ( All Read ts, All PrimBytes ts, RepresentableList ts-         , BoundedDims ds, All KnownXNatType ds)+         , BoundedDims ds, All KnownDimType ds)       => Read (DataFrame (ts :: [Type]) (ds :: [XNat])) where     readPrec = Read.parens . Read.prec 10 $ do       Read.lift . Read.expect $ Read.Ident "XFrame"-      Read.step $ readBoundedMultiDF (tList @Type @ts) (minDims @XNat @ds)+      Read.step $ readBoundedMultiDF (tList @ts) (minimalDims @ds)     readList = Read.readListDefault     readListPrec = Read.readListPrecDefault @@ -343,7 +477,7 @@       => Read (SomeDataFrame (ts :: [Type])) where     readPrec = Read.parens . Read.prec 10 $ do       Read.lift . Read.expect $ Read.Ident "SomeDataFrame"-      Read.step $ readSomeMultiDF (tList @Type @ts)+      Read.step $ readSomeMultiDF (tList @ts)     readList = Read.readListDefault     readListPrec = Read.readListPrecDefault @@ -381,7 +515,7 @@   -} readPrecBoundedDF :: forall (t :: Type) (ds :: [XNat])-                   . (Read t, PrimBytes t, KnownXNatTypes ds)+                   . (Read t, PrimBytes t, All KnownDimType ds)                   => Dims ds -> Read.ReadPrec (DataFrame t ds) -- reading scalar readPrecBoundedDF U@@ -414,7 +548,7 @@   = Read.parens $ lookLex >>= \case     Read.Ident ('D':'F':s)       | Just (Dx (n :: Dim n)) <- (Read.readMaybe ('D':s) :: Maybe SomeDim)-      , Just Dict <- indeedLE m n -- check if the DF dim is not less than m+      , Just Dict <- lessOrEqDim m n         -> case n of           D0 -> do -- need to repack it under different constraint dims             XFrame x <- readPrecBoundedDF @t (Dn D0 :* xns)@@ -428,12 +562,6 @@                 (followedBy x)      _ -> Read.pfail-  where-    indeedLE :: forall (a ::Nat) (b :: Nat) . Dim a -> Dim b -> Maybe (Dict (a <= b))-    indeedLE a b = case compareDim a b of-      SLT -> Just Dict-      SEQ -> Just Dict-      SGT -> Nothing  {- In this case we know Nothing about the dimensionality of a DataFrame.@@ -451,7 +579,7 @@     Read.+++     (lookLex >>= \case        Read.Ident ('D':'F':s)-         | Just (Dx (d :: Dim d)) <- (Read.readMaybe ('D':s) :: Maybe SomeDim)+         | Just (Dx (d@D :: Dim d)) <- (Read.readMaybe ('D':s) :: Maybe SomeDim)            -> case d of              D0 | Dict <- inferKnownBackend @t @'[0]                  -> SomeDataFrame <$> readPrecFixedDF @t (D0 :* U)@@ -479,7 +607,7 @@     return (x :*: xs)  readBoundedMultiDF :: forall (ts :: [Type]) (ds :: [XNat])-                    . (All Read ts, All PrimBytes ts, KnownXNatTypes ds)+                    . (All Read ts, All PrimBytes ts, All KnownDimType ds)                    => TypeList ts                    -> Dims ds                    -> Read.ReadPrec (DataFrame ts ds)@@ -562,9 +690,9 @@ -- | A scalar DataFrame is just a newtype wrapper on a value. pattern S :: forall (t :: Type) . t -> DataFrame t ('[] :: [Nat]) -- rely on that Scalar is just two times newtype alias to t-pattern S x <- (unsafeCoerce# -> x)+pattern S x <- (unScalar -> x)   where-    S = unsafeCoerce#+    S = scalar {-# COMPLETE S #-}  @@ -800,25 +928,27 @@                -> Int -> r)           -> DataFrame t (d ': ds)           -> r-unpackDF' k df+unpackDF' k   | d :* Dims <- dims @(d ': ds)   , Dict <- inferKnownBackend @t @(d ': ds)   , Dict <- inferKnownBackend @t @ds-    = case arrayContent# df of-        (# x | #)-          | e <- broadcast x-            -> let f :: forall (zr :: RuntimeRep) (z :: TYPE zr)-                      . (Int -> DataFrame t ds -> z) -> Int -> z-                   f consume = (`consume` e)-               in k Dict f 0-        (# | (# cdims, off, arr #) #)-          | cd <- CumulDims . tail $ unCumulDims cdims-          , td <- cdTotalDim# cd-          , n <- case dimVal d of W# w -> word2Int# w-            -> let f :: forall (zr :: RuntimeRep) (z :: TYPE zr)-                      . (Int -> DataFrame t ds -> z) -> Int -> z-                   f consume (I# o) = consume (I# (o -# td)) (fromElems cd o arr)-               in k Dict f (I# (off +# td *# (n -# 1#)))+    = withArrayContent+    ( \x ->+      let e = broadcast x+          f :: forall (zr :: RuntimeRep) (z :: TYPE zr)+             . (Int -> DataFrame t ds -> z) -> Int -> z+          f consume = (`consume` e)+      in k Dict f 0+    )+    ( \cdims off arr ->+      let cd = CumulDims . tail $ unCumulDims cdims+          td = cdTotalDim# cd+          n = case dimVal d of W# w -> word2Int# w+          f :: forall (zr :: RuntimeRep) (z :: TYPE zr)+             . (Int -> DataFrame t ds -> z) -> Int -> z+          f consume (I# o) = consume (I# (o -# td)) (fromElems cd o arr)+      in k Dict f (I# (off +# td *# (n -# 1#)))+    )   | otherwise = error "Numeric.DataFrame.Type.unpackDF: impossible args"  @@ -878,17 +1008,20 @@   -- | Unsafely copy two PrimBytes values into a third one.-unsafeAppendPB :: (PrimBytes x, PrimBytes y, PrimBytes z)+unsafeAppendPB :: forall x y z+                . (PrimBytes x, PrimBytes y, PrimBytes z)                => x -> y -> z-unsafeAppendPB x y-  | sx <- byteSize x-  = case runRW#-    ( \s0 -> case newByteArray# (sx +# byteSize y) s0 of-        (# s1, mba #) -> unsafeFreezeByteArray# mba-            ( writeBytes mba sx y-            ( writeBytes mba 0# x s1))-    ) of (# _, r #) -> fromBytes 0# r-+unsafeAppendPB x y = go (byteSize x) (byteSize y)+  where+    go :: Int# -> Int# -> z+    go 0# _  = fromBytes (byteOffset y) (getBytes y)+    go _  0# = fromBytes (byteOffset x) (getBytes x)+    go sx sy = case runRW#+      ( \s0 -> case newByteArray# (sx +# sy) s0 of+          (# s1, mba #) -> unsafeFreezeByteArray# mba+              ( writeBytes mba sx y+              ( writeBytes mba 0# x s1))+      ) of (# _, r #) -> fromBytes 0# r  -- | Construct a DataFrame from a list of smaller DataFrames. --@@ -911,35 +1044,76 @@ --   Pattern-match against the resulting @XFrame@ to find out its dimensionality. -- --   You must not provide an infinite list as an argument.-fromList :: forall (t :: Type) (ds :: [Nat])-          . (PrimBytes t, Dimensions ds)-         => [DataFrame t ds] -> DataFrame t (XN 0 ': AsXDims ds)+fromList :: forall (t :: Type) (ds :: [Nat]) (xds :: [XNat])+          . (PrimBytes t, Dimensions ds, xds ~ Map N ds, ds ~ UnMap N xds)+         => [DataFrame t ds] -> DataFrame t (XN 0 ': xds) fromList xs     | Dx (D :: Dim n) <- someDimVal . fromIntegral $ length xs     , Dict <- inferKnownBackend @t @(n ': ds)-    , ds@(AsXDims (XDims ds')) <- dims @ds-    , Just Dict <- sameDims ds ds'+    , Dict <- unsafeEqTypes @_ @ds @(DimsBound xds)+    , Dict <- inferExactFixedDims (dims @ds)       = XFrame (fromListWithDefault @t @n @ds undefined xs)     | otherwise-      = error "Numeri.DataFrame.Type/fromList: impossible arguments"-+      = case Dict @(ds ~ UnMap N xds) of+          Dict -> -- just make GHC not complain about unused constraints.+            error "Numeri.DataFrame.Type/fromList: impossible arguments"  -- | Try to convert between @XNat@-indexed DataFrames. -- --   This is useful for imposing restrictions on unknown DataFrames, --   e.g. increasing the minimum number of elements.-constrainDF :: forall (ds :: [XNat]) (ys :: [XNat]) (l :: Type) (ts :: l)-             . (BoundedDims ds, All KnownXNatType ds)-            => DataFrame ts ys -> Maybe (DataFrame ts ds)-constrainDF (XFrame (df :: DataFrame ts ns))+constrainDF :: forall (ds :: [XNat]) (ys :: [XNat]) t+             . (BoundedDims ds, All KnownDimType ds)+            => DataFrame t ys -> Maybe (DataFrame t ds)+constrainDF (XFrame (df :: DataFrame t ns))   | ns <- dims @ns-  = case constrainDims @XNat @ds ns of+  = case constrainDims @ds ns of       Just (XDims (Dims :: Dims ms))         | Dict <- unsafeEqTypes @[Nat] @ns @ms           -> Just $ XFrame df       _   -> Nothing +-- | Place elements of a vector on the main diagonal of a matrix;+--   fill the rest of the matrix with zeroes.+--+--   Note, this function is naturally generalized onto higher dimensions+--    (which can be seen from the type signature).+--+--   Note, the argument of this function does not fully determine its result type.+--   This may cause some obscure type errors.+--   Specify type parameters @n@ and @m@ explicitly or make sure the result type is fixed.+asDiag :: forall (n :: Nat) (m :: Nat) (ds :: [Nat]) (t :: Type)+        . ( Dimensions ds, KnownDim n, KnownDim m+          , KnownBackend t (Min n m :+ ds)+          , KnownBackend t (n :+ m :+ ds)+          , PrimBytes t)+       => DataFrame t (Min n m :+ ds)+       -> DataFrame t (n :+ m :+ ds)+asDiag x+  | elemSize <- byteSize @t undefined+  , dMinNM@D <- minDim (D @n) (D @m)+  , xba <- getBytes x+  , ds <- dims @ds+  , steps@(CumulDims (elemsNR:_:elemsNE:_)) <- cumulDims (D @n :* D @m :* ds)+  , m <- dimVal' @m+  , bsE <- case elemsNE of W# w -> word2Int# w *# elemSize+  , bsR <- case elemsNR of W# w -> word2Int# w *# elemSize+  , bsShift <- case m + 1 of W# w -> word2Int# w *# bsE+  , bsLim <- case m * dimVal dMinNM of W# w -> word2Int# w *# bsE+    = case runRW#+      ( \s0 -> case newByteArray# bsR s0 of+          (# s1, mba #) ->+            let go offSrc offDst s+                  | isTrue# (offDst >=# bsLim) = s+                  | otherwise = go (offSrc +# bsE) (offDst +# bsShift)+                      (copyByteArray# xba offSrc mba offDst bsE s)+            in  unsafeFreezeByteArray# mba+                  (go (byteOffset x) 0# (setByteArray# mba 0# bsR 0# s1)) +      ) of (# _, r #) -> fromElems steps 0# r+  | otherwise+    = error "Numeri.DataFrame.Type/asDiag: impossible arguments"+{-# INLINE asDiag #-}  -- Need this for @packDF'@ to make @Int -> c z@ a proper second-order type -- parameterized by the result type.@@ -955,7 +1129,7 @@       U | S x <- v         -> z S `k` x       D :* (Dims :: Dims ns)-        -> case inferTypeableCons @_ @ds of+        -> case inferTypeableCons @ds of           Dict ->             -- PLZ don't ask me how does this work             unpackDF' (\_ f -> runOff $ packDF'@@ -965,7 +1139,7 @@     gunfold k z _ = case typeableDims @ds of       U      -> k (z S)       D :* (Dims :: Dims ns)-        -> case inferTypeableCons @_ @ds of Dict -> packDF' k z+        -> case inferTypeableCons @ds of Dict -> packDF' k z     toConstr _ = case typeableDims @ds of       U      -> scalarFrameConstr       d :* _ -> singleFrameConstr $ dimVal d@@ -980,11 +1154,11 @@ instance (AllFrames Data ts ds, Typeable ts, Typeable ds)       => Data (DataFrame (ts :: [Type]) (ds :: [Nat])) where     gfoldl _ z Z = z Z-    gfoldl k z (x :*: xs) = case inferTypeableCons @Type @ts of+    gfoldl k z (x :*: xs) = case inferTypeableCons @ts of       Dict -> z (:*:) `k` x `k` xs-    gunfold k z _ = case typeables @Type @ts of+    gunfold k z _ = case typeables @ts of       U      -> z Z-      _ :* _ -> case inferTypeableCons @_ @ts of Dict -> k (k (z (:*:)))+      _ :* _ -> case inferTypeableCons @ts of Dict -> k (k (z (:*:)))     toConstr Z         = multiFrameZConstr     toConstr (_ :*: _) = multiFrameConsConstr     dataTypeOf _ = dataFrameDataType [multiFrameZConstr, multiFrameConsConstr]@@ -1043,13 +1217,14 @@ fromSingleFrame (dd@D :* (Dims :: Dims ds')) x   | Dict <- inferKnownBackend @t @ds   , Dict <- inferKnownBackend @t @ds'-    = G.M1 $ case arrayContent# x of-      (# e | #) -> fillRep @_ @ds' (const $ broadcast e) 0 dd-      (# | (# cdims, off, arr #) #)-       | cd <- CumulDims . tail $ unCumulDims cdims-       , td <- cdTotalDim# cd-                -> fillRep @_ @ds'-                   (\(W# i) -> fromElems cd (off +# td *# word2Int# i) arr) 0 dd+    = G.M1 $ withArrayContent+        (\e -> fillRep @_ @ds' (const $ broadcast e) 0 dd)+        (\cdims off arr ->+           let cd = CumulDims . tail $ unCumulDims cdims+               td = cdTotalDim# cd+           in  fillRep @_ @ds'+                 (\(W# i) -> fromElems cd (off +# td *# word2Int# i) arr) 0 dd+        ) x   where     fillRep :: forall (n :: Nat) (ns :: [Nat])              . (Word -> DataFrame t ns)@@ -1105,7 +1280,7 @@       where         d2  = divDim d D2         d2' = d2 `plusDim` modDim d D2-+{-# INLINE toSingleFrame #-}  type family MultiFrameRepNil (ts :: [Type]) :: (Type -> Type) where     MultiFrameRepNil '[]      = G.C1 ('G.MetaCons "Z" 'G.PrefixI 'False) G.U1@@ -1136,5 +1311,245 @@   +instance (AllFrames Eq ts ds, AllFrames Ord ts ds)+      => Ord (DataFrame (ts :: [Type]) ds) where+    compare Z Z                   = EQ+    compare (a :*: as) (b :*: bs) = compare a b <> compare as bs+++withFixedDF1 :: forall (l :: Type) (ts :: l) (xns :: [XNat])+                       (rep :: RuntimeRep) (r :: TYPE rep)+              . xns ~ Map 'N (DimsBound xns)+             => ( forall (ns :: [Nat])+               . ( All KnownDimType xns, FixedDims xns ns+                 , Dimensions ns+                 , KnownBackends ts ns+                 , ns ~ DimsBound xns+                 , xns ~ Map 'N ns+                 ) => DataFrame ts ns -> r+              ) -> DataFrame ts xns -> r+withFixedDF1 f (XFrame (df :: DataFrame ts ds))+  | Dict <- unsafeEqTypes @_ @ds @(DimsBound xns)+    = f df+{-# INLINE withFixedDF1 #-}++withFixedDF2 :: forall (l :: Type) (ts :: l) (xns :: [XNat])+                       (rep :: RuntimeRep) (r :: TYPE rep)+              . xns ~ Map 'N (DimsBound xns)+             => ( forall (ns :: [Nat])+               . ( All KnownDimType xns, FixedDims xns ns+                 , Dimensions ns+                 , KnownBackends ts ns+                 , ns ~ DimsBound xns+                 , xns ~ Map 'N ns+                 ) => DataFrame ts ns -> DataFrame ts ns -> r+              ) -> DataFrame ts xns -> DataFrame ts xns -> r+withFixedDF2 f (XFrame (a :: DataFrame ts as)) (XFrame (b :: DataFrame ts bs))+  | Dict <- unsafeEqTypes @_ @as @(DimsBound xns)+  , Dict <- unsafeEqTypes @_ @bs @(DimsBound xns)+    = f a b+{-# INLINE withFixedDF2 #-}++instance ( xns ~ Map 'N (DimsBound xns)+         , Eq (DataFrame ts xns)+         , Ord (DataFrame ts (DimsBound xns))+         ) => Ord (DataFrame (ts :: l) (xns :: [XNat])) where+    compare = withFixedDF2 compare+    (>=) = withFixedDF2 (>=)+    (<=) = withFixedDF2 (<=)+    (>)  = withFixedDF2 (>)+    (<)  = withFixedDF2 (<)+    min  = withFixedDF2 ((.) XFrame . min)+    max  = withFixedDF2 ((.) XFrame . max)++instance ( Dimensions xns+         , KnownBackends ts (DimsBound xns)+         , Num (DataFrame ts (DimsBound xns))+         ) => Num (DataFrame (ts :: l) (xns :: [XNat])) where+    (+) = withKnownXDims @xns $ withFixedDF2 ((.) XFrame . (+))+    (-) = withKnownXDims @xns $ withFixedDF2 ((.) XFrame . (-))+    (*) = withKnownXDims @xns $ withFixedDF2 ((.) XFrame . (*))+    negate = withKnownXDims @xns $ withFixedDF1 (XFrame . negate)+    abs    = withKnownXDims @xns $ withFixedDF1 (XFrame . abs)+    signum = withKnownXDims @xns $ withFixedDF1 (XFrame . signum)+    fromInteger = withKnownXDims @xns+      (XFrame . fromInteger @(DataFrame ts (DimsBound xns)))++instance ( Dimensions xns+         , KnownBackends ts (DimsBound xns)+         , Fractional (DataFrame ts (DimsBound xns))+         ) => Fractional (DataFrame (ts :: l) (xns :: [XNat])) where+    (/) = withKnownXDims @xns $ withFixedDF2 ((.) XFrame . (/))+    recip = withKnownXDims @xns $ withFixedDF1 (XFrame . recip)+    fromRational = withKnownXDims @xns+      (XFrame . fromRational @(DataFrame ts (DimsBound xns)))++instance ( Dimensions xns+         , KnownBackends ts (DimsBound xns)+         , Floating (DataFrame ts (DimsBound xns))+         ) => Floating (DataFrame (ts :: l) (xns :: [XNat])) where+    pi    = withKnownXDims @xns $ XFrame (pi :: DataFrame ts (DimsBound xns))+    exp   = withKnownXDims @xns $ withFixedDF1 (XFrame . exp)+    log   = withKnownXDims @xns $ withFixedDF1 (XFrame . log)+    sqrt  = withKnownXDims @xns $ withFixedDF1 (XFrame . sqrt)+    sin   = withKnownXDims @xns $ withFixedDF1 (XFrame . sin)+    cos   = withKnownXDims @xns $ withFixedDF1 (XFrame . cos)+    tan   = withKnownXDims @xns $ withFixedDF1 (XFrame . tan)+    asin  = withKnownXDims @xns $ withFixedDF1 (XFrame . asin)+    acos  = withKnownXDims @xns $ withFixedDF1 (XFrame . acos)+    atan  = withKnownXDims @xns $ withFixedDF1 (XFrame . atan)+    sinh  = withKnownXDims @xns $ withFixedDF1 (XFrame . sinh)+    cosh  = withKnownXDims @xns $ withFixedDF1 (XFrame . cosh)+    tanh  = withKnownXDims @xns $ withFixedDF1 (XFrame . tanh)+    asinh = withKnownXDims @xns $ withFixedDF1 (XFrame . asinh)+    acosh = withKnownXDims @xns $ withFixedDF1 (XFrame . acosh)+    atanh = withKnownXDims @xns $ withFixedDF1 (XFrame . atanh)+    (**)    = withKnownXDims @xns $ withFixedDF2 ((.) XFrame . (**))+    logBase = withKnownXDims @xns $ withFixedDF2 ((.) XFrame . logBase)++instance ( xns ~ Map 'N (DimsBound xns)+         , ProductOrder (DataFrame ts (DimsBound xns))+         ) => ProductOrder (DataFrame (ts :: l) (xns :: [XNat])) where+    cmp = withFixedDF2 cmp++instance ( Dimensions xns+         , KnownBackends ts (DimsBound xns)+         , Bounded (DataFrame ts (DimsBound xns))+         ) => Bounded (DataFrame (ts :: l) (xns :: [XNat])) where+    minBound = withKnownXDims @xns (XFrame (minBound :: DataFrame ts (DimsBound xns)))+    maxBound = withKnownXDims @xns (XFrame (maxBound :: DataFrame ts (DimsBound xns)))++instance ( Dimensions xns+         , KnownBackends ts (DimsBound xns)+         , PrimBytes (DataFrame ts (DimsBound xns))+         ) => PrimBytes (DataFrame (ts :: l) (xns :: [XNat])) where+    type PrimFields (DataFrame ts xns)+      = PrimFields (DataFrame ts (DimsBound xns))+    getBytes = withKnownXDims @xns $ withFixedDF1 getBytes+    getBytesPinned = withKnownXDims @xns $ withFixedDF1 getBytesPinned+    fromBytes i ba+      = withKnownXDims @xns (XFrame (fromBytes i ba :: DataFrame ts (DimsBound xns)))+    readBytes mba i s0+      | (# s1, (a  :: DataFrame ts (DimsBound xns)) #) <- readBytes mba i s0+        = (# s1, withKnownXDims @xns (XFrame a) #)+    writeBytes mba i = withKnownXDims @xns $ withFixedDF1 (writeBytes mba i)+    readAddr addr s0+      | (# s1, (a  :: DataFrame ts (DimsBound xns)) #) <- readAddr addr s0+        = (# s1, withKnownXDims @xns (XFrame a) #)+    writeAddr = withKnownXDims @xns $ withFixedDF1 writeAddr+    byteSize  _ = withKnownXDims @xns (byteSize @(DataFrame ts (DimsBound xns)) undefined)+    byteAlign _ = withKnownXDims @xns (byteAlign @(DataFrame ts (DimsBound xns)) undefined)+    byteOffset  = withKnownXDims @xns (withFixedDF1 byteOffset)+    byteFieldOffset n _+        = withKnownXDims @xns (byteFieldOffset @(DataFrame ts (DimsBound xns)) n undefined)+    indexArray ba i+      = withKnownXDims @xns (XFrame (indexArray ba i :: DataFrame ts (DimsBound xns)))+    readArray mba i s0+      | (# s1, (a  :: DataFrame ts (DimsBound xns)) #) <- readArray mba i s0+        = (# s1, withKnownXDims @xns (XFrame a) #)+    writeArray mba i = withKnownXDims @xns (withFixedDF1 (writeArray mba i))++instance ( Dimensions xns+         , KnownBackend t (DimsBound xns)+         , PrimArray t (DataFrame t (DimsBound xns))+         , PrimBytes t+         ) => PrimArray t (DataFrame t (xns :: [XNat])) where+    broadcast#+      = withKnownXDims @xns (XFrame . broadcast# @t @(DataFrame t (DimsBound xns)))+    ix# i = withKnownXDims @xns (withFixedDF1 (ix# i))+    gen# cd f s0+      | (# s1, (a  :: DataFrame t (DimsBound xns)) #) <- gen# cd f s0+        = (# s1, withKnownXDims @xns (XFrame a) #)+    upd# cd i t = withKnownXDims @xns (withFixedDF1 (XFrame . upd# cd i t))+    withArrayContent# f g = withKnownXDims @xns (withFixedDF1 (withArrayContent f g))+    offsetElems = withKnownXDims @xns (withFixedDF1 offsetElems)+    uniqueOrCumulDims = withKnownXDims @xns (withFixedDF1 uniqueOrCumulDims)+    fromElems# cd i ba+      = withKnownXDims @xns (XFrame (fromElems cd i ba :: DataFrame t (DimsBound xns)))+++-- The following instance only make sense on scalars.++instance ( Enum (DataFrame ts ('[] :: [Nat]))+         , KnownBackends ts ('[] :: [Nat])+         ) => Enum (DataFrame (ts :: l) ('[] :: [XNat])) where+    succ (XFrame x) = XFrame (succ x)+    pred (XFrame x) = XFrame (pred x)+    toEnum  = XFrame . toEnum+    fromEnum (XFrame x) = fromEnum x+    enumFrom (XFrame x) = map XFrame $ enumFrom x+    enumFromThen   (XFrame x) (XFrame y) = map XFrame $ enumFromThen x y+    enumFromTo     (XFrame x) (XFrame y) = map XFrame $ enumFromTo x y+    enumFromThenTo (XFrame x) (XFrame y) (XFrame z)+      = map XFrame $ enumFromThenTo x y z++instance ( Epsilon (DataFrame ts ('[] :: [Nat]))+         , KnownBackends ts ('[] :: [Nat])+         , Eq (DataFrame ts ('[] :: [XNat]))+         ) => Epsilon (DataFrame (ts :: l) ('[] :: [XNat])) where+    epsilon = XFrame epsilon++instance ( Real (DataFrame ts ('[] :: [Nat]))+         , KnownBackends ts ('[] :: [Nat])+         , Eq (DataFrame ts ('[] :: [XNat]))+         ) => Real (DataFrame (ts :: l) ('[] :: [XNat])) where+    toRational (XFrame x) = toRational x++instance ( Integral (DataFrame ts ('[] :: [Nat]))+         , KnownBackends ts ('[] :: [Nat])+         , Eq (DataFrame ts ('[] :: [XNat]))+         ) => Integral (DataFrame (ts :: l) ('[] :: [XNat])) where+    quot (XFrame x) (XFrame y) = XFrame (quot x y)+    rem (XFrame x) (XFrame y) = XFrame (rem x y)+    div (XFrame x) (XFrame y) = XFrame (div x y)+    mod (XFrame x) (XFrame y) = XFrame (mod x y)+    quotRem (XFrame x) (XFrame y) = (XFrame *** XFrame) (quotRem x y)+    divMod (XFrame x) (XFrame y) = (XFrame *** XFrame) (divMod x y)+    toInteger (XFrame x) = toInteger x++instance ( RealExtras (DataFrame t ('[] :: [Nat]))+         , KnownBackend t ('[] :: [Nat])+         , Eq t+         ) => RealExtras (DataFrame (t :: Type) ('[] :: [XNat])) where+    copysign (XFrame x) (XFrame y) = XFrame (copysign x y)++instance ( RealFrac (DataFrame t ('[] :: [Nat]))+         , KnownBackend t ('[] :: [Nat])+         , Eq t+         ) => RealFrac (DataFrame (t :: Type) ('[] :: [XNat])) where+    properFraction (XFrame x) = second XFrame (properFraction x)+    truncate (XFrame x) = truncate x+    round (XFrame x) = round x+    ceiling (XFrame x) = ceiling x+    floor (XFrame x) = floor x++instance ( RealFloat (DataFrame t ('[] :: [Nat]))+         , KnownBackend t ('[] :: [Nat])+         , Eq t+         ) => RealFloat (DataFrame (t :: Type) ('[] :: [XNat])) where+    floatRadix  = const (floatRadix  @(DataFrame t ('[] :: [Nat])) undefined)+    floatDigits = const (floatDigits @(DataFrame t ('[] :: [Nat])) undefined)+    floatRange  = const (floatRange  @(DataFrame t ('[] :: [Nat])) undefined)+    decodeFloat (XFrame x) = decodeFloat x+    encodeFloat i = XFrame . encodeFloat i+    exponent (XFrame x) = exponent x+    significand (XFrame x) = XFrame (significand x)+    scaleFloat i (XFrame x) = XFrame (scaleFloat i x)+    isNaN (XFrame x) = isNaN x+    isInfinite (XFrame x) = isInfinite x+    isDenormalized (XFrame x) = isDenormalized x+    isNegativeZero (XFrame x) = isNegativeZero x+    isIEEE (XFrame x) = isIEEE x+    atan2 (XFrame y) (XFrame x) = XFrame (atan2 y x)++instance ( RealFloatExtras (DataFrame t ('[] :: [Nat]))+         , KnownBackend t ('[] :: [Nat])+         , Eq t+         ) => RealFloatExtras (DataFrame (t :: Type) ('[] :: [XNat])) where+    hypot (XFrame x) (XFrame y) = XFrame (hypot x y)+    maxFinite = XFrame maxFinite+++ unsafeEqTypes :: forall k (a :: k) (b :: k) . Dict (a ~ b)-unsafeEqTypes = unsafeCoerce# (Dict :: Dict (a ~ a))+unsafeEqTypes = unsafeCoerce (Dict :: Dict (a ~ a))
src/Numeric/Matrix.hs view
@@ -3,7 +3,6 @@   , SquareMatrix (..)   , MatrixDeterminant (..)   , MatrixInverse (..)-  , MatrixLU (..), LUFact (..)   , Matrix   , HomTransform4 (..)   , Mat22f, Mat23f, Mat24f@@ -14,10 +13,9 @@   , Mat42d, Mat43d, Mat44d   , mat22, mat33, mat44   , (%*)-  , pivotMat, luSolve   ) where  import Numeric.DataFrame.Internal.Backend () import Numeric.Matrix.Internal-import Numeric.Matrix.Internal.Mat44d     ()-import Numeric.Matrix.Internal.Mat44f     ()+import Numeric.Matrix.Internal.Double     ()+import Numeric.Matrix.Internal.Float      ()
+ src/Numeric/Matrix/Bidiagonal.hs view
@@ -0,0 +1,123 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MagicHash             #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UnboxedTuples         #-}+{-# LANGUAGE UndecidableInstances  #-}++module Numeric.Matrix.Bidiagonal+  ( BiDiag (..), biDiag, bidiagonalHouseholder+  ) where++import Control.Monad+import Control.Monad.ST+import Data.Kind+import Numeric.Basics+import Numeric.DataFrame.ST+import Numeric.DataFrame.SubSpace+import Numeric.DataFrame.Type+import Numeric.Dimensions+import Numeric.Matrix.Internal+import Numeric.Scalar.Internal+import Numeric.Subroutine.Householder+import Numeric.Vector.Internal+++-- | Put two vectors on the main and first upper diagonal.+biDiag :: forall (t :: Type) (n :: Nat) (m :: Nat)+        . (PrimBytes t, Num t)+       => Dims '[n,m]+       -> Vector t (Min n m)+       -> Vector t (Min n m)+       -> Matrix t n m+biDiag (dn@D :* dm@D :* U) a b = runST $ do+    dnm@D <- pure $ minDim dn dm+    rPtr <- thawDataFrame 0+    forM_ [0 .. dimVal dnm - 1] $ \i -> do+      writeDataFrame rPtr (Idx i :* Idx i :* U) $ a ! i+      when (i+1 < dimVal dm) $+        writeDataFrame rPtr (Idx i :* Idx (i+1) :* U) $ b ! i+    unsafeFreezeDataFrame rPtr++-- | Decomposition of a matrix \( A = U B V^\intercal \) such that+--   \( U \) and \( V \) are orthogonal and \( B \) is bidiagonal.+data BiDiag (t :: Type) (n :: Nat)  (m :: Nat)+  = BiDiag+  { bdU     :: Matrix t n n+    -- ^ \( U \) left orthogonal matrix+  , bdUDet  :: Scalar t+    -- ^ A shortcut for evaluating a determinant of \( |U| = \pm 1 \)+  , bdAlpha :: Vector t (Min n m)+    -- ^ Main diagonal of \( B \)+  , bdBeta  :: Vector t (Min n m)+    -- ^ First upper diagonal of \( B \);+    --   its last element equals zero if \( n \geq m \)+  , bdV     :: Matrix t m m+    -- ^ \( B \) left orthogonal matrix+  , bdVDet  :: Scalar t+    -- ^ A shortcut for evaluating a determinant of \( |V| = \pm 1 \)+  }++deriving instance ( Show t, PrimBytes t+                  , KnownDim n, KnownDim m, KnownDim (Min n m))+                  => Show (BiDiag t n m)+deriving instance ( Eq t, PrimBytes t+                  , KnownDim n, KnownDim m, KnownDim (Min n m)+                  , KnownBackend t '[Min n m])+                  => Eq (BiDiag t n m)++{- |+Decompose a matrix \( A = U B V^\intercal \) such that+\( U \) and \( V \) are orthogonal and \( B \) is bidiagonal.++The first returned number+ -}+bidiagonalHouseholder ::+       forall (t :: Type) (n :: Nat) (m :: Nat)+     . (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m)+    => Matrix t n m+    -> BiDiag t n m+bidiagonalHouseholder a = runST $ do+      D <- pure $ minDim (dim @n) (dim @m)+      tmpNPtr <- newDataFrame+      tmpMPtr <- newDataFrame+      uPtr <- thawDataFrame eye+      bPtr <- thawDataFrame a+      vPtr <- thawDataFrame eye+      (ud, vd) <-+        let f (ud, vd) i = do+              ud' <- householderReflectionInplaceL tmpNPtr uPtr bPtr+                     (Idx (i - 1) :* Idx (i - 1) :* U)+              vd' <- householderReflectionInplaceR tmpMPtr vPtr bPtr+                     (Idx (i - 1) :* Idx i :* U)+              return (ud /= ud', vd /= vd')+        in foldM f (False, False) [1 .. lim - 1]++      udn <- householderReflectionInplaceL tmpNPtr uPtr bPtr+                     (Idx (lim - 1) :* Idx (lim - 1) :* U)+      vdn <- if (m > lim)+             then householderReflectionInplaceR tmpMPtr vPtr bPtr+                     (Idx (lim - 1) :* Idx lim :* U)+             else pure False+      bdU <- unsafeFreezeDataFrame uPtr+      bdV <- unsafeFreezeDataFrame vPtr+      b <- unsafeFreezeDataFrame bPtr+      let bdAlpha = iwgen @t @'[Min n m]+            (\(Idx i :* U) -> index (Idx i :* Idx i :* U) b)+          bdBeta  = iwgen @t @'[Min n m]+            (\(Idx i :* U) -> if i+1 < m then index (Idx i :* Idx (i+1) :* U) b else 0)+          bdUDet = if ud /= udn then -1 else 1+          bdVDet = if vd /= vdn then -1 else 1+      return BiDiag {..}+  where+    n = dimVal' @n+    m = dimVal' @m+    lim = max 1 (min n m)
src/Numeric/Matrix/Internal.hs view
@@ -17,7 +17,6 @@   , SquareMatrix (..)   , MatrixDeterminant (..)   , MatrixInverse (..)-  , MatrixLU (..), LUFact (..)   , Matrix   , HomTransform4 (..)   , Mat22f, Mat23f, Mat24f@@ -28,21 +27,13 @@   , Mat42d, Mat43d, Mat44d   , mat22, mat33, mat44   , (%*)-  , pivotMat, luSolve   ) where -import Control.Monad                        (foldM)-import Control.Monad.ST-import Data.Foldable                        (foldl', forM_)-import Data.List                            (delete) import GHC.Base import Numeric.DataFrame.Contraction        ((%*)) import Numeric.DataFrame.Internal.PrimArray-import Numeric.DataFrame.ST-import Numeric.DataFrame.SubSpace import Numeric.DataFrame.Type import Numeric.Dimensions-import Numeric.PrimBytes import Numeric.Scalar.Internal import Numeric.Vector.Internal @@ -70,29 +61,6 @@     inverse :: Matrix t n n -> Matrix t n n  --- | Result of LU factorization with Partial Pivoting---   @ PA = LU @.-data LUFact t n-  = LUFact-  { luLower    :: Matrix t n n-    -- ^ Lower triangular matrix @L@.-    --   All elements on the diagonal of @L@ equal @1@.-  , luUpper    :: Matrix t n n-    -- ^ Upper triangular matrix @U@-  , luPerm     :: Matrix t n n-    -- ^ Row permutation matrix @P@-  , luPermSign :: Scalar t-    -- ^ Sign of permutation @luPermSign == det . luPerm@-  }--deriving instance (Show t, PrimBytes t, KnownDim n) => Show (LUFact t n)-deriving instance (Eq (Matrix t n n), Eq t) => Eq (LUFact t n)--class MatrixLU t (n :: Nat) where-    -- | Compute LU factorization with Partial Pivoting-    lu :: Matrix t n n -> LUFact t n-- -- | Operations on 4x4 transformation matrices and vectors in homogeneous coordinates. --   All angles are specified in radians. --@@ -260,214 +228,3 @@       = let f 0# = ix# 0# df             f k  = ix# k  df + f (k -# n1)         in scalar $ f (n *# n -# 1#)---instance ( KnownDim n, Ord t, Fractional t-         , PrimBytes t-         , PrimArray t (Matrix t n n)-         , PrimArray t (Vector t n)-         , PrimBytes (Vector t n)-         , PrimBytes (Matrix t n n)-         )-         => MatrixInverse t n where-  inverse m = runST $ do-      m' <- newDataFrame-      indexWise_ @t @'[n] @'[n] @'[n, n] @_ @()-        (\is ->-          indexWise_ @t @'[n] @'[] @'[n] @_ @()-            (\(j:*U) -> writeDataFrame m' (j:*is)) . luSolve luM-        ) eye-      unsafeFreezeDataFrame m'-    where-      luM = lu m--    -- much nicer, but probably slower version:-    --   (it is not particularly fast to do an extra transpose-    --       before calculating the inverse)-    -- ewmap (luSolve . lu $ transpose m) eye----instance ( KnownDim n, Ord t, Fractional t-         , PrimBytes t, PrimArray t (Matrix t n n))-         => MatrixDeterminant t n where-  det m = prodF (luUpper f) * prodF (luLower f) * luPermSign f-    where-      f = lu m-      n = case dimVal' @n of W# w -> word2Int# w-      n1 = n +# 1#-      nn1 = n *# n -# 1#-      prodF a = scalar $ prodF' nn1 a-      prodF' 0# a = ix# 0# a-      prodF' k  a = ix# k a * prodF' (k -# n1) a---instance ( KnownDim n, Ord t, Fractional t-         , PrimBytes t, PrimArray t (Matrix t n n))-         => MatrixLU t n where-    lu m' = case runRW# go of-        (# _, (# bu, bl #) #) -> LUFact-            { luLower    = fromElems steps 0# bl-            , luUpper    = fromElems steps 0# bu-            , luPerm     = p-            , luPermSign = si-            }-      where-        dn = dimVal' @n-        dnn = dn * dn-        steps = CumulDims [dnn, dn, 1]-        (m, p, si) = pivotMat m'-        n  = case dn of W# w -> word2Int# w-        nn = case dnn of W# w -> word2Int# w-        tbs = byteSize @t undefined-        bsize = nn *# tbs-        ixm i j = ix# (i *# n +# j) m-        loop :: (Int# -> a -> State# s -> (# State# s, a #))-             -> Int# -> Int# -> a -> State# s -> (# State# s, a #)-        loop f i k x s-          | isTrue# (i ==# k) = (# s, x #)-          | otherwise = case f i x s of-              (# s', y #) -> loop f ( i +# 1# ) k y s'-        go s0-          | (# s1, mbl #) <- newByteArray# bsize s0-          , (# s2, mbu #) <- newByteArray# bsize s1-          , s3 <- setByteArray# mbl 0# bsize 0# s2-          , s4 <- setByteArray# mbu 0# bsize 0# s3-          , readL <- \i j -> readArray @t mbl (i *# n +# j)-          , readU <- \i j -> readArray @t mbu (i *# n +# j)-          , writeL <- \i j -> writeArray @t mbl (i *# n +# j)-          , writeU <- \i j -> writeArray @t mbu (i *# n +# j)-          , computeU <- \i j ->-              let f k x s-                    | (# s' , ukj #) <- readU k j s-                    , (# s'', lik #) <- readL i k s'-                    = (# s'', x - ukj * lik #)-              in loop f 0# i (ixm i j)-          , computeL' <- \i j ->-              let f k x s-                    | (# s' , ukj #) <- readU k j s-                    , (# s'', lik #) <- readL i k s'-                    = (# s'', x - ukj * lik #)-              in loop f 0# j (ixm i j)-          , (# sr, () #) <--              loop-                ( \j _ sj -> case sj of-                    sj0-                      | sj1 <- writeL j j 1 sj0-                      , (# sj2, () #) <- loop-                          ( \i _ sij0 -> case computeU i j sij0 of-                               (# sij1, uij #) -> (# writeU i j uij sij1, () #)-                          ) 0# j () sj1-                      , (# sj3, ujj #) <- computeU j j sj2-                      , sj4 <- writeU j j ujj sj3-                        -> case ujj of-                          0 -> loop-                            ( \i _ sij -> (# writeL i j 0 sij, () #)-                            ) (j +# 1#) n () sj4-                          x -> loop-                            ( \i _ sij0 -> case computeL' i j sij0 of-                                (# sij1, lij #) -> (# writeL i j (lij / x) sij1, () #)-                            ) (j +# 1#) n () sj4-                ) 0# n () s4-          , (# sf0, bl #) <- unsafeFreezeByteArray# mbl sr-          , (# sf1, bu #) <- unsafeFreezeByteArray# mbu sf0-          = (# sf1, (# bu, bl #) #)----- | Solve @Ax = b@ problem given LU decomposition of A.-luSolve :: forall (t :: Type) (n :: Nat)-         . ( KnownDim n, Fractional t-           , PrimArray t (Matrix t n n), PrimArray t (Vector t n))-        => LUFact t n -> Vector t n -> Vector t n-luSolve LUFact {..} b = x-  where-    -- Pb = LUx-    pb = luPerm %* b-    n# = case dimVal' @n of W# w -> word2Int# w-    n = I# n#-    -- Ly = Pb-    y :: Vector t n-    y = runST $ do-      my <- newDataFrame-      let ixA (I# i) (I# j) = scalar $ ix# (i *# n# +# j) luLower-          ixB (I# i) = scalar $ ix# i pb-      forM_ [0..n-1] $ \i -> do-        v <- foldM ( \v j -> do-                      dj <- readDataFrameOff my j-                      return $ v - dj * ixA i j-                   ) (ixB i) [0..i-1]-        writeDataFrameOff my i v-      unsafeFreezeDataFrame my-    -- Ux = y-    x = runST $ do-      mx <- newDataFrame-      let ixA (I# i) (I# j) = scalar $ ix# (i *# n# +# j) luUpper-          ixB (I# i) = scalar $ ix# i y-      forM_ [n-1, n-2 .. 0] $ \i -> do-        v <- foldM ( \v j -> do-                      dj <- readDataFrameOff mx j-                      return $ v - dj * ixA i j-                   ) (ixB i) [i+1..n-1]-        writeDataFrameOff mx i (v / ixA i i)-      unsafeFreezeDataFrame mx----- | Permute rows that the largest magnitude elements in columns are on diagonals.------   Invariants of result matrix:---     * forall j >= i: |M[i,i]| >= M[j,i]---     * if M[i,i] == 0 then forall j >= i: |M[i+1,i+1]| >= M[j,i+1]-pivotMat :: forall (t :: Type) (n :: Nat)-          . (KnownDim n, PrimArray t (Matrix t n n), Ord t, Num t)-         => Matrix t n n -> ( Matrix t n n -- permutated matrix-                            , Matrix t n n -- permutation matrix-                            , Scalar t -- sign of permutation matrix-                            )-pivotMat mat-    = ( let f ( _, [] )   = undefined-            f ( j, i:is )-              | j == n    = f (0, is)-              | otherwise = (# (j+1, i:is), ix i j #)-        in case gen# steps f (0,rowOrder) of-            (# _, r #) -> r-      , let f ( _, [] ) = undefined-            f ( j, x:xs )-               | j == n    = f (0, xs)-               | otherwise = (# ( j + 1, x:xs), if j == x then 1 else 0 #)-        in case gen# steps f (0,rowOrder) of-            (# _, r #) -> r-      , if countMisordered rowOrder `rem` 2 == 1-        then -1 else 1-      )-  where-    dn = dimVal' @n-    steps = CumulDims [dn * dn, dn, 1]-    -- permuted row ordering-    rowOrder = uncurry fillPass $ searchPass 0 [0..n-1]-    -- matrix size-    n = fromIntegral dn-    n# = case n of I# x -> x-    -- sign of permutations-    countMisordered :: [Int] -> Int-    countMisordered [] = 0-    countMisordered (i:is) = foldl' (\c j -> if i > j then succ c else c) 0 is-                           + countMisordered is-    ix (I# i) (I# j) = ix# (i *# n# +# j) mat-    findMax :: Int -> [Int] -> (t, Int)-    findMax j = foldl' (\(ox, oi) i -> let x = abs (ix i j)-                                       in if x > ox then (x, i)-                                                    else (ox, oi)-                      ) (0, 0)-    -- search maximums, leaving Nothing where all rows are 0-    searchPass :: Int -> [Int] -> ([Int], [Maybe Int])-    searchPass j is-      | j == n    = (is, [])-      | otherwise = case findMax j is of-          (0, _) -> (Nothing:) <$> searchPass (j+1) is-          (_, i) -> (Just i:) <$> searchPass (j+1) (delete i is)-    -- replace Nothings with remaining row numbers-    fillPass :: [Int] -> [Maybe Int] -> [Int]-    fillPass _ []                  = []-    fillPass js (Just i : is)      = i : fillPass js is-    fillPass (j:js) (Nothing : is) = j : fillPass js is-    fillPass [] (Nothing : is)     = 0 : fillPass [] is
+ src/Numeric/Matrix/Internal/Double.hs view
@@ -0,0 +1,199 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MagicHash             #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE UnboxedTuples         #-}+{-# LANGUAGE ViewPatterns          #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Numeric.Matrix.Internal.Double () where++import qualified Control.Monad.ST        as ST+import qualified Numeric.DataFrame.ST    as ST+import           Numeric.Dimensions      (KnownDim)+import           Numeric.Matrix.Internal+import           Numeric.Matrix.LU+import           Numeric.Scalar.Internal+import           Numeric.Vector.Internal++{-# INLINE mkMat #-}+mkMat ::+  Double -> Double -> Double -> Double ->+  Double -> Double -> Double -> Double ->+  Double -> Double -> Double -> Double ->+  Double -> Double -> Double -> Double ->+  Mat44d+mkMat+  _11 _12 _13 _14+  _21 _22 _23 _24+  _31 _32 _33 _34+  _41 _42 _43 _44+  = ST.runST $ do+    df <- ST.newDataFrame+    ST.writeDataFrameOff df 0  $ scalar _11+    ST.writeDataFrameOff df 1  $ scalar _12+    ST.writeDataFrameOff df 2  $ scalar _13+    ST.writeDataFrameOff df 3  $ scalar _14+    ST.writeDataFrameOff df 4  $ scalar _21+    ST.writeDataFrameOff df 5  $ scalar _22+    ST.writeDataFrameOff df 6  $ scalar _23+    ST.writeDataFrameOff df 7  $ scalar _24+    ST.writeDataFrameOff df 8  $ scalar _31+    ST.writeDataFrameOff df 9  $ scalar _32+    ST.writeDataFrameOff df 10 $ scalar _33+    ST.writeDataFrameOff df 11 $ scalar _34+    ST.writeDataFrameOff df 12 $ scalar _41+    ST.writeDataFrameOff df 13 $ scalar _42+    ST.writeDataFrameOff df 14 $ scalar _43+    ST.writeDataFrameOff df 15 $ scalar _44+    ST.unsafeFreezeDataFrame df++instance HomTransform4 Double where+  {-# INLINE translate4 #-}+  translate4 (unpackV4# -> (# x, y, z, _ #)) = mkMat+    1 0 0 0+    0 1 0 0+    0 0 1 0+    x y z 1++  {-# INLINE translate3 #-}+  translate3 (unpackV3# -> (# x, y, z #)) = mkMat+    1 0 0 0+    0 1 0 0+    0 0 1 0+    x y z 1++  {-# INLINE rotateX #-}+  rotateX a = mkMat+    1 0 0 0+    0 c s 0+    0 n c 0+    0 0 0 1+    where+      c = cos a+      s = sin a+      n = -s++  {-# INLINE rotateY #-}+  rotateY a = mkMat+    c 0 n 0+    0 1 0 0+    s 0 c 0+    0 0 0 1+    where+      c = cos a+      s = sin a+      n = -s++  {-# INLINE rotateZ #-}+  rotateZ a = mkMat+    c s 0 0+    n c 0 0+    0 0 1 0+    0 0 0 1+    where+      c = cos a+      s = sin a+      n = -s++  {-# INLINE rotate #-}+  rotate (unpackV3# -> (# x, y, z #)) a = mkMat+    (c+xxv)  (yxv+zs) (zxv-ys) 0+    (xyv-zs) (c+yyv)  (zyv+xs) 0+    (xzv+ys) (yzv-xs) (c+zzv)  0+     0        0        0       1+    where+      c = cos a+      v = 1 - c -- v for versine+      s = sin a+      xxv = x * x * v+      xyv = x * y * v+      xzv = x * z * v+      yxv = xyv+      yyv = y * y * v+      yzv = y * z * v+      zxv = xzv+      zyv = yzv+      zzv = z * z * v+      xs = x * s+      ys = y * s+      zs = z * s++  {-# INLINE rotateEuler #-}+  rotateEuler x y z = mkMat+    (cy*cz)  (cx*sz+sx*sy*cz) (sx*sz-cx*sy*cz) 0+    (-cy*sz) (cx*cz-sx*sy*sz) (sx*cz+cx*sy*sz) 0+     sy      (-sx*cy)         (cx*cy)          0+     0        0                0               1+    where+      cx = cos x+      sx = sin x+      cy = cos y+      sy = sin y+      cz = cos z+      sz = sin z++  {-# INLINE lookAt #-}+  lookAt up cam foc = mkMat+    xb1 yb1 zb1 0+    xb2 yb2 zb2 0+    xb3 yb3 zb3 0+    tx  ty  tz  1+    where+      (# xb1, xb2, xb3 #) = unpackV3# xb+      (# yb1, yb2, yb3 #) = unpackV3# yb+      (# zb1, zb2, zb3 #) = unpackV3# zb+      zb = normalized $ cam - foc -- Basis vector for "backward", since +Z is behind the camera+      xb = normalized $ up `cross` zb -- Basis vector for "right"+      yb = zb `cross` xb -- Basis vector for "up"+      ncam = -cam+      tx = unScalar $ xb `dot` ncam+      ty = unScalar $ yb `dot` ncam+      tz = unScalar $ zb `dot` ncam++  {-# INLINE perspective #-}+  perspective n f fovy aspect = mkMat+    dpw 0   0   0+    0   dph 0   0+    0   0   a (-1)+    0   0   b   0+    where+      hpd = tan (fovy * 0.5) -- height/distance+      wpd = aspect * hpd; -- width/distance+      dph = recip hpd -- distance/height+      dpw = recip wpd -- distance/width+      nmf = n - f+      a = (n + f) / nmf+      b = 2 * n * f / nmf++  {-# INLINE orthogonal #-}+  orthogonal n f w h = mkMat+    iw 0  0 0+    0  ih 0 0+    0  0  a 0+    0  0  b 1+    where+      ih = 2 / h+      iw = 2 / w+      nmf = n - f+      a = 2 / nmf+      b = (n + f) / nmf++  {-# INLINE toHomPoint #-}+  toHomPoint (unpackV3# -> (# x, y, z #)) = vec4 x y z 1++  {-# INLINE toHomVector #-}+  toHomVector (unpackV3# -> (# x, y, z #)) = vec4 x y z 0++  {-# INLINE fromHom #-}+  fromHom (unpackV4# -> (# x, y, z, w #))+    | w == 0    = vec3 x y z+    | otherwise = vec3 (x/w) (y/w) (z/w)++instance KnownDim n => MatrixInverse Double n where+    inverse = inverseViaLU++instance KnownDim n => MatrixDeterminant Double n where+    det = detViaLU
+ src/Numeric/Matrix/Internal/Float.hs view
@@ -0,0 +1,199 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MagicHash             #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE UnboxedTuples         #-}+{-# LANGUAGE ViewPatterns          #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Numeric.Matrix.Internal.Float () where++import qualified Control.Monad.ST        as ST+import qualified Numeric.DataFrame.ST    as ST+import           Numeric.Dimensions      (KnownDim)+import           Numeric.Matrix.Internal+import           Numeric.Matrix.LU+import           Numeric.Scalar.Internal+import           Numeric.Vector.Internal++{-# INLINE mkMat #-}+mkMat ::+  Float -> Float -> Float -> Float ->+  Float -> Float -> Float -> Float ->+  Float -> Float -> Float -> Float ->+  Float -> Float -> Float -> Float ->+  Mat44f+mkMat+  _11 _12 _13 _14+  _21 _22 _23 _24+  _31 _32 _33 _34+  _41 _42 _43 _44+  = ST.runST $ do+    df <- ST.newDataFrame+    ST.writeDataFrameOff df 0  $ scalar _11+    ST.writeDataFrameOff df 1  $ scalar _12+    ST.writeDataFrameOff df 2  $ scalar _13+    ST.writeDataFrameOff df 3  $ scalar _14+    ST.writeDataFrameOff df 4  $ scalar _21+    ST.writeDataFrameOff df 5  $ scalar _22+    ST.writeDataFrameOff df 6  $ scalar _23+    ST.writeDataFrameOff df 7  $ scalar _24+    ST.writeDataFrameOff df 8  $ scalar _31+    ST.writeDataFrameOff df 9  $ scalar _32+    ST.writeDataFrameOff df 10 $ scalar _33+    ST.writeDataFrameOff df 11 $ scalar _34+    ST.writeDataFrameOff df 12 $ scalar _41+    ST.writeDataFrameOff df 13 $ scalar _42+    ST.writeDataFrameOff df 14 $ scalar _43+    ST.writeDataFrameOff df 15 $ scalar _44+    ST.unsafeFreezeDataFrame df++instance HomTransform4 Float where+  {-# INLINE translate4 #-}+  translate4 (unpackV4# -> (# x, y, z, _ #)) = mkMat+    1 0 0 0+    0 1 0 0+    0 0 1 0+    x y z 1++  {-# INLINE translate3 #-}+  translate3 (unpackV3# -> (# x, y, z #)) = mkMat+    1 0 0 0+    0 1 0 0+    0 0 1 0+    x y z 1++  {-# INLINE rotateX #-}+  rotateX a = mkMat+    1 0 0 0+    0 c s 0+    0 n c 0+    0 0 0 1+    where+      c = cos a+      s = sin a+      n = -s++  {-# INLINE rotateY #-}+  rotateY a = mkMat+    c 0 n 0+    0 1 0 0+    s 0 c 0+    0 0 0 1+    where+      c = cos a+      s = sin a+      n = -s++  {-# INLINE rotateZ #-}+  rotateZ a = mkMat+    c s 0 0+    n c 0 0+    0 0 1 0+    0 0 0 1+    where+      c = cos a+      s = sin a+      n = -s++  {-# INLINE rotate #-}+  rotate (unpackV3# -> (# x, y, z #)) a = mkMat+    (c+xxv)  (yxv+zs) (zxv-ys) 0+    (xyv-zs) (c+yyv)  (zyv+xs) 0+    (xzv+ys) (yzv-xs) (c+zzv)  0+     0        0        0       1+    where+      c = cos a+      v = 1 - c -- v for versine+      s = sin a+      xxv = x * x * v+      xyv = x * y * v+      xzv = x * z * v+      yxv = xyv+      yyv = y * y * v+      yzv = y * z * v+      zxv = xzv+      zyv = yzv+      zzv = z * z * v+      xs = x * s+      ys = y * s+      zs = z * s++  {-# INLINE rotateEuler #-}+  rotateEuler x y z = mkMat+    (cy*cz)  (cx*sz+sx*sy*cz) (sx*sz-cx*sy*cz) 0+    (-cy*sz) (cx*cz-sx*sy*sz) (sx*cz+cx*sy*sz) 0+     sy      (-sx*cy)         (cx*cy)          0+     0        0                0               1+    where+      cx = cos x+      sx = sin x+      cy = cos y+      sy = sin y+      cz = cos z+      sz = sin z++  {-# INLINE lookAt #-}+  lookAt up cam foc = mkMat+    xb1 yb1 zb1 0+    xb2 yb2 zb2 0+    xb3 yb3 zb3 0+    tx  ty  tz  1+    where+      (# xb1, xb2, xb3 #) = unpackV3# xb+      (# yb1, yb2, yb3 #) = unpackV3# yb+      (# zb1, zb2, zb3 #) = unpackV3# zb+      zb = normalized $ cam - foc -- Basis vector for "backward", since +Z is behind the camera+      xb = normalized $ up `cross` zb -- Basis vector for "right"+      yb = zb `cross` xb -- Basis vector for "up"+      ncam = -cam+      tx = unScalar $ xb `dot` ncam+      ty = unScalar $ yb `dot` ncam+      tz = unScalar $ zb `dot` ncam++  {-# INLINE perspective #-}+  perspective n f fovy aspect = mkMat+    dpw 0   0   0+    0   dph 0   0+    0   0   a (-1)+    0   0   b   0+    where+      hpd = tan (fovy * 0.5) -- height/distance+      wpd = aspect * hpd; -- width/distance+      dph = recip hpd -- distance/height+      dpw = recip wpd -- distance/width+      nmf = n - f+      a = (n + f) / nmf+      b = 2 * n * f / nmf++  {-# INLINE orthogonal #-}+  orthogonal n f w h = mkMat+    iw 0  0 0+    0  ih 0 0+    0  0  a 0+    0  0  b 1+    where+      ih = 2 / h+      iw = 2 / w+      nmf = n - f+      a = 2 / nmf+      b = (n + f) / nmf++  {-# INLINE toHomPoint #-}+  toHomPoint (unpackV3# -> (# x, y, z #)) = vec4 x y z 1++  {-# INLINE toHomVector #-}+  toHomVector (unpackV3# -> (# x, y, z #)) = vec4 x y z 0++  {-# INLINE fromHom #-}+  fromHom (unpackV4# -> (# x, y, z, w #))+    | w == 0    = vec3 x y z+    | otherwise = vec3 (x/w) (y/w) (z/w)++instance KnownDim n => MatrixInverse Float n where+    inverse = inverseViaLU++instance KnownDim n => MatrixDeterminant Float n where+    det = detViaLU
− src/Numeric/Matrix/Internal/Mat44d.hs
@@ -1,186 +0,0 @@-{-# LANGUAGE MagicHash     #-}-{-# LANGUAGE UnboxedTuples #-}-{-# LANGUAGE ViewPatterns  #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Numeric.Matrix.Internal.Mat44d () where--import qualified Control.Monad.ST        as ST-import qualified Numeric.DataFrame.ST    as ST-import           Numeric.Matrix.Internal-import           Numeric.Scalar.Internal-import           Numeric.Vector.Internal--{-# INLINE mkMat #-}-mkMat ::-  Double -> Double -> Double -> Double ->-  Double -> Double -> Double -> Double ->-  Double -> Double -> Double -> Double ->-  Double -> Double -> Double -> Double ->-  Mat44d-mkMat-  _11 _12 _13 _14-  _21 _22 _23 _24-  _31 _32 _33 _34-  _41 _42 _43 _44-  = ST.runST $ do-    df <- ST.newDataFrame-    ST.writeDataFrameOff df 0  $ scalar _11-    ST.writeDataFrameOff df 1  $ scalar _12-    ST.writeDataFrameOff df 2  $ scalar _13-    ST.writeDataFrameOff df 3  $ scalar _14-    ST.writeDataFrameOff df 4  $ scalar _21-    ST.writeDataFrameOff df 5  $ scalar _22-    ST.writeDataFrameOff df 6  $ scalar _23-    ST.writeDataFrameOff df 7  $ scalar _24-    ST.writeDataFrameOff df 8  $ scalar _31-    ST.writeDataFrameOff df 9  $ scalar _32-    ST.writeDataFrameOff df 10 $ scalar _33-    ST.writeDataFrameOff df 11 $ scalar _34-    ST.writeDataFrameOff df 12 $ scalar _41-    ST.writeDataFrameOff df 13 $ scalar _42-    ST.writeDataFrameOff df 14 $ scalar _43-    ST.writeDataFrameOff df 15 $ scalar _44-    ST.unsafeFreezeDataFrame df--instance HomTransform4 Double where-  {-# INLINE translate4 #-}-  translate4 (unpackV4# -> (# x, y, z, _ #)) = mkMat-    1 0 0 0-    0 1 0 0-    0 0 1 0-    x y z 1--  {-# INLINE translate3 #-}-  translate3 (unpackV3# -> (# x, y, z #)) = mkMat-    1 0 0 0-    0 1 0 0-    0 0 1 0-    x y z 1--  {-# INLINE rotateX #-}-  rotateX a = mkMat-    1 0 0 0-    0 c s 0-    0 n c 0-    0 0 0 1-    where-      c = cos a-      s = sin a-      n = -s--  {-# INLINE rotateY #-}-  rotateY a = mkMat-    c 0 n 0-    0 1 0 0-    s 0 c 0-    0 0 0 1-    where-      c = cos a-      s = sin a-      n = -s--  {-# INLINE rotateZ #-}-  rotateZ a = mkMat-    c s 0 0-    n c 0 0-    0 0 1 0-    0 0 0 1-    where-      c = cos a-      s = sin a-      n = -s--  {-# INLINE rotate #-}-  rotate (unpackV3# -> (# x, y, z #)) a = mkMat-    (c+xxv)  (yxv+zs) (zxv-ys) 0-    (xyv-zs) (c+yyv)  (zyv+xs) 0-    (xzv+ys) (yzv-xs) (c+zzv)  0-     0        0        0       1-    where-      c = cos a-      v = 1 - c -- v for versine-      s = sin a-      xxv = x * x * v-      xyv = x * y * v-      xzv = x * z * v-      yxv = xyv-      yyv = y * y * v-      yzv = y * z * v-      zxv = xzv-      zyv = yzv-      zzv = z * z * v-      xs = x * s-      ys = y * s-      zs = z * s--  {-# INLINE rotateEuler #-}-  rotateEuler x y z = mkMat-    (cy*cz)  (cx*sz+sx*sy*cz) (sx*sz-cx*sy*cz) 0-    (-cy*sz) (cx*cz-sx*sy*sz) (sx*cz+cx*sy*sz) 0-     sy      (-sx*cy)         (cx*cy)          0-     0        0                0               1-    where-      cx = cos x-      sx = sin x-      cy = cos y-      sy = sin y-      cz = cos z-      sz = sin z--  {-# INLINE lookAt #-}-  lookAt up cam foc = mkMat-    xb1 yb1 zb1 0-    xb2 yb2 zb2 0-    xb3 yb3 zb3 0-    tx  ty  tz  1-    where-      (# xb1, xb2, xb3 #) = unpackV3# xb-      (# yb1, yb2, yb3 #) = unpackV3# yb-      (# zb1, zb2, zb3 #) = unpackV3# zb-      zb = normalized $ cam - foc -- Basis vector for "backward", since +Z is behind the camera-      xb = normalized $ up `cross` zb -- Basis vector for "right"-      yb = zb `cross` xb -- Basis vector for "up"-      ncam = -cam-      tx = unScalar $ xb `dot` ncam-      ty = unScalar $ yb `dot` ncam-      tz = unScalar $ zb `dot` ncam--  {-# INLINE perspective #-}-  perspective n f fovy aspect = mkMat-    dpw 0   0   0-    0   dph 0   0-    0   0   a (-1)-    0   0   b   0-    where-      hpd = tan (fovy * 0.5) -- height/distance-      wpd = aspect * hpd; -- width/distance-      dph = recip hpd -- distance/height-      dpw = recip wpd -- distance/width-      nmf = n - f-      a = (n + f) / nmf-      b = 2 * n * f / nmf--  {-# INLINE orthogonal #-}-  orthogonal n f w h = mkMat-    iw 0  0 0-    0  ih 0 0-    0  0  a 0-    0  0  b 1-    where-      ih = 2 / h-      iw = 2 / w-      nmf = n - f-      a = 2 / nmf-      b = (n + f) / nmf--  {-# INLINE toHomPoint #-}-  toHomPoint (unpackV3# -> (# x, y, z #)) = vec4 x y z 1--  {-# INLINE toHomVector #-}-  toHomVector (unpackV3# -> (# x, y, z #)) = vec4 x y z 0--  {-# INLINE fromHom #-}-  fromHom (unpackV4# -> (# x, y, z, w #))-    | w == 0    = vec3 x y z-    | otherwise = vec3 (x/w) (y/w) (z/w)
− src/Numeric/Matrix/Internal/Mat44f.hs
@@ -1,186 +0,0 @@-{-# LANGUAGE MagicHash     #-}-{-# LANGUAGE UnboxedTuples #-}-{-# LANGUAGE ViewPatterns  #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Numeric.Matrix.Internal.Mat44f () where--import qualified Control.Monad.ST        as ST-import qualified Numeric.DataFrame.ST    as ST-import           Numeric.Matrix.Internal-import           Numeric.Scalar.Internal-import           Numeric.Vector.Internal--{-# INLINE mkMat #-}-mkMat ::-  Float -> Float -> Float -> Float ->-  Float -> Float -> Float -> Float ->-  Float -> Float -> Float -> Float ->-  Float -> Float -> Float -> Float ->-  Mat44f-mkMat-  _11 _12 _13 _14-  _21 _22 _23 _24-  _31 _32 _33 _34-  _41 _42 _43 _44-  = ST.runST $ do-    df <- ST.newDataFrame-    ST.writeDataFrameOff df 0  $ scalar _11-    ST.writeDataFrameOff df 1  $ scalar _12-    ST.writeDataFrameOff df 2  $ scalar _13-    ST.writeDataFrameOff df 3  $ scalar _14-    ST.writeDataFrameOff df 4  $ scalar _21-    ST.writeDataFrameOff df 5  $ scalar _22-    ST.writeDataFrameOff df 6  $ scalar _23-    ST.writeDataFrameOff df 7  $ scalar _24-    ST.writeDataFrameOff df 8  $ scalar _31-    ST.writeDataFrameOff df 9  $ scalar _32-    ST.writeDataFrameOff df 10 $ scalar _33-    ST.writeDataFrameOff df 11 $ scalar _34-    ST.writeDataFrameOff df 12 $ scalar _41-    ST.writeDataFrameOff df 13 $ scalar _42-    ST.writeDataFrameOff df 14 $ scalar _43-    ST.writeDataFrameOff df 15 $ scalar _44-    ST.unsafeFreezeDataFrame df--instance HomTransform4 Float where-  {-# INLINE translate4 #-}-  translate4 (unpackV4# -> (# x, y, z, _ #)) = mkMat-    1 0 0 0-    0 1 0 0-    0 0 1 0-    x y z 1--  {-# INLINE translate3 #-}-  translate3 (unpackV3# -> (# x, y, z #)) = mkMat-    1 0 0 0-    0 1 0 0-    0 0 1 0-    x y z 1--  {-# INLINE rotateX #-}-  rotateX a = mkMat-    1 0 0 0-    0 c s 0-    0 n c 0-    0 0 0 1-    where-      c = cos a-      s = sin a-      n = -s--  {-# INLINE rotateY #-}-  rotateY a = mkMat-    c 0 n 0-    0 1 0 0-    s 0 c 0-    0 0 0 1-    where-      c = cos a-      s = sin a-      n = -s--  {-# INLINE rotateZ #-}-  rotateZ a = mkMat-    c s 0 0-    n c 0 0-    0 0 1 0-    0 0 0 1-    where-      c = cos a-      s = sin a-      n = -s--  {-# INLINE rotate #-}-  rotate (unpackV3# -> (# x, y, z #)) a = mkMat-    (c+xxv)  (yxv+zs) (zxv-ys) 0-    (xyv-zs) (c+yyv)  (zyv+xs) 0-    (xzv+ys) (yzv-xs) (c+zzv)  0-     0        0        0       1-    where-      c = cos a-      v = 1 - c -- v for versine-      s = sin a-      xxv = x * x * v-      xyv = x * y * v-      xzv = x * z * v-      yxv = xyv-      yyv = y * y * v-      yzv = y * z * v-      zxv = xzv-      zyv = yzv-      zzv = z * z * v-      xs = x * s-      ys = y * s-      zs = z * s--  {-# INLINE rotateEuler #-}-  rotateEuler x y z = mkMat-    (cy*cz)  (cx*sz+sx*sy*cz) (sx*sz-cx*sy*cz) 0-    (-cy*sz) (cx*cz-sx*sy*sz) (sx*cz+cx*sy*sz) 0-     sy      (-sx*cy)         (cx*cy)          0-     0        0                0               1-    where-      cx = cos x-      sx = sin x-      cy = cos y-      sy = sin y-      cz = cos z-      sz = sin z--  {-# INLINE lookAt #-}-  lookAt up cam foc = mkMat-    xb1 yb1 zb1 0-    xb2 yb2 zb2 0-    xb3 yb3 zb3 0-    tx  ty  tz  1-    where-      (# xb1, xb2, xb3 #) = unpackV3# xb-      (# yb1, yb2, yb3 #) = unpackV3# yb-      (# zb1, zb2, zb3 #) = unpackV3# zb-      zb = normalized $ cam - foc -- Basis vector for "backward", since +Z is behind the camera-      xb = normalized $ up `cross` zb -- Basis vector for "right"-      yb = zb `cross` xb -- Basis vector for "up"-      ncam = -cam-      tx = unScalar $ xb `dot` ncam-      ty = unScalar $ yb `dot` ncam-      tz = unScalar $ zb `dot` ncam--  {-# INLINE perspective #-}-  perspective n f fovy aspect = mkMat-    dpw 0   0   0-    0   dph 0   0-    0   0   a (-1)-    0   0   b   0-    where-      hpd = tan (fovy * 0.5) -- height/distance-      wpd = aspect * hpd; -- width/distance-      dph = recip hpd -- distance/height-      dpw = recip wpd -- distance/width-      nmf = n - f-      a = (n + f) / nmf-      b = 2 * n * f / nmf--  {-# INLINE orthogonal #-}-  orthogonal n f w h = mkMat-    iw 0  0 0-    0  ih 0 0-    0  0  a 0-    0  0  b 1-    where-      ih = 2 / h-      iw = 2 / w-      nmf = n - f-      a = 2 / nmf-      b = (n + f) / nmf--  {-# INLINE toHomPoint #-}-  toHomPoint (unpackV3# -> (# x, y, z #)) = vec4 x y z 1--  {-# INLINE toHomVector #-}-  toHomVector (unpackV3# -> (# x, y, z #)) = vec4 x y z 0--  {-# INLINE fromHom #-}-  fromHom (unpackV4# -> (# x, y, z, w #))-    | w == 0    = vec3 x y z-    | otherwise = vec3 (x/w) (y/w) (z/w)
+ src/Numeric/Matrix/LU.hs view
@@ -0,0 +1,201 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+module Numeric.Matrix.LU+  ( MatrixLU (..), LU (..)+  , luSolveR, luSolveL+  , detViaLU, inverseViaLU+  ) where++import Control.Monad+import Control.Monad.ST+import Data.Kind+import Numeric.DataFrame.Internal.PrimArray+import Numeric.DataFrame.ST+import Numeric.DataFrame.SubSpace+import Numeric.DataFrame.Type+import Numeric.Dimensions+import Numeric.Matrix.Internal+import Numeric.Scalar.Internal+import Numeric.Subroutine.SolveTriangular+++-- | Result of LU factorization with Partial Pivoting+--   \( PA = LU \).+data LU (t :: Type) (n :: Nat)+  = LU+  { luLower   :: Matrix t n n+    -- ^ Unit lower triangular matrix \(L\).+    --   All elements on the diagonal of @L@ equal @1@.+    --   The rest of the elements satisfy \(|l_{ij}| \leq 1\).+  , luUpper   :: Matrix t n n+    -- ^ Upper triangular matrix \(U\)+  , luPerm    :: Matrix t n n+    -- ^ Row permutation matrix \(P\)+  , luPermDet :: Scalar t+    -- ^ Sign of permutation @luPermDet == det . luPerm@; \(|P| = \pm 1\).+  }++deriving instance (Show t, PrimBytes t, KnownDim n) => Show (LU t n)+deriving instance (Eq (Matrix t n n), Eq t) => Eq (LU t n)++class (KnownDim n, Ord t, Fractional t, PrimBytes t, KnownBackend t '[n,n])+      => MatrixLU t (n :: Nat) where+    -- | Compute LU factorization with Partial Pivoting+    lu :: Matrix t n n -> LU t n+++instance (KnownDim n, Ord t, Fractional t, PrimBytes t, KnownBackend t '[n,n])+         => MatrixLU t n where+    lu a = runST $ do+        pPtr <- unsafeThawDataFrame $ iwgen  @_ @'[n] @'[] (\(Idx i :* U) -> S i)+        uPtr <- thawDataFrame a+        lPtr <- newDataFrame+        temp <- newDataFrame+        detPositive <- luInplace temp pPtr uPtr+        p <- unsafeFreezeDataFrame pPtr+        -- split U and L+        forM_ [0..n-1] $ \i -> do+          let ni = n*i+          forM_ [0..n-1] $ \j -> case compare i j of+              GT -> do+                lij <- readDataFrameOff uPtr (ni + j)+                writeDataFrameOff uPtr (ni + j) 0+                writeDataFrameOff lPtr (ni + j) lij+              EQ -> writeDataFrameOff lPtr (ni + j) 1+              LT -> writeDataFrameOff lPtr (ni + j) 0+        luLower <- unsafeFreezeDataFrame lPtr+        luUpper <- unsafeFreezeDataFrame uPtr+        let luPermDet = if detPositive then 1 else -1+            luPerm = iwgen @_ @'[n,n] @'[]+              (\(Idx i :* Idx j :* U) -> if S j == p ! i then 1 else 0)+        return LU {..}+      where+        n = fromIntegral (dimVal' @n) :: Int+++-- | Solve @Ax = b@ problem given LU decomposition of A.+luSolveR ::+       forall t (n :: Nat) (ds :: [Nat])+     . (MatrixLU t n, Dimensions ds)+    => LU t n -> DataFrame t (n :+ ds) -> DataFrame t (n :+ ds)+luSolveR LU {..} b = runST $ do+    xPtr <- thawDataFrame (luPerm %* b) -- NB: wasting resources!+    solveLowerTriangularR luLower xPtr+    solveUpperTriangularR luUpper xPtr+    unsafeFreezeDataFrame xPtr++-- | Solve @xA = b@ problem given LU decomposition of A.+luSolveL ::+       forall t (n :: Nat) (ds :: [Nat])+     . (MatrixLU t n, Dimensions ds)+    => LU t n -> DataFrame t (ds +: n) -> DataFrame t (ds +: n)+luSolveL LU {..} b+  | dn  <- dim @n+  , dds <- dims @ds+  , Dims <- Snoc dds dn+  , Dict <- Dict @(SnocList ds n _)+  = runST $ do+    xPtr <- thawDataFrame b+    solveUpperTriangularL xPtr luUpper+    solveLowerTriangularL xPtr luLower+    (%* luPerm) <$> unsafeFreezeDataFrame xPtr+luSolveL _ _ = error "luSolveL: impossible pattern"++-- | Calculate inverse of a matrix via LU decomposition+inverseViaLU :: forall (t :: Type) (n :: Nat)+              . MatrixLU t n => Matrix t n n -> Matrix t n n+inverseViaLU a = runST $ do+    xPtr <- unsafeThawDataFrame luPerm -- luPerm is only ever used once+    solveLowerTriangularR luLower xPtr+    solveUpperTriangularR luUpper xPtr+    unsafeFreezeDataFrame xPtr+  where+    LU {..} = lu a+-- perfectly correct, but slightly slower versions:+-- inverseViaLU a = luSolveR (lu a) eye+-- inverseViaLU a = luSolveL (lu a) eye++-- | Calculate determinant of a matrix via LU decomposition+detViaLU :: forall (t :: Type) (n :: Nat)+          . MatrixLU t n => Matrix t n n -> Scalar t+detViaLU m = foldl (\x off -> scalar (ixOff off luUpper) * x) luPermDet [0,n+1..n*n]+  where+    n = fromIntegral (dimVal' @n) :: Int+    LU {..} = lu m++{- |+Run LU decomposition with partial pivoting inplace, such that+the upper triangular part of matrix \(A\) becomes \(U\) and+the lower triangular part (without diagonal) of matrix  \(A\) becomes \(L\).++\(U\) is upper triangular.+\(L\) is unit lower triangular; all diagonal elements of \(L\) are implicit and+equal to 1; the rest of the elements a smaller than one \(|l_{ij}| \leq 1\).++Pivoting is represented as a permutation vector \(p\);+returned value is the sign of the permutation (positive if @True@, negative otherwise).++NB: Initialize \(p\) with indices @0..n-1@.++Reference: Algorithm 3.4.1 on p.128+       of "Matrix Computations" 4th edition by G. H. Golub and C. F. Van Loan.+ -}+luInplace ::+       forall (s :: Type) (t :: Type) (n :: Nat)+     . (PrimBytes t, Fractional t, Ord t, KnownDim n)+    => STDataFrame s t '[n]    -- ^ Temporary buffer+    -> STDataFrame s Word '[n] -- ^ Current state of permutation \(p\)+    -> STDataFrame s t '[n,n]  -- ^ Current state of \(A\)+    -> ST s Bool+luInplace temp pPtr aPtr = foldM (\b -> fmap (b /=) . go) True [0..n-2]+  where+    n = fromIntegral (dimVal' @n) :: Int++    -- Runs an iteration of the algorithm;+    --- returns whether there was a swap of rows.+    go :: Int -> ST s Bool+    go k = do+      mu <- findPivot  k+      let swapped = k /= mu+      when swapped $ swapRows k mu+      akk <- readDataFrameOff aPtr (k*(n+1))+      when (akk /= 0) $ do+        let rakk = recip akk+        forM_ [k+1..n-1] $ \i -> do+          let ni = n*i+          aik <- (rakk *) <$> readDataFrameOff aPtr (ni + k)+          writeDataFrameOff aPtr (ni + k) aik+          forM_ [k+1..n-1] $ \j -> do+            akj <- readDataFrameOff aPtr (n*k + j)+            aij <- readDataFrameOff aPtr (ni + j)+            writeDataFrameOff aPtr (ni + j) (aij - aik*akj)+      return swapped++    findPivot :: Int -> ST s Int+    findPivot k = snd <$> foldM findPivotF (0, k) [k..n-1]+      where+        findPivotF :: (Scalar t, Int) -> Int -> ST s (Scalar t, Int)+        findPivotF aj@(a, _) i = do+          x <- abs <$> readDataFrameOff aPtr (n*i + k)+          return (if x > a then (x, i) else aj)++    swapRows :: Int -> Int -> ST s ()+    swapRows i j = do+      let iPtr = subDataFrameView' (fromIntegral i :* U) aPtr+          jPtr = subDataFrameView' (fromIntegral j :* U) aPtr+      copyMutableDataFrame' U iPtr temp+      copyMutableDataFrame' U jPtr iPtr+      copyMutableDataFrame' U temp jPtr+      t <- readDataFrameOff pPtr i+      readDataFrameOff pPtr j >>= writeDataFrameOff pPtr i+      writeDataFrameOff pPtr j t
+ src/Numeric/Matrix/QR.hs view
@@ -0,0 +1,231 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+module Numeric.Matrix.QR+  ( QR (..), LQ (..), MatrixQR (..)+  , detViaQR, inverseViaQR+  , qrSolveR, qrSolveL+  ) where+++import Control.Monad+import Control.Monad.ST+import Data.Kind+import Numeric.Basics+import Numeric.DataFrame.ST+import Numeric.DataFrame.SubSpace+import Numeric.DataFrame.Type+import Numeric.Dimensions+import Numeric.Matrix.Internal+import Numeric.Scalar.Internal+import Numeric.Subroutine.Householder+import Numeric.Subroutine.SolveTriangular++import Unsafe.Coerce (unsafeCoerce)++-- | Result of QR factorization+--   \( A = QR \).+data QR (t :: Type) (n :: Nat) (m :: Nat)+  = QR+  { qrQ    :: Matrix t n n+    -- ^ Orthogonal matrix \( Q \)+  , qrQDet :: Scalar t+    -- ^ A shortcut for evaluating a determinant of \( |Q| = \pm 1 \)+  , qrR    :: Matrix t n m+    -- ^ Upper-triangular matrix \( R \)+  }++-- | Result of LQ factorization+--   \( A = LQ \).+data LQ (t :: Type) (n :: Nat) (m :: Nat)+  = LQ+  { lqL    :: Matrix t n m+      -- ^ Lower-triangular matrix \( L \)+  , lqQ    :: Matrix t m m+    -- ^ Orthogonal matrix \( Q \)+  , lqQDet :: Scalar t+    -- ^ A shortcut for evaluating a determinant of \( |Q| = \pm 1 \)+  }++deriving instance ( Eq t, PrimBytes t+                  , KnownDim n, KnownDim m) => Eq (QR t n m)+deriving instance ( Show t, PrimBytes t+                  , KnownDim n, KnownDim m) => Show (QR t n m)+deriving instance ( Eq t, PrimBytes t+                  , KnownDim n, KnownDim m) => Eq (LQ t n m)+deriving instance ( Show t, PrimBytes t+                  , KnownDim n, KnownDim m) => Show (LQ t n m)+++class (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m)+      => MatrixQR t (n :: Nat) (m :: Nat) where+    -- | Compute QR factorization+    qr :: Matrix t n m -> QR t n m+    -- | Compute LQ factorization+    lq :: Matrix t n m -> LQ t n m++instance (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m)+      => MatrixQR t (n :: Nat) (m :: Nat) where+    qr a+      | lim == 0 = QR undefined undefined 1+      | otherwise = runST $ do+        uPtr <- newDataFrame+        pPtr <- unsafeThawDataFrame eye+        rPtr <- thawDataFrame a+        detNegative <-+          let f x i = (x /=) <$> householderReflectionInplaceL+                                   uPtr pPtr rPtr (Idx i :* Idx i :* U)+          in  foldM f False [0..lim - 1]+        qrR <- unsafeFreezeDataFrame rPtr+        qrQ <- unsafeFreezeDataFrame pPtr+        let qrQDet = if detNegative then -1 else 1+        return QR {..}+      where+        n = dimVal' @n+        m = dimVal' @m+        lim = min n m+    lq a+      | lim == 0 = LQ undefined undefined 1+      | otherwise = runST $ do+        uPtr <- newDataFrame+        pPtr <- unsafeThawDataFrame eye+        lPtr <- thawDataFrame a+        detNegative <-+          let f x i = (x /=) <$> householderReflectionInplaceR+                                   uPtr pPtr lPtr (Idx i :* Idx i :* U)+          in  foldM f False [0..lim - 1]+        lqL <- unsafeFreezeDataFrame lPtr+        -- WARNING! todo: get rid of transpose.+        lqQ <- transpose <$> unsafeFreezeDataFrame pPtr+        let lqQDet = if detNegative then -1 else 1+        return LQ {..}+      where+        n = dimVal' @n+        m = dimVal' @m+        lim = min n m++-- | Calculate determinant of a matrix via QR decomposition+detViaQR :: forall t n . MatrixQR t n n => Matrix t n n -> Scalar t+detViaQR m = foldl (\x off -> scalar (ixOff off qrR) * x) qrQDet [0,n+1..n*n]+  where+    n = fromIntegral (dimVal' @n) :: Int+    QR {..} = qr m++-- | Calculate inverse of a matrix via QR decomposition+inverseViaQR :: forall t n . MatrixQR t n n => Matrix t n n -> Matrix t n n+inverseViaQR = (`qrSolveR` eye)++{- |+Compute a QR or LQ decomposition of matrix \( A : n \times m \),+and solve a system of linear equations \( Ax = b \).++If \( n >= m \) QR decomposition is used;+if \( n > m \) this function solves linear least squares problem.+If \( n < m \) (underdetermined system) LQ decomposition is used+  to yield a minimum norm solution.+ -}+qrSolveR ::+       forall t (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (MatrixQR t n m, Dimensions ds)+    => Matrix t n m -> DataFrame t (n :+ ds) -> DataFrame t (m :+ ds)+qrSolveR a b = case compareDim dn dm of+  SEQ | Dict <- (unsafeCoerce (Dict @(m ~ m)) :: Dict (m ~ n))+        -> runST $ do+    let QR {..} = qr a+    xPtr <- thawDataFrame (transpose qrQ %* b) -- NB: make a stateful product for transposed mat+    solveUpperTriangularR qrR xPtr+    unsafeFreezeDataFrame xPtr+  SGT | Dict <- unsafeCoerce (Dict @(m <= m)) :: Dict (m <= n)+      , Dict <- unsafeCoerce (Dict @(n ~ n)) :: Dict ((((n - m) + 1) + m) ~ (n + 1) )+      , D <- minusDim dn dm `plusDim` D1+        -> runST $ do+    let QR {..} = qr a+        i0 :: Idxs '[n - m + 1]+        i0 = Idx 0 :* U+    xPtr <- thawDataFrame ( slice i0 $ transpose qrQ %* b+                          ) -- NB: make a stateful product for transposed mat+    solveUpperTriangularR qrR xPtr+    unsafeFreezeDataFrame xPtr+  SLT | Dict <- unsafeCoerce (Dict @(m <= m)) :: Dict (n <= m)+      , Dict <- unsafeCoerce (Dict @(n ~ n)) :: Dict ((((m - n) + 1) + n) ~ (m + 1))+      , Dict <- unsafeCoerce (Dict @(n ~ n)) :: Dict (((n + 1) + (m - n)) ~ (m + 1))+      , dd@D <- minusDim dm dn+      , D <- dd `plusDim` D1+      , D <- dn `plusDim` D1+        -> runST $ do+    let LQ {..} = lq a+        i0 :: Idxs '[m - n + 1]+        i0 = Idx 0 :* U+        iz :: Idxs '[n + 1]+        iz = maxBound :* U+    xPtr <- newDataFrame+    copyDataFrame i0 b xPtr+    copyDataFrame iz (0 :: DataFrame t ((m - n) ': ds)) xPtr+    solveLowerTriangularR lqL (subDataFrameView i0 xPtr)+    (transpose lqQ %*) <$> unsafeFreezeDataFrame xPtr+      -- NB: make a stateful product for transposed mat+  _ -> error "qrSolveR: impossible pattern"+  where+    dn = dim @n+    dm = dim @m+++{- |+Compute a QR or LQ decomposition of matrix \( A : n \times m \),+and solve a system of linear equations \( xA = b \).++If \( n <= m \) LQ decomposition is used;+if \( n < m \) this function solves linear least squares problem.+If \( n > m \) (underdetermined system) QR decomposition is used+  to yield a minimum norm solution.+ -}+qrSolveL ::+       forall t (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (MatrixQR t n m, Dimensions ds)+    => Matrix t n m -> DataFrame t (ds +: m) -> DataFrame t (ds +: n)+qrSolveL a b+  | Dims <- Snoc (dims @ds) dn+  , Dims <- Snoc (dims @ds) dm+  , Dict <- Dict @(SnocList ds n _) -- remind GHC that we have (ds +: n)+  , Dict <- Dict @(SnocList ds m _) -- remind GHC that we have (ds +: m)+    = case compareDim dn dm of+  SEQ | Dict <- (unsafeCoerce (Dict @(m ~ m)) :: Dict (m ~ n))+        -> runST $ do+    let LQ {..} = lq a+    xPtr <- thawDataFrame (b %* transpose lqQ) -- NB: make a stateful product for transposed mat+    solveLowerTriangularL xPtr lqL+    unsafeFreezeDataFrame xPtr+  SGT | Dict <- unsafeCoerce (Dict @(m <= m)) :: Dict (m <= n)+      , Dict <- unsafeCoerce (Dict @(n ~ n)) :: Dict ((m + (n - m)) ~ n)+      , D <- minusDim dn dm+        -> runST $ do+    let QR {..} = qr a+    xPtr <- thawDataFrame b+    solveUpperTriangularL xPtr qrR+    ewmap @t @ds @'[n] (\x -> qrQ %* appendDF x (0 :: DataFrame t '[n - m]))+      <$> unsafeFreezeDataFrame xPtr+  SLT | Dict <- unsafeCoerce (Dict @(m <= m)) :: Dict (n <= m)+      , Dict <- unsafeCoerce (Dict @(n ~ n)) :: Dict ((((m - n) + 1) + n) ~ (m + 1))+      , D <- minusDim dm dn `plusDim` D1+        -> runST $ do+    let LQ {..} = lq a+        i0 :: Idx (m - n + 1)+        i0 = Idx 0+    xPtr <- thawDataFrame (b %* transpose lqQ) -- NB: make a stateful product for transposed mat+    solveLowerTriangularL xPtr lqL+    ewmap @t @ds @'[n] (sslice i0)+      <$> unsafeFreezeDataFrame xPtr+  _ -> error "qrSolveL/compareDim: impossible pattern"+  | otherwise = error "qrSolveL: impossible pattern"+  where+    dn = dim @n+    dm = dim @m
+ src/Numeric/Matrix/SVD.hs view
@@ -0,0 +1,799 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+module Numeric.Matrix.SVD+  ( MatrixSVD (..), SVD (..)+  , svd1, svd2, svd3, svd3q+  ) where++import Control.Monad+import Control.Monad.ST+import Data.Kind+import Numeric.Basics+import Numeric.DataFrame.Internal.PrimArray+import Numeric.DataFrame.ST+import Numeric.DataFrame.SubSpace+import Numeric.DataFrame.Type+import Numeric.Dimensions+import Numeric.Matrix.Bidiagonal+import Numeric.Matrix.Internal+import Numeric.Quaternion.Internal+import Numeric.Scalar.Internal+import Numeric.Subroutine.Sort+import Numeric.Tuple+import Numeric.Vector.Internal++-- | Result of SVD factorization+--   @ M = svdU %* asDiag svdS %* transpose svdV @.+--+--   Invariants:+--+--   * Singular values `svdS` are in non-increasing order and are non-negative.+--   * svdU and svdV are orthogonal matrices+--   * det svdU == 1+--+--   NB: <https://en.wikipedia.org/wiki/Singular_value_decomposition SVD on wiki>+data SVD (t :: Type) (n :: Nat) (m :: Nat)+  = SVD+  { svdU :: Matrix t n n+    -- ^ Left-singular basis matrix+  , svdS :: Vector t (Min n m)+    -- ^ Vector of singular values+  , svdV :: Matrix t m m+    -- ^ Right-singular basis matrix+  }++deriving instance ( Show t, PrimBytes t+                  , KnownDim n, KnownDim m, KnownDim (Min n m))+                  => Show (SVD t n m)+deriving instance ( Eq (Matrix t n n)+                  , Eq (Matrix t m m)+                  , Eq (Vector t (Min n m)))+                  => Eq (SVD t n m)++class RealFloatExtras t+    => MatrixSVD (t :: Type) (n :: Nat) (m :: Nat) where+    -- | Compute SVD factorization of a matrix+    svd :: IterativeMethod => Matrix t n m -> SVD t n m++-- | Obvious dummy implementation of SVD for 1x1 matrices+svd1 :: (PrimBytes t, Num t, Eq t) => Matrix t 1 1 -> SVD t 1 1+svd1 m = SVD+    { svdU = 1+    , svdS = broadcast $ abs x+    , svdV = broadcast $ if x == 0 then 1 else signum x+    }+  where+    x = ixOff 0 m++-- | SVD of a 2x2 matrix can be computed analytically+--+--   Related discussion:+--+--   https://scicomp.stackexchange.com/questions/8899/robust-algorithm-for-2-times-2-svd/+--+--   https://ieeexplore.ieee.org/document/486688+svd2 :: forall t . RealFloatExtras t => Matrix t 2 2 -> SVD t 2 2+svd2 (DF2 (DF2 m00 m01) (DF2 m10 m11)) =+    SVD+    { svdU = DF2 (DF2         uc  us)+                 (DF2 (negate us) uc)+    , svdS = DF2 sigma1 (abs sigma2)+    , svdV = DF2 (DF2 vc  (sg2 (negate vs)))+                 (DF2 vs  (sg2 vc         ))+    }+  where+    x1 = m00 - m11 -- 2F+    x2 = m00 + m11 -- 2E+    y1 = m01 + m10 -- 2G+    y2 = m01 - m10 -- 2H+    yy = y1*y2+    h1 = hypot x1 y1 -- h1 >= abs x1+    h2 = hypot x2 y2 -- h2 >= abs x2+    sigma1 = 0.5 * (h2 + h1)  -- sigma1 >= abs sigma2+    sigma2 = 0.5 * (h2 - h1)  -- can be negative, which is accounted by sg2+    sg2 = negateUnless (sigma2 >= 0)+    hx1 = h1 + x1+    hx2 = h2 + x2+    hxhx = hx1*hx2+    hxy  = hx1*y2+    yhx  = y1*hx2+    (uc', us', vc', vs') = case (x1 > 0 || y1 /= 0, x2 > 0 || y2 /= 0) of+      (True , True ) -> (hxhx + yy, hxy - yhx, hxhx - yy, hxy + yhx)+      (True , False) -> (y1,  hx1, -y1, hx1)+      (False, True ) -> (y2, -hx2, -y2, hx2)+      (False, False) -> (1, 0, -1, 0)+    ru = recip $ hypot uc' us'+    rv = recip $ hypot vc' vs'+    uc = uc' * ru+    us = us' * ru+    vc = vc' * rv+    vs = vs' * rv++-- | Get SVD decomposition of a 3x3 matrix using `svd3q` function.+--+--   This function reorders the singular components under the hood to make sure+--   @s1 >= s2 >= s3 >= 0@.+--   Thus, it has some overhead on top of `svd3q`.+svd3 :: forall t . (Quaternion t, RealFloatExtras t) => Matrix t 3 3 -> SVD t 3 3+svd3 m = SVD+        { svdU = toMatrix33 u+        , svdS = DF3 s1 s2 s3'+        , svdV = neg3If (s3 < 0) (toMatrix33 v)+        }+  where+    (u, (DF3 s1 s2 s3), v) = svd3q m+    s3' = abs s3+    neg3If :: Bool -> Matrix t 3 3 -> Matrix t 3 3+    neg3If False = id+    neg3If True  = ewmap @t @'[3] neg3+    neg3 :: Vector t 3 -> Vector t 3+    neg3 (DF3 a b c) = DF3 a b (negate c)+++-- | Get SVD decomposition of a 3x3 matrix, with orthogonal matrices U and V+--   represented as quaternions.+--   Important: U and V are bound to be rotations at the expense of the last+--              singular value being possibly negative.+--+--   This is an adoptation of a specialized 3x3 SVD algorithm described in+--     "Computing the Singular Value Decomposition of 3x3 matrices+--      with minimal branching and elementary floating point operations",+--   by  A. McAdams, A. Selle, R. Tamstorf, J. Teran, E. Sifakis.+--+--   http://pages.cs.wisc.edu/~sifakis/papers/SVD_TR1690.pdf+svd3q :: forall t . (Quaternion t, RealFloatExtras t)+      => Matrix t 3 3 -> (Quater t, Vector t 3, Quater t)+svd3q m = (u, s, v)+  where+    v = jacobiEigenQ (transpose m %* m)+    (s, u) = uncurry fixSigns $ qrDecomposition3 (m %* toMatrix33 v)+    -- last bit: make sure    s1 >= s2 >= 0+    fixSigns :: Vector t 3 -> Quater t -> (Vector t 3, Quater t)+    fixSigns (DF3 s1 s2 s3) q@(Quater a b c d) = case (s1 >= 0, s2 >= 0) of+      (True , True ) -> (mk3 s1 s2 s3, q)+      (False, True ) -> (mk3 (negate s1) s2 (negate s3), Quater (-c)  d   a  (-b))+      (True , False) -> (mk3 s1 (negate s2) (negate s3), Quater   d   c (-b) (-a))+      (False, False) -> (mk3 (negate s1) (negate s2) s3, Quater   b (-a)  d  (-c))+    -- one more thing:+    --   the singular values are ordered, but may have small errors;+    --   as a result adjacent values may seem to be out of order by a very small number+    mk3 :: Scalar t -> Scalar t -> Scalar t -> Vector t 3+    mk3 s1 s2 s3' = case (s1 >= s2, s1 >= abs s3, s2 >= abs s3) of+        (True , True , True ) -> DF3 s1 s2     s3' -- s1 >= s2 >= s3+        (True , True , False) -> DF3 s1 s3 (cs s2) -- s1 >= s3 >  s2+        (True , False, _    ) -> DF3 s3 s1 (cs s2) -- s3 >  s1 >= s2+        (False, True , True ) -> DF3 s2 s1     s3' -- s2 >  s1 >= s3+        (False, _    , False) -> DF3 s3 s2 (cs s1) -- s3 >  s2 >  s1+        (False, False, True ) -> DF3 s2 s3 (cs s1) -- s2 >= s3 >  s1+      where+        s3 = abs s3'+        cs = negateUnless (s3' >= 0)+++-- | Approximate values for cos (a/2) and sin (a/2) of a Givens rotation for+--    a 2x2 symmetric matrix. (Algorithm 2)+jacobiGivensQ :: forall t . RealFloatExtras t => t -> t -> t -> (t, t)+jacobiGivensQ aii aij ajj+    | g*sh*sh < ch*ch = (w * ch, w * sh)+    | otherwise       = (c', s')+  where+    ch = 2 * (aii-ajj)+    sh = aij+    w = recip $ hypot ch sh+    g  = 5.82842712474619 :: t  -- 3 + sqrt 8+    c' = 0.9238795325112867 :: t -- cos (pi/8)+    s' = 0.3826834323650898 :: t -- sin (pi/8)+++-- | A quaternion for a QR Givens iteration+qrGivensQ :: forall t . RealFloatExtras t => t -> t -> (t, t)+qrGivensQ a1 a2+    | a1 < 0    = (sh * w, ch * w)+    | otherwise = (ch * w, sh * w)+  where+    rho2 = a1*a1 + a2*a2+    sh = if rho2 > M_EPS then a2 else 0+    ch = abs a1 + sqrt (max rho2 M_EPS)+    w = recip $ hypot ch sh -- TODO: consider something like a hypot+++-- | One iteration of the Jacobi algorithm on a symmetric 3x3 matrix+--+--   The three words arguments are indices:+--     0 <= i /= j /= k <= 2+jacobiEigen3Iteration :: (Quaternion t, RealFloatExtras t)+                     => Int -> Int -> Int+                     -> STDataFrame s t '[3,3]+                     -> ST s (Quater t)+jacobiEigen3Iteration i j k sPtr = do+    sii <- readDataFrameOff sPtr ii+    sij <- readDataFrameOff sPtr ij+    sjj <- readDataFrameOff sPtr jj+    sik <- readDataFrameOff sPtr ik+    sjk <- readDataFrameOff sPtr jk+    -- Coefficients for a quaternion corresponding to a Givens rotation+    let (ch, sh) = jacobiGivensQ sii sij sjj+        a = ch*ch - sh*sh+        b = 2 * sh*ch+        aa = a * a+        ab = a * b+        bb = b * b+    -- update the matrix+    writeDataFrameOff sPtr ii $+      aa * sii + 2 * ab * sij + bb * sjj+    writeDataFrameOff sPtr ij $+      ab * (sjj - sii) + (aa - bb) * sij+    writeDataFrameOff sPtr jj $+      bb * sii - 2 * ab * sij + aa * sjj+    writeDataFrameOff sPtr ik $ a * sik + b * sjk+    writeDataFrameOff sPtr jk $ a * sjk - b * sik++    -- write the quaternion+    qPtr <- unsafeThawDataFrame 0+    writeDataFrameOff qPtr k (negate sh)+    writeDataFrameOff qPtr 3 ch+    fromVec4 <$> unsafeFreezeDataFrame qPtr+  where+    ii = i*3 + i+    ij = if i < j then i*3 + j else j*3 + i+    jj = j*3 + j+    ik = if i < k then i*3 + k else k*3 + i+    jk = if j < k then j*3 + k else k*3 + j+++-- | Total number of the Givens rotations during the Jacobi eigendecomposition+--   part of the 3x3 SVD equals eigenItersX3*3.+--   Value `eigenItersX3 = 6` corresponds to 18 iterations and gives a good precision.+eigenItersX3 :: Int+eigenItersX3 = 12++-- | Run a few iterations of the Jacobi algorithm on a real-valued 3x3 symmetric matrix.+--   The eigenvectors basis of such matrix is orthogonal, and can be represented as+--   a quaternion.+jacobiEigenQ :: forall t+              . (Quaternion t, RealFloatExtras t)+             => Matrix t 3 3 -> Quater t+jacobiEigenQ m = runST $ do+    mPtr <- thawDataFrame m+    q  <- go eigenItersX3 mPtr 1+    s1 <- readDataFrameOff mPtr 0+    s2 <- readDataFrameOff mPtr 4+    s3 <- readDataFrameOff mPtr 8+    return $ sortQ s1 s2 s3 * q+  where+    go :: Int -> STDataFrame s t '[3,3] -> Quater t -> ST s (Quater t)+    go 0 _ q = pure q++    -- -- primitive cyclic iteration;+    -- --   fast, but the convergence is not perfect+    -- --+    -- -- set eigenItersX3 = 6 for good precision+    -- go n p q = do+    --   q1 <- jacobiEigen3Iteration 0 1 2 p+    --   q2 <- jacobiEigen3Iteration 1 2 0 p+    --   q3 <- jacobiEigen3Iteration 2 0 1 p+    --   go (n - 1) p (q3 * q2 * q1 * q)++    -- Pick the largest element on lower triangle;+    --   slow because of branching, but has a better convergence+    --+    --  set eigenItersX3 = 12 for good precision+    --    (slightly faster than the cyclic version with -O0)+    go n p q = do+      a10 <- abs <$> readDataFrameOff p 1+      a20 <- abs <$> readDataFrameOff p 2+      a21 <- abs <$> readDataFrameOff p 5+      q' <- jiter n p a10 a20 a21+      go (n - 1) p (q' * q)+    jiter :: Int -> STDataFrame s t '[3,3]+          -> Scalar t -> Scalar t -> Scalar t -> ST s (Quater t)+    jiter n p a10 a20 a21+      | gt2 a10 a20 a21+        = jacobiEigen3Iteration 0 1 2 p+      | gt2 a20 a10 a21+        = jacobiEigen3Iteration 2 0 1 p+      | gt2 a21 a10 a20+        = jacobiEigen3Iteration 1 2 0 p+      | otherwise+        = case mod n 3 of+            0 -> jacobiEigen3Iteration 0 1 2 p+            1 -> jacobiEigen3Iteration 2 0 1 p+            _ -> jacobiEigen3Iteration 1 2 0 p+    gt2 :: Scalar t -> Scalar t -> Scalar t -> Bool+    gt2 a b c = case compare a b of+                  GT -> a >= c+                  EQ -> a >  c+                  LT -> False++    -- Make such a quaternion that rotates the matrix so that:+    -- abs s1 >= abs s2 >= abs s3+    -- Note, the corresponding singular values may be negative, which must be+    -- taken into account later.+    sortQ :: Scalar t -> Scalar t -> Scalar t -> Quater t+    sortQ s1 s2 s3 = sortQ' (s1 >= s2) (s1 >= s3) (s2 >= s3)+    sortQ' :: Bool -> Bool -> Bool -> Quater t+    sortQ' True  True  True  = Quater 0 0 0 1                    -- s1 >= s2 >= s3+    sortQ' True  True  False = Quater M_SQRT1_2 0 0 (-M_SQRT1_2) -- s1 >= s3 >  s2+    sortQ' True  False _     = Quater 0.5 0.5 0.5 0.5            -- s3 >  s1 >= s2+    sortQ' False True  True  = Quater 0 0 M_SQRT1_2 (-M_SQRT1_2) -- s2 >  s1 >= s3+    sortQ' False _     False = Quater 0 M_SQRT1_2 0 (-M_SQRT1_2) -- s3 >  s2 >  s1+    sortQ' False False True  = Quater 0.5 0.5 0.5 (-0.5)         -- s2 >= s3 >  s1+++-- | One Givens rotation for a QR algorithm on a 3x3 matrix+--+--   The three words arguments are indices:+--     0 <= i /= j /= k <= 2+--+--     if i < j then the eigen values are already sorted!+qrDecomp3Iteration :: (Quaternion t, RealFloatExtras t)+                   => Int -> Int -> Int+                   -> STDataFrame s t '[3,3]+                   -> ST s (Quater t)+qrDecomp3Iteration i j k sPtr = do+    sii <- readDataFrameOff sPtr ii+    sij <- readDataFrameOff sPtr ij+    sji <- readDataFrameOff sPtr ji+    sjj <- readDataFrameOff sPtr jj+    sik <- readDataFrameOff sPtr ik+    sjk <- readDataFrameOff sPtr jk+    -- Coefficients for a quaternion corresponding to a Givens rotation+    let (ch, sh) = qrGivensQ sii sji+        a = ch*ch - sh*sh+        b = 2 * sh*ch+    -- update the matrix+    writeDataFrameOff sPtr ii $ a * sii + b * sji+    writeDataFrameOff sPtr ij $ a * sij + b * sjj+    writeDataFrameOff sPtr ik $ a * sik + b * sjk+    writeDataFrameOff sPtr ji 0 --  a * sji - b * sii+    writeDataFrameOff sPtr jj $ a * sjj - b * sij+    writeDataFrameOff sPtr jk $ a * sjk - b * sik++    -- write the quaternion+    qPtr <- unsafeThawDataFrame 0+    writeDataFrameOff qPtr k (negateUnless leftTriple sh)+    writeDataFrameOff qPtr 3 ch+    fromVec4 <$> unsafeFreezeDataFrame qPtr+  where+    leftTriple = (j - i) /= 1 && (k - j) /= 1+    i3 = i*3+    j3 = j*3+    ii = i3 + i+    ij = i3 + j+    ik = i3 + k+    ji = j3 + i+    jj = j3 + j+    jk = j3 + k++-- | Run QR decomposition in context of 3x3 svd: AV = US = QR+--   The input here is matrix AV+--   The R upper-triangular matrix here is in fact a diagonal matrix Sigma;+--   The Q orthogonal matrix is matrix U in the svd decomposition,+--     represented here as a quaternion.+qrDecomposition3 :: (Quaternion t, RealFloatExtras t)+                 => Matrix t 3 3 -> (Vector t 3, Quater t)+qrDecomposition3 m = runST $ do+    mPtr <- thawDataFrame m+    q1 <- qrDecomp3Iteration 0 1 2 mPtr+    q2 <- qrDecomp3Iteration 0 2 1 mPtr+    q3 <- qrDecomp3Iteration 1 2 0 mPtr+    sig0 <- readDataFrameOff mPtr 0+    sig1 <- readDataFrameOff mPtr 4+    sig2 <- readDataFrameOff mPtr 8+    return (DF3 sig0 sig1 sig2, q3 * q2 * q1)+++instance RealFloatExtras t => MatrixSVD t 1 1 where+    svd = svd1++instance RealFloatExtras t => MatrixSVD t 2 2 where+    svd = svd2++instance (RealFloatExtras t, Quaternion t) => MatrixSVD t 3 3 where+    svd = svd3++instance {-# INCOHERENT #-}+         ( RealFloatExtras t, KnownDim n, KnownDim m)+         => MatrixSVD t n m where+    svd a = runST $ do+      D <- pure dnm+      Dict <- pure $ minIsSmaller dn dm -- GHC is not convinced :(+      alphas <- unsafeThawDataFrame bdAlpha+      betas <- unsafeThawDataFrame bdBeta+      uPtr <- unsafeThawDataFrame bdU+      vPtr <- unsafeThawDataFrame bdV++      -- remove last beta if m > n+      bLast <- readDataFrameOff betas nm1+      when (abs bLast > M_EPS) $+        svdGolubKahanZeroCol alphas betas vPtr nm1++      -- main routine for a bidiagonal matrix+      let maxIter = 3*nm -- number of tries+      withinIters <- svdBidiagonalInplace alphas betas uPtr vPtr nm maxIter+      unless withinIters . tooManyIterations+        $ "SVD - Givens rotation sweeps for a bidiagonal matrix ("+           ++ show maxIter ++ " sweeps max)."++      -- sort singular values+      sUnsorted <- unsafeFreezeDataFrame alphas+      let sSorted :: Vector (Tuple '[t, Word]) (Min n m)+          sSorted = sortBy (\(S (x :! _)) (S (y :! _)) -> compare y x)+                  $ iwmap @_ @_ @'[] (\(Idx i :* U) (S x) -> S (abs x :! i :! U) ) sUnsorted+          svdS = ewmap @t @_ @'[] (\(S (x :! _)) -> S x) sSorted+          perm = ewmap @Word @_ @'[] (\(S (_ :! i :! U)) -> S i) sSorted+          pCount =+             if nm < 2+             then 0 :: Word+             else foldl (\s (i, j) -> if perm!i > perm!j then succ s else s)+                        0 [(i, j) | i <- [0..nm2w], j <- [i+1..nm2w+1]]+          pPositive = even pCount++      -- alphas and svdS are now out of sync, but that is not a problem++      -- make sure det U == 1+      when ((bdUDet < 0) == pPositive) $ do+        readDataFrameOff alphas 0 >>= writeDataFrameOff alphas 0 . negate+        forM_ [0..n - 1] $ \i ->+          readDataFrameOff uPtr (i*n) >>= writeDataFrameOff uPtr (i*n) . negate++      -- negate negative singular values+      forM_ [0..nm1] $ \i -> do+        s <- readDataFrameOff alphas i+        when (s < 0) $ do+          writeDataFrameOff alphas i $ negate s+          forM_ [0..m - 1] $ \j ->+            readDataFrameOff vPtr (j*m + i)+              >>= writeDataFrameOff vPtr (j*m + i) . negate++      -- apply permutations if necessary+      if pCount == 0+      then do+        svdU <- unsafeFreezeDataFrame uPtr+        svdV <- unsafeFreezeDataFrame vPtr+        return SVD {..}+      else do+        svdU' <- unsafeFreezeDataFrame uPtr+        svdV' <- unsafeFreezeDataFrame vPtr+        let svdU = iwgen @_ @_ @'[] $ \(i :* Idx j :* U) ->+              if j >= dimVal dnm+              then index (i :* Idx j :* U) svdU'+              else index (i :* Idx (unScalar $ perm!j) :* U) svdU'+            svdV = iwgen @_ @_ @'[] $ \(i :* Idx j :* U) ->+              if j >= dimVal dnm+              then index (i :* Idx j :* U) svdV'+              else index (i :* Idx (unScalar $ perm!j) :* U) svdV'+        return SVD {..}+      where+        n = fromIntegral $ dimVal dn :: Int+        m = fromIntegral $ dimVal dm :: Int+        dn = dim @n+        dm = dim @m+        dnm = minDim dn dm+        nm1 = nm - 1+        nm = fromIntegral (dimVal dnm) :: Int+        nm2w = fromIntegral (max (nm - 2) 0) :: Word+        -- compute the bidiagonal form b first, solve svd for b.+        BiDiag {..} = bidiagonalHouseholder a++++{- Compute svd for a square bidiagonal matrix inplace+   \( B = U S V^\intercal \)++@+  B = | a1 b1 0     ... 0 |+      | 0  a2 b2 0  ... 0 |+      | 0  0 a3 b3  ... 0 |+      | ................. |+      | 0  0  ... an1 bn1 |+      | 0  0  ...  0  an  | bn? (in case if n > m)+@+ -}+svdBidiagonalInplace ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (nm :: Nat)+     . ( IterativeMethod, RealFloatExtras t+       , KnownDim n, KnownDim m, KnownDim nm, nm ~ Min n m)+    => STDataFrame s t '[nm] -- ^ the main diagonal of B and then the singular values.+    -> STDataFrame s t '[nm] -- ^ first upper diagonal of B+    -> STDataFrame s t '[n,n] -- ^ U+    -> STDataFrame s t '[m,m] -- ^ V+    -> Int -- ^ 0 < q <= nm -- size of a reduced matrix, such that leftover is diagonal+    -> Int -- iters+    -> ST s Bool -- whether the algorithm succeeds within the maxIter+svdBidiagonalInplace _ _ _ _ 0 _ = pure True+svdBidiagonalInplace _ _ _ _ 1 _ = pure True+svdBidiagonalInplace _ _ _ _ _ 0 = pure False+svdBidiagonalInplace aPtr bPtr uPtr vPtr q' iter = do+    Dict <- pure $ minIsSmaller (dim @n) (dim @m)+    (p, q) <- findCounters q'+    if (q /= 0)+    then do+      findZeroDiagonal p q >>= \case+        Just k+          | k == q-1  -> svdGolubKahanZeroCol aPtr bPtr vPtr (k-1)+          | otherwise -> svdGolubKahanZeroRow aPtr bPtr uPtr k+        Nothing -> svdGolubKahanStep aPtr bPtr uPtr vPtr p q+      svdBidiagonalInplace aPtr bPtr uPtr vPtr q (iter - 1)+    else return True+  where+    -- nm = fromIntegral $ dimVal' @nm :: Int++    -- Check if off-diagonal elements are close to zero and nullify them+    -- if they are small along the way.+    -- And find such indices p and q that satisfy condition in alg. 8.6.2+    -- on p. 492. of "Matrix Computations " (4-th edition).+    -- Except these are inverted:+    --   p -- is the starting index of B22 (last submatrix with non-zero superdiagonal)+    --   q -- is the starting index of B33 (diagonal submatrix)+    --+    -- that is, p and q determine the index and the size of next work piece.+    findCounters :: Int -> ST s (Int, Int)+    findCounters = goQ+      where+        checkEps :: Int -> ST s Bool+        checkEps k = do+          b <- abs <$> readDataFrameOff bPtr (k-1)+          if b == 0+          then return True+          else do+            a1 <- abs <$> readDataFrameOff aPtr (k-1)+            a2 <- abs <$> readDataFrameOff aPtr  k+            if b <= M_EPS * (max (a1 + a2) 1)+            then True <$ writeDataFrameOff bPtr (k-1) 0+            else return False+        goQ :: Int -> ST s (Int, Int)+        goQ 0 = pure (0, 0) -- guard against calling with q == 0+        goQ 1 = pure (0, 0) -- 1x1 matrix is always diagonal+        goQ k = checkEps (k-1) >>= \case+          True  -> goQ (k-1)+          False -> flip (,) k <$> goP (k-2)+        goP :: Int -> ST s Int+        goP 0 = pure 0+        goP k = checkEps k >>= \case+          True  -> return k+          False -> goP (k-1)++    -- For indices p and q (p < q), find the biggest index (< q) such that+    --  a[p] == 0+    findZeroDiagonal :: Int -> Int -> ST s (Maybe Int)+    findZeroDiagonal p q+      | k < p     = pure Nothing+      | otherwise = do+        ak <- readDataFrameOff aPtr k+        if ak == 0+        then pure $ Just k+        else if abs ak <= M_EPS+             then Just k <$ writeDataFrameOff aPtr k 0+             else findZeroDiagonal p k+      where+        k = q - 1+++-- | Apply a series of column transformations to make b[k] (and whole column k+1) zero+--    (page 491, 1st paragraph) when a[k+1] == 0.+--   To make this element zero, I apply a series of Givens transforms on columns+--   (multiply on the right).+--+--   Prerequisites:+--     * a[k+1] == 0+--     * 0 <= k < min n (m-1)+--   Invariants:+--     * matrix \(B :: n \times m \) is bidiagonal, represented by two diagonals;+--     * matrix V is orthogonal+--     * \( B = A V^\intercal \), where \(A :: n \times m\) is an implicit original matrix+--   Results:+--     * Same bidiagonal matrix with b[k] == 0; i.e. (k+1)-th column is zero.+--     * matrix V is updated (multiplied on the right)+--+--   NB: All changes are made inplace.+--+svdGolubKahanZeroCol ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat)+     . (RealFloatExtras t, KnownDim n, KnownDim m, n <= m)+    => STDataFrame s t '[n] -- ^ the main diagonal of \(B\)+    -> STDataFrame s t '[n] -- ^ first upper diagonal of \(B\)+    -> STDataFrame s t '[m,m] -- ^ \(V\)+    -> Int -- ^ 0 <= k < min (n+1) m+    -> ST s ()+svdGolubKahanZeroCol aPtr bPtr vPtr k+  | k < 0 || k >= lim = error $ unwords+      [ "svdGolubKahanZeroCol: k =", show k+      , "is outside of a valid range 0 <= k <", show lim]+    -- this trick is to convince GHC that constraint (n <= m) is not redundant+  | Dict <- Dict @(n <= m) = do+    b <- readDataFrameOff bPtr k+    writeDataFrameOff bPtr k 0+    foldM_ goGivens b [k, k-1 .. 0]+  where+    n = fromIntegral $ dimVal' @n :: Int+    m = fromIntegral $ dimVal' @m :: Int+    lim = min n (m-1)+    goGivens :: Scalar t -> Int -> ST s (Scalar t)+    goGivens 0 _ = return 0 -- non-diagonal element is nullified prematurely+    goGivens b i = do+      ai <- readDataFrameOff aPtr i+      let rab = recip $ hypot b ai+          c = ai*rab+          s = b *rab+      updateGivensMat vPtr i (k+1) c s+      writeDataFrameOff aPtr i $ ai*c + b*s -- B[i,i]+      if i == 0+      then return 0+      else do+        bi1 <- readDataFrameOff bPtr (i - 1)  -- B[i,i-1]+        writeDataFrameOff bPtr (i - 1) $ bi1 * c+        return $ negate (bi1 * s)++-- | Apply a series of row transformations to make b[k] (and whole column k) zero+--    (page 490, last paragraph) when a[k] == 0.+--   To make this element zero, I apply a series of Givens transforms on rows+--   (multiply on the left).+--+--   Prerequisites:+--     * a[k] == 0+--     * 0 <= k < n - 1+--   Invariants:+--     * matrix \(B :: m \times n \) is bidiagonal, represented by two diagonals;+--     * matrix U is orthogonal+--     * \( B = U A \), where \(A :: m \times n \) is an implicit original matrix+--   Results:+--     * Same bidiagonal matrix with b[k] == 0; i.e. k-th column is zero.+--     * matrix U is updated (multiplied on the right)+--+--   NB: All changes are made inplace.+--+svdGolubKahanZeroRow ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat)+     . (RealFloatExtras t, KnownDim n, KnownDim m, n <= m)+    => STDataFrame s t '[n] -- ^ the main diagonal of B+    -> STDataFrame s t '[n] -- ^ first upper diagonal of B+    -> STDataFrame s t '[m,m] -- ^ U+    -> Int -- ^ 0 <= k < n - 1+    -> ST s ()+svdGolubKahanZeroRow aPtr bPtr uPtr k+  | k < 0 || k >= n1 = error $ unwords+      [ "svdGolubKahanZeroRow: k =", show k+      , "is outside of a valid range 0 <= k <", show n1]+    -- this trick is to convince GHC that constraint (n <= m) is not redundant+  | Dict <- Dict @(n <= m) = do+    b <- readDataFrameOff bPtr k+    writeDataFrameOff bPtr k 0+    foldM_ goGivens b [k+1..n1]+  where+    n = fromIntegral $ dimVal' @n :: Int+    n1 = n - 1+    goGivens :: Scalar t -> Int -> ST s (Scalar t)+    goGivens 0 _ = return 0 -- non-diagonal element is nullified prematurely+    goGivens b j = do+      aj <- readDataFrameOff aPtr j+      bj <- readDataFrameOff bPtr j+      let rab = recip $ hypot b aj+          c = aj*rab+          s =  b*rab+      updateGivensMat uPtr k j c (negate s)+      writeDataFrameOff aPtr j $ b*s + aj*c+      writeDataFrameOff bPtr j $ bj*c+      return $ negate (bj * s)++-- | A Golub-Kahan bidiagonal SVD step on an unreduced matrix+svdGolubKahanStep ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (nm :: Nat)+     . ( RealFloatExtras t+       , KnownDim n, KnownDim m, KnownDim nm, nm ~ Min n m)+    => STDataFrame s t '[nm] -- ^ the main diagonal of B and then the singular values.+    -> STDataFrame s t '[nm] -- ^ first upper diagonal of B+    -> STDataFrame s t '[n,n] -- ^ U+    -> STDataFrame s t '[m,m] -- ^ V+    -> Int -- ^ p : 0 <= p < q <= nm; p <= q - 2+    -> Int -- ^ q : 0 <= p < q <= nm; p <= q - 2+    -> ST s ()+svdGolubKahanStep aPtr bPtr uPtr vPtr p q+  | p > q - 2 || p < 0 || q > nm+    = error $ unwords+        [ "svdGolubKahanStep: p =", show p, "and q =", show q+        , "do not satisfy p <= q - 2 or 0 <= p < q <=", show nm]+  | Dict <- Dict @(nm ~ Min n m) = do+    (y,z) <- getWilkinsonShiftYZ+    goGivens2 y z p+  where+    nm = fromIntegral $ dimVal' @nm :: Int++    -- get initial values for one recursion sweep.+    -- Note, input must satisfy: q >= p+2+    getWilkinsonShiftYZ :: ST s (Scalar t, Scalar t)+    getWilkinsonShiftYZ  = do+      a1 <- readDataFrameOff aPtr p+      b1 <- readDataFrameOff bPtr p+      am <- readDataFrameOff aPtr (q-2)+      an <- readDataFrameOff aPtr (q-1)+      bm <- if q >= p + 3+            then readDataFrameOff bPtr (q-3)+            else pure 0+      bn <- readDataFrameOff bPtr (q-2)+      let t11 = a1*a1+          t12 = a1*b1+          tmm = am*am + bm*bm+          tnn = an*an + bn*bn+          tnm = am*bn+          d   = 0.5*(tmm - tnn)+          mu  = tnn + d - negateUnless (d >= 0) (hypot d tnm)+      return (t11 - mu, t12)++    -- yv = b[k-1]; zv = B[k-1,k+1] -- to be eliminated by 1st Givens r+    -- yu = a[k];   zu = B[k+1,k-1] -- to be eliminated by 2nd Givens r+    goGivens2 :: Scalar t -> Scalar t -> Int -> ST s ()+    goGivens2 yv zv k = do+          a1 <- readDataFrameOff aPtr k     -- B[k,k]+          a2 <- readDataFrameOff aPtr (k+1) -- B[k+1,k+1]+          b1 <- readDataFrameOff bPtr k     -- B[k,k+1]+          let a1' = a1*cv + b1*sv  -- B[k,k] == yu+              a2' = a2*cv          -- B[k+1,k+1]+              b0' = yv*cv + zv*sv  -- B[k-1,k]+              b1' = b1*cv - a1*sv  -- B[k,k+1]+              yu  = a1'            -- B[k,k]+              zu  = a2*sv          -- B[k+1,k]+              ryzu = recip $ hypot yu zu+              cu = yu * ryzu+              su = zu * ryzu+              a1'' = yu *cu + zu *su+              a2'' = a2'*cu - b1'*su+              b1'' = b1'*cu + a2'*su+          updateGivensMat vPtr k (k+1) cv sv+          updateGivensMat uPtr k (k+1) cu su++          when (k > p) $ writeDataFrameOff bPtr (k-1) b0'+          writeDataFrameOff bPtr k b1''+          writeDataFrameOff aPtr k a1''+          writeDataFrameOff aPtr (k+1) a2''+          when (k < q - 2) $ do+            b2 <- readDataFrameOff bPtr (k+1) -- B[k+1,k+2]+            let b2'' = b2*cu+                zvn  = b2*su+            writeDataFrameOff bPtr (k+1) b2''+            goGivens2 b1'' zvn (k+1)+        where+          ryzv = recip $ hypot yv zv+          cv = yv * ryzv+          sv = zv * ryzv++-- | Update a transformation matrix with a Givens transform (on the right)+updateGivensMat ::+       forall (s :: Type) (t :: Type) (n :: Nat)+     . (PrimBytes t, Num t, KnownDim n)+    => STDataFrame s t '[n,n]+    -> Int -> Int+    -> Scalar t -> Scalar t -> ST s ()+updateGivensMat p i j c s = forM_ [0..n-1] $ \k -> do+    let nk = n*k+        ioff = nk + i+        joff = nk + j+    uki <- readDataFrameOff p ioff+    ukj <- readDataFrameOff p joff+    writeDataFrameOff p ioff $ uki*c + ukj*s+    writeDataFrameOff p joff $ ukj*c - uki*s+  where+    n = fromIntegral $ dimVal' @n :: Int+++minIsSmaller :: forall (n :: Nat) (m :: Nat)+              . Dim n -> Dim m -> Dict (Min n m <= n, Min n m <= m)+minIsSmaller dn dm+  | Just Dict <- lessOrEqDim dnm dn+  , Just Dict <- lessOrEqDim dnm dm+    = Dict+  | otherwise+    = error "minIsSmaller: impossible type-level comparison"+  where+    dnm = minDim dn dm
src/Numeric/PrimBytes.hs view
@@ -90,7 +90,6 @@ import           GHC.Generics import           GHC.Int import           GHC.IO               (IO (..))-import           GHC.Ptr              (Ptr (..)) import           GHC.Word import           Numeric.Dimensions import qualified Numeric.Tuple.Lazy   as TL@@ -1328,7 +1327,7 @@  anyList :: forall (k :: Type) (xs :: [k])         . RepresentableList xs => [Any]-anyList = unsafeCoerce# (tList @_ @xs)+anyList = unsafeCoerce# (tList @xs) {-# INLINE anyList #-}  instance RepresentableList xs => PrimBytes (Idxs (xs :: [k])) where@@ -1368,7 +1367,7 @@         go i (W# x :xs) s = go (plusAddr# i SIZEOF_HSWORD#) xs                                (writeWordOffAddr# i 0# x s)     {-# INLINE writeAddr #-}-    byteSize _ = case dimVal (order' @_ @xs) of+    byteSize _ = case dimVal (order' @xs) of       W# n -> byteSize (undefined :: Idx x) *# word2Int# n     {-# INLINE byteSize #-}     byteAlign _ = byteAlign (undefined :: Idx x)@@ -1376,14 +1375,14 @@     byteFieldOffset _ _ = negateInt# 1#     {-# INLINE byteFieldOffset #-}     indexArray ba off-      | n@(W# n#) <- dimVal (order' @_ @xs)+      | n@(W# n#) <- dimVal (order' @xs)         = unsafeCoerce# (go (off *# word2Int# n#) n)       where         go _ 0 = []         go i n = W# (indexWordArray# ba i) : go (i +# 1#) (n-1)     {-# INLINE indexArray #-}     readArray mba off s-      | n@(W# n#) <- dimVal (order' @_ @xs)+      | n@(W# n#) <- dimVal (order' @xs)         = unsafeCoerce# (go (off *# word2Int# n#) n s)       where         go _ 0 s0 = (# s0, [] #)@@ -1393,7 +1392,7 @@             = (# s2, W# w : xs #)     {-# INLINE readArray #-}     writeArray mba off is-      | W# n# <- dimVal (order' @_ @xs)+      | W# n# <- dimVal (order' @xs)         = go (off *# word2Int# n#) (listIdxs is)       where         go _ [] s         = s@@ -1437,7 +1436,7 @@          , L.All PrimBytes xs          ) => PrimBytes (TS.Tuple xs) where     type PrimFields (TS.Tuple xs) = TupleFields 1 xs-    fromBytes off ba = go 0# (tList @_ @xs)+    fromBytes off ba = go 0# (tList @xs)       where         go :: L.All PrimBytes ds            => Int# -> TypeList ds -> TS.Tuple ds@@ -1447,7 +1446,7 @@           , n' <- roundUpInt n (byteAlign x)           = TS.Id (fromBytes (off +# n') ba) :* go (n' +# byteSize x) ts     {-# INLINE fromBytes #-}-    readBytes mb off = go mb 0# (tList @_ @xs)+    readBytes mb off = go mb 0# (tList @xs)       where         go :: L.All PrimBytes ds            => MutableByteArray# s@@ -1469,7 +1468,7 @@           | n' <- roundUpInt n (byteAlign x)           = go mb (n' +# byteSize x) xs ts (writeBytes mb (off +# n') x s)     {-# INLINE writeBytes #-}-    readAddr addr = go 0# (tList @_ @xs)+    readAddr addr = go 0# (tList @xs)       where         go :: L.All PrimBytes ds            => Int# -> TypeList ds -> State# s -> (# State# s, TS.Tuple ds #)@@ -1490,7 +1489,7 @@           | n' <- roundUpInt n (byteAlign x)           = go (n' +# byteSize x) xs ts (writeAddr x (plusAddr# addr n') s)     {-# INLINE writeAddr #-}-    byteSize _ = go 0# 1# (tList @_ @xs)+    byteSize _ = go 0# 1# (tList @xs)       where         go :: L.All PrimBytes ys => Int# -> Int# -> TypeList ys -> Int#         go s a Empty     = s `roundUpInt` a@@ -1499,7 +1498,7 @@                            in  go ( roundUpInt s xa +# byteSize x)                                   ( maxInt a xa ) ps     {-# INLINE byteSize #-}-    byteAlign _ = go (tList @_ @xs)+    byteAlign _ = go (tList @xs)       where         go :: L.All PrimBytes ys => TypeList ys -> Int#         go Empty     = 0#@@ -1507,7 +1506,7 @@     {-# INLINE byteAlign #-}     byteFieldOffset name _       | Just n <- readMaybe $ symbolVal' name-        = go (n-1) 0# (tList @_ @xs)+        = go (n-1) 0# (tList @xs)       | otherwise = negateInt# 1#       where         go :: L.All PrimBytes ys => Word -> Int# -> TypeList ys -> Int#
src/Numeric/ProductOrd/NonTransitive.hs view
@@ -35,8 +35,6 @@ import Data.Data import Data.Foldable import Data.Kind         (Type)-import Data.Monoid       as Mon (Monoid (..))-import Data.Semigroup    as Sem (Semigroup (..)) import Foreign.Storable  (Storable) import GHC.Generics 
src/Numeric/ProductOrd/Partial.hs view
@@ -35,8 +35,6 @@ import Data.Data import Data.Foldable import Data.Kind         (Type)-import Data.Monoid       as Mon (Monoid (..))-import Data.Semigroup    as Sem (Semigroup (..)) import Foreign.Storable  (Storable) import GHC.Generics 
src/Numeric/Quaternion/Internal.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-} {-# LANGUAGE MagicHash           #-} {-# LANGUAGE PatternSynonyms     #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -9,7 +10,9 @@     ( Quaternion (..), Quater(Quater)     ) where +import Numeric.DataFrame.Type  (KnownBackend) import Numeric.Matrix.Internal (Matrix)+import Numeric.PrimBytes       (PrimBytes) import Numeric.Vector.Internal (Vector) import Text.Read @@ -21,7 +24,10 @@ {-# COMPLETE Quater #-}  -- | Quaternion operations-class Quaternion t where+class ( Floating (Quater t), Floating t, Ord t, PrimBytes t+      , KnownBackend t '[3], KnownBackend t '[4]+      , KnownBackend t '[3,3], KnownBackend t '[4, 4]+      ) => Quaternion t where     -- | Quaternion data type. The ordering of coordinates is @(x,y,z,w)@,     --   where @w@ is the argument, and @x y z@ are the components of a 3D vector     data Quater t
src/Numeric/Quaternion/Internal/QDouble.hs view
@@ -10,19 +10,18 @@ {-# LANGUAGE UnboxedTuples              #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-}-{-# OPTIONS_GHC -fno-warn-orphans  #-}+{-# OPTIONS_GHC -fno-warn-orphans       #-} module Numeric.Quaternion.Internal.QDouble     ( QDouble, Quater (..)     ) where  import qualified Control.Monad.ST                     as ST import           Data.Coerce                          (coerce)+import           Numeric.Basics import           Numeric.DataFrame.Internal.PrimArray import qualified Numeric.DataFrame.ST                 as ST import           Numeric.DataFrame.Type-import           Numeric.PrimBytes                    (PrimBytes) import           Numeric.Quaternion.Internal-import           Numeric.Scalar.Internal import           Numeric.Vector.Internal  type QDouble = Quater Double@@ -31,11 +30,11 @@ deriving instance PrimArray Double (Quater Double)  instance Quaternion Double where-    newtype Quater Double = QDouble Vec4d+    newtype Quater Double = QDouble (Vector Double 4)     {-# INLINE packQ #-}-    packQ = coerce (vec4 :: Double -> Double -> Double -> Double -> Vec4d)+    packQ = coerce (vec4 :: Double -> Double -> Double -> Double -> Vector Double 4)     {-# INLINE unpackQ# #-}-    unpackQ# = coerce (unpackV4# :: Vec4d -> (# Double, Double, Double, Double #))+    unpackQ# = coerce (unpackV4# :: Vector Double 4 -> (# Double, Double, Double, Double #))     {-# INLINE fromVecNum #-}     fromVecNum (unpackV3# -> (# x, y, z #))  = packQ x y z     {-# INLINE fromVec4 #-}@@ -47,7 +46,7 @@     {-# INLINE im #-}     im (unpackQ# -> (# x, y, z, _ #)) = packQ x y z 0.0     {-# INLINE re #-}-    re (unpackQ# -> (# _, _, _, w #)) = packQ 0.0 0.0 0.0 w+    re (unpackQ# -> (# _, _, _, w #)) = packQ 0 0 0 w     {-# INLINE imVec #-}     imVec (unpackQ# -> (# x, y, z, _ #)) = vec3 x y z     {-# INLINE taker #-}@@ -72,7 +71,7 @@                 (l*z + d*k + t2 * (y*i - x*j))     {-# INLINE getRotScale #-}     getRotScale a b = case (# unpackV3# a, unpackV3# b #) of-      (# _, (# 0, 0, 0 #) #) -> packQ 0.0 0.0 0.0 0.0+      (# _, (# 0, 0, 0 #) #) -> packQ 0 0 0 0       (# (# 0, 0, 0 #), _ #) -> let x = (1 / 0 :: Double) in packQ x x x x       (# (# a1, a2, a3 #), (# b1, b2, b3 #) #) ->         let ma = sqrt (a1*a1 + a2*a2 + a3*a3)@@ -99,7 +98,7 @@           (# t1, t2, t3 #) -> packQ (t1 * r) (t2 * r) (t3 * r) (c / ma2)     {-# INLINE axisRotation #-}     axisRotation v a = case unpackV3# v of-      (# 0, 0, 0 #) -> packQ 0.0 0.0 0.0 (if abs a < pi then 1 else -1)+      (# 0, 0, 0 #) -> packQ 0 0 0 (negateUnless (abs a < M_PI) 1)       (# x, y, z #) ->         let c = cos (a * 0.5)             s = sin (a * 0.5)@@ -261,39 +260,35 @@       = QDouble (a - b)     {-# INLINE (-) #-}     (unpackQ# -> (# a1, a2, a3, a4 #)) * (unpackQ# -> (# b1, b2, b3, b4 #))-      = packQ-           ((a4 * b1) +-            (a1 * b4) +-            (a2 * b3) --            (a3 * b2)-            )-           ((a4 * b2) --            (a1 * b3) +-            (a2 * b4) +-            (a3 * b1)-            )-           ((a4 * b3) +-            (a1 * b2) --            (a2 * b1) +-            (a3 * b4)-            )-           ((a4 * b4) --            (a1 * b1) --            (a2 * b2) --            (a3 * b3)-            )+      = packQ ((a4 * b1) + (a1 * b4) + (a2 * b3) - (a3 * b2))+              ((a4 * b2) - (a1 * b3) + (a2 * b4) + (a3 * b1))+              ((a4 * b3) + (a1 * b2) - (a2 * b1) + (a3 * b4))+              ((a4 * b4) - (a1 * b1) - (a2 * b2) - (a3 * b3))     {-# INLINE (*) #-}     negate (QDouble a) = QDouble (negate a)     {-# INLINE negate #-}-    abs = packQ 0.0 0.0 0.0 . sqrt . square+    abs = packQ 0 0 0 . sqrt . square     {-# INLINE abs #-}     signum q@(unpackQ# -> (# x, y, z, w #))-      = case square q of-          0.0 -> packQ 0.0 0.0 0.0 0.0-          qd -> case recip (sqrt qd) of-             s -> packQ (x * s) (y * s) (z * s) (w * s)+      | qd == 0   = q+      | otherwise = case ix + iy + iz + iw + nn of+        0 -> packQ (x * l) (y * l) (z * l) (w * l)+        1 -> packQ (copysign 1 x) 0 0 0+        2 -> packQ 0 (copysign 1 y) 0 0+        4 -> packQ 0 0 (copysign 1 z) 0+        8 -> packQ 0 0 0 (copysign 1 w)+        _ -> packQ n n n n+      where+        n  = 0 / 0 :: Double+        qd = x*x + y*y + z*z + w*w+        ix = if isInfinite x then 1 else 0 :: Int+        iy = if isInfinite y then 2 else 0 :: Int+        iz = if isInfinite z then 4 else 0 :: Int+        iw = if isInfinite w then 8 else 0 :: Int+        nn = if isNaN x || isNaN y || isNaN z || isNaN w then 16 else 0 :: Int+        l  = recip (sqrt qd)     {-# INLINE signum #-}-    fromInteger = packQ 0.0 0.0 0.0 . fromInteger+    fromInteger = packQ 0 0 0 . fromInteger     {-# INLINE fromInteger #-}  @@ -304,172 +299,253 @@     {-# INLINE (/) #-}     a / b = a * recip b     {-# INLINE fromRational #-}-    fromRational = packQ 0.0 0.0 0.0 . fromRational+    fromRational = packQ 0 0 0 . fromRational   instance Floating QDouble where     {-# INLINE pi #-}-    pi = packQ 0.0 0.0 0.0 3.141592653589793+    pi = packQ 0 0 0 M_PI     {-# INLINE exp #-}     exp (unpackQ# -> (# x, y, z, w #))-      = case (# (x * x) +-                (y * y) +-                (z * z)-             , exp w-             #) of-        (# 0.0, et #) -> packQ 0.0 0.0 0.0 et-        (# mv2, et #) -> case sqrt mv2 of-          mv -> case et * sin mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (et * cos mv)+      | mv2 == 0  = packQ x y z ew+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        ew  = exp w+        l   = ew * sin mv / mv+        arg = ew * cos mv     {-# INLINE log #-}     log = log' (Vec3 1 0 0)     {-# INLINE sqrt #-}     sqrt = sqrt' (Vec3 1 0 0)     {-# INLINE sin #-}     sin (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (sin w)-        mv2 -> case sqrt mv2 of-          mv -> case cos w * sinh mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (sin w * cosh mv)+      | mv2 == 0  = packQ x y z (sin w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = cos w * sinh mv / mv+        arg = sin w * cosh mv     {-# INLINE cos #-}     cos (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (cos w)-        mv2 -> case sqrt mv2 of-          mv -> case sin w * sinh mv / negate mv of-            l -> packQ (x * l) (y * l) (z * l) (cos w * cosh mv)+      | mv2 == 0  = packQ x y z (cos w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = sin w * sinh mv / negate mv+        arg = cos w * cosh mv     {-# INLINE tan #-}     tan (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (tan w)-        mv2 ->-          let mv = sqrt mv2-              chv = cosh mv-              shv = sinh mv-              ct = cos w-              st = sin w-              cq = recip ( (ct * ct * chv * chv) + (st * st * shv * shv) )-              l = chv * shv * cq / mv-          in packQ (x * l) (y * l) (z * l) (ct * st * cq)+      | mv2 == 0       = packQ x y z (tan w)+      | isInfinite mv2 = signum (packQ x y z 0)+      | otherwise      = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv = sqrt mv2+        b = 2*mv+        a = 2*w+        sina = sin a+        eb = exp (-b)+        eb2 = eb*eb+        d = 1 + eb2 + 2 * eb * cos a+        rd = recip d+        pa = M_PI - abs a+        rd' = 2 / (b*b + pa*pa)+        (l, arg) =+          if d >= M_EPS+          then ((1 - eb2) * rd / mv, 2 * sina * eb * rd)+          else (2 * rd' , negate sina * rd')     {-# INLINE sinh #-}     sinh (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (sinh w)-        mv2 -> case sqrt mv2 of-          mv -> case cosh w * sin mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (sinh w * cos mv)+      | mv2 == 0  = packQ x y z (sinh w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = cosh w * sin mv / mv+        arg = sinh w * cos mv     {-# INLINE cosh #-}     cosh (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (cosh w)-        mv2 -> case sqrt mv2 of-          mv -> case sinh w * sin mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (cosh w * cos mv)+      | mv2 == 0  = packQ x y z (cosh w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = sinh w * sin mv / mv+        arg = cosh w * cos mv     {-# INLINE tanh #-}     tanh (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (tanh w)-        mv2 ->-          let mv = sqrt mv2-              cv = cos mv-              sv = sin mv-              cht = cosh w-              sht = sinh w-              cq = recip ( (cht * cht * cv * cv) + (sht * sht * sv * sv) )-              l = cv * sv * cq / mv-          in packQ (x * l) (y * l) (z * l) (cht * sht * cq)+      | mv2 == 0       = packQ x y z (tanh w)+      | isInfinite mv2 = packQ 0 0 0 (signum w)+      | otherwise      = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv = sqrt mv2+        b = 2*w+        a = 2*mv+        eb = exp (- abs b)+        eb2 = eb*eb+        d = 1 + eb2 + 2 * eb * cos a+        rd = recip d+        pa = M_PI - a+        rd' = 2 / (b*b + pa*pa)+        (l, arg) =+          if d >= M_EPS+          then (2 * sin a * eb * rd / mv, copysign (1 - eb2) b * rd)+          else (2 * rd' , b * rd')     {-# INLINE asin #-}-    asin q = -i * log' axis (i*q + sqrt' axis (1 - q*q))-        where-          axis = sigVec q-          i = fromVecNum axis 0+    -- The original formula:+    -- asin q = -i * log (i*q + sqrt (1 - q*q))+    -- below is a more numerically stable version.+    asin (unpackQ# -> (# x, y, z, w #))+      | v2 == 0   = if w2 <= 1+                    then packQ x y z (asin w)+                    else packQ l 0 0 arg+      | otherwise  = packQ (x*c) (y*c) (z*c) arg+      where+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        w1qq = 0.5 *(1 - w2 + v2)       -- real part of (1 - q*q)/2+        l1qq = sqrt (w1qq*w1qq + w2*v2) -- length of (1 - q*q)/2+        sp2 = l1qq + w1qq+        sn2 = l1qq - w1qq+        sp = sqrt sp2+        sn = copysign (sqrt sn2) w+        -- choose a more stable (symbolically equiv) version+        dp = if 2 * v2 <= sp2 then sp - v else v2 / ((sp + v)*(sn2 + v2))+        dn = if 2 * w2 <= sn2 then w - sn else w2 / ((sn + w)*(sp2 + w2))+        (wD, vD) = case compare w1qq 0 of+            GT -> (dp, w * dp / sp)+            LT -> (v * dn / sn, dn)+            EQ -> (-v, w)+        l = -0.5 * log (wD*wD + vD*vD)+        c = l / v+        arg = atan2 vD wD     {-# INLINE acos #-}-    acos q = pi/2 - asin q+    acos q = M_PI_2 - asin q     {-# INLINE atan #-}     -- atan q = i / 2 * log ( (i + q) / (i - q) )     atan (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0 -> packQ 0 0 0 (atan w)-        v2 ->-          let v = sqrt v2-              w2 = w*w-              vw2 = w2 + v2-              t  = 1 + vw2-              c  = 0.25 * log ((t + 2*v) / (t - 2*v)) / v-          in packQ (c*x) (c*y) (c*z) $ 0.5 * atan2 (2*w) (1 - vw2)+      | v2 == 0   = packQ x y z (atan w)+      | otherwise = packQ (x*c) (y*c) (z*c) arg+      where+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        q2 = w2 + v2+        v' = v - 1+        mzero = w2 + v'*v'+        (c, arg) =+          if mzero == 0+          then ( sqrt maxFinite / v, 0)+          else ( 0.25 * (log (1 + q2 + 2*v) - log mzero) / v+               , 0.5 * atan2 (2*w) (1 - q2) )     {-# INLINE asinh #-}     -- The original formula:     -- asinh q = log (q + sqrt (q*q + 1))     -- below is a more numerically stable version.     asinh (unpackQ# -> (# x, y, z, w #))-      | v2 == 0-        = packQ 0 0 0 (asinh w)-      | w == 0-        = if v2 <= 1-          then let c = asin v / v-               in  packQ (c*x) (c*y) (c*z) 0-          else let c  = 0.5 * pi / v-                   w' = 0.5 * log (2*v2 - 1 + 2 * v * sqrt ( v2 - 1 ))-               in  packQ (c*x) (c*y) (c*z) w'-      | otherwise-        = let c = atan2 v t / v-              w' = 0.5 * log ( t2  + v2) - log t-                     + if w >= 0-                       then log ( t + w )-                       else log 2 + log w2 - log ( t - w ) - log ( r + w2 + v2 - 1 )-          in packQ (c*x) (c*y) (c*z) w'+      | v2 == 0   = packQ x y z (asinh w)+      | otherwise = packQ (x*c) (y*c) (z*c) arg       where         v2 = (x * x) + (y * y) + (z * z)-        v  = sqrt v2+        v = sqrt v2         w2 = w*w-        wvp1 = w2 - v2 + 1-        r = sqrt $ wvp1*wvp1 + 4*w2*v2-        t = sqrt $ ( r + wvp1 ) * 0.5-        t2 = t*t+        w1qq = 0.5 *(1 + w2 - v2)       -- real part of (1 + q*q)/2+        l1qq = sqrt (w1qq*w1qq + w2*v2) -- length of (1 + q*q)/2+        sp2 = l1qq + w1qq+        sn2 = l1qq - w1qq+        sp = sqrt sp2+        sn = copysign (sqrt sn2) w+        -- choose a more stable (symbolically equiv) version+        dp = if 2 * w >= - sp then w + sp else w2 / ((sp - w)*(w2 + sn2))+        dn = if 2 * v <= - sn || sn >= 0+                              then v + sn else v2 / ((v - sn)*(v2 + sp2))+        (wD, vD) = case compare w1qq 0 of+            GT -> (dp, v * dp / sp)+            LT -> (w * dn / sn, dn)+            EQ -> (w, v)+        c = atan2 vD wD / v+        arg = 0.5 * log (wD*wD + vD*vD)     {-# INLINE acosh #-}+    -- The original formula:+    -- asinh q = log (q + sqrt (q + 1) * sqrt (q - 1))+    -- below is a more numerically stable version.     -- note, log (q + sqrt (q*q - 1)) would not work, because that would not     -- be the principal value.-    acosh q = log' axis (q + sqrt' axis (q + 1) * sqrt' axis (q - 1))+    acosh (unpackQ# -> (# x, y, z, w #))+      | v2 == 0   = packQ x y z (acosh w)+      | otherwise = packQ (x*c) (y*c) (z*c) arg       where-        axis = sigVec q+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        w1qq = 0.5 *(w2 - v2 - 1)       -- real part of (q*q - 1)/2+        l1qq = sqrt (w1qq*w1qq + w2*v2) -- length of (q*q - 1)/2+        sp2 = l1qq + w1qq+        sn2 = l1qq - w1qq+        sp = sqrt sp2+        sn = copysign (sqrt sn2) w+        -- choose a more stable (symbolically equiv) version+        dp = if 2 * w >= - sp then w + sp else w2 / ((w - sp)*(w2 + sn2))+        dn = if 2 * v <= - sn || sn >= 0+                              then v + sn else v2 / ((sn - v)*(v2 + sp2))+        (wD, vD) = case compare w1qq 0 of+            GT -> (dp, v * dp / sp)+            LT -> (w * dn / sn, dn)+            EQ -> (w, v)+        c = atan2 vD wD / v+        arg = 0.5 * log (wD*wD + vD*vD)     {-# INLINE atanh #-}-    atanh q = 0.5 * log' (sigVec q) ((1+q)/(1-q))+    -- atanh q = 0.5 * log ( (1 + q) / (1 - q) )+    atanh (unpackQ# -> (# x, y, z, w #))+      | v2 ==  0  = packQ x y z (atanh w)+      | otherwise = packQ (x*c) (y*c) (z*c) (copysign arg w)+      where+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        q2 = w2 + v2+        w' = abs w - 1+        c  = 0.5 * atan2 (2*v) (1 - q2) / v+        arg = if w' == 0+              then (1/0)+              else 0.25 * (log (1 + q2 + 2 * abs w) - log (v2 + w'*w')) + -- If q is negative real, provide a fallback axis to align log.-log' :: Vec3d -> QDouble -> QDouble+log' :: Vector Double 3 -> QDouble -> QDouble log' r (unpackQ# -> (# x, y, z, w #))   = case (x * x) + (y * y) + (z * z) of     0.0 | w >= 0-           -> packQ 0.0 0.0 0.0 (log w)+           -> packQ 0 0 0 (log w)         | Vec3 rx ry rz <- r-           ->  packQ (pi*rx) (pi*ry) (pi*rz) (log (negate w))-    mv2 -> case (# sqrt (mv2 + (w * w)), sqrt mv2 #) of-      (# mq, mv #) -> case atan2 mv w / mv of-        l -> packQ (x * l) (y * l) (z * l) (log mq)+           ->  packQ (M_PI*rx) (M_PI*ry) (M_PI*rz) (log (negate w))+    mv2 -> case (# mv2 + w * w, sqrt mv2 #) of+      (# q2, mv #) -> case atan2 mv w / mv of+        l -> packQ (x * l) (y * l) (z * l) (0.5 * log q2)   -- If q is negative real, provide a fallback axis to align sqrt.-sqrt' :: Vec3d -> QDouble -> QDouble+sqrt' :: Vector Double 3 -> QDouble -> QDouble sqrt' r (unpackQ# -> (# x, y, z, w #))-  = case (x * x) + (y * y) + (z * z) of-    0.0 | w >= 0-          -> packQ 0.0 0.0 0.0 (sqrt w)-        | Vec3 rx ry rz <- r-        , sw <- sqrt (negate w)-          -> packQ (sw*rx) (sw*ry) (sw*rz) 0-    mv2 ->-      let mq = sqrt (mv2 + w * w)-          l2 = sqrt mq-          tq = w / (mq * 2.0)-          sina = sqrt (0.5 - tq) * l2 / sqrt mv2-      in packQ (x * sina) (y * sina) (z * sina) (sqrt (0.5 + tq) * l2)--sigVec :: QDouble -> Vec3d-sigVec (unpackQ# -> (# x, y, z, _ #))-  = case sqrt ((x * x) + (y * y) + (z * z)) of-      0 -> vec3 1 0 0-      l -> vec3 (x/l) (y/l) (z/l)+  | v2 == 0 && w >= 0+    = packQ x y z (sqrt w)+  | v2 == 0+  , Vec3 rx ry rz <- r+  , sw <- sqrt (negate w)+    = packQ (sw*rx) (sw*ry) (sw*rz) 0+  | otherwise+    = packQ (x * c) (y * c) (z * c) arg+  where+    v2 = (x * x) + (y * y) + (z * z)+    mq = sqrt (v2 + w * w)+    arg = sqrt $ 0.5 * if w >= 0 then mq + w else v2 / (mq - w)+    c = 0.5 / arg  instance Eq QDouble where     {-# INLINE (==) #-}
src/Numeric/Quaternion/Internal/QFloat.hs view
@@ -10,19 +10,18 @@ {-# LANGUAGE UnboxedTuples              #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-}-{-# OPTIONS_GHC -fno-warn-orphans  #-}+{-# OPTIONS_GHC -fno-warn-orphans       #-} module Numeric.Quaternion.Internal.QFloat     ( QFloat, Quater (..)     ) where  import qualified Control.Monad.ST                     as ST import           Data.Coerce                          (coerce)+import           Numeric.Basics import           Numeric.DataFrame.Internal.PrimArray import qualified Numeric.DataFrame.ST                 as ST import           Numeric.DataFrame.Type-import           Numeric.PrimBytes                    (PrimBytes) import           Numeric.Quaternion.Internal-import           Numeric.Scalar.Internal import           Numeric.Vector.Internal  type QFloat = Quater Float@@ -31,11 +30,11 @@ deriving instance PrimArray Float (Quater Float)  instance Quaternion Float where-    newtype Quater Float = QFloat Vec4f+    newtype Quater Float = QFloat (Vector Float 4)     {-# INLINE packQ #-}-    packQ = coerce (vec4 :: Float -> Float -> Float -> Float -> Vec4f)+    packQ = coerce (vec4 :: Float -> Float -> Float -> Float -> Vector Float 4)     {-# INLINE unpackQ# #-}-    unpackQ# = coerce (unpackV4# :: Vec4f -> (# Float, Float, Float, Float #))+    unpackQ# = coerce (unpackV4# :: Vector Float 4 -> (# Float, Float, Float, Float #))     {-# INLINE fromVecNum #-}     fromVecNum (unpackV3# -> (# x, y, z #))  = packQ x y z     {-# INLINE fromVec4 #-}@@ -47,7 +46,7 @@     {-# INLINE im #-}     im (unpackQ# -> (# x, y, z, _ #)) = packQ x y z 0.0     {-# INLINE re #-}-    re (unpackQ# -> (# _, _, _, w #)) = packQ 0.0 0.0 0.0 w+    re (unpackQ# -> (# _, _, _, w #)) = packQ 0 0 0 w     {-# INLINE imVec #-}     imVec (unpackQ# -> (# x, y, z, _ #)) = vec3 x y z     {-# INLINE taker #-}@@ -72,7 +71,7 @@                 (l*z + d*k + t2 * (y*i - x*j))     {-# INLINE getRotScale #-}     getRotScale a b = case (# unpackV3# a, unpackV3# b #) of-      (# _, (# 0, 0, 0 #) #) -> packQ 0.0 0.0 0.0 0.0+      (# _, (# 0, 0, 0 #) #) -> packQ 0 0 0 0       (# (# 0, 0, 0 #), _ #) -> let x = (1 / 0 :: Float) in packQ x x x x       (# (# a1, a2, a3 #), (# b1, b2, b3 #) #) ->         let ma = sqrt (a1*a1 + a2*a2 + a3*a3)@@ -99,7 +98,7 @@           (# t1, t2, t3 #) -> packQ (t1 * r) (t2 * r) (t3 * r) (c / ma2)     {-# INLINE axisRotation #-}     axisRotation v a = case unpackV3# v of-      (# 0, 0, 0 #) -> packQ 0.0 0.0 0.0 (if abs a < pi then 1 else -1)+      (# 0, 0, 0 #) -> packQ 0 0 0 (negateUnless (abs a < M_PI) 1)       (# x, y, z #) ->         let c = cos (a * 0.5)             s = sin (a * 0.5)@@ -261,39 +260,35 @@       = QFloat (a - b)     {-# INLINE (-) #-}     (unpackQ# -> (# a1, a2, a3, a4 #)) * (unpackQ# -> (# b1, b2, b3, b4 #))-      = packQ-           ((a4 * b1) +-            (a1 * b4) +-            (a2 * b3) --            (a3 * b2)-            )-           ((a4 * b2) --            (a1 * b3) +-            (a2 * b4) +-            (a3 * b1)-            )-           ((a4 * b3) +-            (a1 * b2) --            (a2 * b1) +-            (a3 * b4)-            )-           ((a4 * b4) --            (a1 * b1) --            (a2 * b2) --            (a3 * b3)-            )+      = packQ ((a4 * b1) + (a1 * b4) + (a2 * b3) - (a3 * b2))+              ((a4 * b2) - (a1 * b3) + (a2 * b4) + (a3 * b1))+              ((a4 * b3) + (a1 * b2) - (a2 * b1) + (a3 * b4))+              ((a4 * b4) - (a1 * b1) - (a2 * b2) - (a3 * b3))     {-# INLINE (*) #-}     negate (QFloat a) = QFloat (negate a)     {-# INLINE negate #-}-    abs = packQ 0.0 0.0 0.0 . sqrt . square+    abs = packQ 0 0 0 . sqrt . square     {-# INLINE abs #-}     signum q@(unpackQ# -> (# x, y, z, w #))-      = case square q of-          0.0 -> packQ 0.0 0.0 0.0 0.0-          qd -> case recip (sqrt qd) of-             s -> packQ (x * s) (y * s) (z * s) (w * s)+      | qd == 0   = q+      | otherwise = case ix + iy + iz + iw + nn of+        0 -> packQ (x * l) (y * l) (z * l) (w * l)+        1 -> packQ (copysign 1 x) 0 0 0+        2 -> packQ 0 (copysign 1 y) 0 0+        4 -> packQ 0 0 (copysign 1 z) 0+        8 -> packQ 0 0 0 (copysign 1 w)+        _ -> packQ n n n n+      where+        n  = 0 / 0 :: Float+        qd = x*x + y*y + z*z + w*w+        ix = if isInfinite x then 1 else 0 :: Int+        iy = if isInfinite y then 2 else 0 :: Int+        iz = if isInfinite z then 4 else 0 :: Int+        iw = if isInfinite w then 8 else 0 :: Int+        nn = if isNaN x || isNaN y || isNaN z || isNaN w then 16 else 0 :: Int+        l  = recip (sqrt qd)     {-# INLINE signum #-}-    fromInteger = packQ 0.0 0.0 0.0 . fromInteger+    fromInteger = packQ 0 0 0 . fromInteger     {-# INLINE fromInteger #-}  @@ -304,172 +299,253 @@     {-# INLINE (/) #-}     a / b = a * recip b     {-# INLINE fromRational #-}-    fromRational = packQ 0.0 0.0 0.0 . fromRational+    fromRational = packQ 0 0 0 . fromRational   instance Floating QFloat where     {-# INLINE pi #-}-    pi = packQ 0.0 0.0 0.0 3.141592653589793+    pi = packQ 0 0 0 M_PI     {-# INLINE exp #-}     exp (unpackQ# -> (# x, y, z, w #))-      = case (# (x * x) +-                (y * y) +-                (z * z)-             , exp w-             #) of-        (# 0.0, et #) -> packQ 0.0 0.0 0.0 et-        (# mv2, et #) -> case sqrt mv2 of-          mv -> case et * sin mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (et * cos mv)+      | mv2 == 0  = packQ x y z ew+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        ew  = exp w+        l   = ew * sin mv / mv+        arg = ew * cos mv     {-# INLINE log #-}     log = log' (Vec3 1 0 0)     {-# INLINE sqrt #-}     sqrt = sqrt' (Vec3 1 0 0)     {-# INLINE sin #-}     sin (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (sin w)-        mv2 -> case sqrt mv2 of-          mv -> case cos w * sinh mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (sin w * cosh mv)+      | mv2 == 0  = packQ x y z (sin w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = cos w * sinh mv / mv+        arg = sin w * cosh mv     {-# INLINE cos #-}     cos (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (cos w)-        mv2 -> case sqrt mv2 of-          mv -> case sin w * sinh mv / negate mv of-            l -> packQ (x * l) (y * l) (z * l) (cos w * cosh mv)+      | mv2 == 0  = packQ x y z (cos w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = sin w * sinh mv / negate mv+        arg = cos w * cosh mv     {-# INLINE tan #-}     tan (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (tan w)-        mv2 ->-          let mv = sqrt mv2-              chv = cosh mv-              shv = sinh mv-              ct = cos w-              st = sin w-              cq = recip ( (ct * ct * chv * chv) + (st * st * shv * shv) )-              l = chv * shv * cq / mv-          in packQ (x * l) (y * l) (z * l) (ct * st * cq)+      | mv2 == 0       = packQ x y z (tan w)+      | isInfinite mv2 = signum (packQ x y z 0)+      | otherwise      = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv = sqrt mv2+        b = 2*mv+        a = 2*w+        sina = sin a+        eb = exp (-b)+        eb2 = eb*eb+        d = 1 + eb2 + 2 * eb * cos a+        rd = recip d+        pa = M_PI - abs a+        rd' = 2 / (b*b + pa*pa)+        (l, arg) =+          if d >= M_EPS+          then ((1 - eb2) * rd / mv, 2 * sina * eb * rd)+          else (2 * rd' , negate sina * rd')     {-# INLINE sinh #-}     sinh (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (sinh w)-        mv2 -> case sqrt mv2 of-          mv -> case cosh w * sin mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (sinh w * cos mv)+      | mv2 == 0  = packQ x y z (sinh w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = cosh w * sin mv / mv+        arg = sinh w * cos mv     {-# INLINE cosh #-}     cosh (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (cosh w)-        mv2 -> case sqrt mv2 of-          mv -> case sinh w * sin mv / mv of-            l -> packQ (x * l) (y * l) (z * l) (cosh w * cos mv)+      | mv2 == 0  = packQ x y z (cosh w)+      | otherwise = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv  = sqrt mv2+        l   = sinh w * sin mv / mv+        arg = cosh w * cos mv     {-# INLINE tanh #-}     tanh (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0.0 -> packQ 0.0 0.0 0.0 (tanh w)-        mv2 ->-          let mv = sqrt mv2-              cv = cos mv-              sv = sin mv-              cht = cosh w-              sht = sinh w-              cq = recip ( (cht * cht * cv * cv) + (sht * sht * sv * sv) )-              l = cv * sv * cq / mv-          in packQ (x * l) (y * l) (z * l) (cht * sht * cq)+      | mv2 == 0       = packQ x y z (tanh w)+      | isInfinite mv2 = packQ 0 0 0 (signum w)+      | otherwise      = packQ (x * l) (y * l) (z * l) arg+      where+        mv2 = (x * x) + (y * y) + (z * z)+        mv = sqrt mv2+        b = 2*w+        a = 2*mv+        eb = exp (- abs b)+        eb2 = eb*eb+        d = 1 + eb2 + 2 * eb * cos a+        rd = recip d+        pa = M_PI - a+        rd' = 2 / (b*b + pa*pa)+        (l, arg) =+          if d >= M_EPS+          then (2 * sin a * eb * rd / mv, copysign (1 - eb2) b * rd)+          else (2 * rd' , b * rd')     {-# INLINE asin #-}-    asin q = -i * log' axis (i*q + sqrt' axis (1 - q*q))-        where-          axis = sigVec q-          i = fromVecNum axis 0+    -- The original formula:+    -- asin q = -i * log (i*q + sqrt (1 - q*q))+    -- below is a more numerically stable version.+    asin (unpackQ# -> (# x, y, z, w #))+      | v2 == 0   = if w2 <= 1+                    then packQ x y z (asin w)+                    else packQ l 0 0 arg+      | otherwise  = packQ (x*c) (y*c) (z*c) arg+      where+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        w1qq = 0.5 *(1 - w2 + v2)       -- real part of (1 - q*q)/2+        l1qq = sqrt (w1qq*w1qq + w2*v2) -- length of (1 - q*q)/2+        sp2 = l1qq + w1qq+        sn2 = l1qq - w1qq+        sp = sqrt sp2+        sn = copysign (sqrt sn2) w+        -- choose a more stable (symbolically equiv) version+        dp = if 2 * v2 <= sp2 then sp - v else v2 / ((sp + v)*(sn2 + v2))+        dn = if 2 * w2 <= sn2 then w - sn else w2 / ((sn + w)*(sp2 + w2))+        (wD, vD) = case compare w1qq 0 of+            GT -> (dp, w * dp / sp)+            LT -> (v * dn / sn, dn)+            EQ -> (-v, w)+        l = -0.5 * log (wD*wD + vD*vD)+        c = l / v+        arg = atan2 vD wD     {-# INLINE acos #-}-    acos q = pi/2 - asin q+    acos q = M_PI_2 - asin q     {-# INLINE atan #-}     -- atan q = i / 2 * log ( (i + q) / (i - q) )     atan (unpackQ# -> (# x, y, z, w #))-      = case (x * x) + (y * y) + (z * z) of-        0 -> packQ 0 0 0 (atan w)-        v2 ->-          let v = sqrt v2-              w2 = w*w-              vw2 = w2 + v2-              t  = 1 + vw2-              c  = 0.25 * log ((t + 2*v) / (t - 2*v)) / v-          in packQ (c*x) (c*y) (c*z) $ 0.5 * atan2 (2*w) (1 - vw2)+      | v2 == 0   = packQ x y z (atan w)+      | otherwise = packQ (x*c) (y*c) (z*c) arg+      where+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        q2 = w2 + v2+        v' = v - 1+        mzero = w2 + v'*v'+        (c, arg) =+          if mzero == 0+          then ( sqrt maxFinite / v, 0)+          else ( 0.25 * (log (1 + q2 + 2*v) - log mzero) / v+               , 0.5 * atan2 (2*w) (1 - q2) )     {-# INLINE asinh #-}     -- The original formula:     -- asinh q = log (q + sqrt (q*q + 1))     -- below is a more numerically stable version.     asinh (unpackQ# -> (# x, y, z, w #))-      | v2 == 0-        = packQ 0 0 0 (asinh w)-      | w == 0-        = if v2 <= 1-          then let c = asin v / v-               in  packQ (c*x) (c*y) (c*z) 0-          else let c  = 0.5 * pi / v-                   w' = 0.5 * log (2*v2 - 1 + 2 * v * sqrt ( v2 - 1 ))-               in  packQ (c*x) (c*y) (c*z) w'-      | otherwise-        = let c = atan2 v t / v-              w' = 0.5 * log ( t2  + v2) - log t-                     + if w >= 0-                       then log ( t + w )-                       else log 2 + log w2 - log ( t - w ) - log ( r + w2 + v2 - 1 )-          in packQ (c*x) (c*y) (c*z) w'+      | v2 == 0   = packQ x y z (asinh w)+      | otherwise = packQ (x*c) (y*c) (z*c) arg       where         v2 = (x * x) + (y * y) + (z * z)-        v  = sqrt v2+        v = sqrt v2         w2 = w*w-        wvp1 = w2 - v2 + 1-        r = sqrt $ wvp1*wvp1 + 4*w2*v2-        t = sqrt $ ( r + wvp1 ) * 0.5-        t2 = t*t+        w1qq = 0.5 *(1 + w2 - v2)       -- real part of (1 + q*q)/2+        l1qq = sqrt (w1qq*w1qq + w2*v2) -- length of (1 + q*q)/2+        sp2 = l1qq + w1qq+        sn2 = l1qq - w1qq+        sp = sqrt sp2+        sn = copysign (sqrt sn2) w+        -- choose a more stable (symbolically equiv) version+        dp = if 2 * w >= - sp then w + sp else w2 / ((sp - w)*(w2 + sn2))+        dn = if 2 * v <= - sn || sn >= 0+                              then v + sn else v2 / ((v - sn)*(v2 + sp2))+        (wD, vD) = case compare w1qq 0 of+            GT -> (dp, v * dp / sp)+            LT -> (w * dn / sn, dn)+            EQ -> (w, v)+        c = atan2 vD wD / v+        arg = 0.5 * log (wD*wD + vD*vD)     {-# INLINE acosh #-}+    -- The original formula:+    -- asinh q = log (q + sqrt (q + 1) * sqrt (q - 1))+    -- below is a more numerically stable version.     -- note, log (q + sqrt (q*q - 1)) would not work, because that would not     -- be the principal value.-    acosh q = log' axis (q + sqrt' axis (q + 1) * sqrt' axis (q - 1))+    acosh (unpackQ# -> (# x, y, z, w #))+      | v2 == 0   = packQ x y z (acosh w)+      | otherwise = packQ (x*c) (y*c) (z*c) arg       where-        axis = sigVec q+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        w1qq = 0.5 *(w2 - v2 - 1)       -- real part of (q*q - 1)/2+        l1qq = sqrt (w1qq*w1qq + w2*v2) -- length of (q*q - 1)/2+        sp2 = l1qq + w1qq+        sn2 = l1qq - w1qq+        sp = sqrt sp2+        sn = copysign (sqrt sn2) w+        -- choose a more stable (symbolically equiv) version+        dp = if 2 * w >= - sp then w + sp else w2 / ((w - sp)*(w2 + sn2))+        dn = if 2 * v <= - sn || sn >= 0+                              then v + sn else v2 / ((sn - v)*(v2 + sp2))+        (wD, vD) = case compare w1qq 0 of+            GT -> (dp, v * dp / sp)+            LT -> (w * dn / sn, dn)+            EQ -> (w, v)+        c = atan2 vD wD / v+        arg = 0.5 * log (wD*wD + vD*vD)     {-# INLINE atanh #-}-    atanh q = 0.5 * log ((1+q)/(1-q))+    -- atanh q = 0.5 * log ( (1 + q) / (1 - q) )+    atanh (unpackQ# -> (# x, y, z, w #))+      | v2 ==  0  = packQ x y z (atanh w)+      | otherwise = packQ (x*c) (y*c) (z*c) (copysign arg w)+      where+        v2 = (x * x) + (y * y) + (z * z)+        v = sqrt v2+        w2 = w*w+        q2 = w2 + v2+        w' = abs w - 1+        c  = 0.5 * atan2 (2*v) (1 - q2) / v+        arg = if w' == 0+              then (1/0)+              else 0.25 * (log (1 + q2 + 2 * abs w) - log (v2 + w'*w')) + -- If q is negative real, provide a fallback axis to align log.-log' :: Vec3f -> QFloat -> QFloat+log' :: Vector Float 3 -> QFloat -> QFloat log' r (unpackQ# -> (# x, y, z, w #))   = case (x * x) + (y * y) + (z * z) of     0.0 | w >= 0-           -> packQ 0.0 0.0 0.0 (log w)+           -> packQ 0 0 0 (log w)         | Vec3 rx ry rz <- r-           ->  packQ (pi*rx) (pi*ry) (pi*rz) (log (negate w))-    mv2 -> case (# sqrt (mv2 + (w * w)), sqrt mv2 #) of-      (# mq, mv #) -> case atan2 mv w / mv of-        l -> packQ (x * l) (y * l) (z * l) (log mq)+           ->  packQ (M_PI*rx) (M_PI*ry) (M_PI*rz) (log (negate w))+    mv2 -> case (# mv2 + w * w, sqrt mv2 #) of+      (# q2, mv #) -> case atan2 mv w / mv of+        l -> packQ (x * l) (y * l) (z * l) (0.5 * log q2)   -- If q is negative real, provide a fallback axis to align sqrt.-sqrt' :: Vec3f -> QFloat -> QFloat+sqrt' :: Vector Float 3 -> QFloat -> QFloat sqrt' r (unpackQ# -> (# x, y, z, w #))-  = case (x * x) + (y * y) + (z * z) of-    0.0 | w >= 0-          -> packQ 0.0 0.0 0.0 (sqrt w)-        | Vec3 rx ry rz <- r-        , sw <- sqrt (negate w)-          -> packQ (sw*rx) (sw*ry) (sw*rz) 0-    mv2 ->-      let mq = sqrt (mv2 + w * w)-          l2 = sqrt mq-          tq = w / (mq * 2.0)-          sina = sqrt (0.5 - tq) * l2 / sqrt mv2-      in packQ (x * sina) (y * sina) (z * sina) (sqrt (0.5 + tq) * l2)--sigVec :: QFloat -> Vec3f-sigVec (unpackQ# -> (# x, y, z, _ #))-  = case sqrt ((x * x) + (y * y) + (z * z)) of-      0 -> vec3 1 0 0-      l -> vec3 (x/l) (y/l) (z/l)+  | v2 == 0 && w >= 0+    = packQ x y z (sqrt w)+  | v2 == 0+  , Vec3 rx ry rz <- r+  , sw <- sqrt (negate w)+    = packQ (sw*rx) (sw*ry) (sw*rz) 0+  | otherwise+    = packQ (x * c) (y * c) (z * c) arg+  where+    v2 = (x * x) + (y * y) + (z * z)+    mq = sqrt (v2 + w * w)+    arg = sqrt $ 0.5 * if w >= 0 then mq + w else v2 / (mq - w)+    c = 0.5 / arg  instance Eq QFloat where     {-# INLINE (==) #-}
src/Numeric/Scalar/Internal.hs view
@@ -11,11 +11,8 @@     , pattern S     ) where --import Data.Type.Lits             (Nat)-import GHC.Base                   (unsafeCoerce#)-import Numeric.DataFrame.SubSpace (SubSpace (ewgen))-import Numeric.DataFrame.Type     (DataFrame, pattern S)+import Numeric.DataFrame.Internal.PrimArray (broadcast)+import Numeric.DataFrame.Type  -- | Alias for zero-dimensional DataFrame type Scalar t = DataFrame t ('[] :: [Nat])@@ -24,20 +21,8 @@ type Sci   = Scalar Int type Scw   = Scalar Word --- | Convert scalar back to ordinary type-unScalar :: Scalar t -> t--- rely on that Scalar is just two times newtype alias to t-unScalar = unsafeCoerce#-{-# INLINE unScalar #-}---- | Convert any type to scalar wrapper-scalar :: t -> Scalar t--- rely on that Scalar is just two times newtype alias to t-scalar = unsafeCoerce#-{-# INLINE scalar #-}- -- | Broadcast scalar value onto a whole data frame-fromScalar :: SubSpace t ds '[] ds-           => Scalar t -> DataFrame t ds-fromScalar = ewgen+fromScalar :: PrimArray t (DataFrame t ds)+           => Scalar t -> DataFrame t (ds :: [Nat])+fromScalar = broadcast . unScalar {-# INLINE fromScalar #-}
+ src/Numeric/Subroutine/Householder.hs view
@@ -0,0 +1,278 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE StandaloneDeriving    #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeOperators         #-}+{-# LANGUAGE UndecidableInstances  #-}+module Numeric.Subroutine.Householder+  ( householderReflectionInplaceR+  , householderReflectionInplaceL+  ) where+++import Control.Monad+import Control.Monad.ST+import Data.Kind+import Numeric.Basics+import Numeric.DataFrame.ST+import Numeric.DataFrame.Type+import Numeric.Dimensions+import Numeric.Scalar.Internal+++{- | Run a Householder transformation inplace.++     Given some orthongonal matrix \(P\), some matrix \(R\) and index \((k,l)\),+     reflects \(R\) along some hyperplane, such that all elements of \(R\)+     below index \( (k, l) \) become zeros,+     then updates \(P\) with the inverse of the same transform as \(R\).++     Notes and invariants:++       1. The transformation happens inplace for both matrices \(P\) and \(R\);+          if \( R = P^\intercal A \), then \( R' = P^*PR = P'^\intercal A \), where+           \( P' \) and \( R' \) are the updated versions of the input matrices,+           \( P^* \) and \( A \) are implicit matrices.++       2. All elements below and to the left of index \(k,l\) in \(R\)+          are assumed (and not checked) to be zeros;+          these are not touched by the subroutine to save flops.++       3. A logical starting value for \(P\) is an identity matrix.+          The subroutine can be used for a QR decomposition:+            \( Q = P \).++     Returns @True@ if reflection has been performed, and @False@ if it was not needed.+     This can be used to track the sign of @det P@.+ -}+householderReflectionInplaceL ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat)+     . (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m)+    => STDataFrame s t '[n] -- ^ Temporary buffer for a Householder axis vector+    -> STDataFrame s t '[n,n]  -- ^ Current state of \(P^\intercal\)+    -> STDataFrame s t '[n,m]  -- ^ Current state of \(R\)+    -> Idxs '[n,m] -- ^ Pivot element+    -> ST s Bool+householderReflectionInplaceL u p r (Idx i :* Idx j :* U)+    = householderReflectionInplaceL' u p r+      (fromIntegral $ dimVal' @n)+      (fromIntegral $ dimVal' @m)+      (fromIntegral i)+      (fromIntegral j)++householderReflectionInplaceL' ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat)+     . (PrimBytes t, Epsilon t, Ord t)+    => STDataFrame s t '[n] -- ^ Temporary buffer for a Householder axis vector+    -> STDataFrame s t '[n,n]  -- ^ \(P^\intercal\)+    -> STDataFrame s t '[n,m]  -- ^ \(R\)+    -> Int -- ^ \(n\)+    -> Int -- ^ \(m\)+    -> Int -- ^ \( 0 \leq k < n \)+    -> Int -- ^ \( 0 \leq l < m \)+    -> ST s Bool+householderReflectionInplaceL' uPtr pPtr rPtr n m k l = do+    -- pivot element (k,l) of new R+    alpha <- getAlphaAndUpdateU+    u2 <- getU2+    -- u2 == 0 means the column is already zeroed+    if u2 > M_EPS+    then do+      let c = 2 / u2 -- a mult constant for updating matrices+      -- update R+      updateRl alpha+      forM_ [l+1..m-1] $ updateRi c+      -- update P+      forM_ [0..n-1] $ updatePi c+      return True+    else return False+  where+    n' = n - k -- remaining rows+    rOff0 = k*m + l -- offset of element (k,l) in matrix R++    -- u = Rk - alpha*ek+    getAlphaAndUpdateU :: ST s (Scalar t)+    getAlphaAndUpdateU = do+      alpha' <- sqrt . fst <$> nTimesM n'+        (\(r, off) -> do+          x <- readDataFrameOff rPtr off+          when (abs x <= M_EPS) $ writeDataFrameOff rPtr off 0+          return (r + x*x, off + m)+        ) (0, rOff0)+      x0 <- readDataFrameOff rPtr rOff0+      let alpha = if x0 >= 0 then negate alpha' else alpha'+      -- update (lower part of) u+      writeDataFrameOff uPtr k (x0 - alpha)+      when (n' >= 1) $ void $ nTimesM (n' - 1)+        (\(i, off) -> (i+1, off+m) <$+          (readDataFrameOff rPtr off >>= writeDataFrameOff uPtr i)+        ) (k+1, rOff0+m)+      return alpha++    -- l-th column of R zeroes below pivot+    updateRl :: Scalar t -> ST s ()+    updateRl alpha = do+      writeDataFrameOff rPtr rOff0 alpha+      when (n' >= 1) $ void $ nTimesM (n' - 1)+        (\off -> (off+m) <$ writeDataFrameOff rPtr off 0) (rOff0+m)++    -- update i-th column of R+    updateRi :: Scalar t -> Int -> ST s ()+    updateRi c i = do+      -- dot product of u and Ri+      uRi <- fmap fst . flip (nTimesM n') (0, (k, k*m+i)) $ \(r, (j, off)) -> do+        ju  <- readDataFrameOff uPtr j+        jiR <- readDataFrameOff rPtr off+        return (r + ju * jiR, (j+1, off+m))+      let c' = c * uRi+      -- update each element+      void $ flip (nTimesM n') (k, k*m+i) $ \(j, off) -> do+        ju  <- readDataFrameOff uPtr j+        jiR <- readDataFrameOff rPtr off+        writeDataFrameOff rPtr off $ jiR - c'*ju+        return (j+1, off+m)++    -- update i-th row of P+    updatePi :: Scalar t -> Int -> ST s ()+    updatePi c i = do+      let off0 = i*n+      -- dot product of u and Pi+      uPi <- fmap fst . flip (nTimesM n') (0, k) $ \(r, j) -> do+        ju  <- readDataFrameOff uPtr  j+        ijP <- readDataFrameOff pPtr (off0 + j)+        return (r + ju * ijP, j+1)+      let c' = c * uPi+      -- update each element+      forM_ [k..n-1] $ \j -> do+        ju  <- readDataFrameOff uPtr j+        ijP <- readDataFrameOff pPtr (off0 + j)+        writeDataFrameOff pPtr (off0 + j) $ ijP - c'*ju++    -- get module squared of u (for Q = I - 2 u*uT / |u|^2 )+    getU2 :: ST s (Scalar t)+    getU2 = fst <$> nTimesM n'+      (\(r, off) -> (\x -> (r + x*x, off + 1)) <$> readDataFrameOff uPtr off) (0, k)++{- | Run a Householder transformation inplace.++  Similar to `householderReflectionInplaceR`, but works from right to left+   - use to zero elements to the right from the pivot.++     Returns @True@ if reflection has been performed, and @False@ if it was not needed.+     This can be used to track the sign of @det P@.+ -}+householderReflectionInplaceR ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat)+     . (PrimBytes t, Ord t, Epsilon t, KnownDim n, KnownDim m)+    => STDataFrame s t '[m] -- ^ Temporary buffer for a Householder axis vector+    -> STDataFrame s t '[m,m]  -- ^ Current state of \(P^\intercal\)+    -> STDataFrame s t '[n,m]  -- ^ Current state of \(R\)+    -> Idxs '[n,m] -- ^ Pivot element+    -> ST s Bool+householderReflectionInplaceR u p r (Idx i :* Idx j :* U)+    = householderReflectionInplaceR' u p r+      (fromIntegral $ dimVal' @n)+      (fromIntegral $ dimVal' @m)+      (fromIntegral i)+      (fromIntegral j)++householderReflectionInplaceR' ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat)+     . (PrimBytes t, Epsilon t, Ord t)+    => STDataFrame s t '[m] -- ^ Temporary buffer for a Householder axis vector+    -> STDataFrame s t '[m,m]  -- ^ \(P^\intercal\)+    -> STDataFrame s t '[n,m]  -- ^ \(R\)+    -> Int -- ^ \(n\)+    -> Int -- ^ \(m\)+    -> Int -- ^ \( 0 \leq k < n \)+    -> Int -- ^ \( 0 \leq l < m \)+    -> ST s Bool+householderReflectionInplaceR' uPtr pPtr rPtr n m k l = do+    -- pivot element (k,l) of new R+    alpha <- getAlphaAndUpdateU+    u2 <- getU2+    -- u2 == 0 means the column is already zeroed+    if u2 > M_EPS+    then do+      let c = 2 / u2 -- a mult constant for updating matrices+      -- update R+      updateRk alpha+      forM_ [k+1..n-1] $ updateRi c+      -- update P+      forM_ [0..m-1] $ updatePi c+      return True+    else return False+  where+    m' = m - l -- remaining cols+    rOff0 = k*m + l -- offset of element (k,l) in matrix R++    -- u = Rl - alpha*el+    getAlphaAndUpdateU :: ST s (Scalar t)+    getAlphaAndUpdateU = do+      alpha' <- sqrt . fst <$> nTimesM m'+        (\(r, off) -> do+          x <- readDataFrameOff rPtr off+          when (abs x <= M_EPS) $ writeDataFrameOff rPtr off 0+          return (r + x*x, off + 1)+        ) (0, rOff0)+      x0 <- readDataFrameOff rPtr rOff0+      let alpha = if x0 >= 0 then negate alpha' else alpha'+      -- update (lower part of) u+      writeDataFrameOff uPtr l (x0 - alpha)+      forM_ [1..m'-1] $ \i ->+        readDataFrameOff rPtr (rOff0 + i) >>= writeDataFrameOff uPtr (l + i)+      return alpha++    -- k-th row of R zeroes below pivot+    updateRk :: Scalar t -> ST s ()+    updateRk alpha = do+      writeDataFrameOff rPtr rOff0 alpha+      forM_ [rOff0+1..rOff0+m'-1] $ flip (writeDataFrameOff rPtr) 0++    -- update i-th row of R+    updateRi :: Scalar t -> Int -> ST s ()+    updateRi c i = do+      let off0 = i*m+      -- dot product of u and Ri+      uRi <- fmap fst . flip (nTimesM m') (0, l) $ \(r, j) -> do+        ju  <- readDataFrameOff uPtr  j+        jiR <- readDataFrameOff rPtr (off0 + j)+        return (r + ju * jiR, j+1)+      let c' = c * uRi+      -- update each element+      forM_ [l..m-1] $ \j -> do+        ju  <- readDataFrameOff uPtr j+        jiR <- readDataFrameOff rPtr (off0 + j)+        writeDataFrameOff rPtr (off0 + j) $ jiR - c'*ju++    -- update i-th row of P+    updatePi :: Scalar t -> Int -> ST s ()+    updatePi c i = do+      let off0 = i*m+      -- dot product of u and Pi+      uPi <- fmap fst . flip (nTimesM m') (0, l) $ \(r, j) -> do+        ju  <- readDataFrameOff uPtr  j+        ijP <- readDataFrameOff pPtr (off0 + j)+        return (r + ju * ijP, j+1)+      let c' = c * uPi+      -- update each element+      forM_ [l..m-1] $ \j -> do+        ju  <- readDataFrameOff uPtr j+        ijP <- readDataFrameOff pPtr (off0 + j)+        writeDataFrameOff pPtr (off0 + j) $ ijP - c'*ju++    -- get module squared of u (for Q = I - 2 u*uT / |u|^2 )+    getU2 :: ST s (Scalar t)+    getU2 = fst <$> nTimesM m'+      (\(r, off) -> (\x -> (r + x*x, off + 1)) <$> readDataFrameOff uPtr off) (0, l)+++nTimesM :: Monad m => Int -> (a -> m a) -> a -> m a+nTimesM 0 _ x = pure x+nTimesM n m x = m x >>= nTimesM (n - 1) m
+ src/Numeric/Subroutine/SolveTriangular.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-}+{- |+A few ways to solve a system of linear equations in ST monad.+The tesult is always computed inplace.+ -}+module Numeric.Subroutine.SolveTriangular+  ( solveUpperTriangularR+  , solveUpperTriangularL+  , solveLowerTriangularR+  , solveLowerTriangularL+  ) where+++import Control.Monad+import Control.Monad.ST+import Data.Kind+import Numeric.DataFrame.Internal.PrimArray+import Numeric.DataFrame.ST+import Numeric.DataFrame.Type+import Numeric.Dimensions+++{- |+Solve a system of linear equations \( Rx = b \)+   or a linear least squares problem \( \min {|| Rx - b ||}^2 \),+where \( R \) is an upper-triangular matrix.++DataFrame \( b \) is modified in-place; by the end of the process \( b_m = x \).++NB: you can use `subDataFrameView` to truncate @b@ without performing a copy.+ -}+solveUpperTriangularR ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (PrimBytes t, Fractional t, Eq t, KnownDim m, m <= n)+    => DataFrame t '[n,m]       -- ^ \(R\)+    -> STDataFrame s t  (m :+ ds) -- ^ Current state of \(b_m\)+                                  --   (first @m@ rows of @b@)+    -> ST s ()+solveUpperTriangularR r bPtr | Dict <- Dict @(m <= n) = mapM_ go [m-1,m-2..0]+  where+    m = fromIntegral $ dimVal' @m :: Int+    k = fromIntegral kw :: Int+    CumulDims (_:kw:_) = getDataFrameSteps bPtr+    go :: Int -> ST s ()+    go i | rii == 0  = forM_ [0..k-1] $ \j -> writeDataFrameOff bPtr (ki + j) 0+         | otherwise = forM_ [0..k-1] $ \j -> do+            bij <- (rrii*) <$> readDataFrameOff bPtr (ki + j)+            writeDataFrameOff bPtr (ki + j) bij+            forM_ [0..i-1] $ \t -> do+              let rti = scalar (ixOff (m*t + i) r)+                  ix = k*t + j+              btj <- readDataFrameOff bPtr ix+              writeDataFrameOff bPtr ix (btj - rti*bij)+      where+        mi = m*i+        ki = k*i+        rii = scalar (ixOff (mi + i) r)+        rrii = recip rii+++{- |+Solve a system of linear equations \( xR = b \),+where \( R \) is an upper-triangular matrix.++DataFrame \( b \) is modified in-place; by the end of the process \( b = x_m \).+The \( (n - m) \) rows of \(R\) are not used.+Pad each dimension of \(x\) with \( (n - m) \) zeros if you want to get the full+solution.+ -}+solveUpperTriangularL ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (PrimBytes t, Fractional t, Eq t, KnownDim m, m <= n)+    => STDataFrame s t  (ds +: m) -- ^ Current state of \(b\)+                                  --   (first @m@ "columns" of x)+    -> DataFrame t '[n,m]         -- ^ \(R\)+    -> ST s ()+solveUpperTriangularL bPtr r | Dict <- Dict @(m <= n) = mapM_ go [0..m-1]+  where+    m = fromIntegral $ dimVal' @m :: Int+    k = fromIntegral mkw `quot` m+    CumulDims (mkw:_) = getDataFrameSteps bPtr+    go :: Int -> ST s ()+    go i | rii == 0  = forM_ [0..k-1] $ \j -> writeDataFrameOff bPtr (m*j + i) 0+         | otherwise = forM_ [0..k-1] $ \j -> do+            let mj = m*j+            bji <- (rrii*) <$> readDataFrameOff bPtr (mj + i)+            writeDataFrameOff bPtr (mj + i) bji+            forM_ [i+1..m-1] $ \t -> do+              let rit = scalar (ixOff (mi + t) r)+              bjt <- readDataFrameOff bPtr (mj + t)+              writeDataFrameOff bPtr (mj + t) (bjt - rit*bji)+      where+        mi = m*i+        rii = scalar (ixOff (mi + i) r)+        rrii = recip rii++{- |+Solve a system of linear equations \( Lx = b \),+where \( L \) is a lower-triangular matrix.++DataFrame \( b \) is modified in-place; by the end of the process \( b = x_n \).+The \( (m - n) \) columns of \(L\) are not used.+Pad \(x\) with \( (m - n) \) zero elements if you want to get the full solution.+ -}+solveLowerTriangularR ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (PrimBytes t, Fractional t, Eq t, KnownDim n, KnownDim m, n <= m)+    => DataFrame t '[n,m]         -- ^ \(L\)+    -> STDataFrame s t  (n :+ ds) -- ^ Current state of \(b\)+                                  --   (first @n@ elements of x)+    -> ST s ()+solveLowerTriangularR l bPtr | Dict <- Dict @(n <= m) = mapM_ go [0..n-1]+  where+    m = fromIntegral $ dimVal' @m :: Int+    n = fromIntegral $ dimVal' @n :: Int+    k = fromIntegral kw :: Int+    CumulDims (_:kw:_) = getDataFrameSteps bPtr+    go :: Int -> ST s ()+    go i | lii == 0  = forM_ [0..k-1] $ \j -> writeDataFrameOff bPtr (ki + j) 0+         | otherwise = forM_ [0..k-1] $ \j -> do+            bij <- (rlii*) <$> readDataFrameOff bPtr (ki + j)+            writeDataFrameOff bPtr (ki + j) bij+            forM_ [i+1..n-1] $ \t -> do+              let rti = scalar (ixOff (m*t + i) l)+                  ix = k*t + j+              btj <- readDataFrameOff bPtr ix+              writeDataFrameOff bPtr ix (btj - rti*bij)+      where+        mi = m*i+        ki = k*i+        lii = scalar (ixOff (mi + i) l)+        rlii = recip lii++{- |+Solve a system of linear equations \( xL = b \)+   or a linear least squares problem \( \min {|| xL - b ||}^2 \),+where \( L \) is a lower-triangular matrix.++DataFrame \( b \) is modified in-place; by the end of the process \( b_n = x \).+The last \( (m - n) \) columns of \(L\) and \(b\) and are not touched.+ -}+solveLowerTriangularL ::+       forall (s :: Type) (t :: Type) (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (PrimBytes t, Fractional t, Eq t, KnownDim n, KnownDim m, n <= m)+    => STDataFrame s t  (ds +: m) -- ^ Current state of \(b\)+    -> DataFrame t '[n,m]         -- ^ \(L\)+    -> ST s ()+solveLowerTriangularL bPtr l | Dict <- Dict @(n <= m) = mapM_ go [n-1,n-2..0]+  where+    m = fromIntegral $ dimVal' @m :: Int+    n = fromIntegral $ dimVal' @n :: Int+    k = fromIntegral kmw `quot` m+    CumulDims (kmw:_) = getDataFrameSteps bPtr+    go :: Int -> ST s ()+    go i | lii == 0  = forM_ [0..k-1] $ \j -> writeDataFrameOff bPtr (m*j + i) 0+         | otherwise = forM_ [0..k-1] $ \j -> do+            let mj = m*j+            bji <- (rlii*) <$> readDataFrameOff bPtr (mj + i)+            writeDataFrameOff bPtr (mj + i) bji+            forM_ [0..i-1] $ \t -> do+              let lit = scalar (ixOff (mi + t) l)+                  ix = m*j + t+              bjt <- readDataFrameOff bPtr ix+              writeDataFrameOff bPtr ix (bjt - lit*bji)+      where+        mi = m*i+        lii = scalar (ixOff (mi + i) l)+        rlii = recip lii
+ src/Numeric/Subroutine/Sort.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE DataKinds             #-}+{-# LANGUAGE FlexibleContexts      #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PolyKinds             #-}+{-# LANGUAGE RecordWildCards       #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE TypeApplications      #-}+{-# LANGUAGE TypeFamilies          #-}+{-# LANGUAGE TypeInType            #-}+{-# LANGUAGE TypeOperators         #-}+module Numeric.Subroutine.Sort+  ( SortBy (..), sortBy, sort+  , SortableDataFrame+  ) where+++import Control.Monad+import Control.Monad.ST+import Control.Monad.ST.Unsafe+import Data.Kind+import Data.Type.Lits+import Numeric.DataFrame.Internal.PrimArray+import Numeric.DataFrame.ST+import Numeric.DataFrame.Type+import Numeric.Dimensions+import Unsafe.Coerce++-- | Sort a @DataFrame@ along the first dimension.+--+--   Note: the elements (which are of type @DataFrame t ns@) are compared+--         lexicographically.+sort :: forall (t :: Type) n ns+      . ( SortableDataFrame t (n ': ns), Ord t, SortBy n)+     => DataFrame t (n ': ns)+     -> DataFrame t (n ': ns)+sort df = case dimKind @(KindOf n) of+    DimKNat  -> case uniqueOrCumulDims df of+      Left _ -> df -- all equal, no need for sorting.+      Right steps+        | SomeDims (Dims :: Dims ms) <- fromSteps steps+        , Dict <- (unsafeCoerce (Dict @(ns ~ ns)) :: Dict (ns ~ ms))+          -> sortBy compare df+        | otherwise+          -> error "sort/DimNat/uniqueOrCumulDims -- impossible pattern"+    DimKXNat+        | XFrame (df' :: DataFrame t ms) <- df+        , D :* Dims <- dims @ms+          -> XFrame (sortBy compare df')+        | otherwise+          -> error "sort/DimXNat -- impossible pattern"++-- | Sort a @DataFrame@ along the first dimension using given comparison function.+sortBy :: forall (t :: Type) n ns+        . ( SortableDataFrame t (n ': ns)+          , SortBy n)+       => (DataFrame t ns -> DataFrame t ns -> Ordering)+       -> DataFrame t (n ': ns)+       -> DataFrame t (n ': ns)+sortBy cmp df = case dimKind @(KindOf n) of+    DimKNat -> runST $+      flip (withThawDataFrame (const $ pure df)) df $ \mdf -> do+        sortByInplace+          (\x y -> cmp <$> unsafeFreezeDataFrame x <*> unsafeFreezeDataFrame y)+          mdf+        unsafeFreezeDataFrame mdf+    DimKXNat+      | XFrame dfN <- df+      , D :* Dims <- dims `inSpaceOf` dfN+        -> XFrame (sortBy (\a b -> cmp (XFrame a) (XFrame b)) dfN)+      | otherwise+        -> error "sortBy/DimXNat -- impossible pattern"++-- | The required context for sorting a DataFrame is slightly different+--   for @Nat@ and @XNat@ indexed arrays.+--   This type family abstracts away the difference.+type family SortableDataFrame (t :: Type) (ns :: [k]) :: Constraint where+    SortableDataFrame t ((n ': ns) :: [Nat])+      = (PrimArray t (DataFrame t ns), PrimArray t (DataFrame t (n ': ns)))+    SortableDataFrame t ((n ': ns) :: [XNat])+      = PrimBytes t+++class BoundedDim n => SortBy n where+    -- | Note, "Inplace" here means the input frame is modified.+    --   It does not mean the algorithm does not use extra space (it does use).+    sortByInplace :: PrimBytes t+                  => (STDataFrame s t ns -> STDataFrame s t ns -> ST s Ordering)+                      -- ^ must not modify state!+                  -> STDataFrame s t (n ': ns)+                  -> ST s ()+++instance SortBy 0 where+    sortByInplace _ _ = pure ()++instance SortBy 1 where+    sortByInplace _ _ = pure ()++instance SortBy 2 where+    sortByInplace cmp xs = cmp a b >>= \case+        GT -> do+          tmp <- oneMoreDataFrame a+          swapDF tmp a b+        _  -> pure ()+      where+        a = subDataFrameView' (Idx 0 :* U) xs+        b = subDataFrameView' (Idx 1 :* U) xs++instance SortBy 3 where+    sortByInplace cmp xs = join $+        go <$> (unsafeDupableInterleaveST (oneMoreDataFrame a))+           <*> cmp a b <*> cmp b c <*> cmp a c+      where+        a = subDataFrameView' (Idx 0 :* U) xs+        b = subDataFrameView' (Idx 1 :* U) xs+        c = subDataFrameView' (Idx 2 :* U) xs+        go tmp GT LT GT -- b < c < a+          = swap3DF tmp a b c+        go tmp LT GT GT -- c < a < b+          = swap3DF tmp b a c+        go tmp GT bc ac | bc /= GT && ac /= GT+          = swapDF tmp a b+        go tmp ab GT ac | ab /= GT && ac /= GT+          = swapDF tmp b c+        go tmp ab bc GT | ab /= LT && bc /= LT+          = swapDF tmp a c+        go _ _ _ _ = pure ()++instance SortBy 4 where+    sortByInplace cmp xs = do+        tmp <- unsafeDupableInterleaveST (oneMoreDataFrame a)+        cmpSwap tmp a c+        cmpSwap tmp b d+        cmpSwap tmp a b+        cmpSwap tmp c d+        cmpSwap tmp b c+      where+        a = subDataFrameView' (Idx 0 :* U) xs+        b = subDataFrameView' (Idx 1 :* U) xs+        c = subDataFrameView' (Idx 2 :* U) xs+        d = subDataFrameView' (Idx 3 :* U) xs+        cmpSwap tmp x y = cmp x y >>= \case+          GT -> swapDF tmp x y+          _  -> pure ()++instance {-# INCOHERENT #-}+         KnownDim n => SortBy (n :: Nat) where+    sortByInplace cmp (xs :: STDataFrame s t (n ': ns)) = do+        tmp <- oneMoreDataFrame xs+        copyMutableDataFrame' U xs tmp+        mergeSort D tmp xs+      where+        mergeSort :: Dim (d :: Nat)+                  -> STDataFrame s t (d ': ns)+                  -> STDataFrame s t (d ': ns)+                  -> ST s ()+        mergeSort D0 _ _ = pure ()+        mergeSort D1 _ _ = pure ()+        mergeSort (d@D :: Dim d) b a = do+          d2l@D <- pure $ divDim d D2+          Just d2r@D <- pure $ minusDimM d d2l+          d2li@D <- pure $ plusDim d2l D1+          d2ri@D <- pure $ plusDim d2r D1+          Just Dict <- pure $ sameDim (plusDim d D1) (plusDim d2li d2r)+          Just Dict <- pure $ sameDim (plusDim d D1) (plusDim d2ri d2l)+          let leA = subDataFrameView @t @d @(d - Div d 2 + 1) @(Div d 2) @'[]+                                     (Idx 0 :* U) a+              riA = subDataFrameView @t @d @(Div d 2 + 1) @(d - Div d 2) @'[]+                                     (Idx (dimVal d2l) :* U) a+              leB = subDataFrameView @t @d @(d - Div d 2 + 1) @(Div d 2) @'[]+                                     (Idx 0 :* U) b+              riB = subDataFrameView @t @d @(Div d 2 + 1) @(d - Div d 2) @'[]+                                     (Idx (dimVal d2l) :* U) b+          mergeSort d2l leA leB+          mergeSort d2r riA riB+          merge d2l d2r d leB riB a+        merge :: forall (a :: Nat) (b :: Nat) (ab :: Nat)+               . Dim a -> Dim b -> Dim ab+              -> STDataFrame s t (a ': ns)+              -> STDataFrame s t (b ': ns)+              -> STDataFrame s t (ab ': ns)+              -> ST s ()+        merge da@D db@D dab@D a b ab = foldM_ f (Just (0,0)) [0 .. dimVal dab - 1]+          where+            f Nothing _ = pure Nothing+            f (Just (i,j)) k+              | i >= dimVal da+              , Dx dj@(D :: Dim j) <- someDimVal j+              , D <- plusDim dj D1+              , Just bmj@D <- minusDimM db dj+              , Just bmji@D <- minusDimM (plusDim dab D1) bmj+              , Just Dict <- sameDim (plusDim dab D1) (plusDim bmji bmj)+              , Just Dict <- sameDim (plusDim db D1) (dj `plusDim` D1 `plusDim` bmj)+                = Nothing <$ copyMutableDataFrame @t @ab @(ab + 1 - (b - j))+                                                            @(b - j) (Idx k :* U)+                    (subDataFrameView @t @b @(j + 1) @(b - j) (Idx j :* U) b) ab+              | j >= dimVal db+              , Dx di@(D :: Dim i) <- someDimVal i+              , D <- plusDim di D1+              , Just bmi@D <- minusDimM da di+              , Just bmii@D <- minusDimM (plusDim dab D1) bmi+              , Just Dict <- sameDim (plusDim dab D1) (plusDim bmii bmi)+              , Just Dict <- sameDim (plusDim da D1) (di `plusDim` D1 `plusDim` bmi)+                = Nothing <$ copyMutableDataFrame (Idx k :* U)+                    (subDataFrameView @t @a @(i + 1) @(a - i) (Idx i :* U) a) ab+              | otherwise+                = cmp (subDataFrameView' (Idx i :* U) a)+                      (subDataFrameView' (Idx j :* U) b) >>= \case+                    GT -> Just (i, j + 1)+                          <$ copyMutableDataFrame' (Idx k :* U)+                                         (subDataFrameView' (Idx j :* U) b) ab+                    _ -> Just (i + 1, j)+                          <$ copyMutableDataFrame' (Idx k :* U)+                                         (subDataFrameView' (Idx i :* U) a) ab+++instance BoundedDim xn => SortBy (xn :: XNat) where+    sortByInplace cmp (XSTFrame xs)+      | D :* _ <- dims `inSpaceOf` xs+        = sortByInplace (\x y -> cmp (castDataFrame x) (castDataFrame y)) xs+      | otherwise = error "sortByInplace: impossible pattern"+++-- | Swap contents of two DataFrames+swapDF :: forall (s :: Type) (t :: Type) (ns :: [Nat])+        . PrimBytes t+       => STDataFrame s t ns -- ^ Temporary buffer+       -> STDataFrame s t ns+       -> STDataFrame s t ns+       -> ST s ()+swapDF tmp a b = do+  copyMutableDataFrame' U a tmp+  copyMutableDataFrame' U b a+  copyMutableDataFrame' U tmp b++-- | Rotate left contents of three DataFrames+swap3DF :: forall (s :: Type) (t :: Type) (ns :: [Nat])+        . PrimBytes t+       => STDataFrame s t ns -- ^ Temporary buffer+       -> STDataFrame s t ns+       -> STDataFrame s t ns+       -> STDataFrame s t ns+       -> ST s ()+swap3DF tmp a b c = do+  copyMutableDataFrame' U a tmp+  copyMutableDataFrame' U b a+  copyMutableDataFrame' U c b+  copyMutableDataFrame' U tmp c
src/Numeric/Vector/Internal.hs view
@@ -8,7 +8,9 @@ {-# LANGUAGE PatternSynonyms           #-} {-# LANGUAGE PolyKinds                 #-} {-# LANGUAGE ScopedTypeVariables       #-}+{-# LANGUAGE TypeApplications          #-} {-# LANGUAGE TypeFamilies              #-}+{-# LANGUAGE TypeInType                #-} {-# LANGUAGE TypeOperators             #-} {-# LANGUAGE UnboxedTuples             #-} {-# LANGUAGE UndecidableInstances      #-}@@ -29,6 +31,7 @@     , det2, cross, (×)     ) where +import Data.Kind import Numeric.DataFrame.SubSpace import Numeric.DataFrame.Type import Numeric.Scalar.Internal@@ -97,8 +100,8 @@       f _        = scalar b   {-# INLINE vec2 #-}   unpackV2# v =-    (# unScalar (indexOffset# 0# v)-     , unScalar (indexOffset# 1# v) #)+    (# unScalar (indexOffset 0 v)+     , unScalar (indexOffset 1 v) #)   {-# INLINE unpackV2# #-}  instance {-# OVERLAPPABLE #-} SubSpace t '[3] '[] '[3] => Vector3 t where@@ -109,9 +112,9 @@       f _        = scalar c   {-# INLINE vec3 #-}   unpackV3# v =-    (# unScalar (indexOffset# 0# v)-     , unScalar (indexOffset# 1# v)-     , unScalar (indexOffset# 2# v) #)+    (# unScalar (indexOffset 0 v)+     , unScalar (indexOffset 1 v)+     , unScalar (indexOffset 2 v) #)   {-# INLINE unpackV3# #-}  instance {-# OVERLAPPABLE #-} SubSpace t '[4] '[] '[4] => Vector4 t where@@ -123,10 +126,10 @@       f _        = scalar d   {-# INLINE vec4 #-}   unpackV4# v =-    (# unScalar (indexOffset# 0# v)-     , unScalar (indexOffset# 1# v)-     , unScalar (indexOffset# 2# v)-     , unScalar (indexOffset# 3# v) #)+    (# unScalar (indexOffset 0 v)+     , unScalar (indexOffset 1 v)+     , unScalar (indexOffset 2 v)+     , unScalar (indexOffset 3 v) #)   {-# INLINE unpackV4# #-}  @@ -137,7 +140,7 @@          , Num (Vector t n)          , SubSpace t '[n] '[] '[n]          )-      => Vector t n -> Vector t n -> Vector t n+      => Vector t (n :: Nat) -> Vector t n -> Vector t n (.*.) a b = fromScalar . ewfoldl (+) 0 $ a * b infixl 7 .*. @@ -146,7 +149,7 @@        , Num (Vector t n)        , SubSpace t '[n] '[] '[n]        )-    => Vector t n -> Vector t n -> Scalar t+    => Vector t (n :: Nat) -> Vector t n -> Scalar t dot a b = ewfoldl (+) 0 $ a * b  -- | Dot product of two vectors@@ -155,41 +158,47 @@        , Num (Vector t n)        , SubSpace t '[n] '[] '[n]        )-    => Vector t n -> Vector t n -> Scalar t+    => Vector t (n :: Nat) -> Vector t n -> Scalar t (·) = dot {-# INLINE (·) #-}   -- | Sum of absolute values-normL1 :: ( Num t, SubSpace t '[n] '[] '[n] )-       => Vector t n -> Scalar t+normL1 :: ( Num (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n] )+       => Vector t (n :: k) -> DataFrame t ('[] :: [k]) normL1 = ewfoldr (\a -> (abs a +)) 0  -- | hypot function (square root of squares)-normL2 :: ( Floating t , SubSpace t '[n] '[] '[n] )-       => Vector t n -> Scalar t+normL2 :: ( Floating (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n] )+       => Vector t (n :: k) -> DataFrame t ('[] :: [k]) normL2 = sqrt . ewfoldr (\a -> (a*a +)) 0  -- | Normalize vector w.r.t. Euclidean metric (L2).-normalized :: ( Floating t , Fractional (Vector t n), SubSpace t '[n] '[] '[n] )+normalized :: forall (k :: Type) (t :: Type) (n :: k)+            . ( Floating (DataFrame t ('[] :: [k]))+              , SubSpace t '[n] '[] '[n] )            => Vector t n -> Vector t n-normalized v = v / n+normalized v = ewmap @t @'[n] @'[] (*rn) v   where-    n = fromScalar . sqrt $ ewfoldr (\a -> (a*a +)) 0 v+    rn = recip . sqrt $ ewfoldr (\a -> (a*a +)) 0 v  -- | Maximum of absolute values-normLPInf :: ( Ord t, Num t , SubSpace t '[n] '[] '[n] )-          => Vector t n -> Scalar t+normLPInf :: ( Ord (DataFrame t ('[] :: [k]))+             , Num (DataFrame t ('[] :: [k]))+             , SubSpace t '[n] '[] '[n] )+          => Vector t (n :: k) -> DataFrame t ('[] :: [k]) normLPInf = ewfoldr (max . abs) 0  -- | Minimum of absolute values-normLNInf :: ( Ord t, Num t , SubSpace t '[n] '[] '[n] )-          => Vector t n -> Scalar t-normLNInf x = ewfoldr (min . abs) (scalar . abs $ ixOff 0 x) x+normLNInf :: ( Ord (DataFrame t ('[] :: [k]))+             , Num (DataFrame t ('[] :: [k]))+             , SubSpace t '[n] '[] '[n] )+          => Vector t (n :: k) -> DataFrame t ('[] :: [k])+normLNInf x = ewfoldr (min . abs) (abs $ indexOffset 0 x) x  -- | Norm in Lp space-normLP :: ( Floating t , SubSpace t '[n] '[] '[n] )-       => Int -> Vector t n -> Scalar t+normLP :: (Floating (DataFrame t ('[] :: [k])), SubSpace t '[n] '[] '[n])+       => Int -> Vector t (n :: k) -> DataFrame t ('[] :: [k]) normLP i' = (**ri) . ewfoldr (\a -> (a**i +)) 0   where     i  = fromIntegral i'@@ -202,23 +211,15 @@  -- | Take a determinant of a matrix composed from two 2D vectors. --   Like a cross product in 2D.-det2 :: ( Num t, SubSpace t '[2] '[] '[2] )+det2 :: ( Num t, PrimBytes t )      => Vector t 2 -> Vector t 2 -> Scalar t-det2 a b = (a ! 0 :* U) * (b ! 1 :* U)-         - (a ! 1 :* U) * (b ! 0 :* U)+det2 (DF2 a0 a1) (DF2 b0 b1) = a0*b1 - b0*a1  -- | Cross product-cross :: ( Num t, SubSpace t '[3] '[] '[3] )+cross :: ( Num t, PrimBytes t )       => Vector t 3 -> Vector t 3 -> Vector t 3-cross a b = vec3 ( unScalar-                 $ (a ! 1 :* U) * (b ! 2 :* U)-                 - (a ! 2 :* U) * (b ! 1 :* U) )-                 ( unScalar-                 $ (a ! 2 :* U) * (b ! 0 :* U)-                 - (a ! 0 :* U) * (b ! 2 :* U) )-                 ( unScalar-                 $ (a ! 0 :* U) * (b ! 1 :* U)-                 - (a ! 1 :* U) * (b ! 0 :* U) )+cross (DF3 a0 a1 a2) (DF3 b0 b1 b2)+  = DF3 (a1*b2 - a2*b1) (a2*b0 - a0*b2) (a0*b1 - a1*b0)   -- | Cross product for two vectors in 3D
+ test/Numeric/Arbitraries.hs view
@@ -0,0 +1,614 @@+{-# LANGUAGE AllowAmbiguousTypes       #-}+{-# LANGUAGE CPP                       #-}+{-# LANGUAGE ConstraintKinds           #-}+{-# LANGUAGE DataKinds                 #-}+{-# LANGUAGE ExistentialQuantification #-}+{-# LANGUAGE FlexibleContexts          #-}+{-# LANGUAGE FlexibleInstances         #-}+{-# LANGUAGE FunctionalDependencies    #-}+{-# LANGUAGE GADTs                     #-}+{-# LANGUAGE MultiParamTypeClasses     #-}+{-# LANGUAGE PartialTypeSignatures     #-}+{-# LANGUAGE PolyKinds                 #-}+{-# LANGUAGE QuasiQuotes               #-}+{-# LANGUAGE RankNTypes                #-}+{-# LANGUAGE ScopedTypeVariables       #-}+{-# LANGUAGE TemplateHaskell           #-}+{-# LANGUAGE TypeApplications          #-}+{-# LANGUAGE TypeOperators             #-}+{-# LANGUAGE UndecidableInstances      #-}+{-# OPTIONS_GHC -fno-warn-orphans      #-}+-- | Provide instance of Arbitrary for all DataFrame types.+--   Also, this module is an example of fancy type inference and DataFrame+--   traversals with monadic actions.+module Numeric.Arbitraries where++import Test.QuickCheck++#if !(MIN_VERSION_base(4,13,0))+import Control.Monad.Fail+#endif+import           Data.Int+import           Data.Kind            (Type)+import           Data.List            (inits, tails)+import           Data.Semigroup       hiding (All)+import           Data.Word+import           Language.Haskell.TH  (ExpQ, Q, TypeQ)+import qualified Language.Haskell.TH  as TH+import           Numeric.DataFrame+import           Numeric.Dimensions+import           Numeric.Quaternion+import qualified Numeric.Tuple.Lazy   as LT+import qualified Numeric.Tuple.Strict as ST++-- | Maximum number of elements in SomeDims lists+maxDims :: Word+maxDims = 5++-- | Some tests are rather slow when we have too many elements+maxTotalDim :: Word+maxTotalDim = 400++-- | Maximum value of @Dim (XN _)@+maxDimSize :: Word+maxDimSize = 30++-- | Odds of using `fromScalar` constructor instead of element-by-element.+--   Interpret as "one to fromScalarChanceFactor"+fromScalarChanceFactor :: Int+fromScalarChanceFactor = 5++concatDimsQ :: TypeQ -> TypeQ -> TypeQ+concatDimsQ as bs = [t| Concat $(as) $(bs) |]++aFewPropVariants :: ExpQ -> ExpQ+aFewPropVariants = TH.listE . replicate 100++someElemTypeFQ :: Q TypeQ+someElemTypeFQ = TH.runIO . generate $ elements elemTypesF++someElemTypeIQ :: Q TypeQ+someElemTypeIQ = TH.runIO . generate $ elements elemTypesI++someElemTypeQ :: Q TypeQ+someElemTypeQ = TH.runIO . generate . elements $ elemTypesI ++ elemTypesF++elemTypesF :: [TypeQ]+elemTypesF = [ [t|Float|], [t|Double|] ]++elemTypesI :: [TypeQ]+elemTypesI =+  [ [t|Int|],  [t|Int8|],  [t|Int16|],  [t|Int32|],  [t|Int64|]+  , [t|Word|], [t|Word8|], [t|Word16|], [t|Word32|], [t|Int64|]+  ]+++-- | Generate type (n :: Nat) at compile time+someDimNQ :: Q TypeQ+someDimNQ = TH.litT . TH.numTyLit . toInteger+         <$> TH.runIO (generate (chooseDim 1))++-- | Generate type (n :: XNat) at compile time+someDimXQ :: Q TypeQ+someDimXQ = fmap pure $ do+  d <- TH.litT . TH.numTyLit . toInteger+     <$> TH.runIO (generate (chooseDim 1))+  TH.runIO (generate arbitrary) >>=+    \isXN -> if isXN then [t|XN $(d)|] else [t|N $(d)|]++-- | Generate type (N n) at compile time+someDimXfixedQ :: Q TypeQ+someDimXfixedQ = fmap pure $ do+  d <- TH.litT . TH.numTyLit . toInteger+     <$> TH.runIO (generate (chooseDim 1))+  [t| N $(d) |]++-- | Generate type (ns :: [k]) at compile time+someDimsQ :: Q TypeQ+someDimsQ = do+  isXNat <- TH.runIO (generate arbitrary)+  if isXNat then someDimsXQ+            else someDimsNQ++-- | Generate type (ns :: [Nat]) at compile time+someDimsNQ :: Q TypeQ+someDimsNQ = fmap pure $ TH.runIO (removeDims <$> generate arbitrary)+         >>= \(SomeDims ds) -> wordsToDimsNQ (listDims ds)++-- | Generate type (Map 'N (ns :: [Nat])) at compile time+someDimsXQfixed :: Q TypeQ+someDimsXQfixed = fmap pure $ TH.runIO (removeDims <$> generate arbitrary)+         >>= \(SomeDims ds) -> wordsToDimsXQfixed (listDims ds)++-- | Generate type (Map 'N (ns :: [Nat])) at compile time+someDimsXQ :: Q TypeQ+someDimsXQ = fmap pure $ TH.runIO (removeDims <$> generate arbitrary)+         >>= \(SomeDims ds) -> wordsToDimsXQ(listDims ds)++-- | Generate type (ns :: [k]) at compile time+someLenAsBsQ :: Int -> Q (TypeQ, TypeQ)+someLenAsBsQ len = do+  isXNat <- TH.runIO (generate arbitrary)+  if isXNat then someLenAsBsXQ len+            else someLenAsBsNQ len++-- | Generate type (ns :: [k]) at compile time+someAsBsQ :: Q (TypeQ, TypeQ)+someAsBsQ = do+  isXNat <- TH.runIO (generate arbitrary)+  if isXNat then someAsBsXQ+            else someAsBsNQ++-- | Generate type (ns :: [k]) at compile time+someAsBsQfixed :: Q (TypeQ, TypeQ)+someAsBsQfixed = do+  isXNat <- TH.runIO (generate arbitrary)+  if isXNat then someAsBsXQfixed+            else someAsBsNQ++-- | Generate type (as :: [Nat], bs :: [Nat]) at compile time,+--   given a fixed length of the first dims (as).+someLenAsBsNQ :: Int -> Q (TypeQ, TypeQ)+someLenAsBsNQ len = do+    (asw, bsw) <- TH.runIO (generate (genConcatDims len))+    as <- wordsToDimsNQ asw+    bs <- wordsToDimsNQ bsw+    return (pure as, pure bs)++-- | Generate type (as :: [XNat], Map 'N bs :: [XNat]) at compile time,+--   given a fixed length of the first dims (as).+someLenAsBsXQ :: Int -> Q (TypeQ, TypeQ)+someLenAsBsXQ len = do+    (asw, bsw) <- TH.runIO (generate (genConcatDims len))+    as <- wordsToDimsXQ asw+    bs <- wordsToDimsXQfixed bsw+    return (pure as, pure bs)++-- | Generate type (Map 'N as :: [XNat], Map 'N bs :: [XNat]) at compile time,+--   given a fixed length of the first dims (as).+someLenAsBsXQfixed :: Int -> Q (TypeQ, TypeQ)+someLenAsBsXQfixed len = do+    (asw, bsw) <- TH.runIO (generate (genConcatDims len))+    as <- wordsToDimsXQfixed asw+    bs <- wordsToDimsXQfixed bsw+    return (pure as, pure bs)++-- | Generate type (as :: [Nat], bs :: [Nat]) at compile time.+someAsBsNQ :: Q (TypeQ, TypeQ)+someAsBsNQ = TH.runIO (generate (choose (0, fromIntegral maxDims - 1)))+  >>= someLenAsBsNQ++-- | Generate type (as :: [XNat], Map 'N bs :: [XNat]) at compile time.+someAsBsXQ :: Q (TypeQ, TypeQ)+someAsBsXQ = TH.runIO (generate (choose (0, fromIntegral maxDims - 1)))+  >>= someLenAsBsXQ++-- | Generate type (Map 'N as :: [XNat], Map 'N bs :: [XNat]) at compile time.+someAsBsXQfixed:: Q (TypeQ, TypeQ)+someAsBsXQfixed = TH.runIO (generate (choose (0, fromIntegral maxDims - 1)))+  >>= someLenAsBsXQfixed+++wordsToDimsNQ :: [Word] -> TypeQ+wordsToDimsNQ = (\ns -> [t| ($(ns) :: [Nat]) |]) . foldr f TH.promotedNilT+  where+    f :: Word -> TypeQ -> TypeQ+    f w l = let d = TH.litT . TH.numTyLit $ toInteger w+            in  TH.promotedConsT `TH.appT` d `TH.appT` l++wordsToDimsXQfixed :: [Word] -> TypeQ+wordsToDimsXQfixed = (\ns -> [t| ($(ns) :: [XNat]) |]) . foldr f TH.promotedNilT+  where+    f :: Word -> TypeQ -> TypeQ+    f w l = let d = TH.litT . TH.numTyLit $ toInteger w+            in  TH.promotedConsT `TH.appT` [t| N $(d) |] `TH.appT` l++wordsToDimsXQ :: [Word] -> TypeQ+wordsToDimsXQ = (\ns -> [t| ($(ns) :: [XNat]) |]) . foldr f TH.promotedNilT+  where+    f :: Word -> TypeQ -> TypeQ+    f w l = let d = TH.litT . TH.numTyLit $ toInteger w+                xd = TH.runIO (generate arbitrary) >>=+                        \isXN -> if isXN then [t|XN $(d)|] else [t|N $(d)|]+            in  TH.promotedConsT `TH.appT` xd `TH.appT` l++-- | Generate two lists of Dims as Words, such that the combined list+--   is under the maxTotalDim limit, but the first list has exactly the given+--   number of dims.+genConcatDims :: Int -> Gen ([Word], [Word])+genConcatDims len+    = arbitrary >>= (\(SomeDims xs) -> checkLen (listDims xs)) . removeDims+  where+    checkLen :: [Word] -> Gen ([Word], [Word])+    checkLen xs =+      let td = product xs+          (as, bs) = splitAt len xs+          l  = length as+      in if l == len then pure (as, bs)+                     else (,) <$> addDims (len - l) (maxTotalDim `quot` td) as+                              <*> pure bs+    addDims :: Int -> Word -> [Word] -> Gen [Word]+    addDims 0 _ xs = pure xs+    addDims n lim xs = do+      x <- choose (1, max 1 (min lim maxDimSize))+      addDims (n-1) (lim `quot` x) (x : xs)+++-- | Remove dims from a dim list until its totalDim is less than maxTotalDim+removeDims :: SomeDims -> SomeDims+removeDims = removeDimsAbove maxTotalDim++-- | Remove dims from a dim list until its totalDim is less than a given value+removeDimsAbove :: Word -> SomeDims -> SomeDims+removeDimsAbove _ (SomeDims U) = SomeDims U+removeDimsAbove z (SomeDims nns@(_ :* ns))+  | totalDim nns > z = removeDimsAbove z (SomeDims ns)+  | otherwise        = SomeDims nns++-- | Reduce individual XN-dims untils its totalDim is less than maxTotalDim+reduceDims :: (All KnownDimType xns, BoundedDims xns)+           => Dims (xns :: [XNat]) -> Dims (xns :: [XNat])+reduceDims = reduceDims' 1++reduceDims' :: (All KnownDimType xns, BoundedDims xns)+            => Word -> Dims (xns :: [XNat]) -> Dims (xns :: [XNat])+reduceDims' _ U = U+reduceDims' l nns@(n :* ns)+  | totalDim nns * l <= maxTotalDim = nns+  | otherwise = case n of+      Dn d -> n :* reduceDims' (l * dimVal d) ns+      (Dx d :: Dim xn) -> case compareDim (dimBound @xn) D2 of+        SLT -> Dx D2 :* reduceDims' (l * 2) ns+        SEQ -> Dx D2 :* reduceDims' (l * 2) ns+        SGT -> n :* reduceDims' (l * dimVal d) ns++-- | Most of the time, we assume the error is proportional to the maginutude of+--   the biggest element.+maxElem :: (SubSpace t ds '[] ds, Ord t, Num t)+        => DataFrame t (ds :: [Nat]) -> Scalar t+maxElem = ewfoldr' (max . abs) 0++rotateList :: [a] -> [[a]]+rotateList xs = init (zipWith (++) (tails xs) (inits xs))++class (RealFloatExtras t, Show t) => Approx t x | x -> t where+    -- | Check if two values are approximately equal+    approxEq :: t -- ^ Extra multiplier constant+             -> x -> x -> Property++-- | Check if two values are approximately equal.+(=~=) :: Approx t x => x -> x -> Property+(=~=) = approxEq 1+infix 4 =~=++instance Approx Double Double where+    approxEq c a b = counterexample+      (unlines+        [ "  Double approxEq failed:"+        , "    values:    "   ++ show (a, b)+        , "    error:     "   ++ show err+        , "    tolerance: "   ++ show tol+        ]+      ) $ err <= tol+      where+        err = abs (a - b)+        mel = abs a `max` abs b `max` 1+        tol = M_EPS*mel*c++instance Approx Float Float where+    approxEq c a b = counterexample+      (unlines+        [ "  Double approxEq failed:"+        , "    values:    "   ++ show (a, b)+        , "    error:     "   ++ show err+        , "    tolerance: "   ++ show tol+        ]+      ) $ err <= tol+      where+        err = abs (a - b)+        mel = abs a `max` abs b `max` 1+        tol = M_EPS*mel*c++instance MonadFail Gen where fail = error++instance (Quaternion t, Arbitrary t, Num t) => Arbitrary (Quater t) where+  arbitrary = sequence+    [ Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary+    , Quater <$> arbitrary <*> pure 0 <*> pure 0 <*> pure 0+    , Quater <$> pure 0 <*> arbitrary <*> pure 0 <*> pure 0+    , Quater <$> pure 0 <*> pure 0 <*> arbitrary <*> pure 0+    , Quater <$> pure 0 <*> pure 0 <*> pure 0 <*> arbitrary+    , Quater <$> arbitrary <*> arbitrary <*> pure 0 <*> pure 0+    , Quater <$> arbitrary <*> pure 0 <*> arbitrary <*> pure 0+    , Quater <$> arbitrary <*> pure 0 <*> pure 0 <*> arbitrary+    , Quater <$> pure 0 <*> arbitrary <*> arbitrary <*> pure 0+    , Quater <$> pure 0 <*> arbitrary <*> pure 0 <*> arbitrary+    , Quater <$> pure 0 <*> pure 0 <*> arbitrary <*> arbitrary+    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> pure 0+    , Quater <$> arbitrary <*> arbitrary <*> pure 0 <*> arbitrary+    , Quater <$> arbitrary <*> pure 0 <*> arbitrary <*> arbitrary+    , Quater <$> pure 0 <*> arbitrary <*> arbitrary <*> arbitrary+    ] >>= elements++  shrink (Quater x y z t)+      -- shrink either real or the whole imaginary part+    = ($) <$> zipWith3 Quater (shrink x) (shrink y) (shrink z) <*> shrink t++instance (RealFloatExtras t, Show t, Quaternion t) => Approx t (Quater t) where+    approxEq c a b = counterexample+        (unlines+          [ "  Quaternion approxEq failed:"+          , "    max elem:  "   ++ show mel+          , "    error:     "   ++ show err+          , "    tolerance: "   ++ show tol+          ]+        ) $ err <= tol+      where+        v1 = toVec4 a+        v2 = toVec4 b+        err = unScalar $ maxElem (v1 - v2)+        mel = unScalar $ 1 `max` maxElem v1 `max` maxElem v2+        tol = M_EPS*mel*c++instance (Arbitrary t, PrimBytes t, Num t, Ord t, Dimensions ds)+      => Arbitrary (DataFrame t (ds :: [Nat])) where+    arbitrary = do+        full <- (1 < ) <$> choose (1, fromScalarChanceFactor)+        zeroChance <- choose (0, 8)+        if full -- I want to check fromScalar code path sometimes+        then arbitrary >>= elementWise @_ @ds @'[] (f zeroChance) . ewgen . scalar+        else fromScalar . scalar <$> arbitrary+      where+        f :: (Arbitrary a, Num a) => Double -> Scalar a -> Gen (Scalar a)+        f zeroChance _ = do+          dice <- (zeroChance >=) <$> choose (0, 10)+          if dice+          then return 0+          else scalar <$> arbitrary+    shrink df+        | Just (Max ma) <- ewfoldMap @t @ds @'[] @ds+            ((\x -> if x == 0 then Nothing else Just (Max x)) . abs) df+           = [ ewmap (\x -> if abs x == ma then 0 else x) df+             , ewmap (scalar . withAbs . unScalar) df+             ]+        | otherwise = []+            where+              withAbs :: t -> t+              withAbs x+                | abs x <= 1 = 0+                | otherwise  = signum x * closest2 (abs x) 1+              closest2 :: t -> t -> t+              closest2 x b = if x <= b * 2 then b else closest2 x (b*2)++instance (RealFloatExtras t, Show t, Dimensions ds)+       => Approx (DataFrame t ('[] :: [Nat])) (DataFrame t (ds :: [Nat])) where+    approxEq (S t) = approxEqDF t++instance (RealFloatExtras t, Show t)+       => Approx (DataFrame t ('[] :: [XNat])) (DataFrame t (ds :: [XNat])) where+    approxEq (XFrame (S t)) (XFrame a) (XFrame b) = case sameDims da db of+        Just Dict -> approxEqDF t a b+        Nothing -> counterexample+          (unlines+            [ "  DataFrame approxEq failed [XNat] due to different dims:"+            , "    dims a:  "   ++ show da+            , "    dims b:  "   ++ show db+            ]+          ) False+      where+        da = dims `inSpaceOf` a+        db = dims `inSpaceOf` b++approxEqDF ::+       forall t (ds :: [Nat])+     . ( Dimensions ds+       , Show t, RealFloatExtras t+       , KnownBackend t ds)+    => t -> DataFrame t ds -> DataFrame t (ds :: [Nat]) -> Property+approxEqDF c a b+  | U <- dims @ds = counterexample+      (unlines+        [ "  Scalar approxEq failed:"+        , "    values:    "   ++ show (unScalar a, unScalar b)+        , "    error:     "   ++ show err+        , "    tolerance: "   ++ show tol+        ]+      ) $ err <= tol+  | otherwise = counterexample+      (unlines+        [ "  DataFrame approxEq failed:"+        , "    max elem:  "   ++ show mel+        , "    error:     "   ++ show err+        , "    tolerance: "   ++ show tol+        ]+      ) $ err <= tol+  where+    err = unScalar $ maxElem (a - b)+    mel = unScalar $ maxElem a `max` maxElem b `max` 1+    tol = M_EPS*mel*c++instance ( All Arbitrary ts, All PrimBytes ts, All Num ts, All Ord ts+         , RepresentableList ts, Dimensions ds)+      => Arbitrary (DataFrame ts (ds :: [Nat])) where+    -- We create arbitrary MultiFrame by combining several SingleFrames.+    -- SingleFrames are "variables" or "columns" of a MultiFrame that are+    -- independent byte arrays bounded by a common dimensions type signature.+    arbitrary = -- Use RepresentableList to find out how many columns are there.+                case tList @ts of+        -- Zero columns, empty MultiFrame+        U -> return Z+        -- Cons-like construction.+        -- Note, pattern matching TypeList brings RepresentableList evidence+        -- for Tail ts.+        _ :* (TypeList :: TypeList ts') -> do+          at   <- arbitrary+          ats' <- arbitrary @(DataFrame ts' ds)+          return (at :*: ats')+    -- MultiFrame is a newtype wrapper on a TypedList.+    -- Thus, we can always recover RepresentableList ts by using function @types@+    shrink (at :*: ats@(MultiFrame ats'))+      | TypeList <- types ats'+      = (:*:) <$> shrink at <*> shrink ats+    shrink _ = []++-- | Generate a random word not smaller than the given number, and not bigger+--   than maxDimSize. Also tend to generate smaller values more often to have+--   a chance to pack more dims within maxTotalDim.+chooseDim :: Word -> Gen Word+chooseDim lowLim = f <$> choose (0, maxDimSize)+  where+    l = realToFrac lowLim :: Double+    f :: Word -> Word+    f w = let x = realToFrac w :: Double+              n = realToFrac maxDimSize :: Double+          in round $ l + max 0 (n - l) * (x / n) ** 3++instance KnownDim a => Arbitrary (Dim (N a)) where+    arbitrary = return $ Dn (dim @a)+    shrink _ = []++instance KnownDim m => Arbitrary (Dim (XN m)) where+    arbitrary = do+      dimN <- chooseDim $ dimVal' @m+      case constrainDim @(XN m) (someDimVal dimN) of+        Nothing -> error "impossible argument"+        Just d  -> return d+    shrink _ = []++instance Arbitrary SomeDims where+    arbitrary = do+      dimN <- choose (0, maxDims) :: Gen Word+      wdims <- mapM (\_ -> chooseDim 1) [1..dimN]+      return $ someDimsVal wdims+    shrink (SomeDims U)         = []+    shrink (SomeDims (_ :* ds)) = [SomeDims ds]++instance Arbitrary (Dims '[]) where+    arbitrary = return U+    shrink _ = []++instance (KnownDim n, Arbitrary (Dims xs)) => Arbitrary (Dims (N n ': xs)) where+    arbitrary = (:*) <$> arbitrary <*> arbitrary+    shrink _ = []++instance (KnownDim m, Arbitrary (Dims xs)) => Arbitrary (Dims (XN m ': xs)) where+    arbitrary = (:*) <$> arbitrary <*> arbitrary+    shrink _ = []++instance (Arbitrary t, PrimBytes t, Num t, Ord t)+      => Arbitrary (SomeDataFrame t) where+    arbitrary = do+      SomeDims (Dims :: Dims ds) <- removeDims <$> arbitrary+      SomeDataFrame <$> arbitrary @(DataFrame t ds)+    shrink (SomeDataFrame df) = SomeDataFrame <$> shrink df++-- All same as above, just change constraints a bit+instance ( All Arbitrary ts, All PrimBytes ts, All Num ts, All Ord ts+         , RepresentableList ts)+      => Arbitrary (SomeDataFrame ts) where+    arbitrary = do+      SomeDims ds <- removeDims <$> arbitrary+      case ds of+        (Dims :: Dims ds) -> case inferKnownBackend @ts @ds of+          Dict -> SomeDataFrame <$> arbitrary @(DataFrame ts ds)+    shrink (SomeDataFrame df) = SomeDataFrame <$> shrink df+++instance ( Arbitrary t, PrimBytes t, Num t, Ord t+         , Arbitrary (Dims xs), All KnownDimType xs, BoundedDims xs)+      => Arbitrary (DataFrame t (xs :: [XNat])) where+    arbitrary = do+      XDims (Dims :: Dims ds) <- reduceDims <$> arbitrary @(Dims xs)+      XFrame <$> arbitrary @(DataFrame t ds)+    shrink (XFrame df) = XFrame <$> shrink df++instance ( All Arbitrary ts, All PrimBytes ts, All Num ts, All Ord ts+         , RepresentableList ts+         , Arbitrary (Dims xs), All KnownDimType xs, BoundedDims xs)+      => Arbitrary (DataFrame ts (xs :: [XNat])) where+    arbitrary = do+      ds <- reduceDims <$> arbitrary @(Dims xs)+      case ds of+        XDims (Dims :: Dims ds) -> case inferKnownBackend @ts @ds of+          Dict -> XFrame <$> arbitrary @(DataFrame ts ds)+    shrink (XFrame df) = XFrame <$> shrink df+++instance KnownDim n => Arbitrary (Idx (n :: Nat)) where+    arbitrary = Idx <$> choose (minBound, dimVal' @n - 1)++instance KnownDim n => Arbitrary (Idx (N n)) where+    arbitrary = Idx <$> choose (minBound, dimVal' @n - 1)++instance KnownDim n => Arbitrary (Idx (XN n)) where+    arbitrary = Idx <$> choose (minBound, dimVal' @n - 1)++instance Dimensions ns => Arbitrary (Idxs (ns :: [Nat])) where+    arbitrary = go (dims @ns)+      where+        go :: forall (bs :: [Nat]) . Dims bs -> Gen (Idxs bs)+        go U         = pure U+        go (D :* bs) = (:*) <$> arbitrary <*> go bs++instance (BoundedDims ns, All KnownDimType ns) => Arbitrary (Idxs (ns :: [XNat])) where+    arbitrary = go (minimalDims @ns)+      where+        go :: forall (bs :: [XNat])+            . (BoundedDims bs, All KnownDimType bs) => Dims bs -> Gen (Idxs bs)+        go U            = pure U+        go (Dn D :* bs) = (:*) <$> arbitrary <*> go bs+        go (Dx D :* bs) = (:*) <$> arbitrary <*> go bs+++instance (RepresentableList xs, All Arbitrary xs) => Arbitrary (ST.Tuple xs) where+    arbitrary = go (tList @xs)+      where+        go :: forall (bs :: [Type])+            . All Arbitrary bs+           => TypeList bs -> Gen (ST.Tuple bs)+        go U         = pure U+        go (_ :* bs) = (ST.:$) <$> arbitrary <*> go bs++instance (RepresentableList xs, All Arbitrary xs) => Arbitrary (LT.Tuple xs) where+    arbitrary = go (tList @xs)+      where+        go :: forall (bs :: [Type])+            . All Arbitrary bs+           => TypeList bs -> Gen (LT.Tuple bs)+        go U         = pure U+        go (_ :* bs) = (LT.:$) <$> arbitrary <*> go bs++data AnyMatrix+data NonSingular++data SomeSquareMatrix prop t+  = forall (n :: Nat)+  . (KnownDim n, KnownBackend t '[n], KnownBackend t '[n, n])+  => SSM (DataFrame t '[n,n])++instance (Show t, PrimBytes t) => Show (SomeSquareMatrix prop t) where+  show (SSM df) = show df++instance (Arbitrary t, PrimBytes t, Num t, Ord t)+      => Arbitrary (SomeSquareMatrix AnyMatrix t) where+    arbitrary = do+      Dx (D :: Dim n) <- arbitrary @(Dim (XN 2))+      SSM <$> arbitrary @(DataFrame t '[n,n])+    shrink (SSM df)= SSM <$> shrink df++instance (Arbitrary t, PrimBytes t, Num t, Ord t)+      => Arbitrary (SomeSquareMatrix NonSingular t) where+    arbitrary = do+      SSM (someMat :: DataFrame t '[n, n]) <- arbitrary @(SomeSquareMatrix AnyMatrix t)+      -- https://en.wikipedia.org/wiki/Diagonally_dominant_matrix+      return . SSM $+        iwmap @t @'[n] @'[n] @'[n,n]+              @t @'[n] @'[n,n]+          ( \i v ->+            let s = ewfoldl (\a -> (a +) . abs) 1 v+            in update i s v+          ) someMat+    shrink _ = []
− test/Numeric/DataFrame/Arbitraries.hs
@@ -1,274 +0,0 @@-{-# LANGUAGE AllowAmbiguousTypes       #-}-{-# LANGUAGE ConstraintKinds           #-}-{-# LANGUAGE DataKinds                 #-}-{-# LANGUAGE ExistentialQuantification #-}-{-# LANGUAGE FlexibleContexts          #-}-{-# LANGUAGE FlexibleInstances         #-}-{-# LANGUAGE GADTs                     #-}-{-# LANGUAGE PartialTypeSignatures     #-}-{-# LANGUAGE PolyKinds                 #-}-{-# LANGUAGE RankNTypes                #-}-{-# LANGUAGE ScopedTypeVariables       #-}-{-# LANGUAGE TypeApplications          #-}-{-# LANGUAGE TypeOperators             #-}-{-# LANGUAGE UndecidableInstances      #-}-{-# OPTIONS_GHC -fno-warn-orphans  #-}--- | Provide instance of Arbitrary for all DataFrame types.---   Also, this module is an example of fancy type inference and DataFrame---   traversals with monadic actions.-module Numeric.DataFrame.Arbitraries where--import Test.QuickCheck--import           Data.Kind            (Type)-import           Data.Semigroup       hiding (All)-import           Numeric.DataFrame-import           Numeric.Dimensions-import           Numeric.Quaternion-import qualified Numeric.Tuple.Lazy   as LT-import qualified Numeric.Tuple.Strict as ST---maxDims :: Word-maxDims = 5--maxDimSize :: Word-maxDimSize = 7--fromScalarChanceFactor :: Int-fromScalarChanceFactor = 5---instance (Quaternion t, Arbitrary t, Num t) => Arbitrary (Quater t) where-  arbitrary = sequence-    [ Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary-    , Quater <$> arbitrary <*> pure 0 <*> pure 0 <*> pure 0-    , Quater <$> pure 0 <*> arbitrary <*> pure 0 <*> pure 0-    , Quater <$> pure 0 <*> pure 0 <*> arbitrary <*> pure 0-    , Quater <$> pure 0 <*> pure 0 <*> pure 0 <*> arbitrary-    , Quater <$> arbitrary <*> arbitrary <*> pure 0 <*> pure 0-    , Quater <$> arbitrary <*> pure 0 <*> arbitrary <*> pure 0-    , Quater <$> arbitrary <*> pure 0 <*> pure 0 <*> arbitrary-    , Quater <$> pure 0 <*> arbitrary <*> arbitrary <*> pure 0-    , Quater <$> pure 0 <*> arbitrary <*> pure 0 <*> arbitrary-    , Quater <$> pure 0 <*> pure 0 <*> arbitrary <*> arbitrary-    , Quater <$> arbitrary <*> arbitrary <*> arbitrary <*> pure 0-    , Quater <$> arbitrary <*> arbitrary <*> pure 0 <*> arbitrary-    , Quater <$> arbitrary <*> pure 0 <*> arbitrary <*> arbitrary-    , Quater <$> pure 0 <*> arbitrary <*> arbitrary <*> arbitrary-    ] >>= elements--  shrink (Quater x y z t)-      -- shrink either real or the whole imaginary part-    = ($) <$> zipWith3 Quater (shrink x) (shrink y) (shrink z) <*> shrink t----instance (Arbitrary t, PrimBytes t, Num t, Ord t, Dimensions ds)-      => Arbitrary (DataFrame t (ds :: [Nat])) where-    arbitrary-        | -- First, we need to find out exact array implementation to use-          -- inside this DataFrame.-          -- We need to do that whenever exact value of ds is not known-          Dict <- inferKnownBackend @t @ds-          -- After that, GHC can infer all necessary fancy things like SubSpace-          -- to do complex operations on sub-dimensions of a DataFrame.-          ---          -- Note, we could put SubSpace into constraints of this instance as well.-          -- That would render the above lines unnecessary, but would make-          -- inference more difficult later.-        = do-        full <- (1 < ) <$> choose (1, fromScalarChanceFactor)-        if full -- I want to check fromScalar code path sometimes-        then arbitrary >>= elementWise @_ @ds @'[] f . ewgen . scalar-        else fromScalar . scalar <$> arbitrary-      where-        f :: Arbitrary a => Scalar a -> Gen (Scalar a)-        f _ = scalar <$> arbitrary-    shrink df-        | Dict <- inferKnownBackend @t @ds-        , mma <- ewfoldMap @t @ds @'[] @ds-            ((\x -> if x == 0 then Nothing else Just (Max x)) . abs) df-        = case mma of-            Nothing-              -> [] -- all-zero is the most primitive DF possible-            Just (Max ma)-             -> [ ewmap (\x -> if abs x == ma then 0 else x) df-                , ewmap (scalar . withAbs . unScalar) df-                ]-            where-              withAbs :: t -> t-              withAbs x-                | abs x <= 1 = 0-                | otherwise  = signum x * closest2 (abs x) 1-              closest2 :: t -> t -> t-              closest2 x b = if x <= b * 2 then b else closest2 x (b*2)--instance ( All Arbitrary ts, All PrimBytes ts, All Num ts, All Ord ts-         , RepresentableList ts, Dimensions ds)-      => Arbitrary (DataFrame ts (ds :: [Nat])) where-    -- We create arbitrary MultiFrame by combining several SingleFrames.-    -- SingleFrames are "variables" or "columns" of a MultiFrame that are-    -- independent byte arrays bounded by a common dimensions type signature.-    arbitrary = -- Use RepresentableList to find out how many columns are there.-                case tList @_ @ts of-        -- Zero columns, empty MultiFrame-        U -> return Z-        -- Cons-like construction.-        -- Note, pattern matching TypeList brings RepresentableList evidence-        -- for Tail ts.-        _ :* (TypeList :: TypeList ts') -> do-          at   <- arbitrary-          ats' <- arbitrary @(DataFrame ts' ds)-          return (at :*: ats')-    -- MultiFrame is a newtype wrapper on a TypedList.-    -- Thus, we can always recover RepresentableList ts by using function @types@-    shrink (at :*: ats@(MultiFrame ats'))-      | TypeList <- types ats'-      = (:*:) <$> shrink at <*> shrink ats-    shrink _ = []---instance KnownDim a => Arbitrary (Dim (N a)) where-    arbitrary = return $ Dn (dim @a)-    shrink _ = []--instance KnownDim m => Arbitrary (Dim (XN m)) where-    arbitrary = do-      dimN <- choose (dimVal' @m, maxDims)-      case constrainDim @XNat @(XN m) (someDimVal dimN) of-        Nothing -> error "impossible argument"-        Just d  -> return d-    shrink _ = []--instance Arbitrary SomeDims where-    arbitrary = do-      dimN <- choose (0, maxDims) :: Gen Word-      wdims <- mapM (\_ -> choose (2, maxDimSize) :: Gen Word) [1..dimN]-      return $ someDimsVal wdims-    shrink (SomeDims U)         = []-    shrink (SomeDims (_ :* ds)) = [SomeDims ds]--instance Arbitrary (Dims '[]) where-    arbitrary = return U-    shrink _ = []--instance (KnownDim n, Arbitrary (Dims xs)) => Arbitrary (Dims (N n ': xs)) where-    arbitrary = (:*) <$> arbitrary <*> arbitrary-    shrink _ = []--instance (KnownDim m, Arbitrary (Dims xs)) => Arbitrary (Dims (XN m ': xs)) where-    arbitrary = (:*) <$> arbitrary <*> arbitrary-    shrink _ = []--instance (Arbitrary t, PrimBytes t, Num t, Ord t)-      => Arbitrary (SomeDataFrame t) where-    arbitrary = do-      -- Generate random dimension list-      SomeDims ds <- arbitrary-      --  and pattern-match against it with Dims pattern.-      --  This gives Dimensions ds evidence immediately.-      case ds of-        -- We also need to figure out an array implementation...-        (Dims :: Dims ds) -> case inferKnownBackend @t @ds of-          -- ... and generating a random DataFrame becomes a one-liner-          Dict -> SomeDataFrame <$> arbitrary @(DataFrame t ds)-    shrink (SomeDataFrame df) = SomeDataFrame <$> shrink df---- All same as above, just change constraints a bit-instance ( All Arbitrary ts, All PrimBytes ts, All Num ts, All Ord ts-         , RepresentableList ts)-      => Arbitrary (SomeDataFrame ts) where-    arbitrary = do-      SomeDims ds <- arbitrary-      case ds of-        (Dims :: Dims ds) -> case inferKnownBackend @ts @ds of-          Dict -> SomeDataFrame <$> arbitrary @(DataFrame ts ds)-    shrink (SomeDataFrame df) = SomeDataFrame <$> shrink df--instance ( Arbitrary t, PrimBytes t, Num t, Ord t-         , Arbitrary (Dims xs), All KnownXNatType xs)-      => Arbitrary (DataFrame t (xs :: [XNat])) where-    arbitrary = do-      ds <- arbitrary @(Dims xs)-      case ds of-        XDims (_ :: Dims ds) -> case inferKnownBackend @t @ds of-          Dict -> XFrame <$> arbitrary @(DataFrame t ds)-    shrink (XFrame df) = XFrame <$> shrink df--instance ( All Arbitrary ts, All PrimBytes ts, All Num ts, All Ord ts-         , RepresentableList ts-         , Arbitrary (Dims xs), All KnownXNatType xs)-      => Arbitrary (DataFrame ts (xs :: [XNat])) where-    arbitrary = do-      ds <- arbitrary @(Dims xs)-      case ds of-        XDims (_ :: Dims ds) -> case inferKnownBackend @ts @ds of-          Dict -> XFrame <$> arbitrary @(DataFrame ts ds)-    shrink (XFrame df) = XFrame <$> shrink df---instance KnownDim n => Arbitrary (Idx n) where-    arbitrary = elements [0..]--instance Dimensions ns => Arbitrary (Idxs ns) where-    arbitrary = go (Dims @ns)-      where-        go :: forall (bs :: [Nat]) . Dims bs -> Gen (Idxs bs)-        go U         = pure U-        go (D :* bs) = (:*) <$> arbitrary <*> go bs--instance (RepresentableList xs, All Arbitrary xs) => Arbitrary (ST.Tuple xs) where-    arbitrary = go (tList @Type @xs)-      where-        go :: forall (bs :: [Type])-            . All Arbitrary bs-           => TypeList bs -> Gen (ST.Tuple bs)-        go U         = pure U-        go (_ :* bs) = (ST.:$) <$> arbitrary <*> go bs--instance (RepresentableList xs, All Arbitrary xs) => Arbitrary (LT.Tuple xs) where-    arbitrary = go (tList @Type @xs)-      where-        go :: forall (bs :: [Type])-            . All Arbitrary bs-           => TypeList bs -> Gen (LT.Tuple bs)-        go U         = pure U-        go (_ :* bs) = (LT.:$) <$> arbitrary <*> go bs--data AnyMatrix-data NonSingular--data SomeSquareMatrix prop t-  = forall (n :: Nat)-  . (KnownDim n, KnownBackend t '[n], KnownBackend t '[n, n])-  => SSM (DataFrame t '[n,n])--instance (Show t, PrimBytes t) => Show (SomeSquareMatrix prop t) where-  show (SSM df) = show df--instance (Arbitrary t, PrimBytes t, Num t, Ord t)-      => Arbitrary (SomeSquareMatrix AnyMatrix t) where-    arbitrary = do-      dx <- arbitrary @(Dim (XN 2))-      case dx of-        Dx (D :: Dim n) -> case inferKnownBackend @t @'[n] of-          Dict -> SSM <$> arbitrary @(DataFrame t '[n,n])-    shrink (SSM df)= SSM <$> shrink df--instance (Arbitrary t, PrimBytes t, Num t, Ord t)-      => Arbitrary (SomeSquareMatrix NonSingular t) where-    arbitrary = do-      SSM (someMat :: DataFrame t '[n, n]) <- arbitrary @(SomeSquareMatrix AnyMatrix t)-      -- https://en.wikipedia.org/wiki/Diagonally_dominant_matrix-      return . SSM $-        iwmap @t @'[n] @'[n] @'[n,n]-              @t @'[n] @'[n,n]-          ( \i v ->-            let s = ewfoldl (\a -> (a +) . abs) 1 v-            in update i s v-          ) someMat-    shrink _ = []
test/Numeric/DataFrame/BasicTest.hs view
@@ -21,12 +21,11 @@ {-# LANGUAGE TypeApplications     #-} {-# LANGUAGE TypeOperators        #-} {-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-overlapping-patterns #-}  module Numeric.DataFrame.BasicTest (runTests) where +import           Numeric.Arbitraries              () import           Numeric.DataFrame-import           Numeric.DataFrame.Arbitraries    () import qualified Numeric.ProductOrd.NonTransitive as NonTransitive import qualified Numeric.ProductOrd.Partial       as Partial import           Test.QuickCheck
test/Numeric/DataFrame/SubSpaceTest.hs view
@@ -1,55 +1,134 @@ {-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-} {-# LANGUAGE GADTs               #-} {-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE QuasiQuotes         #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell     #-} {-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeFamilies        #-} {-# LANGUAGE TypeOperators       #-}+-- overwise GHC dies trying to optimize 100 equal funs in each test+{-# OPTIONS_GHC -O0       #-}  module Numeric.DataFrame.SubSpaceTest (runTests) where +import Data.Typeable       (typeOf)+import Numeric.Arbitraries import Numeric.DataFrame-import Numeric.DataFrame.Arbitraries () import Numeric.Dimensions import Test.QuickCheck -type SFull = '[2,5,4,3,7]-type SPref = '[2,5,4]-type SSuff = '[3,7]+prop_IndexFrame0 :: Property+prop_IndexFrame0 = property $ oneof $( aFewPropVariants $ do+    t <- someElemTypeQ+    (_, ds) <- someLenAsBsQ 0+    [e| do+      df <- arbitrary @(DataFrame $t $ds)+      return $ conjoin+            [ index U df === df+            , indexOffset 0 df === df ]+      |]+  ) -prop_IndexDimMax :: DataFrame Int SPref -> DataFrame Int SSuff -> Bool-prop_IndexDimMax x y =-   (z ! (maxBound `inSpaceOf` x)) == y-  where-    z = ewgen y :: DataFrame Int SFull+prop_IndexFrame1 :: Property+prop_IndexFrame1 = property $ oneof $( aFewPropVariants $ do+    t <- someElemTypeQ+    (as, bs) <- someLenAsBsQ 1+    [e| do+      i@(Idx ii :* U) <- arbitrary @(Idxs $as)+      df <- arbitrary @(DataFrame $t $(concatDimsQ as bs))+      return $ index i df === df ! ii+      |]+  ) -prop_IndexCustom1 :: DataFrame Word SSuff -> Bool-prop_IndexCustom1 x = (z ! 1:*3:*2) == x-  where-    z = ewgen x :: DataFrame Word SFull+prop_IndexFrame2 :: Property+prop_IndexFrame2 = property $ oneof $( aFewPropVariants $ do+    t <- someElemTypeQ+    (as, bs) <- someLenAsBsQ 2+    [e| do+      i@((Idx ii1) :* (Idx ii2) :* U) <- arbitrary @(Idxs $as)+      df <- arbitrary @(DataFrame $t $(concatDimsQ as bs))+      return $ index i df === df ! ii1 ! ii2+      |]+  ) --- TODO:!--- prop_IndexCustom2 :: DataFrame Double SSuff -> Bool--- prop_IndexCustom2 x = (z ! 2:*2:*1) %* eye == x---   where---     z = ewgen x :: DataFrame Double SFull+prop_IndexOffset :: Property+prop_IndexOffset = property $ oneof $( aFewPropVariants $ do+    t <- someElemTypeQ+    (as, bs) <- someAsBsNQ+    [e| do+      i <- arbitrary @(Idxs $as)+      df <- arbitrary @(DataFrame $t $(concatDimsQ as bs))+      let asw = listDims (dims @($as))+          bsN = totalDim (dims @($bs))+          isw = listIdxs i+          off = fromIntegral . snd+              . foldr (\(dn, di) (tn, to) -> (tn*dn, to + tn*di) ) (bsN, 0)+              $ zip asw isw+      return $ index i df === indexOffset off df+      |]+  ) -prop_Foldlr :: DataFrame Double SSuff -> Bool-prop_Foldlr x =-    abs (ewfoldl (+) 10 z - ewfoldr @_ @SPref (+) 0 z - 10)-      <= fromScalar (zmax * 0.0001)-  where-    z = ewgen x :: DataFrame Double SFull-    zmax = ewfoldl @Double @SFull @'[] (max . abs) 0.001 z+prop_Foldlr :: Property+prop_Foldlr = property $ oneof $( aFewPropVariants $ do+    t <- someElemTypeFQ+    (as, bs) <- someAsBsQ+    let asbs = concatDimsQ as bs+    [e| do+      df <- arbitrary @(DataFrame $t $asbs)+      let lim = ewfoldr' @($t) @($asbs) (max.abs) 1 df+              * ewfoldr' @($t) @($as) @($bs) (const (+1)) 0 df+          l = ewfoldl' (+) 10 df+          r = ewfoldr' (+) 0 df + 10 :: DataFrame $t $bs+      return $ approxEq lim l r+      |]+  ) -prop_Ewmap :: DataFrame Double SFull -> Bool-prop_Ewmap x = x * 2 == ewmap @_  @_ @'[Last SFull] (*2) x+prop_LazyFoldlr :: Property+prop_LazyFoldlr = property $ oneof $( aFewPropVariants $ do+    t <- someElemTypeQ+    (as, bs) <- someAsBsQ+    let asbs = concatDimsQ as bs+    [e| do+      n <- fromIntegral <$> choose (0, maxTotalDim `quot` 2)+      df <- arbitrary @(DataFrame $t $asbs)+      let S td = ewfoldr' @($t) @($as) @($bs) (const (+1)) 0 df+          l  = ewfoldl  @($t) @($as) @($bs) (limitedList) (const []) df n+          l' = ewfoldl' @($t) @($as) @($bs) (flip (:)) [] df+          r  = ewfoldr  @($t) @($as) @($bs) (flip limitedList) (const []) df n+          r' = ewfoldr' @($t) @($as) @($bs) (:) [] df -prop_ProdTranspose :: DataFrame Double '[2,6] -> DataFrame Double '[6,7] -> Bool-prop_ProdTranspose x y = transpose (x %* y) == transpose y %* transpose x+      return $+        counterexample+        ( unlines+         [ "Failed with dims:"+         , "  n:   " ++ show n+         , "  td:  " ++ show td+         , "  @as: " ++ show (typeOf $ minimalDims @($as))+         , "  @bs: " ++ show (typeOf $ minimalDims @($bs))+         ]+        ) $ conjoin+          [ if n >= td+            then l === reverse r+            else shouldErr (l === l') .&&. shouldErr (r === r')+          , take n l === take n l'+          , take n r === take n r'+          ]+      |]+  ) where+      shouldErr :: Property -> Property+      shouldErr p = ioProperty $ checkErr+        <$> quickCheckWithResult stdArgs { chatty = False }  p+      checkErr :: Result -> Property+      checkErr Failure { theException = Just _}+        = property True+      checkErr _+        = counterexample "Should have failed with undefined." False+      limitedList :: (Int -> [a]) -> a -> Int -> [a]+      limitedList f a k | k <= 0    = undefined+                        | otherwise = a : f (k - 1) -prop_Eye :: DataFrame Double SFull -> Bool-prop_Eye x = eye %* x == x && x %* eye == x  return [] runTests :: Int -> IO Bool
+ test/Numeric/Matrix/BidiagonalTest.hs view
@@ -0,0 +1,144 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-}++module Numeric.Matrix.BidiagonalTest (runTests) where+++import Control.Monad             (join)+import Data.Kind+import Data.Monoid               (All (..))+import Numeric.Arbitraries+import Numeric.DataFrame+import Numeric.Dimensions+import Numeric.Matrix.Bidiagonal+import Test.QuickCheck++validateBidiagonal :: forall (t :: Type) (n :: Nat) (m :: Nat)+             . ( KnownDim n, KnownDim m+               , RealFloatExtras t, Show t+               , MatrixDeterminant t n+               , MatrixDeterminant t m+               )+            => Matrix t n m -> BiDiag t n m -> Property+validateBidiagonal a BiDiag {..} =+    counterexample+      (unlines+        [ "failed a =~= u %* b %* transpose v:"+        , "a:  " ++ show a+        , "a': " ++ show a'+        , "u:  "   ++ show u+        , "b:  "   ++ show b+        , "v:  "   ++ show v+        ]+      ) (approxEq mag a a')+    .&&.+    counterexample+      (unlines+        [ "u is not quite orthogonal:"+        , "a: "   ++ show a+        , "u: "   ++ show u+        , "b: "   ++ show b+        , "v: "   ++ show v+        ]+      ) (approxEq mag eye (u %* transpose u))+    .&&.+    counterexample+      (unlines+        [ "v is not quite orthogonal:"+        , "a: "  ++ show a+        , "u: "  ++ show u+        , "b: "  ++ show b+        , "v: "  ++ show v+        ]+      ) (approxEq mag eye (v %* transpose v))+    .&&.+    counterexample+      (unlines+        [ "b is not upper-bidiagonal"+        , "a: " ++ show a+        , "u: " ++ show u+        , "b: " ++ show b+        , "v: " ++ show v+        ]+      ) (getAll $ iwfoldMap @t @'[n,m]+            (\(Idx i :* Idx j :* U) x -> All (j == i || j == i + 1 || x == 0))+            b+        )+    .&&.+    counterexample+      (unlines+        [ "Incorrect determinant carried out for U"+        , "a: " ++ show a+        , "u: " ++ show u+        , "bdUDet: " ++ show bdUDet+        , "det u:  " ++ show (det u)+        ]+      ) (approxEq mag bdUDet (det u))+    .&&.+    counterexample+      (unlines+        [ "Incorrect determinant carried out for V"+        , "a: " ++ show a+        , "v: " ++ show v+        , "bdVDet: " ++ show bdVDet+        , "det v:  " ++ show (det v)+        ]+      ) (approxEq mag bdVDet (det v))+  where+    mag = fromIntegral (totalDim $ dims `inSpaceOf` a) ^ (2 :: Int) :: Scalar t+    a'  = u %* b %* transpose v+    b = biDiag dims bdAlpha bdBeta+    u = bdU+    v = bdV++prop_bidiagonalSimple :: Property+prop_bidiagonalSimple = once . conjoin $ map prop_bidiagonal $ xs+  where+    mkM :: Dims ([n,m]) -> [Double] -> DataFrame Double '[XN 1, XN 1]+    mkM ds+      | Just (XDims ds'@Dims) <- constrainDims ds :: Maybe (Dims '[XN 1, XN 1])+        = XFrame . fromFlatList ds' 0+    mkM _ = error "prop_qrSimple: bad dims"+    variants :: Num a => [a] -> [[a]]+    variants as = rotateList as ++ rotateList (map negate as)+    xs :: [DataFrame Double '[XN 1, XN 1]]+    xs = join+      [ [mkM $ D2 :* D2 :* U, mkM $ D5 :* D2 :* U, mkM $ D3 :* D7 :* U]+            <*> [repeat 0, repeat 1, repeat 2]+      , mkM (D2 :* D2 :* U) <$> variants [3,2, 4,1]+      , mkM (D3 :* D3 :* U) <$> variants [0,0,1, 3,2,0, 4,1,0]+      , mkM (D4 :* D2 :* U) <$> variants [3,2, 4,1, 0,0, 0,2]+      , mkM (D2 :* D3 :* U) <$> variants [3,2,0, 4,1,2]+      , mkM (D2 :* D2 :* U) <$> variants [2, 0, 0, 0]+      , mkM (D2 :* D2 :* U) <$> variants [4, 1, 0, 0]+      , mkM (D2 :* D2 :* U) <$> variants [3, 1, -2, 0]+      , [mkM $ D2 :* D3 :* U, mkM $ D3 :* D2 :* U]+            <*> join+                [ variants [2, 0, 0, 0, 0, 0]+                , variants [4, 1, 0, 0, 0, 0]+                , variants [3, 1, -2, 0, 0, 0]+                , variants [3, 0, -2, 9, 0, 0]+                ]+      ]++prop_bidiagonal :: DataFrame Double '[XN 1, XN 1] -> Property+prop_bidiagonal (XFrame x)+  | n@D :* m@D :* U <- dims `inSpaceOf` x+  , D <- minDim n m+    = validateBidiagonal x (bidiagonalHouseholder x)+prop_bidiagonal _ = property False+++++return []+runTests :: Int -> IO Bool+runTests n = $forAllProperties+  $ quickCheckWithResult stdArgs { maxSuccess = n }
+ test/Numeric/Matrix/LUTest.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-}++module Numeric.Matrix.LUTest (runTests) where+++import Control.Monad       (join)+import Data.Kind+import Data.Monoid         (All (..))+import Numeric.Arbitraries+import Numeric.DataFrame+import Numeric.Dimensions+import Numeric.Matrix.LU+import Test.QuickCheck+++validateLU :: forall (t :: Type) (n :: Nat)+             . ( KnownDim n, RealFloatExtras t, Show t+               , MatrixDeterminant t n)+            => Matrix t n n -> LU t n -> Property+validateLU x lux@LU {..} =+    counterexample+      (unlines+        [ "failed luPerm m =~= luLower %* luUpper:"+        , "x:   " ++ show x+        , "px:  " ++ show px+        , "px': " ++ show px'+        , "lu:  " ++ show lux+        ]+      ) (px =~= px')+    .&&.+    counterexample+      (unlines+        [ "Failed an extra invariant det luPerm == luPermDet:"+        , "lu:" ++ show lux+        ]+      ) (luPermDet =~= det luPerm)+    .&&.+    counterexample+      (unlines+        [ "luUpper is not upper-triangular"+        , "lu:" ++ show lux+        , "x:"  ++ show x+        ]+      ) (getAll $ iwfoldMap @t @'[n,n]+            (\(Idx i :* Idx j :* U) a -> All (j >= i || a == 0))+            luUpper+        )+    .&&.+    counterexample+      (unlines+        [ "luLower is not unit lower triangular,"+            ++ " or some of its elements are greater than one"+        , "lu:" ++ show lux+        , "x:"  ++ show x+        ]+      ) (getAll $ iwfoldMap @t @'[n,n]+            (\(Idx i :* Idx j :* U) a -> case compare i j of+                GT -> All (abs a <= 1)+                EQ -> All (a == 1)+                LT -> All (a == 0)+            ) luLower+        )+  where+    px  = luPerm %* x+    px' = luLower %* luUpper+++manualMats :: forall t . (PrimBytes t, Num t) => [SomeSquareMatrix AnyMatrix t]+manualMats = join+      [ [mkM D2, mkM D4, mkM D9]+            <*> [repeat 0, repeat 1, repeat 2]+      , mkM D2 <$> variants [3,2, 4,1]+      , mkM D3 <$> variants [0,0,1, 3,2,0, 4,1,0]+      , mkM D2 <$> variants [2, 0, 0, 0]+      , mkM D2 <$> variants [4, 1, 0, 0]+      , mkM D2 <$> variants [3, 1, -2, 0]+      ]+  where+    mkM :: Dim (n :: Nat) -> [t] -> SomeSquareMatrix AnyMatrix t+    mkM (d@D :: Dim n) = SSM . fromFlatList (d :* d :* U) 0+    mkM _              = error "manualMats: bad dims"+    variants :: Num a => [a] -> [[a]]+    variants as = rotateList as ++ rotateList (map negate as)+++prop_luSimple :: Property+prop_luSimple = once . conjoin $ map prop_lu manualMats++prop_lu :: SomeSquareMatrix AnyMatrix Double -> Property+prop_lu (SSM x) = validateLU x (lu x)+++return []+runTests :: Int -> IO Bool+runTests n = $forAllProperties+  $ quickCheckWithResult stdArgs { maxSuccess = n }
+ test/Numeric/Matrix/QRTest.hs view
@@ -0,0 +1,203 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-}++module Numeric.Matrix.QRTest (runTests) where+++import Control.Monad       (join)+import Data.Kind+import Data.Monoid         (All (..))+import Numeric.Arbitraries+import Numeric.DataFrame+import Numeric.Dimensions+import Numeric.Matrix.QR+import Test.QuickCheck+++validateQR :: forall (t :: Type) (n :: Nat) (m :: Nat)+             . ( KnownDim n, KnownDim m+               , RealFloatExtras t, Show t+               )+            => Matrix t n m -> QR t n m -> Property+validateQR x q@QR {..} =+    counterexample+      (unlines+        [ "failed m =~= qrQ %* qrR:"+        , "m:  " ++ show x+        , "m': " ++ show x'+        , "qr:" ++ show q+        ]+      ) (x =~= x')+    .&&.+    counterexample+      (unlines+        [ "qrQ is not quite orthogonal:"+        , "qr:" ++ show q+        , "m:"  ++ show x+        ]+      ) (eye =~= qrQ %* transpose qrQ)+    .&&.+    counterexample+      (unlines+        [ "qrR is not upper-triangular"+        , "qr:" ++ show q+        , "m:"   ++ show x+        ]+      ) (getAll $ iwfoldMap @t @'[n,m]+            (\(Idx i :* Idx j :* U) a -> All (j >= i || a <= tol))+            qrR+        )+  where+    tol = M_EPS * max 1 (maxElem x)+    x'  = qrQ %* qrR++validateLQ :: forall (t :: Type) (n :: Nat) (m :: Nat)+             . ( KnownDim n, KnownDim m+               , RealFloatExtras t, Show t+               )+            => Matrix t n m -> LQ t n m -> Property+validateLQ x q@LQ {..} =+    counterexample+      (unlines+        [ "failed m =~= lqL %* lqQ:"+        , "m:  " ++ show x+        , "m': " ++ show x'+        , "lq:"  ++ show q+        ]+      ) (x =~= x')+    .&&.+    counterexample+      (unlines+        [ "lqQ is not quite orthogonal:"+        , "lq:" ++ show q+        , "m:"  ++ show x+        ]+      ) (eye =~= lqQ %* transpose lqQ)+    .&&.+    counterexample+      (unlines+        [ "lqL is not lower-triangular"+        , "lq:" ++ show q+        , "m:"  ++ show x+        ]+      ) (getAll $ iwfoldMap @t @'[n,m]+            (\(Idx i :* Idx j :* U) a -> All (j <= i || a <= tol))+            lqL+        )+  where+    tol = M_EPS * max 1 (maxElem x)+    x'  = lqL %* lqQ++manualMats :: [DataFrame Double '[XN 1, XN 1]]+manualMats = join+      [ [mkM $ D2 :* D2 :* U, mkM $ D5 :* D2 :* U, mkM $ D3 :* D7 :* U]+            <*> [repeat 0, repeat 1, repeat 2]+      , mkM (D2 :* D2 :* U) <$> variants [3,2, 4,1]+      , mkM (D3 :* D3 :* U) <$> variants [0,0,1, 3,2,0, 4,1,0]+      , mkM (D4 :* D2 :* U) <$> variants [3,2, 4,1, 0,0, 0,2]+      , mkM (D2 :* D3 :* U) <$> variants [3,2,0, 4,1,2]+      , mkM (D2 :* D2 :* U) <$> variants [2, 0, 0, 0]+      , mkM (D2 :* D2 :* U) <$> variants [4, 1, 0, 0]+      , mkM (D2 :* D2 :* U) <$> variants [3, 1, -2, 0]+      , [mkM $ D2 :* D3 :* U, mkM $ D3 :* D2 :* U]+            <*> join+                [ variants [2, 0, 0, 0, 0, 0]+                , variants [4, 1, 0, 0, 0, 0]+                , variants [3, 1, -2, 0, 0, 0]+                , variants [3, 0, -2, 9, 0, 0]+                ]+      ]+  where+    mkM :: Dims ([n,m]) -> [Double] -> DataFrame Double '[XN 1, XN 1]+    mkM ds+      | Just (XDims ds'@Dims) <- constrainDims ds :: Maybe (Dims '[XN 1, XN 1])+        = XFrame . fromFlatList ds' 0+    mkM _ = error "prop_qrSimple: bad dims"+    variants :: Num a => [a] -> [[a]]+    variants as = rotateList as ++ rotateList (map negate as)++prop_lqSimple :: Property+prop_lqSimple = once . conjoin $ map prop_lq manualMats++prop_lq :: DataFrame Double '[XN 1, XN 1] -> Property+prop_lq (XFrame x)+  | n@D :* m@D :* U <- dims `inSpaceOf` x+  , D <- minDim n m+    = validateLQ x (lq x)+prop_lq _ = property False++prop_qrSimple :: Property+prop_qrSimple = once . conjoin $ map prop_qr manualMats++prop_qr :: DataFrame Double '[XN 1, XN 1] -> Property+prop_qr (XFrame x)+  | n@D :* m@D :* U <- dims `inSpaceOf` x+  , D <- minDim n m+    = validateQR x (qr x)+prop_qr _ = property False+++testQRSolve :: forall t n m+             . (MatrixQR t n m, Show t, RealFloatExtras t)+            => Matrix t n m -> Vector t n -> Property+testQRSolve a b =+    counterexample+      (unlines+        [ "failed a' %* (a  %* xr - b) =~= 0"+        , "a:  " ++ show a+        , "b:  " ++ show b+        , "xr: " ++ show xr+        , "zeroR: " ++ show zeroR+        , "zeroL: " ++ show zeroL+        ]+      ) (nonDeficient ==> approxEq mag2 zeroR 0)+    .&&.+    counterexample+      (unlines+        [ "failed (xl %* a' - b) %* a =~= 0"+        , "a': " ++ show a'+        , "b:  " ++ show b+        , "xl: " ++ show xl+        ]+      ) (nonDeficient ==> approxEq mag2 zeroL 0)+    .&&.+    counterexample+      (unlines+        [ "failed xr =~= xl"+        , "a': " ++ show a'+        , "b:  " ++ show b+        , "xl: " ++ show xl+        ]+      ) (approxEq mag xr xl)+  where+    qrr = qrR (qr a)+    nonDeficient =+      foldl (\r i -> r && abs (qrr ! i ! i) > M_EPS * mag) True+        [0 .. min (dimVal' @n) (dimVal' @m) - 1]+    nm = totalDim (dims `inSpaceOf` a)+    mag = max 1 (maxElem a `max` maxElem b) * fromIntegral nm+    mag2 = mag*mag+    a' = transpose a+    xr = qrSolveR a  b+    xl = qrSolveL a' b+    zeroR = a' %* (a  %* xr - b)+    zeroL = (xl %* a' - b) %* a+++prop_qrSolve :: Dim (XN 1) -> Dim (XN 1) -> Property+prop_qrSolve (Dx (D :: Dim n)) (Dx (D :: Dim m)) = property $ do+  a <- arbitrary @(DataFrame Double '[n,m])+  b <- arbitrary @(DataFrame Double '[n])+  return $ testQRSolve a b++return []+runTests :: Int -> IO Bool+runTests n = $forAllProperties+  $ quickCheckWithResult stdArgs { maxSuccess = n }
+ test/Numeric/Matrix/SVDTest.hs view
@@ -0,0 +1,182 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-}++module Numeric.Matrix.SVDTest (runTests) where+++import Control.Monad+import Data.Kind+import Data.Maybe          (isJust)+import Numeric.Arbitraries+import Numeric.DataFrame+import Numeric.Dimensions+import Numeric.Matrix.SVD+import Test.QuickCheck++-- check invariants of SVD+validateSVD :: forall (t :: Type) (n :: Nat) (m :: Nat)+             . ( KnownDim n, KnownDim m, KnownDim (Min n m)+               , RealFloatExtras t, Show t+               , MatrixDeterminant t n+               )+            => t -> Matrix t n m -> SVD t n m -> Property+validateSVD extraTolerance x s@SVD {..}+  | nm <- fromIntegral $ dimVal' @n * dimVal' @m =+    counterexample+      (unlines+        [ "failed m =~= u %* asDiag s %* transpose v:"+        , "m:  " ++ show x+        , "m': " ++ show x'+        , "svd:" ++ show s+        ]+      ) (approxEq (S $ nm * nm * extraTolerance) x x')+    .&&.+    counterexample+      (unlines+        [ "SVD left-singular basis is not quite orthogonal:"+        , "svd:" ++ show s+        , "m:"   ++ show x+        ]+      ) (eye =~= svdU %* transpose svdU)+    .&&.+    counterexample+      (unlines+        [ "Failed an extra invariant det svdU == 1:"+        , "svd:" ++ show s+        , "m:"   ++ show x+        ]+      ) (1 =~= det svdU)+    .&&.+    counterexample+      (unlines+        [ "SVD right-singular basis is not quite orthogonal:"+        , "svd:" ++ show s+        , "m:"   ++ show x+        ]+      ) (eye =~= svdV %* transpose svdV)+    .&&.+      counterexample+        (unlines+          [ "Bad singular values (should be decreasing, non-negative):"+          , "svd:" ++ show s+          , "m:"   ++ show x+          ]+        )+        (isJust $ ewfoldr @_ @'[Min n m] @'[] checkIncreasing (Just 0) svdS)+  where+    checkIncreasing :: Scalar t -> Maybe (Scalar t) -> Maybe (Scalar t)+    checkIncreasing _ Nothing = Nothing+    checkIncreasing a (Just b)+      | a >= b    = Just a+      | otherwise = Nothing+    x'  = svdU %* asDiag svdS %* transpose svdV++prop_svd2x :: Property+prop_svd2x = once . conjoin $ map prop_svd2 $ xs ++ map negate xs+  where+    mkM :: [Double] -> Mat22d+    mkM = fromFlatList dims 0+    xs :: [Mat22d]+    xs =+      [ 0, 1, 2, eye]+      ++ map mkM (rotateList [4,0,0,0])+      ++ map mkM (rotateList [4,3,0,0])+      ++ map mkM (rotateList [4,-3,0,0])+      ++ map mkM (rotateList [3,0,-2,0])+      ++ map mkM (rotateList [3,1,-2,0])+      ++ map mkM (rotateList [1,1,3,3])+      ++ map ((eye + ). mkM) (rotateList [4,0,0,0])+      ++ map ((eye - ). mkM) (rotateList [4,0,0,0])++prop_svd2 :: Matrix Double 2 2 -> Property+prop_svd2 m = validateSVD 1 m (svd2 m)++prop_svd3x :: Property+prop_svd3x = once . conjoin $ map prop_svd3 $ xs ++ map negate xs+  where+    mkM :: [Double] -> Mat33d+    mkM = fromFlatList dims 0+    xs :: [Mat33d]+    xs =+      [ 0, 1, 2, eye]+      ++ map mkM (rotateList [4,0,0,0,0,0,0,0,0])+      ++ map ((eye + ). mkM) (rotateList [4,0,0,0,0,0,0,0,0])+      ++ map ((eye - ). mkM) (rotateList [4,0,0,0,0,0,0,0,0])+      ++ map mkM (rotateList [4,1,0,0,0,0,0,0,0])+      ++ map mkM (rotateList [4,2,1,0,0,0,0,0,0])+      ++ map mkM (rotateList [4,2,1,0,0,7,0,0,0])+      ++ map mkM (rotateList [-5,0,1,0,0,7,1,0,10])+      ++ map mkM (rotateList [0,4.237014829207297,-2.0275007228244943+                             ,0,-0.9998659636721602,0+                             ,0,0,0.34652350292261475])+      ++ map mkM (rotateList [0,0,15.33245854346668+                             ,0,-18.99787842921179,0+                             ,0,29.953254288817046,0.78897034887446])+      ++ map mkM (rotateList [-306.5504258807584,0,0+                             ,-58.78957738886663,0,95.51923744049921+                             ,0,0,-292.92428690917154])+      ++ map mkM (rotateList [0,116.15251855804613,-94.95820664249142+                             ,0,-69.551119690005,0+                             ,0,0,46.77872074296825])++++prop_svd3 :: Matrix Double 3 3 -> Property+prop_svd3 m = validateSVD extraTolerance m (svd3 m)+  where+    -- svd3 is fast, but not particularly precise,+    -- though, 5-7 digits of precision are still there.+    extraTolerance = 10e4 :: Double+++prop_svdSimple :: Property+prop_svdSimple = once . conjoin $ prop_svd <$> dfs++dfs :: [DataFrame Double '[XN 1, XN 1]]+dfs = xs+  where+    mkM :: Dims ([n,m]) -> [Double] -> DataFrame Double '[XN 1, XN 1]+    mkM ds+      | Just (XDims ds'@Dims) <- constrainDims ds :: Maybe (Dims '[XN 1, XN 1])+        = XFrame . fromFlatList ds' 0+    mkM _ = error "prop_qrSimple: bad dims"+    variants :: Num a => [a] -> [[a]]+    variants as = rotateList as ++ rotateList (map negate as)+    xs :: [DataFrame Double '[XN 1, XN 1]]+    xs = join+      [ [mkM $ D2 :* D2 :* U, mkM $ D5 :* D2 :* U, mkM $ D3 :* D7 :* U]+            <*> [repeat 0, repeat 1, repeat 2]+      , mkM (D2 :* D2 :* U) <$> variants [3,2, 4,1]+      , mkM (D3 :* D3 :* U) <$> variants [0,0,1, 3,2,0, 4,1,0]+      , mkM (D4 :* D2 :* U) <$> variants [3,2, 4,1, 0,0, 0,2]+      , mkM (D2 :* D3 :* U) <$> variants [3,2,0, 4,1,2]+      , mkM (D2 :* D2 :* U) <$> variants [2, 0, 0, 0]+      , mkM (D2 :* D2 :* U) <$> variants [4, 1, 0, 0]+      , mkM (D2 :* D2 :* U) <$> variants [3, 1, -2, 0]+      , [mkM $ D2 :* D3 :* U, mkM $ D3 :* D2 :* U]+            <*> join+                [ variants [2, 0, 0, 0, 0, 0]+                , variants [4, 1, 0, 0, 0, 0]+                , variants [3, 1, -2, 0, 0, 0]+                , variants [3, 0, -2, 9, 0, 0]+                ]+      ]++prop_svd :: DataFrame Double '[XN 1, XN 1] -> Property+prop_svd (XFrame x)+  | n@D :* m@D :* U <- dims `inSpaceOf` x+  , D <- minDim n m = validateSVD 1 x (svd x)+prop_svd _ = error "prop_svd: impossible pattern"+++return []+runTests :: Int -> IO Bool+runTests n = $forAllProperties+  $ quickCheckWithResult stdArgs { maxSuccess = n }
test/Numeric/MatrixDoubleTest.hs view
@@ -11,77 +11,48 @@   import Data.Fixed-import Data.Semigroup+import Numeric.Arbitraries import Numeric.DataFrame-import Numeric.DataFrame.Arbitraries import Numeric.Dimensions import Test.QuickCheck  type TestElem = Double-type TestDF = DataFrame TestElem -eps :: Scalar TestElem-eps = 0.000000001- dropW :: (SubSpace t '[3] '[] '[3], SubSpace t '[4] '[] '[4])       => Vector t 4 -> Vector t 3 dropW (Vec4 x y z _) = Vec3 x y z --- | Most of the time, the error is proportional to the maginutude of the biggest element-maxElem :: (SubSpace TestElem ds '[] ds)-        => TestDF (ds :: [Nat]) -> Scalar TestElem-maxElem = ewfoldl (\a -> max a . abs) 0---- | For operations like @det@, the error is proportional to maximum possible product---   over rows or columns-maxRows :: forall ds-         . (SubSpace TestElem '[Head ds] (Tail ds) ds)-        => TestDF (ds :: [Nat]) -> Scalar TestElem-maxRows = getProduct . ewfoldMap @_ @'[Head ds] @(Tail ds) @ds (Product . maxElem)--approxEq ::-  forall (ds :: [Nat]) .-  (-    Dimensions ds,-    Num (TestDF ds),-    PrimBytes (TestDF ds),-    PrimArray TestElem (TestDF ds)-  ) =>-  TestDF ds -> TestDF ds -> Bool-approxEq a b = maxElem (a - b) <= eps * m-  where-    m = maxElem a `max` maxElem b-infix 4 `approxEq`- prop_detTranspose :: SomeSquareMatrix AnyMatrix TestElem -> Property-prop_detTranspose (SSM m)-  = let a = det m-        b = det $ transpose m-        n = (case dims `inSpaceOf` m of dn :* _ -> dimVal dn) :: Word-        mag = eps * maxRows m * fromIntegral (product [1..n])-    in  counterexample-          (unlines-            [ "failed det/transpose:"-            , "m:  " ++ show m-            , "mT: " ++ show (transpose m)-            , show a ++ " /= " ++ show b-              ++ " (tolerance: " ++ show mag ++ ")."-            ]-          ) $ abs (a - b) <= mag+prop_detTranspose (SSM m') = counterexample+    (unlines+      [ "Failed det/transpose:"+      , "m:  " ++ show m+      , "mT: " ++ show (transpose m)+      ]+    ) $ approxEq mag a b+  where+    n2 = totalDim (dims `inSpaceOf` m)+    mag = fromIntegral (n2*n2)+    mm = recip $ maxElem m' `max` 1+    m = ewmap (*mm) m'+    a = det m+    b = det $ transpose m  prop_inverse :: SomeSquareMatrix NonSingular TestElem -> Property-prop_inverse (SSM m)-  = let mi = inverse m-        aeq a b = maxElem (b - a) <= eps * maxRows m-    in  counterexample ("failed inverse:" ++-                            show (m, mi, m %* mi, mi %* m)) $-         aeq eye (m %* mi) && aeq eye (mi %* m)--prop_LU :: SomeSquareMatrix NonSingular TestElem -> Bool-prop_LU (SSM m)-  = let f = lu m-        aeq a b = maxElem (b - a) <= eps * maxRows m-    in aeq (luPerm f %* m) (luLower f %* luUpper f)+prop_inverse (SSM m) = check (m %* mi) .&&. check (mi %* m)+  where+    n2 = totalDim (dims `inSpaceOf` m)+    mag = maxElem m `max` maxElem mi `max` 1+        * fromIntegral (n2*n2)+    mi = inverse m+    check a = counterexample+      ( unlines+        [ "Failed inverse:"+        , "  m:    " ++ show m+        , "  mi:   " ++ show mi+        , "  eye': " ++ show a+        ]+      ) $ approxEq mag a eye  prop_translate3vs4 :: Vector TestElem 4 -> Bool prop_translate3vs4 v = translate4 v == translate3 (dropW v)@@ -95,92 +66,96 @@ prop_rotateX :: Vector TestElem 4 -> Property prop_rotateX v@(Vec4 x y z w) =   conjoin [-    v %* rotateX (-2 * pi)   `approxEq` v,-    v %* rotateX (-1.5 * pi) `approxEq` vec4 x (-z) y w,-    v %* rotateX (-pi)       `approxEq` vec4 x (-y) (-z) w,-    v %* rotateX (-0.5 * pi) `approxEq` vec4 x z (-y) w,-    v %* rotateX 0           `approxEq` v,-    v %* rotateX (0.5 * pi)  `approxEq` vec4 x (-z) y w,-    v %* rotateX pi          `approxEq` vec4 x (-y) (-z) w,-    v %* rotateX (1.5 * pi)  `approxEq` vec4 x z (-y) w,-    v %* rotateX (2 * pi)    `approxEq` v+    v %* rotateX (-2 * pi)   =~= v,+    v %* rotateX (-1.5 * pi) =~= vec4 x (-z) y w,+    v %* rotateX (-pi)       =~= vec4 x (-y) (-z) w,+    v %* rotateX (-0.5 * pi) =~= vec4 x z (-y) w,+    v %* rotateX 0           =~= v,+    v %* rotateX (0.5 * pi)  =~= vec4 x (-z) y w,+    v %* rotateX pi          =~= vec4 x (-y) (-z) w,+    v %* rotateX (1.5 * pi)  =~= vec4 x z (-y) w,+    v %* rotateX (2 * pi)    =~= v   ]  prop_rotateY :: Vector TestElem 4 -> Property prop_rotateY v@(Vec4 x y z w) =   conjoin [-    v %* rotateY (-2 * pi)   `approxEq` v,-    v %* rotateY (-1.5 * pi) `approxEq` vec4 z y (-x) w,-    v %* rotateY (-pi)       `approxEq` vec4 (-x) y (-z) w,-    v %* rotateY (-0.5 * pi) `approxEq` vec4 (-z) y x w,-    v %* rotateY 0           `approxEq` v,-    v %* rotateY (0.5 * pi)  `approxEq` vec4 z y (-x) w,-    v %* rotateY pi          `approxEq` vec4 (-x) y (-z) w,-    v %* rotateY (1.5 * pi)  `approxEq` vec4 (-z) y x w,-    v %* rotateY (2 * pi)    `approxEq` v+    v %* rotateY (-2 * pi)   =~= v,+    v %* rotateY (-1.5 * pi) =~= vec4 z y (-x) w,+    v %* rotateY (-pi)       =~= vec4 (-x) y (-z) w,+    v %* rotateY (-0.5 * pi) =~= vec4 (-z) y x w,+    v %* rotateY 0           =~= v,+    v %* rotateY (0.5 * pi)  =~= vec4 z y (-x) w,+    v %* rotateY pi          =~= vec4 (-x) y (-z) w,+    v %* rotateY (1.5 * pi)  =~= vec4 (-z) y x w,+    v %* rotateY (2 * pi)    =~= v   ]  prop_rotateZ :: Vector TestElem 4 -> Property prop_rotateZ v@(Vec4 x y z w) =   conjoin [-    v %* rotateZ (-2 * pi)   `approxEq` v,-    v %* rotateZ (-1.5 * pi) `approxEq` vec4 (-y) x z w,-    v %* rotateZ (-pi)       `approxEq` vec4 (-x) (-y) z w,-    v %* rotateZ (-0.5 * pi) `approxEq` vec4 y (-x) z w,-    v %* rotateZ 0           `approxEq` v,-    v %* rotateZ (0.5 * pi)  `approxEq` vec4 (-y) x z w,-    v %* rotateZ pi          `approxEq` vec4 (-x) (-y) z w,-    v %* rotateZ (1.5 * pi)  `approxEq` vec4 y (-x) z w,-    v %* rotateZ (2 * pi)    `approxEq` v+    v %* rotateZ (-2 * pi)   =~= v,+    v %* rotateZ (-1.5 * pi) =~= vec4 (-y) x z w,+    v %* rotateZ (-pi)       =~= vec4 (-x) (-y) z w,+    v %* rotateZ (-0.5 * pi) =~= vec4 y (-x) z w,+    v %* rotateZ 0           =~= v,+    v %* rotateZ (0.5 * pi)  =~= vec4 (-y) x z w,+    v %* rotateZ pi          =~= vec4 (-x) (-y) z w,+    v %* rotateZ (1.5 * pi)  =~= vec4 y (-x) z w,+    v %* rotateZ (2 * pi)    =~= v   ]  prop_rotate :: TestElem -> Property prop_rotate a =   conjoin [-    rotate (vec3 1 0 0) a `approxEq` rotateX a,-    rotate (vec3 0 1 0) a `approxEq` rotateY a,-    rotate (vec3 0 0 1) a `approxEq` rotateZ a+    rotate (vec3 1 0 0) a =~= rotateX a,+    rotate (vec3 0 1 0) a =~= rotateY a,+    rotate (vec3 0 0 1) a =~= rotateZ a   ] -prop_rotateEuler :: TestElem -> TestElem -> TestElem -> Bool+prop_rotateEuler :: TestElem -> TestElem -> TestElem -> Property prop_rotateEuler pitch yaw roll =-  rotateEuler pitch yaw roll `approxEq` rotateZ roll %* rotateY yaw %* rotateX pitch+  rotateEuler pitch yaw roll =~= rotateZ roll %* rotateY yaw %* rotateX pitch  prop_lookAt :: Vector TestElem 3 -> Vector TestElem 3 -> Vector TestElem 3 -> Property prop_lookAt up cam foc =-  (apart cam foc && apart up cam) ==>+  (apart cam foc && nonColinear up zb && nonColinear zb xb) ==>   conjoin [-    (normalized . fromHom $ toHomPoint foc %* m) `approxEq` vec3 0 0 (-1),-    fromHom (toHomPoint cam %* m) `approxEq` 0,-    fromHom (toHomVector xb %* m) `approxEq` vec3 1 0 0,-    fromHom (toHomVector yb %* m) `approxEq` vec3 0 1 0,-    fromHom (toHomVector zb %* m) `approxEq` vec3 0 0 1+    (normalized . fromHom $ toHomPoint foc %* m) `aeq` vec3 0 0 (-1),+    fromHom (toHomPoint cam %* m) `aeq` 0,+    fromHom (toHomVector xb %* m) `aeq` vec3 1 0 0,+    fromHom (toHomVector yb %* m) `aeq` vec3 0 1 0,+    fromHom (toHomVector zb %* m) `aeq` vec3 0 0 1   ]   where+    aeq :: Vector TestElem 3 -> Vector TestElem 3 -> Property+    aeq = approxEq 10     apart :: Vector TestElem 3 -> Vector TestElem 3 -> Bool-    apart a b = maxElem (a - b) > 0.01 * (maxElem a `max` maxElem b)+    apart a b = normL2 (a - b) > max (2 * sqrt M_EPS) (0.1 * (normL2 a + normL2 b))+    nonColinear :: Vector TestElem 3 -> Vector TestElem 3 -> Bool+    nonColinear a b = normL2 (cross a b) > 0.1 * abs (dot a b)     m = lookAt up cam foc     zb = normalized $ cam - foc     xb = normalized $ up `cross` zb     yb = zb `cross` xb -prop_perspective :: TestElem -> TestElem -> TestElem -> TestElem -> Bool+prop_perspective :: TestElem -> TestElem -> TestElem -> TestElem -> Property prop_perspective a b c d =-  and [-    projectTo 0 0 n       `approxEq` vec3 0 0 (-1),-    projectTo 0 0 f       `approxEq` vec3 0 0 1,-    projectTo 1 1 n       `approxEq` vec3 1 1 (-1),-    projectTo 1 (-1) n    `approxEq` vec3 1 (-1) (-1),-    projectTo (-1) 1 n    `approxEq` vec3 (-1) 1 (-1),-    projectTo (-1) (-1) n `approxEq` vec3 (-1) (-1) (-1),-    projectTo 1 1 f       `approxEq` vec3 1 1 1,-    projectTo 1 (-1) f    `approxEq` vec3 1 (-1) 1,-    projectTo (-1) 1 f    `approxEq` vec3 (-1) 1 1,-    projectTo (-1) (-1) f `approxEq` vec3 (-1) (-1) 1+  conjoin [+    projectTo 0 0 n       =~= vec3 0 0 (-1),+    projectTo 0 0 f       =~= vec3 0 0 1,+    projectTo 1 1 n       =~= vec3 1 1 (-1),+    projectTo 1 (-1) n    =~= vec3 1 (-1) (-1),+    projectTo (-1) 1 n    =~= vec3 (-1) 1 (-1),+    projectTo (-1) (-1) n =~= vec3 (-1) (-1) (-1),+    projectTo 1 1 f       =~= vec3 1 1 1,+    projectTo 1 (-1) f    =~= vec3 1 (-1) 1,+    projectTo (-1) 1 f    =~= vec3 (-1) 1 1,+    projectTo (-1) (-1) f =~= vec3 (-1) (-1) 1   ]   where     n = 1.0 + mod' a 9.0 -- Near plane in range [1, 10)-    f = n + 1.0 + mod' b 99.0 -- Far plane in range [n + 1, n + 100)+    f = 2*n + mod' b 99.0 -- Far plane in range [2*n, 2*n + 100)     fovy = (0.1 * pi) + mod' c (0.8 * pi) -- Y-axis field of view in range [0.1*pi, 0.9*pi)     aspect = 0.25 + mod' d 4.0 -- Aspect ration in range [1/4, 4/1]     hpd = tan (fovy * 0.5) -- height/distance@@ -188,23 +163,23 @@     m = perspective n f fovy aspect     projectTo x' y' z = fromHom $ vec4 (x' * wpd * z) (y' * hpd * z) (-z) 1 %* m -prop_orthogonal :: TestElem -> TestElem -> TestElem -> TestElem -> Bool+prop_orthogonal :: TestElem -> TestElem -> TestElem -> TestElem -> Property prop_orthogonal a b c d =-  and [-    projectTo 0 0 n       `approxEq` vec3 0 0 (-1),-    projectTo 0 0 f       `approxEq` vec3 0 0 1,-    projectTo 1 1 n       `approxEq` vec3 1 1 (-1),-    projectTo 1 (-1) n    `approxEq` vec3 1 (-1) (-1),-    projectTo (-1) 1 n    `approxEq` vec3 (-1) 1 (-1),-    projectTo (-1) (-1) n `approxEq` vec3 (-1) (-1) (-1),-    projectTo 1 1 f       `approxEq` vec3 1 1 1,-    projectTo 1 (-1) f    `approxEq` vec3 1 (-1) 1,-    projectTo (-1) 1 f    `approxEq` vec3 (-1) 1 1,-    projectTo (-1) (-1) f `approxEq` vec3 (-1) (-1) 1+  conjoin [+    projectTo 0 0 n       =~= vec3 0 0 (-1),+    projectTo 0 0 f       =~= vec3 0 0 1,+    projectTo 1 1 n       =~= vec3 1 1 (-1),+    projectTo 1 (-1) n    =~= vec3 1 (-1) (-1),+    projectTo (-1) 1 n    =~= vec3 (-1) 1 (-1),+    projectTo (-1) (-1) n =~= vec3 (-1) (-1) (-1),+    projectTo 1 1 f       =~= vec3 1 1 1,+    projectTo 1 (-1) f    =~= vec3 1 (-1) 1,+    projectTo (-1) 1 f    =~= vec3 (-1) 1 1,+    projectTo (-1) (-1) f =~= vec3 (-1) (-1) 1   ]   where     n = 1.0 + mod' a 9.0 -- Near plane in range [1, 10)-    f = n + 1.0 + mod' b 99.0 -- Far plane in range [n + 1, n + 100)+    f = 2*n + mod' b 99.0 -- Far plane in range [2*n, 2*n + 100)     w = 1.0 + mod' c 9999.0 -- Width in range [1, 10000)     h = 1.0 + mod' d 9999.0 -- Height in range [1, 10000)     m = orthogonal n f w h@@ -216,11 +191,11 @@ prop_toHomVector :: Vector TestElem 3 -> Bool prop_toHomVector v@(Vec3 x y z) = toHomVector v == vec4 x y z 0 -prop_fromHom :: Vector TestElem 4 -> Bool+prop_fromHom :: Vector TestElem 4 -> Property prop_fromHom v@(Vec4 x y z w) =   case w of-    0 -> fromHom v == vec3 x y z-    _ -> fromHom v `approxEq` vec3 (x/w) (y/w) (z/w)+    0 -> fromHom v === vec3 x y z+    _ -> fromHom v =~= vec3 (x/w) (y/w) (z/w)  return [] runTests :: Int -> IO Bool
test/Numeric/MatrixFloatTest.hs view
@@ -11,83 +11,48 @@   import Data.Fixed-import Data.Semigroup+import Numeric.Arbitraries import Numeric.DataFrame-import Numeric.DataFrame.Arbitraries import Numeric.Dimensions import Test.QuickCheck  type TestElem = Float-type TestDF = DataFrame TestElem -eps :: Scalar TestElem-eps = 0.00001- dropW :: (SubSpace t '[3] '[] '[3], SubSpace t '[4] '[] '[4])       => Vector t 4 -> Vector t 3 dropW (Vec4 x y z _) = Vec3 x y z --- | Most of the time, the error is proportional to the maginutude of the biggest element-maxElem :: (SubSpace TestElem ds '[] ds)-        => TestDF (ds :: [Nat]) -> Scalar TestElem-maxElem = ewfoldl (\a -> max a . abs) 0---- | For operations like @det@, the error is proportional to maximum possible product---   over rows or columns-maxRows :: forall ds-         . (SubSpace TestElem '[Head ds] (Tail ds) ds)-        => TestDF (ds :: [Nat]) -> Scalar TestElem-maxRows = getProduct . ewfoldMap @_ @'[Head ds] @(Tail ds) @ds (Product . maxElem)--approxEq ::-  forall (ds :: [Nat]) .-  (-    Dimensions ds,-    Num (TestDF ds),-    PrimBytes (TestDF ds),-    PrimArray TestElem (TestDF ds)-  ) =>-  TestDF ds -> TestDF ds -> Bool-approxEq a b = maxElem (a - b) <= eps * m-  where-    m = maxElem a `max` maxElem b-infix 4 `approxEq`- prop_detTranspose :: SomeSquareMatrix AnyMatrix TestElem -> Property-prop_detTranspose (SSM m)-  = let a = det m-        b = det $ transpose m-        n = (case dims `inSpaceOf` m of dn :* _ -> dimVal dn) :: Word-        mag = eps * maxRows m * fromIntegral (product [1..n])-    in  counterexample-          (unlines-            [ "failed det/transpose:"-            , "m:  " ++ show m-            , "mT: " ++ show (transpose m)-            , show a ++ " /= " ++ show b-              ++ " (tolerance: " ++ show mag ++ ")."-            ]-          ) $ abs (a - b) <= mag+prop_detTranspose (SSM m') = counterexample+    (unlines+      [ "Failed det/transpose:"+      , "m:  " ++ show m+      , "mT: " ++ show (transpose m)+      ]+    ) $ approxEq mag a b+  where+    n2 = totalDim (dims `inSpaceOf` m)+    mag = fromIntegral (n2*n2)+    mm = recip $ maxElem m' `max` 1+    m = ewmap (*mm) m'+    a = det m+    b = det $ transpose m  prop_inverse :: SomeSquareMatrix NonSingular TestElem -> Property-prop_inverse (SSM m)-  = let mi = inverse m-        aeq a b = maxElem (b - a) <= eps * maxRows m-    in  counterexample ("failed inverse:" ++-                            show (m, mi, m %* mi, mi %* m)) $-         aeq eye (m %* mi) && aeq eye (mi %* m)---- TODO: improve lu!--- lu factorization is very unstable in some cases------ >>> m = unsafeFromFlatList (Dims @'[4,4]) 0 [1,0,1,-2, 0,-1,1,2, 2,-4,2,-2, 4,-8,-2,2 ] :: Mat44f--- >>> det m == 0--- >>> det (transpose m) == 60-prop_LU :: SomeSquareMatrix NonSingular TestElem -> Bool-prop_LU (SSM m)-  = let f = lu m-        aeq a b = maxElem (b - a) <= eps * maxRows m-    in aeq (luPerm f %* m) (luLower f %* luUpper f)+prop_inverse (SSM m) = check (m %* mi) .&&. check (mi %* m)+  where+    n2 = totalDim (dims `inSpaceOf` m)+    mag = maxElem m `max` maxElem mi `max` 1+        * fromIntegral (n2*n2)+    mi = inverse m+    check a = counterexample+      ( unlines+        [ "Failed inverse:"+        , "  m:    " ++ show m+        , "  mi:   " ++ show mi+        , "  eye': " ++ show a+        ]+      ) $ approxEq mag a eye  prop_translate3vs4 :: Vector TestElem 4 -> Bool prop_translate3vs4 v = translate4 v == translate3 (dropW v)@@ -101,92 +66,96 @@ prop_rotateX :: Vector TestElem 4 -> Property prop_rotateX v@(Vec4 x y z w) =   conjoin [-    v %* rotateX (-2 * pi)   `approxEq` v,-    v %* rotateX (-1.5 * pi) `approxEq` vec4 x (-z) y w,-    v %* rotateX (-pi)       `approxEq` vec4 x (-y) (-z) w,-    v %* rotateX (-0.5 * pi) `approxEq` vec4 x z (-y) w,-    v %* rotateX 0           `approxEq` v,-    v %* rotateX (0.5 * pi)  `approxEq` vec4 x (-z) y w,-    v %* rotateX pi          `approxEq` vec4 x (-y) (-z) w,-    v %* rotateX (1.5 * pi)  `approxEq` vec4 x z (-y) w,-    v %* rotateX (2 * pi)    `approxEq` v+    v %* rotateX (-2 * pi)   =~= v,+    v %* rotateX (-1.5 * pi) =~= vec4 x (-z) y w,+    v %* rotateX (-pi)       =~= vec4 x (-y) (-z) w,+    v %* rotateX (-0.5 * pi) =~= vec4 x z (-y) w,+    v %* rotateX 0           =~= v,+    v %* rotateX (0.5 * pi)  =~= vec4 x (-z) y w,+    v %* rotateX pi          =~= vec4 x (-y) (-z) w,+    v %* rotateX (1.5 * pi)  =~= vec4 x z (-y) w,+    v %* rotateX (2 * pi)    =~= v   ]  prop_rotateY :: Vector TestElem 4 -> Property prop_rotateY v@(Vec4 x y z w) =   conjoin [-    v %* rotateY (-2 * pi)   `approxEq` v,-    v %* rotateY (-1.5 * pi) `approxEq` vec4 z y (-x) w,-    v %* rotateY (-pi)       `approxEq` vec4 (-x) y (-z) w,-    v %* rotateY (-0.5 * pi) `approxEq` vec4 (-z) y x w,-    v %* rotateY 0           `approxEq` v,-    v %* rotateY (0.5 * pi)  `approxEq` vec4 z y (-x) w,-    v %* rotateY pi          `approxEq` vec4 (-x) y (-z) w,-    v %* rotateY (1.5 * pi)  `approxEq` vec4 (-z) y x w,-    v %* rotateY (2 * pi)    `approxEq` v+    v %* rotateY (-2 * pi)   =~= v,+    v %* rotateY (-1.5 * pi) =~= vec4 z y (-x) w,+    v %* rotateY (-pi)       =~= vec4 (-x) y (-z) w,+    v %* rotateY (-0.5 * pi) =~= vec4 (-z) y x w,+    v %* rotateY 0           =~= v,+    v %* rotateY (0.5 * pi)  =~= vec4 z y (-x) w,+    v %* rotateY pi          =~= vec4 (-x) y (-z) w,+    v %* rotateY (1.5 * pi)  =~= vec4 (-z) y x w,+    v %* rotateY (2 * pi)    =~= v   ]  prop_rotateZ :: Vector TestElem 4 -> Property prop_rotateZ v@(Vec4 x y z w) =   conjoin [-    v %* rotateZ (-2 * pi)   `approxEq` v,-    v %* rotateZ (-1.5 * pi) `approxEq` vec4 (-y) x z w,-    v %* rotateZ (-pi)       `approxEq` vec4 (-x) (-y) z w,-    v %* rotateZ (-0.5 * pi) `approxEq` vec4 y (-x) z w,-    v %* rotateZ 0           `approxEq` v,-    v %* rotateZ (0.5 * pi)  `approxEq` vec4 (-y) x z w,-    v %* rotateZ pi          `approxEq` vec4 (-x) (-y) z w,-    v %* rotateZ (1.5 * pi)  `approxEq` vec4 y (-x) z w,-    v %* rotateZ (2 * pi)    `approxEq` v+    v %* rotateZ (-2 * pi)   =~= v,+    v %* rotateZ (-1.5 * pi) =~= vec4 (-y) x z w,+    v %* rotateZ (-pi)       =~= vec4 (-x) (-y) z w,+    v %* rotateZ (-0.5 * pi) =~= vec4 y (-x) z w,+    v %* rotateZ 0           =~= v,+    v %* rotateZ (0.5 * pi)  =~= vec4 (-y) x z w,+    v %* rotateZ pi          =~= vec4 (-x) (-y) z w,+    v %* rotateZ (1.5 * pi)  =~= vec4 y (-x) z w,+    v %* rotateZ (2 * pi)    =~= v   ]  prop_rotate :: TestElem -> Property prop_rotate a =   conjoin [-    rotate (vec3 1 0 0) a `approxEq` rotateX a,-    rotate (vec3 0 1 0) a `approxEq` rotateY a,-    rotate (vec3 0 0 1) a `approxEq` rotateZ a+    rotate (vec3 1 0 0) a =~= rotateX a,+    rotate (vec3 0 1 0) a =~= rotateY a,+    rotate (vec3 0 0 1) a =~= rotateZ a   ] -prop_rotateEuler :: TestElem -> TestElem -> TestElem -> Bool+prop_rotateEuler :: TestElem -> TestElem -> TestElem -> Property prop_rotateEuler pitch yaw roll =-  rotateEuler pitch yaw roll `approxEq` rotateZ roll %* rotateY yaw %* rotateX pitch+  rotateEuler pitch yaw roll =~= rotateZ roll %* rotateY yaw %* rotateX pitch  prop_lookAt :: Vector TestElem 3 -> Vector TestElem 3 -> Vector TestElem 3 -> Property prop_lookAt up cam foc =-  (apart cam foc && apart up cam) ==>+  (apart cam foc && nonColinear up zb && nonColinear zb xb) ==>   conjoin [-    (normalized . fromHom $ toHomPoint foc %* m) `approxEq` vec3 0 0 (-1),-    fromHom (toHomPoint cam %* m) `approxEq` 0,-    fromHom (toHomVector xb %* m) `approxEq` vec3 1 0 0,-    fromHom (toHomVector yb %* m) `approxEq` vec3 0 1 0,-    fromHom (toHomVector zb %* m) `approxEq` vec3 0 0 1+    (normalized . fromHom $ toHomPoint foc %* m) `aeq` vec3 0 0 (-1),+    fromHom (toHomPoint cam %* m) `aeq` 0,+    fromHom (toHomVector xb %* m) `aeq` vec3 1 0 0,+    fromHom (toHomVector yb %* m) `aeq` vec3 0 1 0,+    fromHom (toHomVector zb %* m) `aeq` vec3 0 0 1   ]   where+    aeq :: Vector TestElem 3 -> Vector TestElem 3 -> Property+    aeq = approxEq 10     apart :: Vector TestElem 3 -> Vector TestElem 3 -> Bool-    apart a b = maxElem (a - b) > 0.01 * (maxElem a `max` maxElem b)+    apart a b = normL2 (a - b) > max (2 * sqrt M_EPS) (0.1 * (normL2 a + normL2 b))+    nonColinear :: Vector TestElem 3 -> Vector TestElem 3 -> Bool+    nonColinear a b = normL2 (cross a b) > 0.1 * abs (dot a b)     m = lookAt up cam foc     zb = normalized $ cam - foc     xb = normalized $ up `cross` zb     yb = zb `cross` xb -prop_perspective :: TestElem -> TestElem -> TestElem -> TestElem -> Bool+prop_perspective :: TestElem -> TestElem -> TestElem -> TestElem -> Property prop_perspective a b c d =-  and [-    projectTo 0 0 n       `approxEq` vec3 0 0 (-1),-    projectTo 0 0 f       `approxEq` vec3 0 0 1,-    projectTo 1 1 n       `approxEq` vec3 1 1 (-1),-    projectTo 1 (-1) n    `approxEq` vec3 1 (-1) (-1),-    projectTo (-1) 1 n    `approxEq` vec3 (-1) 1 (-1),-    projectTo (-1) (-1) n `approxEq` vec3 (-1) (-1) (-1),-    projectTo 1 1 f       `approxEq` vec3 1 1 1,-    projectTo 1 (-1) f    `approxEq` vec3 1 (-1) 1,-    projectTo (-1) 1 f    `approxEq` vec3 (-1) 1 1,-    projectTo (-1) (-1) f `approxEq` vec3 (-1) (-1) 1+  conjoin [+    projectTo 0 0 n       =~= vec3 0 0 (-1),+    projectTo 0 0 f       =~= vec3 0 0 1,+    projectTo 1 1 n       =~= vec3 1 1 (-1),+    projectTo 1 (-1) n    =~= vec3 1 (-1) (-1),+    projectTo (-1) 1 n    =~= vec3 (-1) 1 (-1),+    projectTo (-1) (-1) n =~= vec3 (-1) (-1) (-1),+    projectTo 1 1 f       =~= vec3 1 1 1,+    projectTo 1 (-1) f    =~= vec3 1 (-1) 1,+    projectTo (-1) 1 f    =~= vec3 (-1) 1 1,+    projectTo (-1) (-1) f =~= vec3 (-1) (-1) 1   ]   where     n = 1.0 + mod' a 9.0 -- Near plane in range [1, 10)-    f = n + 1.0 + mod' b 99.0 -- Far plane in range [n + 1, n + 100)+    f = 2*n + mod' b 99.0 -- Far plane in range [2*n, 2*n + 100)     fovy = (0.1 * pi) + mod' c (0.8 * pi) -- Y-axis field of view in range [0.1*pi, 0.9*pi)     aspect = 0.25 + mod' d 4.0 -- Aspect ration in range [1/4, 4/1]     hpd = tan (fovy * 0.5) -- height/distance@@ -194,23 +163,23 @@     m = perspective n f fovy aspect     projectTo x' y' z = fromHom $ vec4 (x' * wpd * z) (y' * hpd * z) (-z) 1 %* m -prop_orthogonal :: TestElem -> TestElem -> TestElem -> TestElem -> Bool+prop_orthogonal :: TestElem -> TestElem -> TestElem -> TestElem -> Property prop_orthogonal a b c d =-  and [-    projectTo 0 0 n       `approxEq` vec3 0 0 (-1),-    projectTo 0 0 f       `approxEq` vec3 0 0 1,-    projectTo 1 1 n       `approxEq` vec3 1 1 (-1),-    projectTo 1 (-1) n    `approxEq` vec3 1 (-1) (-1),-    projectTo (-1) 1 n    `approxEq` vec3 (-1) 1 (-1),-    projectTo (-1) (-1) n `approxEq` vec3 (-1) (-1) (-1),-    projectTo 1 1 f       `approxEq` vec3 1 1 1,-    projectTo 1 (-1) f    `approxEq` vec3 1 (-1) 1,-    projectTo (-1) 1 f    `approxEq` vec3 (-1) 1 1,-    projectTo (-1) (-1) f `approxEq` vec3 (-1) (-1) 1+  conjoin [+    projectTo 0 0 n       =~= vec3 0 0 (-1),+    projectTo 0 0 f       =~= vec3 0 0 1,+    projectTo 1 1 n       =~= vec3 1 1 (-1),+    projectTo 1 (-1) n    =~= vec3 1 (-1) (-1),+    projectTo (-1) 1 n    =~= vec3 (-1) 1 (-1),+    projectTo (-1) (-1) n =~= vec3 (-1) (-1) (-1),+    projectTo 1 1 f       =~= vec3 1 1 1,+    projectTo 1 (-1) f    =~= vec3 1 (-1) 1,+    projectTo (-1) 1 f    =~= vec3 (-1) 1 1,+    projectTo (-1) (-1) f =~= vec3 (-1) (-1) 1   ]   where     n = 1.0 + mod' a 9.0 -- Near plane in range [1, 10)-    f = n + 1.0 + mod' b 99.0 -- Far plane in range [n + 1, n + 100)+    f = 2*n + mod' b 99.0 -- Far plane in range [2*n, 2*n + 100)     w = 1.0 + mod' c 9999.0 -- Width in range [1, 10000)     h = 1.0 + mod' d 9999.0 -- Height in range [1, 10000)     m = orthogonal n f w h@@ -222,11 +191,11 @@ prop_toHomVector :: Vector TestElem 3 -> Bool prop_toHomVector v@(Vec3 x y z) = toHomVector v == vec4 x y z 0 -prop_fromHom :: Vector TestElem 4 -> Bool+prop_fromHom :: Vector TestElem 4 -> Property prop_fromHom v@(Vec4 x y z w) =   case w of-    0 -> fromHom v == vec3 x y z-    _ -> fromHom v `approxEq` vec3 (x/w) (y/w) (z/w)+    0 -> fromHom v === vec3 x y z+    _ -> fromHom v =~= vec3 (x/w) (y/w) (z/w)  return [] runTests :: Int -> IO Bool
test/Numeric/PrimBytesTest.hs view
@@ -28,11 +28,11 @@ import           GHC.Exts import           GHC.Generics import           GHC.Word-import           Numeric.DataFrame.Arbitraries ()+import           Numeric.Arbitraries  () import           Numeric.Dimensions import           Numeric.PrimBytes-import qualified Numeric.Tuple.Lazy            as LT-import qualified Numeric.Tuple.Strict          as ST+import qualified Numeric.Tuple.Lazy   as LT+import qualified Numeric.Tuple.Strict as ST import           Spec.Util import           Test.QuickCheck 
test/Numeric/QuaterDoubleTest.hs view
@@ -2,42 +2,30 @@ {-# LANGUAGE TemplateHaskell #-} module Numeric.QuaterDoubleTest (runTests) where -import Numeric.DataFrame.Arbitraries ()+import Numeric.Arbitraries+import Numeric.Basics import Numeric.Quaternion-import Numeric.Scalar import Numeric.Vector import Test.QuickCheck  type T = Double -eps :: T-eps = 1e-7- -- | Some non-linear function are very unstable; --   it would be a downting task to determine the uncertainty precisely.---   Instead, I just make sure the numbers are not so big to find at least+--   Instead, I just make sure the tolerance is small enough to find at least --   the most obvious bugs.-smaller :: Quater T -> Quater T-smaller q@(Quater x y z w)-  = if square q >= 1 then Quater (f x) (f y) (f z) (f w) else q+--   This function increases the tolerance by the span of magnitudes in q.+qSpan :: Quater T -> T+qSpan (Quater a b c d) = asSpan . foldl mm (1,1) $ map (\x -> x*x) [a, b, c, d]   where-    f :: T -> T-    f a | abs a > 2 = signum a * log (abs a)-        | otherwise = a+    mm :: (T,T) -> T -> (T,T)+    mm (mi, ma) x+      | x > M_EPS = (min mi x, max ma x)+      | otherwise = (mi, ma)+    asSpan :: (T,T) -> T+    asSpan (mi, ma) = ma / mi -(=~=) :: Quater T -> Quater T -> Property-(=~=) = approxEq eps-infix 4 =~= --- Even lower precision - for naturally fragile operations-approxEq :: T -> Quater T -> Quater T -> Property-approxEq e a b = property $ err <= c * scalar e-    where-      v1 = toVec4 a-      v2 = toVec4 b-      c = 1 `max` normL1 v1 `max` normL1 v2-      err = normL1 $ v1 - v2- prop_Eq :: Quater T -> Bool prop_Eq q = and     [ q == q@@ -58,19 +46,20 @@  prop_GetRotScale :: Vector T 3 -> Vector T 3 -> Property prop_GetRotScale a b-  = a /= 0 ==> approxEq eps' (fromVecNum (rotScale q a) 0) (fromVecNum b 0)+    = normL2 a * ab > M_EPS * normL2 b+      ==> approxEq (recip ab) b (rotScale q a)   where     q = getRotScale a b     -- when a and b are almost opposite, precision of getRotScale suffers a lot-    -- compensate it by increasing eps:-    eps' = if cross a b == 0-           then eps-           else eps / (max eps . min 1 . unScalar $-                         1 + normalized a `dot` normalized b)+    -- compensate it by increasing tolerance:+    ab = min 1 $ 1 + normalized a `dot` normalized b + prop_InverseRotScale :: Quater T -> Vector T 3 -> Property prop_InverseRotScale q v-  = square q > eps ==> fromVecNum (rotScale (1/q) (rotScale q v)) 0 =~= fromVecNum v 0+  = min (recip s) s > M_EPS ==> v =~= rotScale (1/q) (rotScale q v)+  where+    s = square q  prop_NegateToMatrix33 :: Quater T -> Bool prop_NegateToMatrix33 q = toMatrix33 q == toMatrix33 (negate q)@@ -95,53 +84,59 @@  prop_UnitQ :: Quater T -> Property prop_UnitQ q-  = square q > eps ==> realToFrac (square (q / q)) =~= 1+  = square q > M_EPS ==> square (q / q) =~= 1   prop_ExpLog :: Quater T -> Property-prop_ExpLog q | square q < eps = log (exp q) =~= q-              | otherwise = exp (log q) =~= q+prop_ExpLog q | square q < M_EPS = approxEq (qSpan q) q $ log (exp q)+              | otherwise        = approxEq (qSpan q) q $ exp (log q)  prop_SinAsin :: Quater T -> Property-prop_SinAsin q = sin (asin q') =~= q'-    where-      q' = signum q+prop_SinAsin q = approxEq (qSpan q `max` qSpan q') q $ sin q'+  where+    q' = asin q  prop_CosAcos :: Quater T -> Property-prop_CosAcos q = cos (acos q') =~= q'-    where-      q' = signum q+prop_CosAcos q = approxEq (qSpan q `max` qSpan q') q $ cos q'+  where+    q' = acos q  prop_TanAtan :: Quater T -> Property-prop_TanAtan q = tan (atan q') =~= q'-    where-      q' = sqrt (smaller q) -- because this inverse fun is fragile+prop_TanAtan q = approxEq (qSpan q `max` qSpan q') q $ tan q'+  where+    q' = atan q  prop_SinhAsinh :: Quater T -> Property-prop_SinhAsinh q = sinh (asinh q') =~= q'-    where-      q' = sqrt (smaller q) -- because this inverse fun is fragile+prop_SinhAsinh q = approxEq (qSpan q `max` qSpan q') q $ sinh q'+  where+    q' = asinh q  prop_CoshAcosh :: Quater T -> Property-prop_CoshAcosh q = cosh (acosh q) =~= q+prop_CoshAcosh q = approxEq (qSpan q `max` qSpan q') q $ cosh q'+  where+    q' = acosh q  prop_TanhAtanh :: Quater T -> Property-prop_TanhAtanh q = tanh (atanh q') =~= q'-    where-      q' = sqrt (smaller q) -- because this inverse fun is fragile+prop_TanhAtanh q = approxEq (qSpan q `max` qSpan q') q $ tanh q'+  where+    q' = atanh q  prop_SqrtSqr :: Quater T -> Property-prop_SqrtSqr q = sqrt q * sqrt q =~= q+prop_SqrtSqr q = approxEq (qSpan q) q $ sqrt q * sqrt q  prop_SinCos :: Quater T -> Property-prop_SinCos q = sin q' * sin q' + cos q' * cos q' =~= 1-    where-      q' = sqrt (smaller q) -- because it involves exponents+prop_SinCos q' = approxEq (qSpan s `max` qSpan c) 1 $ c * c + s * s+  where+    q = signum q' -- avoid exploding exponents+    s = sin q+    c = cos q  prop_SinhCosh :: Quater T -> Property-prop_SinhCosh q = cosh q' * cosh q' - sinh q' * sinh q' =~= 1-    where-      q' = sqrt (smaller q) -- because it involves exponents+prop_SinhCosh q' = approxEq (qSpan s `max` qSpan c) 1 $ c * c - s * s+  where+    q = signum q' -- avoid exploding exponents+    s = sinh q+    c = cosh q  prop_ReadShow :: Quater T -> Bool prop_ReadShow q = q == read (show q)
test/Numeric/QuaterFloatTest.hs view
@@ -2,42 +2,30 @@ {-# LANGUAGE TemplateHaskell #-} module Numeric.QuaterFloatTest (runTests) where -import Numeric.DataFrame.Arbitraries ()+import Numeric.Arbitraries+import Numeric.Basics import Numeric.Quaternion-import Numeric.Scalar import Numeric.Vector import Test.QuickCheck  type T = Float -eps :: T-eps = 1e-3- -- | Some non-linear function are very unstable; --   it would be a downting task to determine the uncertainty precisely.---   Instead, I just make sure the numbers are not so big to find at least+--   Instead, I just make sure the tolerance is small enough to find at least --   the most obvious bugs.-smaller :: Quater T -> Quater T-smaller q@(Quater x y z w)-  = if square q >= 1 then Quater (f x) (f y) (f z) (f w) else q+--   This function increases the tolerance by the span of magnitudes in q.+qSpan :: Quater T -> T+qSpan (Quater a b c d) = asSpan . foldl mm (1,1) $ map (\x -> x*x) [a, b, c, d]   where-    f :: T -> T-    f a | abs a > 2 = signum a * log (abs a)-        | otherwise = a+    mm :: (T,T) -> T -> (T,T)+    mm (mi, ma) x+      | x > M_EPS = (min mi x, max ma x)+      | otherwise = (mi, ma)+    asSpan :: (T,T) -> T+    asSpan (mi, ma) = ma / mi -(=~=) :: Quater T -> Quater T -> Property-(=~=) = approxEq eps-infix 4 =~= --- Even lower precision - for naturally fragile operations-approxEq :: T -> Quater T -> Quater T -> Property-approxEq e a b = property $ err <= c * scalar e-    where-      v1 = toVec4 a-      v2 = toVec4 b-      c = 1 `max` normL1 v1 `max` normL1 v2-      err = normL1 $ v1 - v2- prop_Eq :: Quater T -> Bool prop_Eq q = and     [ q == q@@ -58,19 +46,20 @@  prop_GetRotScale :: Vector T 3 -> Vector T 3 -> Property prop_GetRotScale a b-  = a /= 0 ==> approxEq eps' (fromVecNum (rotScale q a) 0) (fromVecNum b 0)+    = normL2 a * ab > M_EPS * normL2 b+      ==> approxEq (recip ab) b (rotScale q a)   where     q = getRotScale a b     -- when a and b are almost opposite, precision of getRotScale suffers a lot-    -- compensate it by increasing eps:-    eps' = if cross a b == 0-           then eps-           else eps / (max eps . min 1 . unScalar $-                         1 + normalized a `dot` normalized b)+    -- compensate it by increasing tolerance:+    ab = min 1 $ 1 + normalized a `dot` normalized b + prop_InverseRotScale :: Quater T -> Vector T 3 -> Property prop_InverseRotScale q v-  = square q > eps ==> fromVecNum (rotScale (1/q) (rotScale q v)) 0 =~= fromVecNum v 0+  = min (recip s) s > M_EPS ==> v =~= rotScale (1/q) (rotScale q v)+  where+    s = square q  prop_NegateToMatrix33 :: Quater T -> Bool prop_NegateToMatrix33 q = toMatrix33 q == toMatrix33 (negate q)@@ -95,53 +84,59 @@  prop_UnitQ :: Quater T -> Property prop_UnitQ q-  = square q > eps ==> realToFrac (square (q / q)) =~= 1+  = square q > M_EPS ==> square (q / q) =~= 1   prop_ExpLog :: Quater T -> Property-prop_ExpLog q | square q < eps = log (exp q) =~= q-              | otherwise = exp (log q) =~= q+prop_ExpLog q | square q < M_EPS = approxEq (qSpan q) q $ log (exp q)+              | otherwise        = approxEq (qSpan q) q $ exp (log q)  prop_SinAsin :: Quater T -> Property-prop_SinAsin q = sin (asin q') =~= q'-    where-      q' = signum q+prop_SinAsin q = approxEq (qSpan q `max` qSpan q') q $ sin q'+  where+    q' = asin q  prop_CosAcos :: Quater T -> Property-prop_CosAcos q = cos (acos q') =~= q'-    where-      q' = signum q+prop_CosAcos q = approxEq (qSpan q `max` qSpan q') q $ cos q'+  where+    q' = acos q  prop_TanAtan :: Quater T -> Property-prop_TanAtan q = tan (atan q') =~= q'-    where-      q' = sqrt (smaller q) -- because this inverse fun is fragile+prop_TanAtan q = approxEq (qSpan q `max` qSpan q') q $ tan q'+  where+    q' = atan q  prop_SinhAsinh :: Quater T -> Property-prop_SinhAsinh q = sinh (asinh q') =~= q'-    where-      q' = sqrt (smaller q) -- because this inverse fun is fragile+prop_SinhAsinh q = approxEq (qSpan q `max` qSpan q') q $ sinh q'+  where+    q' = asinh q  prop_CoshAcosh :: Quater T -> Property-prop_CoshAcosh q = cosh (acosh q) =~= q+prop_CoshAcosh q = approxEq (qSpan q `max` qSpan q') q $ cosh q'+  where+    q' = acosh q  prop_TanhAtanh :: Quater T -> Property-prop_TanhAtanh q = tanh (atanh q') =~= q'-    where-      q' = sqrt (smaller q) -- because this inverse fun is fragile+prop_TanhAtanh q = approxEq (qSpan q `max` qSpan q') q $ tanh q'+  where+    q' = atanh q  prop_SqrtSqr :: Quater T -> Property-prop_SqrtSqr q = sqrt q * sqrt q =~= q+prop_SqrtSqr q = approxEq (qSpan q) q $ sqrt q * sqrt q  prop_SinCos :: Quater T -> Property-prop_SinCos q = sin q' * sin q' + cos q' * cos q' =~= 1-    where-      q' = sqrt (smaller q) -- because it involves exponents+prop_SinCos q' = approxEq (qSpan s `max` qSpan c) 1 $ c * c + s * s+  where+    q = signum q' -- avoid exploding exponents+    s = sin q+    c = cos q  prop_SinhCosh :: Quater T -> Property-prop_SinhCosh q = cosh q' * cosh q' - sinh q' * sinh q' =~= 1-    where-      q' = sqrt (smaller q) -- because it involves exponents+prop_SinhCosh q' = approxEq (qSpan s `max` qSpan c) 1 $ c * c - s * s+  where+    q = signum q' -- avoid exploding exponents+    s = sinh q+    c = cosh q  prop_ReadShow :: Quater T -> Bool prop_ReadShow q = q == read (show q)
+ test/Numeric/Subroutine/SolveTriangularTest.hs view
@@ -0,0 +1,249 @@+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE GADTs               #-}+{-# LANGUAGE PolyKinds           #-}+{-# LANGUAGE RecordWildCards     #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell     #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE TypeOperators       #-}++module Numeric.Subroutine.SolveTriangularTest (runTests) where+++import Control.Monad.ST+import Numeric.Arbitraries+import Numeric.DataFrame+import Numeric.DataFrame.ST+import Numeric.Dimensions+import Numeric.Subroutine.SolveTriangular+import Test.QuickCheck+++arbitraryTriangular ::+       forall (n :: Nat) (m :: Nat)+     . (KnownDim n, KnownDim m, KnownBackend Double '[m])+    => Bool -> Gen (DataFrame Double '[n,m])+arbitraryTriangular upper = iwmap f <$> arbitrary+  where+    f :: Idxs '[n] -> DataFrame Double '[m] -> DataFrame Double '[m]+    f (Idx i :* U) x = iwmap g x+      where+        a = maxElem x+        g :: Idxs '[m] -> Scalar Double -> Scalar Double+        g (Idx j :* U) c+          | if upper then j < i else j > i = 0+          | j == i = if c >= 0 then c + 1 + a else c - 1 - a+          | otherwise = c++-- | Test Rx = b+testSolveUpperTriangularR ::+       forall (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (KnownDim n, KnownDim m, m <= n, Dimensions ds)+    => DataFrame Double '[n,m]     -- ^ R+    -> DataFrame Double  (n :+ ds) -- ^ b+    -> Property+testSolveUpperTriangularR r b+  | dn <- dim @n+  , dm <- dim @m+  , di@D <- dn `minusDim` dm `plusDim` D1+  , i0 <- (Idx 0 :* U) `inSpaceOf` (di :* U)+  , Just Dict <- sameDim (plusDim dn D1) (plusDim di dm)+    = let bm :: DataFrame Double (m :+ ds)+          bm = slice i0 b+          x :: DataFrame Double (m :+ ds)+          x = runST $ do+            xPtr <- thawDataFrame bm+            solveUpperTriangularR r xPtr+            unsafeFreezeDataFrame xPtr+      in counterexample+          (unlines+            [ "failed Rx = b:"+            , "R: " ++ show r+            , "x: " ++ show x+            , "b: " ++ show b+            , "Rx:" ++ show (r %* x)+            ]+          ) (approxEq (maxElem r) b (r %* x))+testSolveUpperTriangularR _ _ = error "impossible pattern"++prop_SolveUpperTriangularR :: Property+prop_SolveUpperTriangularR = property run+  where+    run :: Gen Property+    run = do+      Dx (m@D :: Dim m) <- arbitrary :: Gen (Dim (XN 1))+      Dx (D   :: Dim n) <- arbitrary :: Gen (Dim (XN m))+      justVec           <- arbitrary :: Gen Bool+      SomeDims (Dims :: Dims ds)+                      <- if justVec+                         then pure (SomeDims U)+                         else removeDimsAbove 100 <$> arbitrary+      r <- arbitraryTriangular @n @m True+      b' <- arbitrary @(DataFrame Double (n :+ ds))+      let b = iwmap @_ @(n ': ds) @'[]+                (\(Idx i :* _) x -> if i >= dimVal m then 0 else x) b'+      return $ testSolveUpperTriangularR r b++-- | Test xR = b+testSolveUpperTriangularL ::+       forall (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (KnownDim n, KnownDim m, m <= n, Dimensions ds)+    => DataFrame Double  (ds +: m) -- ^ b+    -> DataFrame Double '[n,m] -- ^ r+    -> Property+testSolveUpperTriangularL b r+  | dn <- dim @n+  , dm <- dim @m+  , dnm@D  <- minusDim dn dm+  , Dims <- Snoc (dims @ds) dn+  , Dims <- Snoc (dims @ds) dm+  , Dict <- Dict @(SnocList ds n _)+  , Dict <- Dict @(SnocList ds m _)+  , Just Dict <- sameDim dn (plusDim dm dnm)+    = let padZeroes :: DataFrame Double (ds +: m) -> DataFrame Double (ds +: n)+          padZeroes = ewmap @_ @ds @'[n] $ \a -> appendDF a (0 `inSpaceOf` (dnm :* U))+          x :: DataFrame Double (ds +: n)+          x = runST $ do+            xPtr <- thawDataFrame b+            solveUpperTriangularL xPtr r+            padZeroes <$> unsafeFreezeDataFrame xPtr+      in  counterexample+            (unlines+              [ "failed xR = b:"+              , "R: " ++ show r+              , "x: " ++ show x+              , "b: " ++ show b+              , "xR:" ++ show (x %* r)+              ]+            ) (approxEq (maxElem r) b (x %* r))+testSolveUpperTriangularL _ _ = error "impossible pattern"++prop_SolveUpperTriangularL :: Property+prop_SolveUpperTriangularL = property run+  where+    run :: Gen Property+    run = do+      Dx (m@D :: Dim m) <- arbitrary :: Gen (Dim (XN 1))+      Dx (D   :: Dim n) <- arbitrary :: Gen (Dim (XN m))+      justVec           <- arbitrary :: Gen Bool+      SomeDims (ds@Dims :: Dims ds)+                      <- if justVec+                         then pure (SomeDims U)+                         else removeDimsAbove 100 <$> arbitrary+      Dims <- pure $ Snoc ds m+      r <- arbitraryTriangular @n @m True+      b <- arbitrary @(DataFrame Double (ds +: m))+      return $ testSolveUpperTriangularL b r+++-- | Test Lx = b+testSolveLowerTriangularR ::+       forall (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (KnownDim n, KnownDim m, n <= m, Dimensions ds)+    => DataFrame Double '[n,m]     -- ^ L+    -> DataFrame Double  (n :+ ds) -- ^ b+    -> Property+testSolveLowerTriangularR l b+  | dn <- dim @n+  , dm <- dim @m+  , dmn@D <- dm `minusDim` dn+  , Just Dict <- sameDim dm (dn `plusDim` dmn)+    = let padZeroes :: DataFrame Double (n :+ ds) -> DataFrame Double (m :+ ds)+          padZeroes z = appendDF z (0 :: DataFrame Double ((m-n) :+ ds))+          x :: DataFrame Double (m :+ ds)+          x = runST $ do+            xPtr <- thawDataFrame b+            solveLowerTriangularR l xPtr+            padZeroes <$> unsafeFreezeDataFrame xPtr+      in counterexample+          (unlines+            [ "failed Lx = b:"+            , "L: " ++ show l+            , "x: " ++ show x+            , "b: " ++ show b+            , "Lx:" ++ show (l %* x)+            ]+          ) (approxEq (maxElem l) b (l %* x))+testSolveLowerTriangularR _ _ = error "impossible pattern"++prop_SolveLowerTriangularR :: Property+prop_SolveLowerTriangularR = property run+  where+    run :: Gen Property+    run = do+      Dx (D :: Dim n) <- arbitrary :: Gen (Dim (XN 1))+      Dx (D :: Dim m) <- arbitrary :: Gen (Dim (XN n))+      justVec         <- arbitrary :: Gen Bool+      SomeDims (Dims :: Dims ds)+                      <- if justVec+                         then pure (SomeDims U)+                         else removeDimsAbove 100 <$> arbitrary+      l <- arbitraryTriangular @n @m False+      b <- arbitrary @(DataFrame Double (n :+ ds))+      return $ testSolveLowerTriangularR l b+++-- | Test xL = b+testSolveLowerTriangularL ::+       forall (n :: Nat) (m :: Nat) (ds :: [Nat])+     . (KnownDim n, KnownDim m, n <= m, Dimensions ds)+    => DataFrame Double  (ds +: m) -- ^ b+    -> DataFrame Double '[n,m] -- ^ L+    -> Property+testSolveLowerTriangularL b l+  | dn <- dim @n+  , dm <- dim @m+  , dmn@D  <- minusDim dm dn+  , Dims <- Snoc (dims @ds) dn+  , Dims <- Snoc (dims @ds) dm+  , Dict <- Dict @(SnocList ds n _)+  , Dict <- Dict @(SnocList ds m _)+  , Just Dict <- sameDim dm (plusDim dn dmn)+  , di@D <- dm `minusDim` dn `plusDim` D1+  , i0 <- (Idx 0 :* U) `inSpaceOf` (di :* U)+  , Just Dict <- sameDim (plusDim dm D1) (plusDim di dn)+    = let dropLast :: DataFrame Double (ds +: m) -> DataFrame Double (ds +: n)+          dropLast = ewmap @_ @ds @'[n] $ slice i0+          x :: DataFrame Double (ds +: n)+          x = runST $ do+            xPtr <- thawDataFrame b+            solveLowerTriangularL xPtr l+            dropLast <$> unsafeFreezeDataFrame xPtr+      in  counterexample+            (unlines+              [ "failed xL = b:"+              , "R: " ++ show l+              , "x: " ++ show x+              , "b: " ++ show b+              , "xL:" ++ show (x %* l)+              ]+            ) (approxEq (maxElem l) b (x %* l))+testSolveLowerTriangularL _ _ = error "impossible pattern"++prop_SolveLowerTriangularL :: Property+prop_SolveLowerTriangularL = property run+  where+    run :: Gen Property+    run = do+      Dx (n@D :: Dim n) <- arbitrary :: Gen (Dim (XN 1))+      Dx (m@D :: Dim m) <- arbitrary :: Gen (Dim (XN n))+      justVec           <- arbitrary :: Gen Bool+      SomeDims (ds@Dims :: Dims ds)+                      <- if justVec+                         then pure (SomeDims U)+                         else removeDimsAbove 100 <$> arbitrary+      Dims <- pure $ Snoc ds m+      Dict <- pure $ Dict @(SnocList ds m _)+      l <- arbitraryTriangular @n @m False+      b' <- arbitrary @(DataFrame Double (ds +: m))+      let b = ewmap @_ @ds @'[m]+                (iwmap @_ @'[m] @'[]+                  (\(Idx i :* _) x -> if i >= dimVal n then 0 else x)+                ) b'+      return $ testSolveLowerTriangularL b l++return []+runTests :: Int -> IO Bool+runTests n = $forAllProperties+  $ quickCheckWithResult stdArgs { maxSuccess = n }
test/Spec.hs view
@@ -5,11 +5,16 @@  import qualified Numeric.DataFrame.BasicTest import qualified Numeric.DataFrame.SubSpaceTest+import qualified Numeric.Matrix.BidiagonalTest+import qualified Numeric.Matrix.LUTest+import qualified Numeric.Matrix.QRTest+import qualified Numeric.Matrix.SVDTest import qualified Numeric.MatrixDoubleTest import qualified Numeric.MatrixFloatTest import qualified Numeric.PrimBytesTest import qualified Numeric.QuaterDoubleTest import qualified Numeric.QuaterFloatTest+import qualified Numeric.Subroutine.SolveTriangularTest   -- | Collection of tests in detailed-0.9 format@@ -22,9 +27,15 @@   , test "QuaterDouble"       $ Numeric.QuaterDoubleTest.runTests n   , test "QuaterFloat"        $ Numeric.QuaterFloatTest.runTests n   , test "PrimBytes"          $ Numeric.PrimBytesTest.runTests n+  , test "Matrix.LU"          $ Numeric.Matrix.LUTest.runTests n+  , test "Matrix.QR"          $ Numeric.Matrix.QRTest.runTests n+  , test "Matrix.Bidiagonal"  $ Numeric.Matrix.BidiagonalTest.runTests n+  , test "Matrix.SVD"         $ Numeric.Matrix.SVDTest.runTests n+  , test "Subroutine.SolveTriangular"+                              $ Numeric.Subroutine.SolveTriangularTest.runTests n   ]   where-    n = 1000 :: Int+    n = 1000  :: Int