packages feed

som 6.5.1 → 7.0.0

raw patch · 4 files changed

+137/−121 lines, 4 filesdep −base-unicode-symbols

Dependencies removed: base-unicode-symbols

Files

som.cabal view
@@ -1,5 +1,5 @@ name:           som-version:        6.5.1+version:        7.0.0 synopsis:       Self-Organising Maps description:    A Kohonen Self-organising Map (SOM) maps input patterns                  onto a regular grid (usually two-dimensional) where each@@ -28,7 +28,6 @@ library   hs-source-dirs:  src   build-depends:   base ==4.*,-                   base-unicode-symbols ==0.2.*,                    binary ==0.7.*,                    containers ==0.5.*,                    grid ==7.*,@@ -49,7 +48,6 @@                    test-framework ==0.8.*,                    som,                    grid ==7.*,-                   base-unicode-symbols ==0.2.*,                    MonadRandom ==0.1.*,                    random ==1.0.*   hs-source-dirs:  test
src/Data/Datamining/Clustering/DSOM.hs view
@@ -15,6 +15,9 @@ -- -- * Rougier, N. & Boniface, Y. (2011). Dynamic self-organising map. --   Neurocomputing, 74 (11), 1840-1847. +--+-- * Kohonen, T. (1982). Self-organized formation of topologically +--   correct feature maps. Biological Cybernetics, 43 (1), 59–69. ------------------------------------------------------------------------  module Data.Datamining.Clustering.DSOM
src/Data/Datamining/Clustering/SOM.hs view
@@ -34,18 +34,13 @@ -- -- * Kohonen, T. (1982). Self-organized formation of topologically  --   correct feature maps. Biological Cybernetics, 43 (1), 59–69.------ * Rougier, N. & Boniface, Y. (2011). Dynamic self-organising map.---   Neurocomputing, 74 (11), 1840-1847.  ------------------------------------------------------------------------  module Data.Datamining.Clustering.SOM   (     -- * Construction-    SOM,-    defaultSOM,-    customSOM,-    decayingGaussian,+    SOM(..),+    DecayingGaussian(..),     -- * Deconstruction     toGridMap,     -- * Advanced control@@ -55,7 +50,7 @@     setCounter   ) where -import Data.Datamining.Clustering.SOMInternal (SOM, defaultSOM,-  customSOM, decayingGaussian, toGridMap, trainNeighbourhood,-  incrementCounter, counter, setCounter)+import Data.Datamining.Clustering.SOMInternal (SOM(..),+  DecayingGaussian(..), toGridMap, trainNeighbourhood, incrementCounter,+  counter, setCounter) 
src/Data/Datamining/Clustering/SOMInternal.hs view
@@ -26,6 +26,57 @@ import GHC.Generics (Generic) import Prelude hiding (lookup) +class LearningFunction f where+  type LearningRate f+  rate :: f -> Int -> Int -> (LearningRate f)++-- | A typical learning function for classifiers.+--   @'DecayingGaussian' r0 rf w0 wf tf@ returns a bell curve-shaped+--   function. At time zero, the maximum learning rate (applied to the+--   BMU) is @r0@, and the neighbourhood width is @w0@. Over time the+--   bell curve shrinks and the learning rate tapers off, until at time+--   @tf@, the maximum learning rate (applied to the BMU) is @rf@,+--   and the neighbourhood width is @wf@. Normally the parameters+--   should be chosen such that:+--+--   * 0 < rf << r0 < 1+--+--   * 0 < wf << w0+--+--   * 0 < tf+--+--   where << means "is much smaller than" (not the Haskell @<<@+--   operator!)+data DecayingGaussian a = DecayingGaussian a a a a Int+  deriving (Eq, Show, Generic)++instance (Floating a, Fractional a, Num a) =>+         LearningFunction (DecayingGaussian a) where+  type LearningRate (DecayingGaussian a) = a+  rate (DecayingGaussian r0 rf w0 wf tf) t d = r * exp (-(d'*d')/(w*w))+    where a = t'/tf'+          r = r0 * ((rf/r0)**a)+          w = w0 * ((wf/w0)**a)+          t' = fromIntegral t+          tf' = fromIntegral tf+          d' = fromIntegral d++-- | A learning function that only updates the BMU and has a constant+--   learning rate.+data StepFunction a = StepFunction a deriving (Eq, Show, Generic)++instance (Fractional a) => LearningFunction (StepFunction a) where+  type LearningRate (StepFunction a) = a+  rate (StepFunction r) _ d = if d == 0 then r else 0.0++-- | A learning function that updates all nodes with the same, constant+--   learning rate. This can be useful for testing.+data ConstantFunction a = ConstantFunction a deriving (Eq, Show, Generic)++instance (Fractional a) => LearningFunction (ConstantFunction a) where+  type LearningRate (ConstantFunction a) = a+  rate (ConstantFunction r) _ _ = r+ -- | A Self-Organising Map (SOM). -- --   Although @SOM@ implements @GridMap@, most users will only need the@@ -39,19 +90,19 @@ --      just return an @error@). It would be problematic to implement --      them because the input SOM and the output SOM would have to have --      the same @Metric@ type.-data SOM gm k p = SOM+data SOM f gm k p = SOM   {     sGridMap :: gm p,-    sLearningFunction :: Int -> Int -> Metric p,+    sLearningFunction :: f,     sCounter :: Int-  } deriving Generic+  } deriving (Eq, Show, Generic) -instance (F.Foldable gm) => F.Foldable (SOM gm k) where+instance (F.Foldable gm) => F.Foldable (SOM f gm k) where   foldr f x g = F.foldr f x (sGridMap g) -instance (G.Grid (gm p)) => G.Grid (SOM gm k p) where-  type Index (SOM gm k p) = G.Index (gm p)-  type Direction (SOM gm k p) = G.Direction (gm p)+instance (G.Grid (gm p)) => G.Grid (SOM f gm k p) where+  type Index (SOM f gm k p) = G.Index (gm p)+  type Direction (SOM f gm k p) = G.Direction (gm p)   indices = G.indices . sGridMap   distance = G.distance . sGridMap   neighbours = G.neighbours . sGridMap@@ -62,8 +113,8 @@   null = G.null . sGridMap   nonNull = G.nonNull . sGridMap -instance (F.Foldable gm, GM.GridMap gm p, G.Grid (GM.BaseGrid gm p)) => GM.GridMap (SOM gm k) p where-  type BaseGrid (SOM gm k) p = GM.BaseGrid gm p+instance (F.Foldable gm, GM.GridMap gm p, G.Grid (GM.BaseGrid gm p)) => GM.GridMap (SOM f gm k) p where+  type BaseGrid (SOM f gm k) p = GM.BaseGrid gm p   toGrid = GM.toGrid . sGridMap   toMap = GM.toMap . sGridMap   mapWithKey = error "Not implemented"@@ -71,11 +122,13 @@     where gm = sGridMap s           gm' = GM.adjustWithKey f k gm -currentLearningFunction :: SOM gm k p -> (Int -> Metric p)-currentLearningFunction s = (sLearningFunction s) (sCounter s)+currentLearningFunction+  :: (LearningFunction f, LearningRate f ~ Metric p)+    => SOM f gm k p -> (Int -> Metric p)+currentLearningFunction s = (rate . sLearningFunction $ s) (sCounter s)  -- | Extracts the grid and current models from the SOM.-toGridMap :: GM.GridMap gm p => SOM gm k p -> gm p+toGridMap :: GM.GridMap gm p => SOM f gm k p -> gm p toGridMap = sGridMap  adjustNode@@ -90,28 +143,30 @@ --   the BMU and trains it and its neighbourhood. trainNeighbourhood   :: (Pattern p, G.Grid (gm p), GM.GridMap gm p,-      G.Index (GM.BaseGrid gm p) ~ G.Index (gm p)) =>-     SOM gm k p -> G.Index (gm p) -> p -> SOM gm k p+      G.Index (GM.BaseGrid gm p) ~ G.Index (gm p), LearningFunction f,+      LearningRate f ~ Metric p) =>+     SOM f gm k p -> G.Index (gm p) -> p -> SOM f gm k p trainNeighbourhood s bmu target = s { sGridMap=gm' }   where gm = sGridMap s         gm' = GM.mapWithKey (adjustNode gm f target bmu) gm         f = currentLearningFunction s -incrementCounter :: SOM gm k p -> SOM gm k p+incrementCounter :: SOM f gm k p -> SOM f gm k p incrementCounter s = setCounter (sCounter s + 1) s -counter :: SOM gm k p -> Int+counter :: SOM f gm k p -> Int counter = sCounter -setCounter :: Int -> SOM gm k p -> SOM gm k p+setCounter :: Int -> SOM f gm k p -> SOM f gm k p setCounter k s = s { sCounter = k }  justTrain   :: (Ord (Metric p), Pattern p, G.Grid (gm p),       GM.GridMap gm (Metric p), GM.GridMap gm p,       G.Index (GM.BaseGrid gm (Metric p)) ~ G.Index (gm p),-      G.Index (GM.BaseGrid gm p) ~ G.Index (gm p)) =>-     SOM gm k p -> p -> SOM gm k p+      G.Index (GM.BaseGrid gm p) ~ G.Index (gm p), LearningFunction f,+      LearningRate f ~ Metric p) =>+     SOM f gm k p -> p -> SOM f gm k p justTrain s p = trainNeighbourhood s bmu p   where ds = GM.toList . GM.map (p `difference`) . sGridMap $ s         bmu = fst . minimumBy (comparing snd) $ ds@@ -119,8 +174,9 @@ instance   (GM.GridMap gm p, k ~ G.Index (GM.BaseGrid gm p), Pattern p,   G.Grid (gm p), GM.GridMap gm (Metric p), k ~ G.Index (gm p),-  k ~ G.Index (GM.BaseGrid gm (Metric p)), Ord (Metric p)) =>-    Classifier (SOM gm) k p where+  k ~ G.Index (GM.BaseGrid gm (Metric p)), Ord (Metric p),+  LearningFunction f, LearningRate f ~ Metric p) =>+    Classifier (SOM f gm) k p where   toList = GM.toList . sGridMap   numModels = G.tileCount . sGridMap   models = GM.elems . sGridMap@@ -132,92 +188,56 @@           s' = trainNeighbourhood s bmu p  --- | Creates a classifier with a default (bell-shaped) learning---   function. Usage is @'defaultSOM' gm r0 rf w0 wf tf@, where:------   [@gm@] The geometry and initial models for this classifier.---   A reasonable choice here is @'lazyGridMap' g ps@, where @g@ is a---   @'HexHexGrid'@, and @ps@ is a set of random patterns.------   [@r0@] See description in @'decayingGaussian2'@.------   [@rf@] See description in @'decayingGaussian2'@.------   [@w0@] See description in @'decayingGaussian2'@.------   [@wf@] See description in @'decayingGaussian2'@.------   [@tf@] See description in @'decayingGaussian2'@.-defaultSOM-  :: Floating (Metric p) => gm p -> Metric p -> Metric p -> Metric p ->-     Metric p -> Int -> SOM gm k p-defaultSOM gm r0 rf w0 wf tf =-  SOM {-        sGridMap=gm,-        sLearningFunction=decayingGaussian2 r0 rf w0 wf tf,-        sCounter=0-      }---- | Creates a classifier with a custom learning function.---   Usage is @'customSOM' gm g@, where:------   [@gm@] The geometry and initial models for this classifier.---   A reasonable choice here is @'lazyGridMap' g ps@, where @g@ is a---   @'HexHexGrid'@, and @ps@ is a set of random patterns.------   [@f@] A function used to adjust the models in the classifier.---   This function will be invoked with two parameters.---   The first parameter will indicate how many patterns (or pattern---   batches) have previously been presented to this classifier.---   Typically this is used to make the learning rate decay over time.---   The second parameter to the function is the grid distance from---   the node being updated to the BMU (Best Matching Unit).---   The output is the learning rate for that node (the amount by---   which the node's model should be updated to match the target).---   The learning rate should be between zero and one.-customSOM :: gm p -> (Int -> Int -> Metric p) -> SOM gm k p-customSOM gm f =-  SOM {-        sGridMap=gm,-        sLearningFunction=f,-        sCounter=0-      }+-- -- | Creates a classifier with a default (bell-shaped) learning+-- --   function. Usage is @'defaultSOM' gm r0 rf w0 wf tf@, where:+-- --+-- --   [@gm@] The geometry and initial models for this classifier.+-- --   A reasonable choice here is @'lazyGridMap' g ps@, where @g@ is a+-- --   @'HexHexGrid'@, and @ps@ is a set of random patterns.+-- --+-- --   [@r0@] See description in @'decayingGaussian2'@.+-- --+-- --   [@rf@] See description in @'decayingGaussian2'@.+-- --+-- --   [@w0@] See description in @'decayingGaussian2'@.+-- --+-- --   [@wf@] See description in @'decayingGaussian2'@.+-- --+-- --   [@tf@] See description in @'decayingGaussian2'@.+-- defaultSOM+--   :: Floating (Metric p) => gm p -> Metric p -> Metric p -> Metric p ->+--      Metric p -> Int -> SOM f gm k p+-- defaultSOM gm r0 rf w0 wf tf =+--   SOM {+--         sGridMap=gm,+--         sLearningFunction=DecayingGaussian r0 rf w0 wf tf,+--         sCounter=0+--       } --- | Configures one possible learning function for classifiers.---   @'decayingGaussian' r0 w0 tMax@ returns a bell curve-shaped---   function. At time zero, the maximum learning rate (applied to the---   BMU) is @r0@, and the neighbourhood width is @w0@. Over time the---   neighbourhood width shrinks and the learning rate tapers off.-decayingGaussian-  :: Floating a => a -> a -> Int -> (Int -> Int -> a)-decayingGaussian r w0 tMax t d = r * s * exp (-(d'*d')/(2*w0*w0*s*s))-    where s = exp (-t'/tMax')-          t' = fromIntegral t-          tMax' = fromIntegral tMax-          d' = fromIntegral d+-- -- | Creates a classifier with a custom learning function.+-- --   Usage is @'customSOM' gm g@, where:+-- --+-- --   [@gm@] The geometry and initial models for this classifier.+-- --   A reasonable choice here is @'lazyGridMap' g ps@, where @g@ is a+-- --   @'HexHexGrid'@, and @ps@ is a set of random patterns.+-- --+-- --   [@f@] A function used to adjust the models in the classifier.+-- --   This function will be invoked with two parameters.+-- --   The first parameter will indicate how many patterns (or pattern+-- --   batches) have previously been presented to this classifier.+-- --   Typically this is used to make the learning rate decay over time.+-- --   The second parameter to the function is the grid distance from+-- --   the node being updated to the BMU (Best Matching Unit).+-- --   The output is the learning rate for that node (the amount by+-- --   which the node's model should be updated to match the target).+-- --   The learning rate should be between zero and one.+-- customSOM+--   :: (LearningFunction f, LearningRate f ~ Metric p)+--     => gm p -> f -> SOM f gm k p+-- customSOM gm f =+--   SOM {+--         sGridMap=gm,+--         sLearningFunction=f,+--         sCounter=0+--       } --- | Configures a typical learning function for classifiers.---   @'decayingGaussian' r0 rf w0 wf tf@ returns a bell curve-shaped---   function. At time zero, the maximum learning rate (applied to the---   BMU) is @r0@, and the neighbourhood width is @w0@. Over time the---   bell curve shrinks and the learning rate tapers off, until at time---   @tf@, the maximum learning rate (applied to the BMU) is @rf@,---   and the neighbourhood width is @wf@. Normally the parameters---   should be chosen such that:------   * 0 < rf << r0 < 1------   * 0 < wf << w0------   * 0 < tf------   where << means "is much smaller than" (not the Haskell @<<@---   operator!) -decayingGaussian2 :: Floating a => a -> a -> a -> a -> Int -> (Int -> Int -> a)-decayingGaussian2 r0 rf w0 wf tf t d = r * exp (-(d'*d')/(w*w))-    where a = t'/tf'-          r = r0 * ((rf/r0)**a)-          w = w0 * ((wf/w0)**a)-          t' = fromIntegral t-          tf' = fromIntegral tf-          d' = fromIntegral d