|
| 1 | +{-# LANGUAGE ConstraintKinds #-} |
| 2 | +{-# LANGUAGE TypeFamilies #-} |
| 3 | +{-# LANGUAGE MultiParamTypeClasses #-} |
| 4 | +{-# LANGUAGE FlexibleInstances #-} |
| 5 | +{-# LANGUAGE GeneralizedNewtypeDeriving #-} |
| 6 | + |
| 7 | +-- | If X is a collection of objects denoted generically by x, then a fuzzy set F(A) in X is a set of ordered pairs. |
| 8 | +-- Each of them consists of an element x and a membership function which maps x to the membership space M. |
| 9 | +module FuzzySet |
| 10 | +( FuzzySet (..) |
| 11 | +, preimage |
| 12 | +, empty |
| 13 | +, add |
| 14 | +, support |
| 15 | +, mu |
| 16 | +, core |
| 17 | +, alphaCut |
| 18 | +, fromList |
| 19 | +, map1 |
| 20 | +, map2 |
| 21 | +, union |
| 22 | +, intersection |
| 23 | +, complement |
| 24 | +, algebraicSum |
| 25 | +, algebraicProduct |
| 26 | +, generalizedProduct |
| 27 | +, ExoFunctor (..) |
| 28 | + ) where |
| 29 | + |
| 30 | +import Prelude hiding (fmap) |
| 31 | +import GHC.Exts (Constraint) |
| 32 | +import qualified Algebra.Lattice as L |
| 33 | +import qualified Data.List as List |
| 34 | +import qualified Data.Map as Map |
| 35 | +import qualified Data.Maybe as Maybe () |
| 36 | + |
| 37 | +-- $setup |
| 38 | +-- >>> import Membership |
| 39 | +-- >>> let zfs1 = fromList [(1, Z 0.2), (2, Z 0.5)] |
| 40 | +-- >>> let zfs2 = fromList [(2, Z 0.2), (3, Z 0.2)] |
| 41 | +-- >>> let pfs1 = fromList [(1, PA 0.2), (2, PA 0.5)] |
| 42 | +-- >>> let pfs2 = fromList [(2, PA 0.2), (3, PA 0.2)] |
| 43 | + |
| 44 | +-- | Returns the preimage of the given set in input |
| 45 | +-- prop> preimage (^2) 25 [1..5] == [5] |
| 46 | +preimage :: (Eq i, Eq j) => (i -> j) -> j -> [i] -> [i] |
| 47 | +preimage f y xs = [x | x <- xs, f x == y] |
| 48 | + |
| 49 | +-- | FuzzySet type definition |
| 50 | +newtype FuzzySet m i = FS (Map.Map i m) deriving (Eq, Ord) |
| 51 | + |
| 52 | +instance (Ord i, L.BoundedLattice m, Show i, Show m) => Show (FuzzySet m i) where |
| 53 | + show (FS fs) = "FuzzySet {" ++ List.intercalate "," [show p | p <- Map.assocs fs] ++ "}" |
| 54 | + |
| 55 | +-- | Returns an empty fuzzy set |
| 56 | +empty :: (Ord i, L.BoundedLattice m) => FuzzySet m i |
| 57 | +empty = FS Map.empty |
| 58 | + |
| 59 | +-- | Inserts a new pair (i, m) to the fuzzy set |
| 60 | +-- prop> add zfs1 (i, L.bottom) == zfs1 |
| 61 | +-- prop> add pfs1 (i, L.bottom) == pfs1 |
| 62 | +add :: (Ord i, Eq m, L.BoundedLattice m) => FuzzySet m i -> (i, m) -> FuzzySet m i |
| 63 | +add (FS fs) (i, m) = if m == L.bottom then FS fs else FS (Map.insert i m fs) |
| 64 | + |
| 65 | +-- | Returns the fuzzy set's support |
| 66 | +-- prop> support zfs1 == [1, 2] |
| 67 | +-- prop> support pfs1 == [1, 2] |
| 68 | +support :: (Ord i, L.BoundedLattice m) => FuzzySet m i -> [i] |
| 69 | +support (FS fs) = Map.keys fs |
| 70 | + |
| 71 | +-- | Returns the element i's membership |
| 72 | +-- if i belongs to the support returns its membership, otherwise returns bottom lattice value |
| 73 | +-- prop> mu zfs1 1 == Z 0.2 |
| 74 | +-- prop> mu zfs1 10 == L.bottom |
| 75 | +-- prop> mu pfs1 1 == PA 0.2 |
| 76 | +-- prop> mu pfs1 10 == L.bottom |
| 77 | +mu :: (Ord i, L.BoundedLattice m) => FuzzySet m i -> i -> m |
| 78 | +mu (FS fs) i = case result of |
| 79 | + Nothing -> L.bottom |
| 80 | + (Just m) -> m |
| 81 | + where result = Map.lookup i fs |
| 82 | + |
| 83 | +-- | Returns the crisp subset of given fuzzy set consisting of all elements with membership equals to one |
| 84 | +-- prop> core (fromList [(-1, Z 0.5), (0, Z 0.8), (1, Z 1.0), (2, Z 0.4)]) == [1] |
| 85 | +-- prop> core (fromList [(-1, PA 0.5), (0, PA 0.8), (1, PA 1.0), (2, PA 0.4)]) == [1] |
| 86 | +core :: (Ord i, Eq m, L.BoundedLattice m) => FuzzySet m i -> [i] |
| 87 | +core fs = preimage (mu fs) L.top (support fs) |
| 88 | + |
| 89 | +-- | Returns those elements whose memberships are greater or equal than the given alpha |
| 90 | +-- prop> alphaCut (fromList [(-1, Z 0.5), (0, Z 0.8), (1, Z 1.0), (2, Z 0.4)]) (Z 0.5) == [-1, 0, 1] |
| 91 | +-- prop> alphaCut (fromList [(-1, PA 0.5), (0, PA 0.8), (1, PA 1.0), (2, PA 0.4)]) (PA 0.5) == [-1, 0, 1] |
| 92 | +alphaCut :: (Ord i, Ord m, L.BoundedLattice m) => FuzzySet m i -> m -> [i] |
| 93 | +alphaCut fs alpha = [i | i <- support fs, mu fs i >= alpha] |
| 94 | + |
| 95 | +-- | Builds a fuzzy set from a list of pairs |
| 96 | +-- prop> fromList [(1, Z 0.2)] == add empty (1, Z 0.2) |
| 97 | +-- prop> fromList [(1, PA 0.2)] == add empty (1, PA 0.2) |
| 98 | +fromList :: (Ord i, Eq m, L.BoundedLattice m) => [(i, m)] -> FuzzySet m i |
| 99 | +fromList = foldl add empty |
| 100 | + |
| 101 | +-- | Applies a unary function to the specified fuzzy set |
| 102 | +-- prop> map1 (*2) zfs1 == fromList [(1, Z 0.4), (2, Z 1.0)] |
| 103 | +-- prop> map1 (*2) pfs1 == fromList [(1, PA 0.4), (2, PA 1.0)] |
| 104 | +map1 :: (Ord i, Eq m, L.BoundedLattice m) => (m -> m) -> FuzzySet m i -> FuzzySet m i |
| 105 | +map1 f fs = fromList [(i, f (mu fs i)) | i <- support fs] |
| 106 | + |
| 107 | +-- | Applies a binary function to the two specified fuzzy sets |
| 108 | +-- prop> map2 (+) zfs1 zfs2 == fromList [(1, Z 0.2), (2, Z 0.7), (3, Z 0.2)] |
| 109 | +-- prop> map2 (+) pfs1 pfs2 == fromList [(1, PA 0.2), (2, PA 0.7), (3, PA 0.2)] |
| 110 | +map2 :: (Ord i, Eq m, L.BoundedLattice m) => (m -> m -> m) -> FuzzySet m i -> FuzzySet m i -> FuzzySet m i |
| 111 | +map2 f fs1 fs2 = fromList [(i, f (mu fs1 i) (mu fs2 i))| i <- union_support] |
| 112 | + where union_support = support fs1 `List.union` support fs2 |
| 113 | + |
| 114 | +-- | Returns the union between the two specified fuzzy sets |
| 115 | +-- prop> union zfs1 zfs2 == fromList [(1, Z 0.2), (2, Z 0.5), (3, Z 0.2)] |
| 116 | +-- prop> union pfs1 pfs2 == fromList [(1,PA 0.2),(2,PA 0.6),(3,PA 0.2)] |
| 117 | +union :: (Ord i, Eq m, L.BoundedLattice m) => FuzzySet m i -> FuzzySet m i -> FuzzySet m i |
| 118 | +union = map2 (L.\/) |
| 119 | + |
| 120 | +-- | Returns the intersection between the two specified fuzzy sets |
| 121 | +-- prop> intersection zfs1 zfs2 == fromList [(2, Z 0.2)] |
| 122 | +-- prop> intersection pfs1 pfs2 == fromList [(2, PA 0.1)] |
| 123 | +intersection :: (Ord i, Eq m, L.BoundedLattice m) => FuzzySet m i -> FuzzySet m i -> FuzzySet m i |
| 124 | +intersection = map2 (L./\) |
| 125 | + |
| 126 | +-- | Returns the complement of the specified fuzzy set |
| 127 | +-- prop> complement zfs1 == fromList [(1, Z 0.8), (2, Z 0.5)] |
| 128 | +-- prop> complement pfs1 == fromList [(1, PA 0.8), (2, PA 0.5)] |
| 129 | +complement :: (Ord i, Num m, Eq m, L.BoundedLattice m) => FuzzySet m i -> FuzzySet m i |
| 130 | +complement fs = fromList [(x, L.top - mu fs x) | x <- support fs] |
| 131 | + |
| 132 | +-- | Returns the algebraic sum between the two specified fuzzy sets |
| 133 | +-- prop> algebraicSum zfs1 zfs2 == fromList [(1, Z 0.2), (2, Z 0.7), (3, Z 0.2)] |
| 134 | +-- prop> algebraicSum pfs1 pfs2 == fromList [(1, PA 0.2), (2, PA 0.7), (3, PA 0.2)] |
| 135 | +algebraicSum :: (Ord i, Eq m, Num m, L.BoundedLattice m) => FuzzySet m i -> FuzzySet m i -> FuzzySet m i |
| 136 | +algebraicSum = map2 (+) |
| 137 | + |
| 138 | +-- | Returns the algebraic product between the two specified fuzzy sets |
| 139 | +-- prop> algebraicProduct zfs1 zfs2 == fromList [(2, Z 0.1)] |
| 140 | +-- prop> algebraicProduct pfs1 pfs2 == fromList [(2, PA 0.1)] |
| 141 | +algebraicProduct :: (Ord i, Eq m, Num m, L.BoundedLattice m) => FuzzySet m i -> FuzzySet m i -> FuzzySet m i |
| 142 | +algebraicProduct = map2 (*) |
| 143 | + |
| 144 | +-- | Returns the cartesian product between two fuzzy sets using the specified function |
| 145 | +-- prop> generalizedProduct (+) zfs1 zfs2 == fromList [((1, 2), Z 0.4), ((1, 3), Z 0.4), ((2, 2), Z 0.7), ((2, 3), Z 0.7)] |
| 146 | +-- prop> generalizedProduct (+) pfs1 pfs2 == fromList [((1, 2), PA 0.4), ((1, 3), PA 0.4), ((2, 2), PA 0.7), ((2, 3), PA 0.7)] |
| 147 | +generalizedProduct :: (Ord i, Ord j, Eq m, L.BoundedLattice m) => (m -> m -> m) -> FuzzySet m i -> FuzzySet m j -> FuzzySet m (i, j) |
| 148 | +generalizedProduct f fs1 fs2 = fromList [((x1, x2), f (mu fs1 x1) (mu fs2 x2) )| x1 <- support fs1, x2 <- support fs2] |
| 149 | + |
| 150 | +-- | Defines a mapping between sub-categories preserving morphisms |
| 151 | +class ExoFunctor f i where |
| 152 | + type SubCatConstraintI f i :: Constraint |
| 153 | + type SubCatConstraintI f i = () |
| 154 | + type SubCatConstraintJ f j :: Constraint |
| 155 | + type SubCatConstraintJ f j = () |
| 156 | + |
| 157 | + fmap :: (SubCatConstraintI f i, SubCatConstraintJ f j) => (i -> j) -> f i -> f j |
| 158 | + |
| 159 | +-- | Defines a functor for the FuzzySet type that allows to implement the Extension principle |
| 160 | +-- prop> fmap (^2) (fromList [(-1, Z 0.5), (0, Z 0.8), (1, Z 1.0), (2, Z 0.4)]) == fromList [(0, Z 0.8), (1, Z 1.0), (4, Z 0.4)] |
| 161 | +-- prop> fmap (^2) (fromList [(-1, PA 0.5), (0, PA 0.8), (1, PA 1.0), (2, PA 0.4)]) == fromList [(0, PA 0.8), (1, PA 1.0), (4, PA 0.4)] |
| 162 | +instance (L.BoundedLattice m, Eq m) => ExoFunctor (FuzzySet m) i where |
| 163 | + type SubCatConstraintI (FuzzySet m) i = Ord i |
| 164 | + type SubCatConstraintJ (FuzzySet m) j = Ord j |
| 165 | + |
| 166 | + fmap f fs = fromList [(f x, mu_y (f x)) | x <- support fs] |
| 167 | + where mu_y y = L.joins1 [ mu fs a | a <- preimage f y (support fs)] |
0 commit comments