Bugs item #1186431, was opened at 2005-04-20 04:50
Message generated for change (Comment added) made by simonmar
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=108032&aid=1186431&group_id=8032

Please note that this message will contain a full copy of the comment thread,
including the initial issue submission, for this request,
not just the latest update.
Category: libraries (other)
Group: 6.4
>Status: Closed
>Resolution: Fixed
Priority: 5
Submitted By: Nobody/Anonymous (nobody)
Assigned to: Nobody/Anonymous (nobody)
Summary: mkGraph Stack Overflow

Initial Comment:
module Data.Graph.Inductive.Graph

mkGraph :: [LNode a] -> [LEdge b] -> gr a b

mkGraph dies on large graphs.

'mkGraph nodes edges' gives stack overflow error.

length nodes -> 20000
length edges -> 400000



----------------------------------------------------------------------

>Comment By: Simon Marlow (simonmar)
Date: 2005-09-12 12:34

Message:
Logged In: YES 
user_id=48280

Closing following comment from the maintainer of the
relevant library.

----------------------------------------------------------------------

Comment By: Martin Erwig (erwig)
Date: 2005-08-26 21:31

Message:
Logged In: YES 
user_id=1335862

I will change the use of foldr to foldl in the next release of the FGL.
However, I do not intend to reimplement the graph representation
using Data.Map.


----------------------------------------------------------------------

Comment By: Don Stewart (dons)
Date: 2005-07-07 04:49

Message:
Logged In: YES 
user_id=880987

Here's a test program:

------------------------------------------------------------------------

module Main where

import Data.Graph.Inductive ( Gr, mkGraph )
import Control.Exception    ( evaluate )

type Graph = Gr () ()

main = do
        let nodes =  [ (n,()) | n <- [1 .. 20000] ] 
            edges =  [ (n,m,())  | (n,_) <- nodes, (m,_) <- nodes, n /= m ]
            g = mkGraph nodes edges :: Graph

        _ <- Control.Exception.evaluate g
        putStrLn "done" 

------------------------------------------------------------------------

Which will overflow:

    $ ghc -O -package fgl Test.hs
    $ ./a.out 
    Stack space overflow: current size 8388608 bytes.
    Use `+RTS -Ksize' to increase it.

Now, we can squash this bug by replacing the foldr in insEdges in
Data.Graph.Inductive.Tree with a foldl':

------------------------------------------------------------------------

    --- /home/dons/fptools/libraries/fgl/Data/Graph/Inductive/Tree.hs
    Thu Jul  7 11:58:34 2005
    +++ ./Tree2.hs  Thu Jul  7 14:07:38 2005
    @@ -3,6 +3,7 @@
     
     module Data.Graph.Inductive.Tree (Gr,UGr) where
     
    +import Data.List        (foldl')
     
     import Data.Graph.Inductive.Graph
     import Data.Graph.Inductive.Internal.FiniteMap
    @@ -44,7 +45,10 @@
       empty           = Gr emptyFM
       isEmpty (Gr g)  = case g of {Empty -> True; _ -> False}
       match           = matchGr
    -  mkGraph vs es   = (insEdges es . insNodes vs) empty
    +  mkGraph vs es   = (insEdges' es . insNodes vs) empty
    +        where
    +          insEdges' es g = foldl' (flip insEdge) g es
    +
       labNodes (Gr g) = map (\(v,(_,l,_))->(v,l)) (fmToList g)
       -- more efficient versions of derived class members
       --

------------------------------------------------------------------------

However, we'll still run out of heap after a couple of minutes anyway.
(this is for n=200 by the way)

    $ time ./a.out
    a.out: out of memory (requested 1048576 bytes)
    ./a.out  21.47s user 7.94s system 14% cpu 3:17.98 total

Down to n=50, some profiling reveals:
    COST CENTRE                    MODULE               %time %alloc

    updFM                          Tree2                 56.2   70.2
    updAdj                         Tree2                 37.5    9.3
    clearPred                      Tree2                  6.2   10.3

Adding some `seq`s to updFM helps a little bit, knocking 25% off the allocs:

    COST CENTRE                    MODULE               %time %alloc

    updFM                          Tree2                 35.7   61.1
    updAdj                         Tree2                 42.9   12.2
    clearPred                      Tree2                 21.4   13.5

Now n=200 still runs out of heap, just takes 25% longer.

Here's updFM, from Data/Graph/Inductive/Internal/FiniteMap.hs:

    updFM :: Ord a => FiniteMap a b -> a -> (b -> b) -> FiniteMap a b
    updFM (Node h l (j,x) r) i f 
           | i<j        =  Node h (updFM l i f) (j,x) r
           | i>j        =  Node h l (j,x) (updFM r i f) 
           | otherwise  =  Node h l (j,f x) r 

versus:
    updFM (Node h l (j,x) r) i f 
           | i<j        =  let l' = updFM l i f in l' `seq` Node h l' (j,x) r
           | i>j        =  let r' = updFM r i f in r' `seq` Node h l (j,x) r'
           | otherwise  =  Node h l (j,f x) r  

I wonder if a Graph implemented as a Data.Map would make any difference.

-- Don Stewart


----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=108032&aid=1186431&group_id=8032
_______________________________________________
Glasgow-haskell-bugs mailing list
Glasgow-haskell-bugs@haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-bugs

Reply via email to