Emping-0.2: src/Abduce.hs
module Abduce ( abdAll, treehasED, cntEDAtt ) where
-- (c) 2007 Hans van Thiel
-- Version 0.2 License GPL
-- module: get partial order, if any, of RNF rules
import Reduce (isSub )
import Data.List ( findIndices, nubBy, partition )
import Data.Tree ( Tree(..), Forest )
-- general purpose functions
-- tree map (fmap not accessible from Data.Tree (???)
treeMap :: (a -> b) -> Tree a -> Tree b
treeMap f (Node x ts) = Node (f x) (map (treeMap f) ts)
---------------------------------------------------
-- define a Poset (WITHOUT EQUALS)
data Porder = HI | LW | NT deriving (Eq)
class (Eq a) => Poset a where
pcompare :: a -> a -> Porder
-- put a poset in a tree, each branch is an ordered chain
-- unordered elements are in the same subforest
ins2Tree :: Poset a => a -> Tree a -> Tree a
ins2Tree x t =
case pcompare x (rootLabel t) of
LW -> Node (rootLabel t) (ins2Forest x (subForest t))
HI -> Node x (t:[])
NT -> t
ins2Forest :: Poset a => a -> Forest a -> Forest a
ins2Forest x [] = (Node x []):[]
ins2Forest x for
| new == for = (Node x []):for
| otherwise = new
where new = map (ins2Tree x) for
-- put a list of partially ordered elements in forest
isRoot :: Poset a => [a] -> a -> Bool
isRoot ls x = and $ map ((LW /=) . (x `pcompare`)) ls
initRoots :: Poset a => [a] -> Forest a
initRoots ls = map ((flip Node) []) ls
lsinFor :: Poset a => [a] -> Forest a -> Forest a
lsinFor [] for = for
lsinFor (x:xs) for = ins2Forest x (lsinFor xs for)
list2Forest :: Poset a => [a] -> Forest a
list2Forest ls = lsinFor res for where
(x,res) = partition (isRoot ls) ls
for = initRoots x
-----------------------------------------------------
-----------------------------------------------------
-- A: match indices of reduced rules with indices of
-- the original(s) denoted by a reduced rule
-- indices of original rule(s) denoted by reduced
-- rule. Note: consequent included, for simplicity
redOrgs :: (Eq a, Eq b) => [[(a,b)]] -> [(a,b)] -> [Int]
redOrgs rules red = findIndices (red `isSub`) rules
-- tuples of the indices of originals and the reduced
-- rule index for orgs and reds with same av consequent
redOPrs :: (Eq a, Eq b) => [[(a,b)]] -> [[(a,b)]] -> [([Int],Int)]
redOPrs rules reds = zip orixls [0..] where
orixls = map (redOrgs rules) reds
-- get all reds denoting the same original (ONE)
-- Note: first denote originals, second reduced equals
getEquals :: [([Int],Int)] -> ([Int],Int) -> ([Int],[Int])
getEquals y (ols,_)=
(ols, [snd x | x <- y, fst x == ols ])
-- group original-red pairs into original-equals paire
-- remove doubles of origs, maybe same, different order
toEquals :: [([Int],Int)] -> [([Int],[Int])]
toEquals orpl = nubBy eqOrg ls where
ls = map (getEquals orpl) orpl
eqOrg (x1,y1) (x2,y2) = isSub x1 x2 && isSub x2 x1
-------------------------------------------------------
-- first orig indices, second red indices matched
-- from rules to reds with same consequent av
redOrgs2Eqs :: (Eq a, Eq b) => [[(a,b)]] -> [[(a,b)]] -> [([Int],[Int])]
redOrgs2Eqs rules reds = toEquals (redOPrs rules reds)
------------------------------------------------------
-- B: show partial order, according to sublists of origs
-- the reds are in implication chain of orig sublists
-- define type RuRe as a poset
type RuRe = ([Int],[Int])
-- first in orig is high, low or not ordered
instance Poset RuRe where
pcompare (x1,y1) (x2,y2)
| isSub x2 x1 = HI
| isSub x1 x2 = LW
| otherwise = NT
---------------------------------------------------
-- convert rules and reds for same consequent into
-- a poset forest
redOrgs2Forest :: (Eq a, Eq b) => [[(a,b)]] -> [[(a,b)]] -> Forest RuRe
redOrgs2Forest rules reds =
list2Forest (redOrgs2Eqs rules reds)
-- order is determined, original indices no longer needed
remOrgs :: Forest RuRe -> Forest [Int]
remOrgs for = map (treeMap snd) for
-- produces the partial order of reduceds, with
-- indices of equals in one list (rules WITH cons)
reds2EqsFor :: (Eq a, Eq b)=> [[(a,b)]] -> [[(a,b)]] -> Forest [Int]
reds2EqsFor rules reds =
remOrgs (redOrgs2Forest rules reds)
-- replace indices list with rule list (of equals)
eqix2reds :: (Eq a, Eq b) => [[(a,b)]] -> [Int] -> [[(a,b)]]
eqix2reds reds exls = map (reds !!) exls
-- from a list of original rules and their reductions
-- get the partial order of the reductions (with conseq)
abd1Val :: (Eq a, Eq b) => [[(a,b)]] -> [[(a,b)]] -> Forest [[(a,b)]]
abd1Val rules reds = map trmf for where
trmf = treeMap (eqix2reds reds)
for = reds2EqsFor rules reds
------------------------------------------------------
-- abduce all reductions for a selected attribute
abdAll :: (Eq a, Eq b) => [[[(a,b)]]] -> [[[(a,b)]]] -> [ Forest [[(a,b)]] ]
abdAll rulegrp redsgrp = zipWith abd1Val rulegrp redsgrp
-------------------------------------------------------
-- check if a tree contains a branch and/or equals
treehasED :: (Eq a, Eq b) => Tree [[(a,b)]] -> Bool
treehasED t | length (rootLabel t) == 1
&& subForest t == [] = False
| otherwise = True
-- count branches and/or equals in forest,
-- fst is number of chains, snd number of singles
cntEDVal :: (Eq a, Eq b) => Forest [[(a,b)]] -> (Int,Int)
cntEDVal for = (dep, sin) where
dep = sum $ fst (unzip temp)
sin = sum $ snd (unzip temp)
temp = map (mark . treehasED) for
mark x | x == True = (1,0)
| x == False = (0,1)
-- count branches and/or equals in attribute abduction
-- fst is chain count, snd is number of unconnected rules
cntEDAtt :: (Eq a, Eq b) => [Forest [[(a,b)]] ] -> (Int,Int)
cntEDAtt forls = (dep, sin) where
dep = sum $ fst (unzip temp)
sin = sum $ snd (unzip temp)
temp = map cntEDVal forls