{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
-- | Ear decomposition of a graph.
module Data.Graph.Inductive.Query.Ear where
import Data.Function
import Data.Graph.Inductive.Basic
import Data.Graph.Inductive.Example
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.Query
import Data.Graph.Inductive.Tree
import Data.List
import Data.Tree
import Data.Tuple
-- | The 'ears' function takes a graph with no node or edge annotation and
-- produces an ear decomposition. Each edge is annotated with a weight. Edges
-- with the same weight are in the same ear.
ears :: forall gr . DynGraph gr => gr () () -> gr () Int
ears g
| isConnected g = gWs
| otherwise = error "called ears on disconnected graph"
where
t :: Tree Node
[t] = dff' g
tps = treeToPaths t
te = treeToEdges t
g' = mkUGraph (nodes g) ((edges g \\ te) \\ (map swap te)) `asTypeOf` g
-- gE is the graph of all edges not in the spanning tree. The edge weight
-- is the distance between the tree root and the lowest common ancestor of
-- the two nodes making up each edge
gE :: gr () Int = mkGraph (labNodes g') (map (lca tps) $ labEdges g')
gE' = mkGraph (labNodes gE) (labEdges gE ++ map (\(a,b) -> (a,b,0)) (te ++ map swap te))
teWs = map (shortestPaths gE') te
gWs = mkGraph (labNodes g') (labEdges gE ++ teWs ++ map swap12 teWs)
shortestPaths :: Gr () Int -> Edge -> LEdge Int
shortestPaths g (u,v) = (u,v,spLength u v g') where
g' = delEdge (u,v) $ delEdge (v,u) g
lca :: [[Node]] -> (LEdge ()) -> (LEdge Int)
lca ps (u,v,())
| any null ps = error $ "null path: " ++ show ps
| otherwise = (u,v,) . (subtract 1) . length . filter (uncurry (==)) $ zip u' v' where
[u'] = filter ((==u) . last) ps
[v'] = filter ((==v) . last) ps
swap12 (a,b,c) = (b,a,c)
sel3 (_,_,s) = s
-- tree edges
treeToEdges :: Tree Node -> [Edge]
treeToEdges (Node _ []) = []
treeToEdges (Node k xs) = map ((k,) . rootLabel) xs ++ concatMap treeToEdges xs
-- paths
treeToPaths :: Tree Node -> [[Node]]
treeToPaths (Node k []) = [[k]]
treeToPaths (Node k xs) = [[k]] ++ [ (k:ys) | ys <- concatMap treeToPaths xs ]
{-
- Test graph
-
fig13 :: Gr () ()
fig13 = undir $ mkUGraph ns es where
ns = [1..9]
es = [ (1,2),(1,4)
, (2,3),(2,5)
, (3,4),(3,6)
, (4,7)
, (5,6),(5,8)
, (6,7)
, (7,9)
, (8,9)
]
-}