sSizeChangeTerminating prog = do
  let (dataExprs, funExprs) = splitProgram prog -- Split program into function and data definitions
  let globalFuns = globalControlPoints funExprs
  let globalConstrs = globalDataConstructors dataExprs
  let initEnv cp = CallGraphEnv (map fst globalFuns) globalConstrs (controlPointData cp) [] -- Define initial environment for call graph
  callGraphs <- mapM (\(cp, e) -> runCallGraph cp e (initEnv cp)) globalFuns -- Create call graph
  let calls = concat callGraphs
  let sizeChangeGraphs = map sizeChangeGraph calls -- Build size-change graphs for each call in the call graph
  let multipaths = concat $ map allMultipaths (cyclicMultipaths sizeChangeGraphs) -- Find all the cyclic multipaths from the generated size-change graphs.
  let collapsedMultipaths = map (\mp -> (mp, collapse mp)) multipaths -- Collapse the cyclic multipaths to one size-change graph
  let unsafeMultipaths = map fst $ filter (\(mp, collapsed) -> isNothing collapsed) collapsedMultipaths -- Find those multipaths which are unsafe
  let safeCollapsedMultipaths = map (\(mp, c) -> (mp, fromJust c)) $ [ (m, c) | (m, c) <- collapsedMultipaths, isJust c ] -- .. And thos which are safe
  let possiblyNonTerminating = -- Find multipaths that possibly give rise to non-termination
        filter (\(mp, collapsed) -> isLoop collapsed && isSelfComposition collapsed) safeCollapsedMultipaths
  let descendingArcsWithGraph m = map (\(mp, collapsed) -> (mp, descendingArcs (identityArcs collapsed))) m -- Find descending size-change arcs in collapsed multipath
  let graphsWithNoDescendingArcs m = filter (\(mp, arcs) -> null arcs) (descendingArcsWithGraph m) -- Find the collapsed multipaths with no descending arcs
  case unsafeMultipaths of
    [] -> case graphsWithNoDescendingArcs possiblyNonTerminating of
            []            -> return $ Termination (map snd safeCollapsedMultipaths)
            nonDescending -> throwError $
                               InfiniteRecursion (head $ map fst nonDescending)
    unsafe -> throwError $ UnsafeMultipathError (head unsafe)

isSizeChangeTerminating prog = do
  let (dataExprs, funExprs) = splitProgram prog -- Split program into function and data definitions
  let globalFuns = globalControlPoints funExprs
  let globalConstrs = globalDataConstructors dataExprs
  let initEnv cp = CallGraphEnv (map fst globalFuns) globalConstrs (controlPointData cp) [] -- Define initial environment for call graph
  callGraphs <- mapM (\(cp, e) -> runCallGraph cp e (initEnv cp)) globalFuns -- Create call graph
  let calls = concat callGraphs
  let sizeChangeGraphs = map sizeChangeGraph calls -- Build size-change graphs for each call in the call graph
  let multipaths = concat $ map allMultipaths (cyclicMultipaths sizeChangeGraphs) -- Find all the cyclic multipaths from the generated size-change graphs.
  let collapsedMultipaths = map (\mp -> (mp, collapse mp)) multipaths -- Collapse the cyclic multipaths to one size-change graph
  let unsafeMultipaths = map fst $ filter (\(mp, collapsed) -> isNothing collapsed) collapsedMultipaths -- Find those multipaths which are unsafe
  let safeCollapsedMultipaths = map (\(mp, c) -> (mp, fromJust c)) $ [ (m, c) | (m, c) <- collapsedMultipaths, isJust c ] -- .. And thos which are safe
  let possiblyNonTerminating = -- Find multipaths that possibly give rise to non-termination
        filter (\(mp, collapsed) -> isLoop collapsed && isSelfComposition collapsed) safeCollapsedMultipaths
  let descendingArcsWithGraph m = map (\(mp, collapsed) -> (mp, descendingArcs (identityArcs collapsed))) m -- Find descending size-change arcs in collapsed multipath
  let graphsWithNoDescendingArcs m = filter (\(mp, arcs) -> null arcs) (descendingArcsWithGraph m) -- Find the collapsed multipaths with no descending arcs
  case unsafeMultipaths of
    [] -> case graphsWithNoDescendingArcs possiblyNonTerminating of
            []            -> return $ Termination (map snd safeCollapsedMultipaths)
            nonDescending -> throwError $
                               InfiniteRecursion (head $ map fst nonDescending)
    unsafe -> throwError $ UnsafeMultipathError (head unsafe)
isSizeChangeTerminating prog = do
  let (dataExprs, funExprs) = splitProgram prog -- Split program into function and data definitions
  let globalFuns = globalControlPoints funExprs
  let globalConstrs = globalDataConstructors dataExprs
  let initEnv cp = CallGraphEnv (map fst globalFuns) globalConstrs (controlPointData cp) [] -- Define initial environment for call graph
  callGraphs <- mapM (\(cp, e) -> runCallGraph cp e (initEnv cp)) globalFuns -- Create call graph
  let calls = concat callGraphs
  let sizeChangeGraphs = map sizeChangeGraph calls -- Build size-change graphs for each call in the call graph
  let multipaths = concat $ map allMultipaths (cyclicMultipaths sizeChangeGraphs) -- Find all the cyclic multipaths from the generated size-change graphs.
  let collapsedMultipaths = map (\mp -> (mp, collapse mp)) multipaths -- Collapse the cyclic multipaths to one size-change graph
  let unsafeMultipaths = map fst $ filter (\(mp, collapsed) -> isNothing collapsed) collapsedMultipaths -- Find those multipaths which are unsafe
  let safeCollapsedMultipaths = map (\(mp, c) -> (mp, fromJust c)) $ [ (m, c) | (m, c) <- collapsedMultipaths, isJust c ] -- .. And thos which are safe
  let possiblyNonTerminating = -- Find multipaths that possibly give rise to non-termination
        filter (\(mp, collapsed) -> isLoop collapsed && isSelfComposition collapsed) safeCollapsedMultipaths
  let descendingArcsWithGraph m = map (\(mp, collapsed) -> (mp, descendingArcs (identityArcs collapsed))) m -- Find descending size-change arcs in collapsed multipath
  let graphsWithNoDescendingArcs m = filter (\(mp, arcs) -> null arcs) (descendingArcsWithGraph m) -- Find the collapsed multipaths with no descending arcs
  case unsafeMultipaths of
    [] -> case graphsWithNoDescendingArcs possiblyNonTerminating of
            []            -> return $ Termination (map snd safeCollapsedMultipaths)
            nonDescending -> throwError $
                               InfiniteRecursion (head $ map fst nonDescending)
    unsafe -> throwError $ UnsafeMultipathError (head unsafe)