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.