Thursday, August 26, 2010

Fuzzy Logic in F#, Example 1

Here is an example of the use of the F# fuzzy logic functions presented yesterday. This example involves the price of tomatoes.

For the purposes of this example, tomatoes come in three sizes: tiny (salad size), small, medium, and large. Of the three larger sizes, people tend to prefer medium, so they are the most expensive. Large (being overripe and watery) are cheaper, and small are the cheapest. However, tiny tomatoes, useful for salads and garnishes, command a premium price.

My solution encodes this tomato wisdom in a set of four rules. It also prints a list of tomato size vs. price, estimated using the rules. I have taken the liberty of graphing this output, complete with gratuitous tomato colorization in the chart below:

And below is the code. It relies on the F# fuzzy logic functions presented in yesterday’s blog. As always, all the code here is presented "as-is" and without warranty or implied fitness of any kind; use at your own risk.

Admittedly, this is not a stunning example of the power of fuzzy logic, but it does illustrate a few of the basic techniques. A good reference, like the previously mentioned Fuzzy Logic With Engineering Applications, by Timothy J. Ross, will reveal the broader range of fuzzy logic techniques.

Tomorrow I will show how conjunction can be used to create rules which use more than one input set to combine different types of data.

module Program
open Trapezoid
// This function will turn a pair of
// fuzzy sets into a function that will
// act as a rule.  The input to the function
// is the x value, and the output is a tuple 
// of the output set area and its centroid.
let makeRule (l0,l1) = 
  let f =
    >> Seq.toArray 
  let a0 = f l0
  let a1 = f l1
  (fun x->
    Trapezoid.height x a0 
    |> Trapezoid.project a1)
// Tomato size in inches.
let tiny   = [(0.0,1.0);(1.0,1.0);(2.0,0.0)]
let small  = [(1.0,0.0);(2.0,1.0);(3.0,0.0)]
let medium = [(2.0,0.0);(3.0,1.0);(4.0,0.0)]
let large  = [(3.0,0.0);(5.0,1.0);(9.0,1.0)]
// Tomato price in $.
let cheap      = [(0.50,0.0);(1.00,1.0);(1.50,0.0)]
let moderate   = [(1.00,0.0);(1.50,1.0);(2.00,0.0)]
let expensive  = [(1.50,0.0);(2.00,1.0);(2.50,0.0)]
let outrageous = [(2.00,0.0);(4.00,1.0);(6.00,0.0)]
// The ruleset.
let rules =
  ] |> makeRule
// Map the ruleset to a range of
// tomato sizes.
for size in 0.25..0.25..5.00 do
  printfn "%f, %f" 
    ( (fun r->r size) rules
     |> List.fold (fun (a,b)(ax,bx)->a+ax,b+ax*bx) (0.0,0.0)
     |> (fun (a,b)->b/a))
printf "Your breakpoint here."


Art said...

Hi Neil.
What about parallel fuzzy performance vs ...?

In the day I met Lofti Zadeh and Bart Kosko ...

TechNeilogy said...

Thanks, Art. One of the fun things about being in computer science is the fact that one can still meet the pioneers. Imagine being a mathematician and having met Newton or Euler! In computer science, that's kind of thing is still possible.

With respect to parallelism, an upcoming entry may answer that. I’ve decided to defer posting my example of fuzzy conjunction in order to demonstrate how a fuzzy logic system can be made simpler and more functional. One of my goals in that is to show that fuzzy logic can allow for the capture of powerful, distilled experience in a form that is simple enough to burn onto an inexpensive chip – or to parallelize on a more complex system.

darklajid said...

Like the article and the series. But I stumbled right at the beginning:

"For the purposes of this example, tomatoes come in three sizes:"

1) tiny (salad size)
2) small
3) medium
4) and large.

TechNeilogy said...

It's a new branch of mathematics I'm working on: Fuzzy Counting, lol.