Getting started:

Required tools:

A standard haskell setup is needed, including:

Both Gtk2hs and GHC can be automatically installed in most Linux distributions using your package manager.

Getting and compiling ffuzz:

You can download and install ffuzz doing:

$ darcs get
$ cd ffuzz
$ runhaskell Setup.hs configure
$ runhaskell Setup.hs build
$ runhaskell Setup.hs haddock
$ runhaskell Setup.hs install

Testing that it works:

Start ghci and type:

*> :m Fuzzy.Set
Prelude Fuzzy.Set> 1.83 `is` tall
Prelude Fuzzy.Set> 1.83 `is` tall /\ short
Prelude Fuzzy.Set> 1.65 `is` tall /\ short
Prelude Fuzzy.Set> :m +Fuzzy.Render
*Fuzzy.Render> Fuzzy.Render.init
*Fuzzy.Render> wrender [tall]

And you should see the following image.

Example 1

Basic examples:

Creating a new Fuzzy Set

In order to create a new Fuzzy Set, you first have to declare its domain, which we call a "Linguistic Variable"

newtype Height = D Double
    deriving (Eq, Ord, Num, Enum, Real, Fractional, Show)

instance Bounded Height where
    minBound = 1.00
    maxBound = 2.10

instance VarLing Height where
    resolution = 0.01

Currently, ffuzz uses the Haskell type class system to know wheter a type can also act as a liguistic variable.

Once done that, declaring a set such as tall is easy, using the predefined sets:

tall :: FSet Height
tall = up 1.60 1.80

Building a shower controller

The following example, classic in the literature, is a fuzzy controller for a shower. The controller needs to control the cold and hot gauges so the flow and temperature is reasonable for the user.

We first declare our linguistic variables:

newtype Temp = Temp Double
newtype Flow = Flow Double
newtype Change = Change Double

Again, before building the controller itself, we need some Fuzzy Sets to represent the knowledge we've got about the shower, so a reasoble set of sets is:

-- Temperature
cold, ok, hot       :: FSet Temp

-- Flow strength
weak, right, strong :: FSet Flow

-- Flow change (NegativeBig... PositiveBig)
nb, nm, ns, z, ps, pm, pb :: FSet Change

Then, the type for the controller should be:

-- Taps are (Hot, Cold)
shower_control :: (Temp, Flow) -> (Change, Change)

this is, it reads the current flow and temperature and returns the needed changes for the hot and cold taps.

A reasonable ruleset (taken from Meeham, Joy), could be the following:

ruleset :: Flow -> Temp -> [(FSet Change, FSet Change)]
ruleset flow temp =
    [temp `is` cold &? flow `is` weak   ==> (pm, z),
     temp `is` cold &? flow `is` right  ==> (pm, z),
     temp `is` cold &? flow `is` strong ==> (z, nb),
     temp `is` ok   &? flow `is` weak   ==> (ps, ps),
     temp `is` ok   &? flow `is` strong ==> (ns, ns),
     temp `is` hot  &? flow `is` weak   ==> (z,  pb),
     temp `is` hot  &? flow `is` right  ==> (nm, pb),
     temp `is` hot  &? flow `is` strong ==> (nb, z)]

Notice that the ruleset is a list of fuzzy sets, so to get any significant result we'll need to aggregate it. We can do this from the haskell interpeter, using a sum aggregator:

*Fuzzy.Examples.Shower> let (hs, cs) = foldl1 (d2 (fapp (+)))
                                       (ruleset 10 20)
*Fuzzy.Examples.Shower> wrender [hs,cs]

So we get the following fuzzy sets:

Shower result 1

All it is remaining is to deffuzify the results, so the final code of the shower control function then looks like:

shower_control :: (Temp, Flow) -> (Change, Change)
shower_control (temp, flow) = (defuz hv, defuz cv)
      defuz = centroid
      (hv, cv) = foldl1 (d2 (\/)) (ruleset flow temp)

We can then build a simulation using the facilities provided by the control library:

shower_sys :: FSystem (Temp, Flow) (Change, Change)
shower_sys = FS {
               initialState = (20,0),
               applyToState = register_taps,
               infer = change_valves

So a 200 steps simulation looks like:

*Fuzzy.Examples.Shower> last $ simulate shower_sys 200
(Temp 34.47912686493167,Flow 12.177642399809779)

The full working example is on the Examples directory.

An advanced example:

Working on it.