packages feed

Emping-0.5: src/Abduce.hs

{- | Emping 0.5 (provisional)

Module Abduce produces a graph of implications (equivalences in one node), between reduced antecedents with the same consequent.

Fri 04 Apr 2008 07:19:00 PM CEST 
-}
module Abduce (abduceTopAll, hasDependencies, orgReg2Ndg, nodeLegend, implicGraphOne, implicGraphAll, RuRe ) where
import Aux
import Data.List ( findIndices, nubBy, nub, (\\) )
import Data.Graph.Inductive
import Control.Monad.State

--------------------------------------------------------------------------------
-- Match indices of reduced rules with indices of the original(s) which include a reduced rule

-- | indices of original rule(s) denoted by the same reduced rule. The antecedents of the original are supersets of the reduced antecedent.
redOrgs :: [Rule] -> Rule -> [Int]
redOrgs rules red = findIndices (\x -> (fst red) `isSub` (fst x)) rules

-- | tuples of the indices of originals and of the reduced rules for orgs and reds with same av consequent. First the originals, second the reduced rule.
redOPrs :: [Rule] -> [Rule] -> [([Int], Int)]
redOPrs rules reds = zip orixls [0..] where
           orixls = map (redOrgs rules) reds

-- | define a type synonym for rule indices and reduced rule indices. First the rule indices, then the reduced indices.
type RuRe = ([Int], [Int])
-- ^ Second is a node in the graph (of equals), first determines the order.


-- | get all reduced rules denoting the same original (ONE). First is originals, second is reduced equals.
getEquals :: [([Int],Int)] -> ([Int],Int) -> RuRe
getEquals  y  (ols,_)=
      (ols, [snd x | x <- y, fst x == ols ])

-- | group original-red pairs into original-equals pairs, remove doubles of original indices (maybe same but in different order)
toEquals :: [([Int],Int)] -> [RuRe]
toEquals orpl = nubBy eqOrg ls where
     ls = map (getEquals orpl) orpl
     eqOrg (x1,_) (x2,_) = isSub x1 x2 && isSub x2 x1

-- | first original indices, second reduced rule indices, matched from original rules to reductions with the same consequent av
redOrgs2Eqs :: [Rule] -> [Rule] -> [RuRe]
redOrgs2Eqs rules reds = toEquals (redOPrs rules reds)

-------------------------------------------------------------------------------
-- Get the implications (partially ordered through the originals they denote)

-- | define a partial order (WITHOUT EQUALS)
data Porder = HI | LW | NT deriving (Eq)

-- | define a comparison function for the partial order of an original rules - equal reductions (indices) pair
pcompare :: RuRe -> RuRe -> Porder
pcompare (x1, _) (x2, _)
         | isSub x2 x1 = HI
         | isSub x1 x2 = LW
         | otherwise = NT

---------------- Top Level Equals (no graph involved)----------------------

-- | get the top of a RuRe pair in a list
getTp :: [RuRe] -> RuRe -> RuRe
getTp ls x = foldr cmpmax x ls where 
                     cmpmax u v | pcompare u v == HI = u
                                | otherwise = v

-- | get all tops from a RuRe list
getTops :: [RuRe] -> [RuRe]
getTops ls = nub $ map (getTp ls) ls

-- | get the indices of the tops
eqixTops :: [Rule] -> [Rule] -> [[Int]]
eqixTops rules  reds =  map snd (getTops $ redOrgs2Eqs rules reds)

-- | replace indices of equals list with actual rule list (of reduced rules) and sort by length
srteqix2reds :: [Rule] -> [Int] -> [Rule]
srteqix2reds reds exls = sortByValNum $ map (reds !!) exls

-- | get the top level for the reductions of a consequent av
abduceTopOne :: [Rule] -> [Rule] -> [[Rule]]
abduceTopOne rules reds = map (srteqix2reds reds) (eqixTops rules reds)

srtabduceTopOne :: [Rule] -> [Rule] -> [[Rule]]
srtabduceTopOne rules = sortListEqs . (abduceTopOne rules)

-- | check if the top level differs in length from the reduced list. No dependencies if not.
hasEDOne :: [[Rule]] -> [Rule] -> Bool
hasEDOne tops reds | (length tops) == (length reds) = False
                   | otherwise = True

-- | get the top levels for the reductions of all values of the consequent attribute
abduceTopAll :: [[Rule]] -> [[Rule]] -> [[[Rule]]]
abduceTopAll rulegrp redsgrp = zipWith srtabduceTopOne rulegrp redsgrp

-- | check the top levels for all consequent values for equals and dependencies
hasDependencies :: [[[Rule]]] -> [[Rule]] -> Bool
hasDependencies topsgrp redsgrp = or $ zipWith hasEDOne topsgrp redsgrp


-------------------------------------------------------------------------
-------------------------------------------------------------------------
-- Build a directed graph of the implications (top down, each edge an entailment).

