packages feed

Emping-0.1: src/Reduce.hs

module Reduce ( redCons ) where

-- (c) 2007 Hans van Thiel
-- Version 0.1 License GPL

-- module: get the reduced normal form of a rule model
-- some general purpose functions

import Data.List (nub, (\\), nubBy, partition )

isSub, isSuper :: Eq a => [a] -> [a] -> Bool
isSub [] y = True
isSub (x:xs) y | not (x `elem` y) = False
               | otherwise = isSub xs y

isSuper = flip isSub

isEq :: Eq a => [a] -> [a] -> Bool
isEq x y = isSub x y && isSub y x

-- minLs needs to take second value because of foldr in extrMin

minLs :: Eq a => [a] -> [a] -> [a]
minLs x y | x `isSub` y = x
          | otherwise = y

-- A: formulate hypothesis from original rules (positive)

hypot :: Eq a => [[a]] -> [a]
hypot = nub . concat

-- B: falsify the hypothesis
--    1. match with all the rules (negative)

match :: Eq a => [a] -> [[a]] -> [[a]]
match h  = map (h \\) 

--    2. transform the orlist of andlists to andlist of orlists

-- test if an attribute is in the list and get it

attElem :: (Eq a, Eq b) => (a,b) -> [(a,b)] -> Maybe (a,b)
attElem x [] = Nothing
attElem x (y:ys) = if fst x == fst y then Just y
                                     else attElem x ys
{- and a predicate to an andlist
     attributes with different values contradict
     attributes with the same value are equal -}

andP :: (Eq a,Eq b) => (a,b) -> [(a,b)] -> [(a,b)]
andP x ans = case attElem x ans of 
                   Nothing -> x:ans
                   Just y -> if snd x == snd y 
                                    then ans
                                    else []            

-- first: anding an orlist to an orlist of andlists
-- remove all the empty lists

repandPls :: (Eq a,Eq b) => [(a,b)] -> [[(a,b)]] -> [[(a,b)]]
repandPls ors als = 
    filter (/= []) [ andP x y | x <- ors, y <- als ]

-- then: extract the smallest sublists from an orlist of andlists

extrMin :: Eq a => [[a]] -> [[a]]
extrMin ls =  nubBy isEq [ getMinin x ls | x <-ls ] 
          where  getMinin x y = foldr minLs x y

-- B.2.1: anding an orlist to an orlist of andlists

andOrAnds :: (Eq a,Eq b) => [(a,b)] -> [[(a,b)]] -> [[(a,b)]]
andOrAnds x = extrMin . (repandPls x)

-- B.2.2: transform andlist of orlists to orlist of andlists in batch

trAndOr :: (Eq a,Eq b) => [[(a,b)]] -> [[(a,b)]]
trAndOr x = foldr andOrAnds (raise (last x)) (init x)
                 where raise ls = [ [y] | y <- ls]

-- C: Verify the falsification result with the original positive rules

verify :: Eq a => [[a]] -> [[a]] -> [[a]]
verify flsd orig = [x | x <- flsd , x `isIn` orig ] where
                    isIn y ls = or (map (isSub y) ls)

-- A, B and C: reduce a list of positive original rules 

redPos :: (Eq a,Eq b) => [[(a,b)]] -> [[(a,b)]] -> [[(a,b)]]
redPos p n = verify (trAndOr (match (hypot p) n)) p

-- reduce a list of attribute-value pairs by selecting the
-- consequent. The consequent attribute is removed from p and n

-- remove the consequent attributes

rmAtt :: (Eq a, Eq b) => a -> [[(a,b)]] -> [[(a,b)]]
rmAtt at rws =  map rm rws where 
                    rm  ls = [y | y <- ls, at /= fst y ]

-- reduce the list of attribute- value pairs (no consequent)

redCons :: (Eq a, Eq b) => (a,b) -> [[(a,b)]] -> [[(a,b)]]
redCons x y = redPos p n where
                    z= partition (x `elem`) y 
                    p = rmAtt (fst x) (fst z)
                    n = rmAtt (fst x) (snd z)