@@ -1,4 +1,5 @@
1import System.Environment (getArgs)
1import System.Environment (getArgs)
2import Control.Applicative
3import Control.Applicative
3import Control.Monad
4import Control.Monad
4import System.Random
5import System.Random
@@ -7,7 +8,7 @@ import Control.Distributed.Process.Node (initRemoteTable)
7import Control.Distributed.Process.Backend.SimpleLocalnet
8import Control.Distributed.Process.Backend.SimpleLocalnet
8import Data.Map (Map)
9import Data.Map (Map)
9import Data.Array (Array, listArray)
10import Data.Array (Array, listArray)
10−import qualified Data.Map as Map (fromList)
11+import qualified Data.Map as Map (fromList, toList, size, elems)
12import qualified CountWords
13import qualified CountWords
13import qualified MapReduce
14import qualified MapReduce
@@ -18,17 +19,6 @@ rtable = MapReduce.__remoteTable
18 . CountWords.__remoteTable
19 . CountWords.__remoteTable
19 $ initRemoteTable
20 $ initRemoteTable
21−constructInput :: [FilePath] -> IO (Map FilePath CountWords.Document)
22−constructInput files = do
23− contents <- mapM readFile files
24− return . Map.fromList $ zip files contents
26−randomPoint :: IO KMeans.Point
27−randomPoint = (,) <$> randomIO <*> randomIO
29−arrayFromList :: [e] -> Array Int e
30−arrayFromList xs = listArray (0, length xs - 1) xs
32main :: IO ()
22main :: IO ()
34 args <- getArgs
24 args <- getArgs
@@ -50,9 +40,51 @@ main = do
50 -- Local k-means
40 -- Local k-means
51 "local" : "kmeans" : [] -> do
41 "local" : "kmeans" : [] -> do
52 points <- replicateM 1000 randomPoint
42 points <- replicateM 1000 randomPoint
53− print $ KMeans.localKMeans (arrayFromList points) (take 10 points)
43+ let kmeans = KMeans.localKMeans (arrayFromList points)
45+ let it 0 = kmeans (take 5 points)
46+ it n = let clusters = it (n - 1) in
47+ kmeans (map snd $ Map.elems clusters)
49+ forM_ ([0 .. 4] :: [Int]) $ \n ->
50+ withFile ("plot" ++ show n) WriteMode $
55 -- Generic slave for distributed examples
53 -- Generic slave for distributed examples
56 "slave" : host : port : [] -> do
54 "slave" : host : port : [] -> do
57 backend <- initializeBackend host port rtable
55 backend <- initializeBackend host port rtable
58 startSlave backend
56 startSlave backend
58+--------------------------------------------------------------------------------
60+--------------------------------------------------------------------------------
62+constructInput :: [FilePath] -> IO (Map FilePath CountWords.Document)
63+constructInput files = do
64+ contents <- mapM readFile files
65+ return . Map.fromList $ zip files contents
67+randomPoint :: IO KMeans.Point
68+randomPoint = (,) <$> randomIO <*> randomIO
70+arrayFromList :: [e] -> Array Int e
71+arrayFromList xs = listArray (0, length xs - 1) xs
73+-- | Create a gnuplot data file for the output of the k-means algorithm
75+-- To plot the data, use
77+-- > plot "<<filename>>" u 1:2:3 with points palette
78+createGnuPlot :: Map KMeans.Cluster ([KMeans.Point], KMeans.Point) -> Handle -> IO ()
79+createGnuPlot clusters h =
80+ mapM_ printPoint . flatten . zip colors . Map.toList $ clusters
82+ printPoint (x, y, color) =
83+ hPutStrLn h $ show x ++ " " ++ show y ++ " " ++ show color
85+ flatten :: [(Float, (KMeans.Cluster, ([KMeans.Point], KMeans.Point)))]
86+ -> [(Double, Double, Float)]
87+ flatten = concat . map (\(color, (_, (points, _))) -> map (\(x, y) -> (x, y, color)) points)
90+ colors = [0, 1 / fromIntegral (Map.size clusters) .. 1]