{- | This module contains parametrized membership function 
    use currying to construct the functions 
    arguments a b c ... are parameters for constructing specific functions 
    x is the variable for which membership is evaluated
-}

module Fuzzy.Sets.MembershipFunctions(
    constant, 
    linear, 
    sigmoid, 
    triangular,
    rectangular,
    trapezoidal,
    gaussian,
    exponential,
) where


import Lattices.ResiduatedLattice


{- | Constant function that returns `a` for any value of `x` \[f(x) = a\]

==== __Examples__

>>> let f = constant 0.5 :: Double -> UILukasiewicz
>>> f 1
0.5

>>> f 100
0.5
-}
constant :: ResiduatedLattice l => Double -> (Double -> l)
constant :: forall l. ResiduatedLattice l => Double -> Double -> l
constant Double
a Double
_ = forall l. BoundedLattice l => Double -> l
mkLattice Double
a


{-| Standart textbook linear function where \[f(x) = ax + b\]

>           / 
>          /   
>         /

==== __Examples__

>>> let f = linear 2 1 :: Double -> UILukasiewicz
>>> f 0
1.0

>>> f 1
3.0

>>> f (-1)
-1.0
-}
linear :: ResiduatedLattice l => Double -> Double -> (Double -> l)
linear :: forall l. ResiduatedLattice l => Double -> Double -> Double -> l
linear Double
a Double
b Double
x =
    let y :: Double
y = Double
a forall a. Num a => a -> a -> a
* Double
x forall a. Num a => a -> a -> a
+ Double
b
    in forall l. BoundedLattice l => Double -> l
mkLattice Double
y


{-| Standart logistic function
Takes K which is growth value of the function and x0 a midpoint of the function. \[f(x) = \frac{1}{1 + e^{ -k(x - x_0)}} \]
               
>                       ______
>                    .´      
>                  /           
>           _____.'       

==== __Examples__

>>> let f = sigmoid 1 0 :: Double -> UILukasiewicz
>>> f 0
0.5

>>> f 1
0.7310585786300049

>>> f (-1)
0.2689414213699951
-}
sigmoid :: ResiduatedLattice l => Double -> Double -> (Double -> l)
sigmoid :: forall l. ResiduatedLattice l => Double -> Double -> Double -> l
sigmoid Double
k Double
x0 Double
x =
    let pow :: Double
pow = -Double
k forall a. Num a => a -> a -> a
* (Double
x forall a. Num a => a -> a -> a
- Double
x0)
    in forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ Double
1 forall a. Fractional a => a -> a -> a
/ (Double
1 forall a. Num a => a -> a -> a
+ (forall a. Floating a => a -> a
exp Double
1 forall a. Floating a => a -> a -> a
** Double
pow))

{-| A combination of two linear functions
with this specific shape. first and second arguments are interval determining where the triangle will be on the number line. \[
\operatorname{tri}(x) =
\begin{cases}
    \frac{x - a}{b - a}, & a \leq x < b \\
    \frac{c - x}{c- b}, & b \leq x \leq c \\
    0, & \text{otherwise}
\end{cases}
\] 0 stands for 'bot' 

>          
>             /\
>          __/  \__

==== __Examples__

>>> let f = triangular 0 1 2 :: Double -> UILukasiewicz
>>> f 0
0.0

>>> f 0.5
0.5

>>> f 1
1.0

>>> f 1.5
0.5

>>> f 2
0.0

-}
triangular :: ResiduatedLattice l => Double -> Double -> Double -> (Double -> l)
triangular :: forall l.
ResiduatedLattice l =>
Double -> Double -> Double -> Double -> l
triangular Double
a Double
b Double
c Double
x 
    | Double
a forall a. Ord a => a -> a -> Bool
<= Double
x Bool -> Bool -> Bool
&& Double
x forall a. Ord a => a -> a -> Bool
< Double
b = forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ (Double
x forall a. Num a => a -> a -> a
- Double
a) forall a. Fractional a => a -> a -> a
/ (Double
b forall a. Num a => a -> a -> a
- Double
a)
    | Double
b forall a. Ord a => a -> a -> Bool
<= Double
x Bool -> Bool -> Bool
&& Double
x forall a. Ord a => a -> a -> Bool
< Double
c = forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ (Double
c forall a. Num a => a -> a -> a
- Double
x) forall a. Fractional a => a -> a -> a
/ (Double
c forall a. Num a => a -> a -> a
- Double
b)
    | Bool
otherwise       = forall l. BoundedLattice l => l
bot
    


{-| Constant function on interval [a, b], first two arguments, else returns 'bot' of Residuated lattice
- this creates a rectangle shaped function. Third argument is height of the set.

>             _____ 
>            |     |
>         ___|     |___


>>> let f = rectangular 1 3 0.8 :: Double -> UILukasiewicz
>>> f 0
0.0

>>> f 2
0.8

>>> f 3
0.8

>>> f 4
0.0
-}
rectangular :: ResiduatedLattice l => Double -> Double -> Double -> (Double -> l)
rectangular :: forall l.
ResiduatedLattice l =>
Double -> Double -> Double -> Double -> l
rectangular Double
a Double
b Double
h Double
x
    | Double
