packages feed

vector-space-map 0.1.0.1 → 0.2.0

raw patch · 3 files changed

+45/−33 lines, 3 filesdep +doctestdep ~basedep ~vector-spacePVP ok

version bump matches the API change (PVP)

Dependencies added: doctest

Dependency ranges changed: base, vector-space

API changes (from Hackage documentation)

- Data.Map.Vector: instance (AdditiveGroup v, Ord k) => AdditiveGroup (MapVector k v)
- Data.Map.Vector: instance (Data k, Data v, Ord k) => Data (MapVector k v)
- Data.Map.Vector: instance (Eq k, Eq v) => Eq (MapVector k v)
- Data.Map.Vector: instance (Ord k, AdditiveGroup v, Num v) => Num (MapVector k v)
- Data.Map.Vector: instance (Ord k, Read k, Read v) => Read (MapVector k v)
- Data.Map.Vector: instance (Ord k, VectorSpace v) => VectorSpace (MapVector k v)
- Data.Map.Vector: instance (Ord k, VectorSpace v, InnerSpace v, AdditiveGroup (Scalar v)) => InnerSpace (MapVector k v)
- Data.Map.Vector: instance (Show k, Show v) => Show (MapVector k v)
- Data.Map.Vector: instance Foldable (MapVector k)
- Data.Map.Vector: instance Functor (MapVector k)
- Data.Map.Vector: instance Ord k => Applicative (MapVector k)
- Data.Map.Vector: instance Traversable (MapVector k)
- Data.Map.Vector: instance Typeable2 MapVector
+ Data.Map.Vector: instance (Data.AdditiveGroup.AdditiveGroup v, GHC.Classes.Ord k) => Data.AdditiveGroup.AdditiveGroup (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (Data.Data.Data k, Data.Data.Data v, GHC.Classes.Ord k) => Data.Data.Data (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Classes.Eq k, GHC.Classes.Eq v) => GHC.Classes.Eq (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Classes.Ord k, Data.Basis.HasBasis v, Data.AdditiveGroup.AdditiveGroup (Data.VectorSpace.Scalar v)) => Data.Basis.HasBasis (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Classes.Ord k, Data.VectorSpace.VectorSpace v) => Data.VectorSpace.VectorSpace (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Classes.Ord k, Data.VectorSpace.VectorSpace v, Data.VectorSpace.InnerSpace v, Data.AdditiveGroup.AdditiveGroup (Data.VectorSpace.Scalar v)) => Data.VectorSpace.InnerSpace (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Classes.Ord k, GHC.Base.Monoid v) => GHC.Base.Monoid (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Classes.Ord k, GHC.Read.Read k, GHC.Read.Read v) => GHC.Read.Read (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance (GHC.Show.Show k, GHC.Show.Show v) => GHC.Show.Show (Data.Map.Vector.MapVector k v)
+ Data.Map.Vector: instance Data.Foldable.Foldable (Data.Map.Vector.MapVector k)
+ Data.Map.Vector: instance Data.Traversable.Traversable (Data.Map.Vector.MapVector k)
+ Data.Map.Vector: instance GHC.Base.Functor (Data.Map.Vector.MapVector k)
+ Data.Map.Vector: instance GHC.Classes.Ord k => GHC.Base.Applicative (Data.Map.Vector.MapVector k)

Files

+ doctests.hs view
@@ -0,0 +1,2 @@+import Test.DocTest
+main = doctest ["-isrc", "src/Data/Map/Vector.hs"]
src/Data/Map/Vector.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE TypeFamilies, FlexibleContexts #-}
 {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable, DeriveDataTypeable #-}
+{-# LANGUAGE TupleSections #-}
 module Data.Map.Vector (MapVector(..)) where
 
 import Prelude hiding (foldr)
@@ -7,8 +8,10 @@ import Data.Traversable
 import Data.Data
 import Control.Applicative
+import Control.Arrow
 import Data.AdditiveGroup
 import Data.VectorSpace
+import Data.Basis
 import Data.Map (Map)
 import qualified Data.Map as Map
 
@@ -17,16 +20,15 @@ -- | Note: '<*>' in the 'Applicative' instance operates under /intersection/.  i.e.:
 --
 -- >>> (MapVector $ Map.fromList [("x", id)]) <*> (MapVector $ Map.fromList [("y", 3)])
--- MapVector (Map.fromList [])
+-- MapVector (fromList [])
 --  
--- '*' in the 'Num' instance performs elementwise multiplication.  It is defined in terms of
--- '<*>' and therefore also operates under intersection:
+-- Use the 'Applicative' instance for elementwise operations:
 --   
--- >>> (MapVector $ Map.fromList [("x", 2), ("y", 3)]) * (MapVector $ Map.fromList [("x", 5),("y", 7)])
--- MapVector (Map.fromList [("x", 10), ("y", 21)])
+-- >>> liftA2 (*) (MapVector $ Map.fromList [("x", 2), ("y", 3)]) (MapVector $ Map.fromList [("x", 5),("y", 7)])
+-- MapVector (fromList [("x",10),("y",21)])
 --   
--- >>> (MapVector $ Map.fromList [("x", 2), ("y", 3)]) * (MapVector $ Map.fromList [("y", 7)])
--- MapVector (Map.fromList [("y", 21)])
+-- >>> liftA2 (*) (MapVector $ Map.fromList [("x", 2), ("y", 3)]) (MapVector $ Map.fromList [("y", 7)])
+-- MapVector (fromList [("y",21)])
 --
 -- '*^' in the 'VectorSpace' instance multiplies by the scalar of v.  Nesting MapVectors preserves
 -- the scalar type, e.g. @Scalar (MapVector k (MapVector k' v))@ = @Scalar v@.
@@ -42,13 +44,18 @@ -- >>> (pure . MapVector $ Map.fromList [("x", 2 :: Int), ("y", 3)]) <.> (MapVector $ Map.fromList [("a", pure (5::Int))])
 -- 25
 --
--- Addition, using either '+' or '^+^', operates under union.
+-- Addition with '^+^' operates under union.
 
 data MapVector k v = 
       MapVector (Map k v) 
     | ConstantMap v -- ^ An infinite-dimensional vector with the same value on all dimensions
     deriving (Eq, Functor, Show, Read, Foldable, Traversable, Typeable, Data)
 
+-- | Respects the inner 'Monoid', unlike 'Map'.
+instance (Ord k, Monoid v) => Monoid (MapVector k v) where
+    mempty  = pure mempty
+    mappend = liftA2 mappend
+  
 instance (Ord k) => Applicative (MapVector k) where 
     pure = ConstantMap
     (ConstantMap f) <*> (ConstantMap v) = ConstantMap $ f v
@@ -79,24 +86,22 @@     (MapVector vs)  <.> (MapVector vs')  = foldl' (^+^) zeroV $ Map.intersectionWith (<.>) vs vs'
     {-# INLINABLE (<.>) #-}
 
-instance (Ord k, AdditiveGroup v, Num v) => Num (MapVector k v) where
-    (+) = (^+^)
-    {-# INLINE (+) #-}
-    x * y = (*) <$> x <*> y
-    {-# INLINE (*) #-}
-    abs = fmap abs
-    {-# INLINE abs #-}
-    fromInteger = pure . fromInteger
-    signum = error "no signum for MapVectors"
-
--- It looks like a HasBasis instance should be possible; 
--- I just haven't spent the time to figure it out.
+instance (Ord k, HasBasis v, AdditiveGroup (Scalar v)) => HasBasis (MapVector k v) where
+    type Basis (MapVector k v) = (k, Basis v)
 
--- (Remember to tighten version bounds on vector-space if this is implemented.)
+    basisValue (k, v) = MapVector $ Map.fromList $ (k, basisValue v):[]
+    
+    decompose (MapVector vs)
+      = Map.toList (decompose<$>vs) >>= \(k,vs) -> first(k,)<$>vs
+    decompose (ConstantMap _) = error "decompose: not defined for ConstantMap.\
+          \ Use decompose', which works properly on infinite-dimensional spaces."
+       -- Note that it would be possible to properly implement 'decompose' under
+       -- the additional constraint that the keys are enumerable. See e.g. the
+       -- @universe-base@ package.
 
---instance (Ord k, HasBasis v) => HasBasis (MapVector k v) where
---    type Basis (MapVector k v) = (k, Basis v)
---    basisValue (k, v) = MapVector $ Map.fromList $ (k, basisValue v):[]
---    
---    decompose (ConstantMap _) = error "decompose: not defined for ConstantMap"
---    decompose (MapVector vs) =  
+    decompose' (MapVector vs) (k,bv) = case Map.lookup k vs of
+         Nothing -> zeroV
+         Just v  -> decompose' v bv
+    decompose' (ConstantMap c) (_,bv) = decompose' c bv
+    
+    
vector-space-map.cabal view
@@ -2,9 +2,9 @@ -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                vector-space-map
-version:             0.1.0.1
+version:             0.2.0
 synopsis:            vector-space operations for finite maps using Data.Map
-description:         Data.Map.Vector provides @MapVector@, a wrapper around @Map@ from @containers@ which supports constant maps, i.e. maps containing only one value.  This allows an identity under intersection and an @Applicative@ instance.  It also has instances of @AdditiveGroup@, @VectorSpace@, @InnerSpace@, and @Num@ with appropriate value types.  Provides operations for addition, subtraction, element-wise multiplication (through @Num@), scalar multiplication (through @VectorSpace@), and dot product.
+description:         Data.Map.Vector provides @MapVector@, a wrapper around @Map@ from @containers@ which supports constant maps, i.e. maps containing only one value.  This allows an identity under intersection and an @Applicative@ instance.  It also has instances of @AdditiveGroup@, @VectorSpace@, @InnerSpace@, and @HasBasis@ with appropriate value types.  Provides operations for addition, subtraction, element-wise operations (through @Applicative@), scalar multiplication (through @VectorSpace@), and dot product.  Also consider Conal Elliott's @total-map@ package.
 homepage:            https://github.com/conklech/vector-space-map
 license:             MIT
 license-file:        LICENSE
@@ -13,7 +13,7 @@ 
 category:            Math
 build-type:          Simple
-cabal-version:       >=1.6
+cabal-version:       >=1.8
 
 source-repository    head
   type:              git
@@ -22,10 +22,15 @@ source-repository    this
   type:              git
   location:          git://github.com/conklech/vector-space-map.git  
-  tag:               0.1.0.1
+  tag:               0.2.0
 
 library
   hs-source-dirs:    src
   exposed-modules:   Data.Map.Vector 
-  build-depends:     base < 5, containers < 0.6, vector-space < 0.9
-                     +  build-depends:     base < 5, containers < 0.6, vector-space >= 0.5 && < 0.11
+
+test-suite doctests
+  type:          exitcode-stdio-1.0
+  ghc-options:   -threaded
+  main-is:       doctests.hs
+  build-depends: base, doctest >= 0.8