Subsumption in partially ordered sets
Graham Klyne
gk at ninebynine.org
Mon Nov 17 10:10:30 EST 2003
I have a need for an algorithm to perform "subsumption" on partially
ordered sets of values. That is, given a selection of values from a
partially ordered set, remove all values from the collection that are less
than some other member of the collection.
Below is some code I have written, which works, but I'm not sure that it's
especially efficient or elegant. Are there any published Haskell libraries
that contain something like this?
#g
--
(The implementation here is based on values of type (Eq a) => [Maybe a],
where the partial ordering is defined by function 'pcompare'. Function
dropSubsumed (and helpers) is the subsumption calculation. testds1,
testds2, testds3, testds4, testds5 are test cases, and all should be True.)
[[
-- Type for result of partial order comparison (PNR is no-relationship)
data PartOrdering = PLT | PEQ | PGT | PNR deriving (Eq, Show)
-- Drop tuples from the supplied list that are subsumed by
-- more specific ones.
--
dropSubsumed :: (Eq a) => [[Maybe a]] -> [[Maybe a]]
dropSubsumed [] = []
dropSubsumed [a] = [a]
dropSubsumed (a1:as) = dropSubsumed1 a1 as
dropSubsumed1 a1 [] = [a1]
dropSubsumed1 a1 (a2:a2s) = case pcompare a1 a2 of
PEQ -> dropSubsumed1 a1 a2s
PGT -> dropSubsumed1 a1 a2s
PLT -> dropSubsumed1 a2 a2s
PNR -> dropSubsumed2 [] a1 $ dropSubsumed1 a2 a2s
-- Merge new head element into list from which subsumed elements
-- have already been removed. The extra (first) parameter is used
-- to construct a result in which the order of remaining elements
-- is preserved with respect to the original list.
dropSubsumed2 a1s a [] = a : revConcat a1s []
dropSubsumed2 a1s a ar@(a2:a2s) = case pcompare a a2 of
PEQ -> a : revConcat a1s a2s
PGT -> a : revConcat a1s a2s
PLT -> revConcat a1s ar
PNR -> dropSubsumed2 (a2:a1s) a a2s
revConcat :: [a] -> [a] -> [a]
revConcat [] a2s = a2s
revConcat (a1:a1s) a2s = revConcat a1s (a1:a2s)
-- Perform subsumption calculation between a pair of tuples
-- A tuple with more information subsumes a one with less but
-- consistent information.
--
pcompare :: (Eq a) => [Maybe a] -> [Maybe a] -> PartOrdering
pcompare a1s a2s = pcompare1 a1s a2s PEQ
pcompare1 [] [] po = po
pcompare1 (Just _:a1s) (Nothing:a2s) po =
if (po == PEQ) || (po==PGT) then pcompare1 a1s a2s PGT else PNR
pcompare1 (Nothing:a1s) (Just _:a2s) po =
if (po == PEQ) || (po==PLT) then pcompare1 a1s a2s PLT else PNR
pcompare1 (a1:a1s) (a2:a2s) po =
if a1 == a2 then pcompare1 a1s a2s po else PNR
pcompare1 _ _ _ = PNR
testds1 = ds1a == ds1b
ds1a = dropSubsumed
[ [Just 'a',Just 'b',Just 'c']
, [Just 'a',Just 'b',Nothing ]
, [Just 'a',Nothing ,Just 'c']
, [Just 'a',Nothing ,Nothing ]
, [Nothing ,Just 'b',Just 'c']
, [Nothing ,Just 'b',Nothing ]
, [Nothing ,Nothing ,Just 'c']
, [Nothing ,Nothing ,Nothing ]
]
ds1b =
[ [Just 'a',Just 'b',Just 'c']
]
testds2 = ds2a == ds2b
ds2a = dropSubsumed
[ [Just 'a',Just 'b',Nothing ]
, [Just 'a',Nothing ,Just 'c']
, [Just 'a',Nothing ,Nothing ]
, [Nothing ,Just 'b',Just 'c']
, [Nothing ,Just 'b',Nothing ]
, [Nothing ,Nothing ,Just 'c']
, [Nothing ,Nothing ,Nothing ]
]
ds2b =
[ [Just 'a',Just 'b',Nothing ]
, [Just 'a',Nothing ,Just 'c']
, [Nothing ,Just 'b',Just 'c']
]
testds3 = ds3a == ds3b
ds3a = dropSubsumed
[ [Just "a1",Just "b1",Just "c1"]
, [Just "a2",Just "b2",Nothing ]
, [Just "a3",Nothing ,Just "c3"]
, [Just "a4",Nothing ,Nothing ]
, [Nothing ,Just "b5",Just "c5"]
, [Nothing ,Just "b6",Nothing ]
, [Nothing ,Nothing ,Just "c7"]
, [Nothing ,Nothing ,Nothing ]
]
ds3b =
[ [Just "a1",Just "b1",Just "c1"]
, [Just "a2",Just "b2",Nothing ]
, [Just "a3",Nothing ,Just "c3"]
, [Just "a4",Nothing ,Nothing ]
, [Nothing ,Just "b5",Just "c5"]
, [Nothing ,Just "b6",Nothing ]
, [Nothing ,Nothing ,Just "c7"]
]
testds4 = ds4a == ds4b
ds4a = dropSubsumed
[ [Just 1, Just 1 ]
, [Just 2, Nothing]
, [Nothing,Just 3 ]
, [Nothing,Nothing]
]
ds4b =
[ [Just 1, Just 1 ]
, [Just 2, Nothing]
, [Nothing,Just 3 ]
]
-- Check handling of equal values
testds5 = ds5a == ds5b
ds5a = dropSubsumed
[ [Just 1, Just 1 ]
, [Just 2, Nothing]
, [Nothing,Just 3 ]
, [Nothing,Nothing]
, [Just 1, Just 1 ]
, [Just 2, Nothing]
, [Nothing,Just 3 ]
]
ds5b =
[ [Just 1, Just 1 ]
, [Just 2, Nothing]
, [Nothing,Just 3 ]
]
]]
More information about the Haskell-Cafe
mailing list