x forall a. Ord a => a -> a -> Bool
>= Double
a Bool -> Bool -> Bool
&& Double
x forall a. Ord a => a -> a -> Bool
<= Double
b = forall l. BoundedLattice l => Double -> l
mkLattice Double
h
    | Bool
otherwise        = forall l. BoundedLattice l => l
bot


{-| Trapezoidal function is combination of triangular and rectangular functions \[
\operatorname{tra}(x) =
\begin{cases}
    \frac{x - a}{b1 - a}, & a \leq x < b1 \\
    1, & b1 \leq x < b2  \\
    \frac{c - x}{c -b2}, & b2 \leq x < c \\
    0, & \text{otherwise}
\end{cases}
\]

>           _______   
>          /       \
>       __/         \__

==== __Examples__

>>> let f = trapezoidal 0 1 3 4 :: Double -> UILukasiewicz
>>> f 0
0.0

>>> f 0.5
0.5

>>> f 1
1.0

>>> f 2
1.0

>>> f 3.5
0.5

>>> f 4
0.0
-}
trapezoidal :: ResiduatedLattice l => Double -> Double -> Double -> Double -> (Double -> l)
trapezoidal :: forall l.
ResiduatedLattice l =>
Double -> Double -> Double -> Double -> Double -> l
trapezoidal Double
a Double
b1 Double
b2 Double
c Double
x 
    | Double
a forall a. Ord a => a -> a -> Bool
<= Double
x Bool -> Bool -> Bool
&& Double
x forall a. Ord a => a -> a -> Bool
< Double
b1   = forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ (Double
x forall a. Num a => a -> a -> a
- Double
a) forall a. Fractional a => a -> a -> a
/ (Double
b1 forall a. Num a => a -> a -> a
- Double
a)
    | Double
b1 forall a. Ord a => a -> a -> Bool
<= Double
x Bool -> Bool -> Bool
&& Double
x forall a. Ord a => a -> a -> Bool
<= Double
b2 = forall l. BoundedLattice l => l
top
    | Double
b2 forall a. Ord a => a -> a -> Bool
<= Double
x Bool -> Bool -> Bool
&& Double
x forall a. Ord a => a -> a -> Bool
< Double
c   = forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ (Double
c forall a. Num a => a -> a -> a
- Double
x) forall a. Fractional a => a -> a -> a
/ (Double
c forall a. Num a => a -> a -> a
- Double
b2)
    | Bool
otherwise = forall l. BoundedLattice l => l
bot


{-| Gausian function, also called Bell Curve

>           
>                     .-' `-.
>                   .'       `.
>                  /           \
>                /               \
>        ______.'                 '.____

==== __Examples__

>>> let f = gaussian 1 0 1 :: Double -> UILukasiewicz
>>> f 0
1.0

>>> f 1
0.6065306597126334

>>> f (-1)
0.6065306597126334

>>> f 2
0.1353352832366127
-}
gaussian :: ResiduatedLattice l => Double -> Double -> Double -> (Double -> l)
gaussian :: forall l.
ResiduatedLattice l =>
Double -> Double -> Double -> Double -> l
gaussian Double
a Double
b Double
c Double
x =
    let e :: Double
e     = forall a. Floating a => a -> a
exp Double
1
        numer :: Double
numer = (Double
x forall a. Num a => a -> a -> a
+ Double
b) forall a. Floating a => a -> a -> a
** Double
2
        denom :: Double
denom = Double
2 forall a. Num a => a -> a -> a
* (Double
c forall a. Floating a => a -> a -> a
** Double
2)
        pow :: Double
pow   = -(Double
numer forall a. Fractional a => a -> a -> a
/ Double
denom)
    in forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ Double
a forall a. Num a => a -> a -> a
* Double
eforall a. Floating a => a -> a -> a
**Double
pow


{-| Exponential function eˣ

>           
>                    |
>                   '  
>                  /   
>                 /     
>        ______.'   

==== __Examples__

>>> let f = exponential :: Double -> UILukasiewicz
>>> f 0
1.0

>>> f 1
2.718281828459045

>>> f (-1)
0.36787944117144233
-}
exponential :: ResiduatedLattice l => Double -> l
exponential :: forall l. ResiduatedLattice l => Double -> l
exponential Double
x = 
    let e :: Double
e = forall a. Floating a => a -> a
exp Double
1
    in forall l. BoundedLattice l => Double -> l
mkLattice forall a b. (a -> b) -> a -> b
$ Double
eforall a. Floating a => a -> a -> a
**Double
x