packages feed

emd 0.1.0.0 → 0.1.1.0

raw patch · 5 files changed

+198/−40 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

+ Numeric.EMD.Unsized: EMD :: ![v a] -> !(v a) -> EMD v a
+ Numeric.EMD.Unsized: EO :: SiftCondition a -> SplineEnd -> Bool -> EMDOpts a
+ Numeric.EMD.Unsized: SCAnd :: (SiftCondition a) -> (SiftCondition a) -> SiftCondition a
+ Numeric.EMD.Unsized: SCOr :: (SiftCondition a) -> (SiftCondition a) -> SiftCondition a
+ Numeric.EMD.Unsized: SCStdDev :: a -> SiftCondition a
+ Numeric.EMD.Unsized: SCTimes :: Int -> SiftCondition a
+ Numeric.EMD.Unsized: SENatural :: SplineEnd
+ Numeric.EMD.Unsized: SENotAKnot :: SplineEnd
+ Numeric.EMD.Unsized: SRIMF :: !(v a) -> !Int -> SiftResult v a
+ Numeric.EMD.Unsized: SRResidual :: !(v a) -> SiftResult v a
+ Numeric.EMD.Unsized: [emdIMFs] :: EMD v a -> ![v a]
+ Numeric.EMD.Unsized: [emdResidual] :: EMD v a -> !(v a)
+ Numeric.EMD.Unsized: [eoClampEnvelope] :: EMDOpts a -> Bool
+ Numeric.EMD.Unsized: [eoSiftCondition] :: EMDOpts a -> SiftCondition a
+ Numeric.EMD.Unsized: [eoSplineEnd] :: EMDOpts a -> SplineEnd
+ Numeric.EMD.Unsized: data EMD v a
+ Numeric.EMD.Unsized: data EMDOpts a
+ Numeric.EMD.Unsized: data SiftCondition a
+ Numeric.EMD.Unsized: data SiftResult v a
+ Numeric.EMD.Unsized: data SplineEnd
+ Numeric.EMD.Unsized: defaultEO :: Fractional a => EMDOpts a
+ Numeric.EMD.Unsized: defaultSC :: Fractional a => SiftCondition a
+ Numeric.EMD.Unsized: emd :: (Vector v a, Fractional a, Ord a) => EMDOpts a -> v a -> Maybe (EMD v a)
+ Numeric.EMD.Unsized: emd' :: (Vector v a, Ord a, Fractional a, Applicative m) => (SiftResult v a -> m r) -> EMDOpts a -> v a -> m (Maybe (EMD v a))
+ Numeric.EMD.Unsized: emdTrace :: (Vector v a, Fractional a, Ord a, MonadIO m) => EMDOpts a -> v a -> m (Maybe (EMD v a))
+ Numeric.EMD.Unsized: instance GHC.Show.Show (v a) => GHC.Show.Show (Numeric.EMD.Unsized.EMD v a)
+ Numeric.EMD.Unsized: sift :: (Vector v a, Fractional a, Ord a) => EMDOpts a -> v a -> Maybe (SiftResult v a)
- Numeric.EMD: emd :: (Vector v a, KnownNat n, Fractional a, Ord a) => EMDOpts a -> Vector v (n + 2) a -> EMD v (n + 2) a
+ Numeric.EMD: emd :: (Vector v a, KnownNat n, Fractional a, Ord a) => EMDOpts a -> Vector v (n + 1) a -> EMD v (n + 1) a
- Numeric.EMD: emd' :: (Vector v a, KnownNat n, Fractional a, Ord a, Applicative m) => (SiftResult v (n + 2) a -> m r) -> EMDOpts a -> Vector v (n + 2) a -> m (EMD v (n + 2) a)
+ Numeric.EMD: emd' :: (Vector v a, KnownNat n, Fractional a, Ord a, Applicative m) => (SiftResult v (n + 1) a -> m r) -> EMDOpts a -> Vector v (n + 1) a -> m (EMD v (n + 1) a)
- Numeric.EMD: emdTrace :: (Vector v a, KnownNat n, Fractional a, Ord a, MonadIO m) => EMDOpts a -> Vector v (n + 2) a -> m (EMD v (n + 2) a)
+ Numeric.EMD: emdTrace :: (Vector v a, KnownNat n, Fractional a, Ord a, MonadIO m) => EMDOpts a -> Vector v (n + 1) a -> m (EMD v (n + 1) a)
- Numeric.EMD: envelopes :: (Vector v a, KnownNat n, Fractional a, Ord a) => SplineEnd -> Bool -> Vector v (n + 2) a -> Maybe (Vector v (n + 2) a, Vector v (n + 2) a)
+ Numeric.EMD: envelopes :: (Vector v a, KnownNat n, Fractional a, Ord a) => SplineEnd -> Bool -> Vector v (n + 1) a -> Maybe (Vector v (n + 1) a, Vector v (n + 1) a)
- Numeric.EMD: sift :: (Vector v a, KnownNat n, Fractional a, Ord a) => EMDOpts a -> Vector v (n + 2) a -> SiftResult v (n + 2) a
+ Numeric.EMD: sift :: (Vector v a, KnownNat n, Fractional a, Ord a) => EMDOpts a -> Vector v (n + 1) a -> SiftResult v (n + 1) a

