A standard haskell setup is needed, including:
Both Gtk2hs and GHC can be automatically installed in most Linux distributions using your package manager.
You can download and install ffuzz doing:
$ darcs get http://babel.ls.fi.upm.es/~egallego/repos/ffuzz/ $ cd ffuzz $ runhaskell Setup.hs configure $ runhaskell Setup.hs build $ runhaskell Setup.hs haddock $ runhaskell Setup.hs install
Start ghci and type:
*> :m Fuzzy.Set Prelude Fuzzy.Set> 1.83 `is` tall 1.0 Prelude Fuzzy.Set> 1.83 `is` tall /\ short 0.0 Prelude Fuzzy.Set> 1.65 `is` tall /\ short 0.24999999999999917 Prelude Fuzzy.Set> :m +Fuzzy.Render *Fuzzy.Render> Fuzzy.Render.init *Fuzzy.Render> wrender [tall]
And you should see the following image.
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
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:
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) where 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.
Working on it.