-- | get nodes from a list of original rules-reductions pairs (start = 1) for an av
myGetNodes :: [RuRe] -> [LNode RuRe]
myGetNodes rurls = zip [1..] rurls

-- | update nodes to get a linear sequence (of nodes)
myUpdateNodes :: [LNode RuRe] -> State Node [LNode RuRe]
myUpdateNodes ndrurls = 
      State (\n -> ( map (plusprior n) ndrurls , n + length ndrurls )) where
                                  plusprior x (nd, rur) = (nd + x, rur)

-- | update all the nodes for an attribute, so they range from 1 to the total number.
contNodes :: [[LNode RuRe]] -> [[LNode RuRe]]
contNodes ndgrls = evalState (mapM myUpdateNodes ndgrls) 0

-- | get labeled nodes from original rules and reductions
rr2Nds :: [Rule] -> [Rule] -> [LNode RuRe]
rr2Nds rules reds = myGetNodes $ redOrgs2Eqs rules reds 

-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------
-- | get labeled nodes from rulegroup and reduction group. THIS is the BASE for all graphs.
orgReg2Ndg :: [[Rule]] -> [[Rule]] -> [[LNode RuRe]]
orgReg2Ndg  rulegrp redgrp = contNodes (zipWith rr2Nds rulegrp redgrp)
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------------------

-- | nodes with reduced reduction equivalences (reds are the reductions for an av)
nodesWRls :: [Rule] -> [LNode RuRe] -> [LNode [Rule]]
nodesWRls reds rurls = map getrule rurls where 
                          getrule (nod, (_,re)) = (nod, srteqix2reds reds re)

-- | get nodes with the indices of the reduction equivalences
nodeLegend :: [[Rule]] -> [[LNode RuRe]] -> [LNode [Rule]]
nodeLegend redsgrp nodegrp = concat $ zipWith nodesWRls redsgrp nodegrp

------------------- get the edges from a list of LNode RuRe --------------

-- | just like getTp, but with nodes (functor here?)
getNdTp :: [LNode RuRe] -> LNode RuRe -> LNode RuRe
getNdTp nodls nod =  
      foldr ndcmpmax nod nodls where 
                   ndcmpmax (nd1,x) (nd2,y) | pcompare x y == HI = (nd1,x)
                                            | otherwise = (nd2,y)

-- | get the top level from a node list (just like getTops)
getNodeTops :: [LNode RuRe] -> [LNode RuRe]
getNodeTops ndls = nub $ map (getNdTp ndls) ndls

-- | split a RuRe list into levels, each level the top of the next lower.
getNodeLevels :: [LNode RuRe] -> [[LNode RuRe]]
getNodeLevels [] = []
getNodeLevels nodls = (getNodeTops nodls):(getNodeLevels $ (nodls \\ (getNodeTops nodls)))

-- | get the edges from a top node to the next lower level
myGtUEdge :: [LNode RuRe] ->  LNode RuRe-> [UEdge]
myGtUEdge lvs tn = zip3 src trgt etyp where
                    src = replicate (length lvs) (fst tn)
                    trgt = map fst rurls
                    etyp = replicate (length lvs) ()
                    rurls = filter (nodecompare tn)  lvs
                    nodecompare (_,x) (_,y) = (pcompare x y) == HI

-- | get the edges from a top level to a lower level (the next)
topUEdges :: [LNode RuRe] -> [LNode RuRe] -> [UEdge]
topUEdges lv1 lv2 = concatMap (myGtUEdge lv2) lv1

-- | get all edges from a level list. Case of only one level returns []
allLevelUEdges :: [[LNode RuRe]] -> [UEdge]
allLevelUEdges [] = error "Abduce allLevelUEdges: list is empty"
allLevelUEdges (_:[]) = []
allLevelUEdges (x:y:ys) = (topUEdges x y) ++ (allLevelUEdges (y:ys))

-- | from a list of nodes, get the corresponding edges
myGetUEdges :: [LNode RuRe] -> [UEdge]
myGetUEdges = allLevelUEdges . getNodeLevels

-- | replace the RuRe with the length of the equivalence list
disrure :: [LNode RuRe] -> [LNode (Int,Int)]
disrure  nodls = map rur2ln nodls where
                          rur2ln (nd, (_ , redidls)) = (nd, (nd, (length redidls))) 

-- | make a graph of a node list
implicGraphOne :: [LNode RuRe] -> Gr (Int,Int) ()
implicGraphOne nodelist =  mkGraph nds edgs where
                                         nds = disrure nodelist
                                         edgs = myGetUEdges nodelist
                                      
-- | make a graph of the group of node lists
implicGraphAll :: [[LNode RuRe]] -> Gr (Int,Int) ()
implicGraphAll nodegroup = mkGraph nds edgs where
                                       nds = disrure $ concat nodegroup
                                       edgs = concatMap myGetUEdges nodegroup