diff --git a/som.cabal b/som.cabal
--- a/som.cabal
+++ b/som.cabal
@@ -1,5 +1,5 @@
 Name:              som
-Version:           7.2.4
+Version:           7.3.0
 Stability:         experimental
 Synopsis:          Self-Organising Maps.
 Description:       A Kohonen Self-organising Map (SOM) maps input patterns 
@@ -33,12 +33,13 @@
 source-repository this
   type:     git
   location: https://github.com/mhwombat/som.git
-  tag:      7.2.4
+  tag:      7.3.0
 
 
 library
   hs-source-dirs:  src
   build-depends:   base ==4.*,
+                   containers ==0.5.*,
                    grid ==7.*,
                    MonadRandom ==0.3.*
   ghc-options:     -Wall
@@ -46,6 +47,8 @@
                    Data.Datamining.Clustering.SOMInternal,
                    Data.Datamining.Clustering.DSOM,
                    Data.Datamining.Clustering.DSOMInternal,
+                   Data.Datamining.Clustering.SSOM,
+                   Data.Datamining.Clustering.SSOMInternal,
                    Data.Datamining.Clustering.Classifier,
                    Data.Datamining.Pattern
 
@@ -56,6 +59,7 @@
                    QuickCheck ==2.7.*,
                    test-framework ==0.8.*,
                    som,
+                   containers ==0.5.*,
                    grid ==7.*,
                    MonadRandom ==0.3.*,
                    random ==1.1.*
