| {-# LANGUAGE FlexibleContexts #-} |
| -- |
| -- Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) |
| -- |
| -- SPDX-License-Identifier: BSD-2-Clause |
| -- |
| |
| module CapDL.Matrix( |
| Matrix |
| ,isConnected |
| ,connect |
| ,newEmptyMatrix |
| ,printMatrix |
| ,printDotMatrix |
| ,showDotMatrix |
| ,getSize |
| ,disconnect |
| ) where |
| |
| import Data.Array.IO |
| |
| import Prelude () |
| import Prelude.Compat |
| import Data.Map (Map) |
| import qualified Data.Map as Map |
| |
| import Control.Monad |
| |
| import Data.Char |
| |
| newtype Matrix = Matrix (IOUArray (Int,Int) Bool) |
| |
| {- This function takes a matrix and prints a literal table representation |
| with 0 for False and 1 for True, should be for debugging only -} |
| printMatrix :: Matrix -> IO() |
| printMatrix (Matrix m) = |
| do ((minx, miny), (maxx, maxy)) <- getBounds m |
| forM_ [minx .. maxx] $ \i -> |
| forM_ [miny .. maxy] $ \j -> |
| do elt <- readArray m (i,j) |
| putStr $ (if elt then "1" else "0") |
| ++ if j == maxy then "\n" else " " |
| |
| {- This function takes a matrix and a map of labels for |
| the nodes being represented by the matrix and prints |
| a .dot file representation of the graph. |
| |
| This is hacky and only works for the specific 'names' used |
| in the -} |
| |
| printDotMatrix :: Matrix -> Map Int (String, Maybe Word) -> IO () |
| printDotMatrix (Matrix m) nameMap = |
| do putStrLn "digraph {" |
| ((min, _), (_, max)) <- getBounds m |
| forM_ [min .. max] $ \i -> |
| do let iobjID = Map.findWithDefault (e i) i nameMap |
| putStrLn $ cf $ fst iobjID |
| forM_ [i .. max] $ \j -> |
| do outb <- readArray m (i,j) |
| inb <- readArray m (j,i) |
| let iname = fst (iobjID) ++ maybe "" show (snd (iobjID)) |
| jobjID = Map.findWithDefault (e j) j nameMap |
| jname = fst (jobjID) ++ maybe "" show (snd (jobjID)) |
| case (inb,outb) of |
| (False, False) -> return () |
| (False, True) -> putStrLn $ cf iname ++ " -> " ++ cf jname ++ ";" |
| (True, False) -> putStrLn $ cf jname ++ " -> " ++ cf iname ++ ";" |
| (True, True) -> putStrLn $ cf iname ++ " -> " ++ cf jname ++ "[dir=both];" |
| putStrLn "}" |
| where |
| e x = error ("Can't find name for object " ++ show x) |
| cf = filter (\c -> isDigit c || isAlpha c) |
| |
| showDotMatrix :: Matrix -> Map Int (String, Maybe Word) -> IO String |
| showDotMatrix (Matrix m) nameMap = |
| do |
| ((min, _), (_, max)) <- getBounds m |
| rows <- forM [min .. max] $ \i -> |
| do let iobjID = Map.findWithDefault (e i) i nameMap |
| cells <- forM [i .. max] $ \j -> |
| do outb <- readArray m (i,j) |
| inb <- readArray m (j,i) |
| let iname = fst (iobjID) ++ maybe "" show (snd (iobjID)) |
| jobjID = Map.findWithDefault (e j) j nameMap |
| jname = fst (jobjID) ++ maybe "" show (snd (jobjID)) |
| return $ case (inb,outb) of |
| (False, False) -> "" |
| (False, True) -> cf iname ++ " -> " ++ cf jname ++ ";\n" |
| (True, False) -> cf jname ++ " -> " ++ cf iname ++ ";\n" |
| (True, True) -> cf iname ++ " -> " ++ cf jname ++ "[dir=both];\n" |
| return $ (cf (fst iobjID)) ++ "\n" ++ (concat cells) |
| return $ "digraph {\n" ++ (concat rows) ++ "}\n" |
| where |
| e x = error ("Can't find name for object " ++ show x) |
| cf = filter (\c -> isDigit c || isAlpha c) |
| |
| isConnected :: Matrix -> Int -> Int -> IO Bool |
| isConnected (Matrix m) x y = readArray m (x,y) |
| |
| {- Sets (x,y) to True -} |
| connect :: Matrix -> Int -> Int -> IO () |
| connect (Matrix m) x y = writeArray m (x,y) True |
| |
| {- Sets (x,y) to False -} |
| disconnect :: Matrix -> Int -> Int -> IO () |
| disconnect (Matrix m) x y = writeArray m (x,y) False |
| |
| {- Returns a new empty matrix -} |
| newEmptyMatrix :: Int -> IO Matrix |
| newEmptyMatrix n = liftM Matrix $ newArray ((0,0),(n-1,n-1)) False |
| |
| {- Returns the dimensions of the matrix -} |
| getSize (Matrix m) = getBounds m |