Files

CHANGELOG.md view
@@ -1,6 +1,15 @@ Changelog ========= +Version 0.1.1.0+---------------++*July 25, 2018*++<https://github.com/mstksg/emd/releases/tag/v0.1.1.0>++*   Unsized interface added.+ Version 0.1.0.0 --------------- 
emd.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 4cb66d27d7d3fcb9f625c87b73448433636262d9476571553b667d1a0f998496+-- hash: 1007f571ef708a0ed8f93f4737361b9f0bfea8a807a6072e8501352715a67175  name:           emd-version:        0.1.0.0+version:        0.1.1.0 synopsis:       Empirical Mode Decomposition (Hilbert-Huang Transform) description:    Please see the README on GitHub at <https://github.com/mstksg/emd#readme> category:       Math@@ -32,6 +32,7 @@   exposed-modules:       Numeric.EMD       Numeric.EMD.Internal.Spline+      Numeric.EMD.Unsized   other-modules:       Numeric.EMD.Internal.Tridiagonal       Numeric.EMD.Internal.Extrema
src/Numeric/EMD.hs view
@@ -24,6 +24,20 @@ -- used to help track down a specific IMF that might be taking more time -- than desired. --+-- This package uses "sized vectors" as its main interface, to ensure:+--+-- 1.  The resulting 'EMD' contains IMFs that are all the same length as+--     the input vector+-- 2.  We provide a vector of size of at least one.+--+-- There are many functions to convert unsized vectors to sized vectors in+-- "Data.Vector.Sized" and associated modules, including 'toSized' (for+-- when you know the size at compile-time) and 'withSized' (for when you+-- don't).+--+-- However, for convenience, "Numeric.EMD.Unsized" is provided with an+-- unsafe unsized interface.+--  module Numeric.EMD (   -- * EMD (Hilbert-Huang Transform)@@ -101,10 +115,16 @@  -- | EMD decomposition (Hilbert-Huang Transform) of a given time series -- with a given sifting stop condition.+--+-- Takes a sized vector to ensure that:+--+-- 1.  The resulting 'EMD' contains IMFs that are all the same length as+--     the input vector+-- 2.  We provide a vector of size of at least one. emd :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)     => EMDOpts a-    -> SVG.Vector v (n + 2) a-    -> EMD v (n + 2) a+    -> SVG.Vector v (n + 1) a+    -> EMD v (n + 1) a emd eo = runIdentity . emd' (const (pure ())) eo  -- | 'emd', but tracing results to stdout as IMFs are found.  Useful for@@ -112,8 +132,8 @@ emdTrace     :: (VG.Vector v a, KnownNat n, Fractional a, Ord a, MonadIO m)     => EMDOpts a-    -> SVG.Vector v (n + 2) a-    -> m (EMD v (n + 2) a)+    -> SVG.Vector v (n + 1) a+    -> m (EMD v (n + 1) a) emdTrace = emd' $ \case     SRResidual _ -> liftIO $ putStrLn "Residual found."     SRIMF _ i    -> liftIO $ printf "IMF found (%d iterations)\n" i@@ -121,10 +141,10 @@ -- | 'emd' with a callback for each found IMF. emd'     :: (VG.Vector v a, KnownNat n, Fractional a, Ord a, Applicative m)-    => (SiftResult v (n + 2) a -> m r)+    => (SiftResult v (n + 1) a -> m r)     -> EMDOpts a-    -> SVG.Vector v (n + 2) a-    -> m (EMD v (n + 2) a)+    -> SVG.Vector v (n + 1) a+    -> m (EMD v (n + 1) a) emd' cb eo = go id   where     go !imfs !v = cb res *> case res of@@ -136,14 +156,14 @@ -- | The result of a sifting operation.  Each sift either yields -- a residual, or a new IMF. data SiftResult v n a = SRResidual !(SVG.Vector v n a)-                      | SRIMF      !(SVG.Vector v n a) !Int   -- number of iterations+                      | SRIMF      !(SVG.Vector v n a) !Int   -- ^ number of iterations  -- | Iterated sifting process, used to produce either an IMF or a residual. sift     :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)     => EMDOpts a-    -> SVG.Vector v (n + 2) a-    -> SiftResult v (n + 2) a+    -> SVG.Vector v (n + 1) a+    -> SiftResult v (n + 1) a sift EO{..} = go 1   where     go !i !v = case sift' eoSplineEnd eoClampEnvelope v of@@ -157,8 +177,8 @@     :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)     => SplineEnd     -> Bool-    -> SVG.Vector v (n + 2) a-    -> Maybe (SVG.Vector v (n + 2) a)+    -> SVG.Vector v (n + 1) a+    -> Maybe (SVG.Vector v (n + 1) a) sift' se cl v = go <$> envelopes se cl v   where     go (mins, maxs) = SVG.zipWith3 (\x mi ma -> x - (mi + ma)/2) v mins maxs@@ -170,8 +190,8 @@     :: (VG.Vector v a, KnownNat n, Fractional a, Ord a)     => SplineEnd     -> Bool-    -> SVG.Vector v (n + 2) a-    -> Maybe (SVG.Vector v (n + 2) a, SVG.Vector v (n + 2) a)+    -> SVG.Vector v (n + 1) a+    -> Maybe (SVG.Vector v (n + 1) a, SVG.Vector v (n + 1) a) envelopes se cl xs = (,) <$> splineAgainst se mins'                          <*> splineAgainst se maxs'   where
src/Numeric/EMD/Internal/Spline.hs view
@@ -43,11 +43,11 @@                | SENatural   deriving (Show, Eq, Ord) -data SplineCoef a = SC { scAlpha  :: !a      -- ^ a-                       , scBeta   :: !a      -- ^ b-                       , scGamma0 :: !a      -- ^ y_{i-1}-                       , scGamma1 :: !a      -- ^ y_i-                       , scDelta  :: !a      -- ^ x_i - x_{i-1}+data SplineCoef a = SC { _scAlpha  :: !a      -- ^ a+                       , _scBeta   :: !a      -- ^ b+                       , _scGamma0 :: !a      -- ^ y_{i-1}+                       , _scGamma1 :: !a      -- ^ y_i+                       , _scDelta  :: !a      -- ^ x_i - x_{i-1}                        }   deriving Show @@ -90,44 +90,43 @@     => SplineEnd     -> M.Map a a            -- ^ (x, y)     -> Maybe (Spline a)-makeSpline se ps = do-    (xy0, ps') <- M.minViewWithKey ps-    SV.withSizedList (M.toList ps') $ \(xsys :: SV.Vector n (a, a)) -> do+makeSpline se ps = SV.withSizedList (M.toList ps) $ \(xsys :: SV.Vector n (a, a)) -> do       Refl <- Proxy @1 `isLE` Proxy @n-      let xs, ys :: SV.Vector (n + 1) a-          (xs, ys) = SV.unzip $ xy0 `SV.cons` xsys-          dxs, dys :: SV.Vector n a+      Refl <- Proxy @2 `isLE` Proxy @n+      let xs, ys :: SV.Vector n a+          (xs, ys) = SV.unzip xsys+          dxs, dys :: SV.Vector (n - 1) a           dxs = SV.tail xs - SV.init xs-          rdxs :: SV.Vector n a+          rdxs :: SV.Vector (n - 1) a           rdxs = recip dxs-          rdxssq :: SV.Vector n a+          rdxssq :: SV.Vector (n - 1) a           rdxssq = rdxs * rdxs           dys  = SV.tail ys - SV.init ys           dydxssq = dys * rdxssq-          mainDiag :: SV.Vector (n - 1) a+          mainDiag :: SV.Vector (n - 2) a           mainDiag = SV.zipWith (\rdx0 rdx1 -> 2 * ( rdx0 + rdx1 ))                         (SV.init rdxs)                         (SV.tail rdxs)-          lowerDiag :: SV.Vector (n - 1) a+          lowerDiag :: SV.Vector (n - 2) a           lowerDiag = SV.take rdxs-          upperDiag :: SV.Vector (n - 1) a+          upperDiag :: SV.Vector (n - 2) a           upperDiag = SV.tail rdxs-          rhs :: SV.Vector (n - 1) a+          rhs :: SV.Vector (n - 2) a           rhs = SV.zipWith (\dydxsq0 dydxsq1 -> 3 * (dydxsq0 + dydxsq1))                         (SV.init dydxssq)                         (SV.tail dydxssq)           EE{..} = case se of             SENotAKnot -> notAKnot rdxs rdxssq dydxssq             SENatural  -> natural rdxs dydxssq-      solution <- solveTridiagonal (lowerDiag `SV.snoc` eeLower1)-                                   (eeMain0 `SV.cons` mainDiag `SV.snoc` eeMain1)-                                   (eeUpper0 `SV.cons` upperDiag)-                                   (eeRhs0 `SV.cons` rhs `SV.snoc` eeRhs1)-      let as :: SV.Vector n a+      solution <- solveTridiagonal (                    lowerDiag `SV.snoc` eeLower1)+                                   (eeMain0   `SV.cons` mainDiag  `SV.snoc` eeMain1 )+                                   (eeUpper0  `SV.cons` upperDiag                   )+                                   (eeRhs0    `SV.cons` rhs       `SV.snoc` eeRhs1  )+      let as :: SV.Vector (n - 1) a           as = SV.zipWith3 (\k dx dy -> k * dx - dy) (SV.init solution) dxs dys-          bs :: SV.Vector n a+          bs :: SV.Vector (n - 1) a           bs = SV.zipWith3 (\k dx dy -> - k * dx + dy) (SV.tail solution) dxs dys-          coefs :: SV.Vector n (a, SplineCoef a)+          coefs :: SV.Vector (n - 1) (a, SplineCoef a)           coefs = SV.zipWith6 (\x α β γ0 γ1 δ -> (x, SC α β γ0 γ1 δ))                     (SV.init xs) as bs (SV.init ys) (SV.tail ys) dxs 
+ src/Numeric/EMD/Unsized.hs view
@@ -0,0 +1,129 @@+{-# LANGUAGE DataKinds                                #-}+{-# LANGUAGE GADTs                                    #-}+{-# LANGUAGE LambdaCase                               #-}+{-# LANGUAGE ScopedTypeVariables                      #-}+{-# LANGUAGE TypeApplications                         #-}+{-# LANGUAGE TypeOperators                            #-}+{-# OPTIONS_GHC -fplugin GHC.TypeLits.KnownNat.Solver #-}+{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise       #-}++-- |+-- Module      : Numeric.EMD.Unsized+-- Copyright   : (c) Justin Le 2018+-- License     : BSD3+--+-- Maintainer  : justin@jle.im+-- Stability   : experimental+-- Portability : non-portable+--+-- Interface of "Numeric.EMD" re-exported in a non-typesafe "unsized" form.+-- Can be more convenient in certain situations, but "Numeric.EMD" is+-- recommended and preferred.+--+++module Numeric.EMD.Unsized (+  -- -- * EMD (Hilbert-Huang Transform)+    emd+  , emdTrace+  , emd'+  , EMD(..)+  , E.EMDOpts(..), E.defaultEO, E.SiftCondition(..), E.defaultSC, E.SplineEnd(..)+  -- -- * Internal+  , sift, SiftResult(..)+  -- , envelopes+  ) where++import           Control.Monad.IO.Class+import           Data.Proxy+import           Data.Type.Equality+import           GHC.TypeLits.Compare+import           GHC.TypeNats+import qualified Data.Vector.Generic       as VG+import qualified Data.Vector.Generic.Sized as SVG+import qualified Numeric.EMD               as E++-- | An @'EMD' v a@ is a Hilbert-Huang transform of a time series with+-- items of type @a@ stored in a vector @v@.+data EMD v a = EMD { emdIMFs     :: ![v a]+                   , emdResidual :: !(v a)+                   }+  deriving Show++-- | The result of a sifting operation.  Each sift either yields+-- a residual, or a new IMF.+data SiftResult v a = SRResidual !(v a)+                    | SRIMF      !(v a) !Int   -- ^ number of iterations+++-- | EMD decomposition (Hilbert-Huang Transform) of a given time series+-- with a given sifting stop condition.+--+-- Returns 'Nothing' if given an empty vector.+--+-- See 'Numeric.EMD.emd' for a type-safe version with guaruntees on the+-- output vector sizes.+emd :: (VG.Vector v a, Fractional a, Ord a)+    => E.EMDOpts a+    -> v a+    -> Maybe (EMD v a)+emd eo v = SVG.withSized v $ \(v' :: SVG.Vector v n a) -> do+    Refl <- Proxy @1 `isLE` Proxy @n+    pure . convertEMD $ E.emd @_ @_ @(n - 1) eo v'++-- | 'emd', but tracing results to stdout as IMFs are found.  Useful for+-- debugging to see how long each step is taking.+--+-- Returns 'Nothing' if given an empty vector.+emdTrace+    :: (VG.Vector v a, Fractional a, Ord a, MonadIO m)+    => E.EMDOpts a+    -> v a+    -> m (Maybe (EMD v a))+emdTrace eo v = SVG.withSized v $ \(v' :: SVG.Vector v n a) ->+    case Proxy @1 `isLE` Proxy @n of+      Nothing   -> pure Nothing+      Just Refl -> Just . convertEMD <$> E.emdTrace @_ @_ @(n - 1) eo v'++-- | 'emd' with a callback for each found IMF.+--+-- Returns 'Nothing' if given an empty vector.+emd'+    :: (VG.Vector v a, Ord a, Fractional a, Applicative m)+    => (SiftResult v a -> m r)+    -> E.EMDOpts a+    -> v a+    -> m (Maybe (EMD v a))+emd' cb eo v = SVG.withSized v $ \(v' :: SVG.Vector v n a) ->+    case Proxy @1 `isLE` Proxy @n of+      Nothing   -> pure Nothing+      Just Refl -> Just . convertEMD <$> E.emd' @_ @_ @(n - 1) (cb . convertSR) eo v'++-- emd' cb eo = go id+--   where+--     go !imfs !v = cb res *> case res of+--         SRResidual r -> pure $ EMD (imfs []) r+--         SRIMF v' _   -> go (imfs . (v':)) (v - v')+--       where+--         res = sift eo v++-- | Iterated sifting process, used to produce either an IMF or a residual.+--+-- Returns 'Nothing' if given an empty vector.+sift+    :: (VG.Vector v a, Fractional a, Ord a)+    => E.EMDOpts a+    -> v a+    -> Maybe (SiftResult v a)+sift eo v = SVG.withSized v $ \(v' :: SVG.Vector v n a) -> do+    Refl <- Proxy @1 `isLE` Proxy @n+    pure $ convertSR . E.sift @_ @_ @(n - 1) eo $ v'++convertSR :: E.SiftResult v n a -> SiftResult v a+convertSR = \case+    E.SRResidual v -> SRResidual $ SVG.fromSized v+    E.SRIMF v i    -> SRIMF (SVG.fromSized v) i++convertEMD :: E.EMD v n a -> EMD v a+convertEMD (E.EMD is r) = EMD (SVG.fromSized <$> is) (SVG.fromSized r)+