{-# LANGUAGE DeriveGeneric #-} module Data.Graph.Libgraph.AlgoDebug where import Data.Graph.Libgraph.Core import Data.Graph.Libgraph.Dagify(collapse,remove) import Prelude hiding (Right) import Data.List(find) import Data.Maybe(isJust) import GHC.Generics data AssistedMessage = InconclusiveProperty String | PassingProperty String deriving (Eq,Show,Ord,Generic) data Judgement = Right | Wrong | Unassessed | Assisted [AssistedMessage] deriving (Eq,Show,Ord,Generic) findFaulty_dag :: (Ord v, Eq a, Show v) => (v -> Judgement) -> Graph v a -> [v] findFaulty_dag judge g = filter isFaulty (vertices g) where isFaulty v = (judge v == Wrong) && (null $ filter ((/=Right) . judge) (succs g v)) findFaulty :: (Ord v, Eq a, Show v) => (v -> Judgement) -> ([v]->v) -> Graph v a -> [v] findFaulty isWrong merge = (findFaulty_dag isWrong) . (collapse merge) . remove next_step :: Eq v => Graph v a -> (v -> Judgement) -> v next_step tree j = case go r of Just v -> v Nothing -> r -- no defect? where r = root tree go v | v == r = findJust (map go (succs tree v)) | j v == Right = Nothing -- v is right; don't examine (grand)children | j v == Wrong = case findJust (map go (succs tree v)) of Nothing -> (Just v) -- v is a faulty node (Just w) -> (Just w) -- found next node w in (grand)children of v | otherwise = Just v -- v is an unassed node findJust mvs = case (find (isJust) mvs) of Just justv -> justv; Nothing -> Nothing {- Divide and Query: Try to find a node that divides the tree in two. -} next_daq :: Ord v => Graph v a -> (v -> Judgement) -> v next_daq tree j = snd (foldr1 f ws) where c = succCache tree ws = weight j c -- start from deepest wrong node; if no wrong nodes start from the root node (case start j c (root tree) of (Just r) -> r; Nothing -> root tree) w = (maximum (map fst ws)) `div` 2 -- the "ideal" weight f x y | abs (w - (fst x)) < abs (w - (fst y)) = x | otherwise = y weight :: (v -> Judgement) -> (v -> [v]) -> v -> [(Int,v)] weight j c v | j v == Right = [(0,v)] -- discard subtrees that are right | otherwise = (w,v) : foldr (++) [] vs where vs = map (weight j c) (c v) -- weighted children w = 1 + (sum $ map (fst . head) vs) -- weight of v -- find starting point (i.e. the "deepest" node that is wrong) start :: (v -> Judgement) -> (v -> [v]) -> v -> Maybe v start j c v = case filter isJust (map (start j c) (c v)) of [] -> if j v == Wrong then Just v else Nothing (w:_) -> w