fromSimple :: Traversable f => Dag f -> Dag.Dag f
fromSimple dag = Dag.Dag r es' (nodeCount dag)
  where
    es  = fmap (fmap Ret) $ edges dag
    es' = IntMap.delete (root dag) es
    r   = es IntMap.! root dag

-- | Checks whether two dags are bisimilar. In particular, we have
-- the following equality
--
-- @
-- bisim g1 g2 = (unravel g1 == unravel g2)
-- @
--
-- That is, two dags are bisimilar iff they have the same unravelling.

-- TODO implement

-- bisim :: forall f . (Eq (f ()), Functor f, Foldable f)  => Dag f -> Dag f -> Bool
-- bisim Dag {root=r1,edges=e1}  Dag {root=r2,edges=e2} = runF r1 r2
--     where run :: (Free f Node, Free f Node) -> Bool
--           run (t1, t2) = runF (step e1 t1) (step e2 t2)
--           step :: Edges f -> Free f Node -> f (Free f Node)
--           step e (Ret n) = e IntMap.! n
--           step _ (In t) = t
--           runF :: f (Free f Node) -> f (Free f Node) -> Bool
--           runF f1 f2 = case eqMod f1 f2 of
--                          Nothing -> False
--                          Just l -> all run l


-- | Checks whether the two given DAGs are isomorphic.

-- iso :: (Traversable f, Foldable f, Eq (f ())) => Dag f -> Dag f -> Bool
-- iso g1 g2 = checkIso eqMod (flatten g1) (flatten g2)


-- | Checks whether the two given DAGs are strongly isomorphic, i.e.
--   their internal representation is the same modulo renaming of
--   nodes.

-- strongIso :: (Functor f, Foldable f, Eq (f (Free f ()))) => Dag f -> Dag f -> Bool
-- strongIso Dag {root=r1,edges=e1,nodeCount=nx1}
--           Dag {root=r2,edges=e2,nodeCount=nx2}
--               = checkIso checkEq (r1,e1,nx1) (r2,e2,nx2)
--     where checkEq t1 t2 = eqMod (In t1) (In t2)
fromSimple :: Traversable f => Dag f -> Dag.Dag f
fromSimple dag = Dag.Dag r es' (nodeCount dag)
  where
    es  = fmap (fmap Ret) $ edges dag
    es' = IntMap.delete (root dag) es
    r   = es IntMap.! root dag

-- | Checks whether two dags are bisimilar. In particular, we have
-- the following equality
--
-- @
-- bisim g1 g2 = (unravel g1 == unravel g2)
-- @
--
-- That is, two dags are bisimilar iff they have the same unravelling.

-- TODO implement

-- bisim :: forall f . (Eq (f ()), Functor f, Foldable f)  => Dag f -> Dag f -> Bool
-- bisim Dag {root=r1,edges=e1}  Dag {root=r2,edges=e2} = runF r1 r2
--     where run :: (Free f Node, Free f Node) -> Bool
--           run (t1, t2) = runF (step e1 t1) (step e2 t2)
--           step :: Edges f -> Free f Node -> f (Free f Node)
--           step e (Ret n) = e IntMap.! n
--           step _ (In t) = t
--           runF :: f (Free f Node) -> f (Free f Node) -> Bool
--           runF f1 f2 = case eqMod f1 f2 of
--                          Nothing -> False
--                          Just l -> all run l


-- | Checks whether the two given DAGs are isomorphic.

-- iso :: (Traversable f, Foldable f, Eq (f ())) => Dag f -> Dag f -> Bool
-- iso g1 g2 = checkIso eqMod (flatten g1) (flatten g2)


-- | Checks whether the two given DAGs are strongly isomorphic, i.e.
--   their internal representation is the same modulo renaming of
--   nodes.

-- strongIso :: (Functor f, Foldable f, Eq (f (Free f ()))) => Dag f -> Dag f -> Bool
-- strongIso Dag {root=r1,edges=e1,nodeCount=nx1}
--           Dag {root=r2,edges=e2,nodeCount=nx2}
--               = checkIso checkEq (r1,e1,nx1) (r2,e2,nx2)
--     where checkEq t1 t2 = eqMod (In t1) (In t2)
fromSimple dag = Dag.Dag r es' (nodeCount dag)
  where
    es  = fmap (fmap Ret) $ edges dag
    es' = IntMap.delete (root dag) es
    r   = es IntMap.! root dag

-- | Checks whether two dags are bisimilar. In particular, we have
-- the following equality
--
-- @
-- bisim g1 g2 = (unravel g1 == unravel g2)
-- @
--
-- That is, two dags are bisimilar iff they have the same unravelling.

-- TODO implement

-- bisim :: forall f . (Eq (f ()), Functor f, Foldable f)  => Dag f -> Dag f -> Bool
-- bisim Dag {root=r1,edges=e1}  Dag {root=r2,edges=e2} = runF r1 r2
--     where run :: (Free f Node, Free f Node) -> Bool
--           run (t1, t2) = runF (step e1 t1) (step e2 t2)
--           step :: Edges f -> Free f Node -> f (Free f Node)
--           step e (Ret n) = e IntMap.! n
--           step _ (In t) = t
--           runF :: f (Free f Node) -> f (Free f Node) -> Bool
--           runF f1 f2 = case eqMod f1 f2 of
--                          Nothing -> False
--                          Just l -> all run l


-- | Checks whether the two given DAGs are isomorphic.

-- iso :: (Traversable f, Foldable f, Eq (f ())) => Dag f -> Dag f -> Bool
-- iso g1 g2 = checkIso eqMod (flatten g1) (flatten g2)


-- | Checks whether the two given DAGs are strongly isomorphic, i.e.
--   their internal representation is the same modulo renaming of
--   nodes.

-- strongIso :: (Functor f, Foldable f, Eq (f (Free f ()))) => Dag f -> Dag f -> Bool
-- strongIso Dag {root=r1,edges=e1,nodeCount=nx1}
--           Dag {root=r2,edges=e2,nodeCount=nx2}
--               = checkIso checkEq (r1,e1,nx1) (r2,e2,nx2)
--     where checkEq t1 t2 = eqMod (In t1) (In t2)