packages feed

loopy-0.0: Graph.hs

--need to change matrix types
module Graph where

import Types
import System.IO.Unsafe(unsafePerformIO)

import Data.List
import Data.IntMap(IntMap)
import qualified Data.IntMap as IntMap
import Control.Monad
import Data.Bits

type Graph = [(Int,Int)] --list of edges
type Graph2 = IntMap (IntMap Chunk, IntMap Chunk)
type Loop = [Int]
type Size = Int

graphFromMatrix :: Int -> Matrix Double -> Graph
graphFromMatrix n m = [(i,j) | i <- [0..n-1], j <- [0..n-1], i /= j, let v = m!!i!!j, v /= 0]


-- Index is the lowest of src and dest link
-- min (src, dest)

data Chunk = Nil
           | Atom Int
           | CrossL Chunk Int
           | CrossR Int Chunk
           | Cross Chunk Int Chunk
           | Or Chunk Chunk
             deriving Show

cross Nil i Nil = Atom i
cross Nil i x = CrossR i x
cross x i Nil = CrossL x i
cross x i y = Cross x i y


loops :: Graph -> [Loop]
loops g = deleteNodes $ graph2 g


graph2 :: Graph -> Graph2
graph2 xs = addLinks IntMap.empty [(a,Nil,b) | (a,b) <- xs]


addLinks :: Graph2 -> [(Int,Chunk,Int)] -> Graph2
addLinks = foldl addLink

addLink :: Graph2 -> (Int,Chunk,Int) -> Graph2
addLink g (src,i,dest) | src < dest = IntMap.insertWith add src  (IntMap.empty, IntMap.singleton dest i) g
    where add _ (x,y) = (x, IntMap.insertWith Or dest i y)
addLink g (src,i,dest) | otherwise  = IntMap.insertWith add dest (IntMap.singleton src i , IntMap.empty) g
    where add _ (x,y) = (IntMap.insertWith Or src i x , y)


deleteNodes :: Graph2 -> [Loop]
deleteNodes g | IntMap.null g = []
              | otherwise = a ++ deleteNodes b
              where (a,b) = deleteNode g


deleteNode :: Graph2 -> ([Loop], Graph2)
deleteNode g = (concatMap flatten [cross Nil i c | (i,c,_) <- lop], addLinks g2 new)
    where
        (lop,new) = partition (\(i,_,j) -> i == j) [(src,cross srci k desti,dest) | (src,srci) <- lhss, (dest,desti) <- rhss]
        (lhss,rhss) = (IntMap.toList lhs, IntMap.toList rhs)
        Just ((k,(lhs,rhs)),g2) = IntMap.minViewWithKey g



flatten :: Chunk -> [Loop]
flatten x = map snd . f $ x
    where
        -- the bits in the Integer represent which indecies are present
        f :: Chunk -> [(Integer, Loop)]
        f Nil = [(0, [])]
        f (Or a b) = f a ++ f b
        f (Cross as b cs) =
            [(aci, a ++ c)
                | let ass = [(ai,a) | (ai,a) <- f as, not $ testBit ai b]
                , (ciPre,cPre) <- f cs, let c = b : cPre
                , not $ testBit ciPre b, let ci = setBit ciPre b
                , (ai,a) <- ass
                , ai .&. ci == 0, let aci = ai .|. ci]

        -- specialisations of Cross
        f (Atom b) = [(bit b, [b])]
        f (CrossR b cs) =
            [(ci, c)
                | (ciPre,cPre) <- f cs, let c = b : cPre
                , not $ testBit ciPre b, let ci = setBit ciPre b]
        f (CrossL as b) =
            [(ai, a)
                | (aiPre,aPre) <- f as, let a = aPre ++ [b]
                , not $ testBit aiPre b, let ai = setBit aiPre b]
--removes any loops containing detritus
detLoops :: Int -> [Loop] -> [Loop]
detLoops detRow [] = []
detLoops detRow ls = if (elem detRow (head ls)) then (detLoops detRow (tail ls)) else (ls ++  (detLoops detRow $ tail ls))

{-
detLoops2 :: Int -> [String] -> [String]
detLoops2 detRow [] = []
detLoops2 detRow ls = if (elem detRow (l)) then (detLoops2 detRow (tail ls)) else (ls ++  (detLoops2 detRow $ tail ls))
	where l = read l2 :: Loop
	      l2 = (head ls)!!0


flatten :: Chunk -> [Loop]
flatten = map snd . f
    where
        f :: Chunk -> [([Int], Loop)]
        f Nil = [([], [])]
        f (Or a b) = f a ++ f b
        f (Cross as b cs) =
            [(aci, a ++ c)
                | let ass = filter (notElemInt b . fst) $ f as
                , (ciPre,cPre) <- f cs, let c = b : cPre
                , b `notElemInt` ciPre, let ci = insertInt b ciPre
                , (ai,a) <- ass
                , disjoint ai ci, let aci = merge ai ci]


notElemInt :: Int -> [Int] -> Bool
notElemInt x [] = True
notElemInt x (y:ys) = x /= y && notElemInt x ys


insertInt :: Int -> [Int] -> [Int]
insertInt x (y:ys) | x < y = x : y : ys
                   | otherwise = y : insertInt x ys
insertInt x [] = [x]


merge :: [Int] -> [Int] -> [Int]
merge (x:xs) (y:ys)
    | x < y = x : merge xs (y:ys)
    | otherwise = y : merge (x:xs) ys
merge xs [] = xs
merge [] ys = ys


disjoint :: [Int] -> [Int] -> Bool
disjoint xs [] = True
disjoint [] ys = True
disjoint (x:xs) (y:ys) = case compare x y of
    EQ -> False
    LT -> disjoint xs (y:ys)
    GT -> disjoint (x:xs) ys
-}





loopsOld :: Graph -> [Loop]
loopsOld g = f [(x,[],y) | (x,y) <- g]
    where
        f [] = out "done" []
        f xs = out (length res, length xs) $ res ++ f xs4
            where
                res = [a:b | (a,b,c) <- loops]
                kill = fst3 $ head xs
                (from,xs2) = partition ((==) kill . fst3) xs
                xs3 = concatMap add xs2
                (loops,xs4) = partition isLoop xs3

                add (a,b,c) | c == kill = [(a,b ++ d:e,f) | (d,e,f) <- from, disjointed b e]
                add x = [x]

        isLoop (a,b,c) = a == c


fst3 (a,b,c) = a

disjointed x y = null $ x `intersect` y



{-# NOINLINE out #-}
out x y = unsafePerformIO $ print x >> return y