I wrote this code in Haskell (instead of Python) for the educational benefit. Can anyone suggest ways to improve this code?
I'm guessing that I'm using
It takes two commandline arguments. The first is a path to a symmetric distance matrix. The second is a threshold. The program interprets vertices to be adjacent if their distance is less than the threshold. Then the program counts the number of connected components and the number of vertices in each connected component and prints this information.
import System.Environment import Data.Matrix hiding (flatten) import qualified Data.Vector as V import Data.Graph import Data.Tree -- Turns a distance matrix to an adjacency matrix using a threshold, then prints the number -- and size of the connected components. -- Usage: run `stack run location_of_distance_matrix threshold` -- Output is in the form (number of bins, [number of vertices in each bin]). main :: IO () main = do args <- getArgs contents <- readFile $ args !! 0 let dmat = fromLists $ (map ((map (read :: String -> Float)) . words) (lines contents)) amat = amatFromDmat dmat $ read (args !! 1) (g,_,_) = graphFromEdges (map (\n -> (n, n, neighbours n amat)) [(1 :: Integer)..(fromIntegral $ ncols amat)]) comp = components g putStrLn $ show $ (length comp, map (length . flatten) comp) -- Transforms a distance matrix into an adjacency matrix using a threshold. amatFromDmat :: Matrix Float -> Float -> Matrix Bool amatFromDmat m e = matrix (nrows m) (ncols m) threshold where threshold (i,j) | i == j = False | m ! (i,j) < e = True | otherwise = False -- Outputs the list of neighbours of a vertex in a graph, taking an adjacency -- matrix. -- The addition and subtraction of 1 are here because vectors are 0-indexed but -- I made my graph vertices 1-indexed. neighbours :: Integer -> Matrix Bool -> [Integer] neighbours n mat = map (fromIntegral . (1+)) $ filter (\m -> row V.! m) [0..(ncols mat)-1] where row = getRow (fromIntegral n) mat
Edit: I found a bug and improved the code a little bit.