diff --git a/src/Data/Datamining/Clustering/SSOM.hs b/src/Data/Datamining/Clustering/SSOM.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Datamining/Clustering/SSOM.hs
@@ -0,0 +1,46 @@
+------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Datamining.Clustering.SSOM
+-- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- License     :  BSD-style
+-- Maintainer  :  amy@nualeargais.ie
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- A Simplified Self-organising Map (SSOM). An SSOM maps input patterns
+-- onto a set, where each element in the set is a model of the input
+-- data. An SSOM is like a Kohonen Self-organising Map (SOM), except
+-- that instead of a grid, it uses a simple set of unconnected models.
+-- Since the models are unconnected, only the model that best matches
+-- the input is ever updated. This makes it faster, however,
+-- topological relationships within the input data are not preserved.
+-- This implementation supports the use of non-numeric patterns.
+--
+-- In layman's terms, a SSOM can be useful when you you want to build
+-- a set of models on some data. A tutorial is available at
+-- <https://github.com/mhwombat/som/wiki>.
+--
+-- References:
+--
+-- * de Buitléir, Amy, Russell, Michael and Daly, Mark. (2012). Wains:
+--   A pattern-seeking artificial life species. Artificial Life, 18 (4),
+--   399-423. 
+-- 
+-- * Kohonen, T. (1982). Self-organized formation of topologically 
+--   correct feature maps. Biological Cybernetics, 43 (1), 59–69.
+------------------------------------------------------------------------
+
+module Data.Datamining.Clustering.SSOM
+  (
+    -- * Construction
+    SSOM(..),
+    Gaussian(..),
+    -- * Deconstruction
+    toMap,
+    -- * Advanced control
+    trainNode,
+  ) where
+
+import Data.Datamining.Clustering.SSOMInternal (SSOM(..),
+  Gaussian(..), toMap, trainNode)
+
diff --git a/src/Data/Datamining/Clustering/SSOMInternal.hs b/src/Data/Datamining/Clustering/SSOMInternal.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Datamining/Clustering/SSOMInternal.hs
@@ -0,0 +1,118 @@
+------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Datamining.Clustering.SSOMInternal
+-- Copyright   :  (c) Amy de Buitléir 2012-2014
+-- License     :  BSD-style
+-- Maintainer  :  amy@nualeargais.ie
+-- Stability   :  experimental
+-- Portability :  portable
+--
+-- A module containing private @SSOM@ internals. Most developers should
+-- use @SSOM@ instead. This module is subject to change without notice.
+--
+------------------------------------------------------------------------
+{-# LANGUAGE TypeFamilies, FlexibleContexts, FlexibleInstances,
+    MultiParamTypeClasses, DeriveGeneric #-}
+
+module Data.Datamining.Clustering.SSOMInternal where
+
+import Data.List (foldl', minimumBy)
+import Data.Ord (comparing)
+import Data.Datamining.Pattern (Pattern(..))
+import Data.Datamining.Clustering.Classifier(Classifier(..))
+import qualified Data.Map.Strict as M
+import GHC.Generics (Generic)
+import Prelude hiding (lookup)
+
+-- | A function used to adjust the models in a classifier.
+class LearningFunction f where
+  type LearningRate f
+  -- | @'rate' f t@ returns the learning rate for a node.
+  --   The parameter @f@ is the learning function.
+  --   The parameter @t@ indicates how many patterns (or pattern
+  --   batches) have previously been presented to the classifier.
+  --   Typically this is used to make the learning rate decay over time.
+  --   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.
+  rate :: f -> LearningRate f -> LearningRate f
+
+-- | A typical learning function for classifiers.
+--   @'Gaussian' r0 rf tf@ returns a gaussian function. At time zero,
+--   the learning rate is @r0@. Over time the learning rate tapers off,
+--   until at time @tf@, the learning rate is @rf@. Normally the
+--   parameters should be chosen such that:
+--
+--   * 0 < rf << r0 < 1
+--
+--   * 0 < tf
+--
+--   where << means "is much smaller than" (not the Haskell @<<@
+--   operator!)
+data Gaussian a = Gaussian a a a
+  deriving (Eq, Show, Generic)
+
+instance (Floating a, Fractional a, Num a)
+    => LearningFunction (Gaussian a) where
+  type LearningRate (Gaussian a) = a
+  rate (Gaussian r0 rf tf) t = r0 * ((rf/r0)**(t/tf))
+
+-- | A Simplified Self-Organising Map (SSOM).
+data SSOM f t k p = SSOM
+  {
+    -- | Maps patterns to nodes.
+    sMap :: M.Map k p,
+    -- | The function used to update the nodes.
+    learningFunction :: f,
+    -- | A counter used as a "time" parameter.
+    --   If you create the SSOM with a counter value @0@, and don't
+    --   directly modify it, then the counter will represent the number
+    --   of patterns that this SSOM has classified.
+    counter :: t
+  } deriving (Eq, Show, Generic)
+
+-- | Extracts the current models from the SSOM.
+--   A synonym for @'sMap'@.
+toMap :: SSOM f t k p -> M.Map k p
+toMap = sMap
+
+-- | Trains the specified node and the neighbourood around it to better
+--   match a target.
+--   Most users should use @train@, which automatically determines
+--   the BMU and trains it and its neighbourhood.
+trainNode
+  :: (Pattern p, LearningFunction f, Metric p ~ LearningRate f,
+    Num (LearningRate f), Ord k, Integral t)
+      => SSOM f t k p -> k -> p -> SSOM f t k p
+trainNode s k target = s { sMap=gm' }
+  where gm = sMap s
+        gm' = M.adjust (makeSimilar target r) k gm
+        r = rate (learningFunction s) (fromIntegral $ counter s)
+
+incrementCounter :: Num t => SSOM f t k p -> SSOM f t k p
+incrementCounter s = s { counter=counter s + 1}
+
+justTrain
+  :: (Ord (Metric p), Pattern p, LearningFunction f,
+    Metric p ~ LearningRate f, Num (LearningRate f), Ord k, Integral t)
+      => SSOM f t k p -> p -> SSOM f t k p
+justTrain s p = trainNode s bmu p
+  where ds = M.toList . M.map (p `difference`) . toMap $ s
+        bmu = f ds
+        f [] = error "SSOM has no models"
+        f xs = fst $ minimumBy (comparing snd) xs
+
+instance
+  (Pattern p, Ord (Metric p), LearningFunction f,
+    Metric p ~ LearningRate f, Num (LearningRate f), Ord k, Integral t)
+      => Classifier (SSOM f t) k p where
+  toList = M.toList . toMap
+  -- TODO: If the # of models is fixed, make more efficient
+  numModels = length . M.keys . sMap
+  models = M.elems . toMap
+  differences s p = M.toList . M.map (p `difference`) $ toMap s
+  trainBatch s = incrementCounter . foldl' justTrain s
+  reportAndTrain s p = (bmu, ds, s')
+    where ds = differences s p
+          bmu = fst $ minimumBy (comparing snd) ds
+          s' = incrementCounter . trainNode s bmu $ p
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -15,6 +15,7 @@
 
 import Data.Datamining.PatternQC ( test )
 import Data.Datamining.Clustering.SOMQC ( test )
+import Data.Datamining.Clustering.SSOMQC ( test )
 import Data.Datamining.Clustering.DSOMQC ( test )
 
 import Test.Framework as TF ( defaultMain, Test )
@@ -23,6 +24,7 @@
 tests = 
   [ 
     Data.Datamining.PatternQC.test,
+    Data.Datamining.Clustering.SSOMQC.test,
     Data.Datamining.Clustering.SOMQC.test,
     Data.Datamining.Clustering.DSOMQC.test
   ]
