[GRASS-user] r.fuzzy.system help with defuzzification

Hello,

https://grass.osgeo.org/grass78/manuals/addons/r.fuzzy.system.html

I'd like to use the =r.fuzzy.system= addons for GRASS, but am having trouble understanding the output. I'm concerned there is a bug. Below is a minimum example I've created to demonstrate the issue. If anyone on this list has experience with these modules or interest in helping getting their documentation improved so that they are easier to use, I can take the lead but would benefit from some help with this.

I have already improved some of the incorrect docs for these addons (see https://github.com/OSGeo/grass-addons/pull/175 ) but am now returning to a bug I opened a few months ago here https://github.com/OSGeo/grass-addons/issues/176

I'm not 100 % certain there is a bug - I could be using or interpreting the results incorrectly. I hope that is the case and this is a simple fix. If code changes are required, I will try to implement them, but would be grateful for pointers about what/where if someone else sees something I have not yet noticed. I am open to including collaborators as co-authors on a paper I'm writing if the effort needed to get this working and the contribution are significant.

Here (and the GitHub issue above) is the best way I can demonstrate the issue:

* GRASS Fuzzy Code Test

+ Four-cell raster map foo = [1, 2, 3, 4]
  + Foo is "low" when 1, "hi" when 4, and linear change between
  + foo_lo = [1, 0.66, 0.33, 0]
  + foo_hi = [0, 0.33, 0.66, 1]
+ Output is "sad" when foo is "lo", "happy" when foo is "hi", and linear between
  + Expected output:
    + out values = [1, 0.66, 0.33, 0]
    + out label: [sad=1 happy=0; sad=0.66 happy=0.33; sad=0.33 happy=0.66; sad=0 happy=1]

** Summary

Results from
#+BEGIN_SRC bash
r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules output=out res=10
r.stats -1l out
#+END_SRC

Are:

#+RESULTS:
| 0.63636363 | sad=1.00 | happy=1.00 |
| 0.54545456 | sad=1.00 | happy=1.00 |
| 0.36363637 | sad=1.00 | happy=1.00 |
| 0.27272728 | sad=1.00 | happy=1.00 |

I can see that I've encoded sadness, presumably because that was listed first in the fuzzy.maps __OUTPUT__ (that file contents is shown below), but both sad=1.0 and happy=1.0 seems incorrect to me.

** Set up domain and helper functions

#+BEGIN_SRC bash :results verbatim
grass -c ./G_fuzzy

export GRASS_OVERWRITE=1
export GRASS_VERBOSE=0
g.region w=0 s=0 e=4 n=1 res=1 -pa -s
#+END_SRC

** Define data

#+BEGIN_SRC bash
r.mapcalc "foo = float(col())"
r.stats -1 foo
#+END_SRC

#+RESULTS:
| 1 |
| 2 |
| 3 |
| 4 |

** Set up rules

#+BEGIN_SRC conf :tangle fuzzy.maps
% foo
$ lo {right; 1,4; linear; 0; 1}
$ hi {left; 1,4; linear; 0; 1}

% _OUTPUT_
$ sad {left; 0,1; linear; 0;1}
$ happy {right; 0,1; linear; 0;1}
#+END_SRC

#+BEGIN_SRC conf :tangle fuzzy.rules
$ happy { foo = hi }
$ sad { foo = lo }
#+END_SRC

** Run the fuzzy system with pixel-level debug output

#+BEGIN_SRC bash :results verbatim
r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules output=out res=10 coors=0.5,0.5
echo " "
r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules output=out res=10x coors=3.5,0.5
#+END_SRC

#+RESULTS:
#+begin_example
ANTECEDENT happy: 0.000
ANTECEDENT sad: 1.000
RESULT (defuzzified): 0.636
UNIVERSE,happy,sad,AGREGATE
0.000,0.000,0.000,0.000
0.091,0.000,0.091,0.091
0.182,0.000,0.182,0.182
0.273,0.000,0.273,0.273
0.364,0.000,0.364,0.364
0.455,0.000,0.455,0.455
0.545,0.000,0.545,0.545
0.636,0.000,0.636,0.636
0.727,0.000,0.727,0.727
0.818,0.000,0.818,0.818
0.909,0.000,0.909,0.909

ANTECEDENT happy: 1.000
ANTECEDENT sad: 0.000
RESULT (defuzzified): 0.273
UNIVERSE,happy,sad,AGREGATE
0.000,1.000,0.000,1.000
0.091,0.909,0.000,0.909
0.182,0.818,0.000,0.818
0.273,0.727,0.000,0.727
0.364,0.636,0.000,0.636
0.455,0.545,0.000,0.545
0.545,0.455,0.000,0.455
0.636,0.364,0.000,0.364
0.727,0.273,0.000,0.273
0.818,0.182,0.000,0.182
0.909,0.091,0.000,0.091
#+end_example

** Run the fuzzy system to get raster output

#+BEGIN_SRC bash
r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules output=out res=10
#+END_SRC

#+RESULTS:

Test the intermediate result from =-m= flag.

#+BEGIN_SRC bash
r.stats -1 out_sad
#+END_SRC

#+RESULTS:
| 1 |
| 0.66666669 |
| 0.33333334 |
| 0 |

#+BEGIN_SRC bash
r.stats -1 out_happy
#+END_SRC

#+RESULTS:
| 0 |
| 0.33333334 |
| 0.66666669 |
| 1 |

Now inspect the final result

#+BEGIN_SRC bash :results verbatim
r.stats -1l out
#+END_SRC

#+RESULTS:
: 0.63636363 sad=1.00 happy=1.00
: 0.54545456 sad=1.00 happy=1.00
: 0.36363637 sad=1.00 happy=1.00
: 0.27272728 sad=1.00 happy=1.00

+ The intermediate results, =out_sad= and =out_happy= make sense, but the final result does not.
+ This suggests there is an issue with the defuzzification step. Let's try other methods.

#+BEGIN_SRC bash :results verbatim
r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules output=out res=10 defuz=bisector imp=minimum
r.stats -1l out
#+END_SRC

#+RESULTS:
:
: 0.63636363 sad=1.00 happy=1.00
: 0.54545456 sad=1.00 happy=1.00
: 0.36363637 sad=1.00 happy=1.00
: 0.27272728 sad=1.00 happy=1.00

Expected results:

Output value = [1,0.6, 0.3, 0] # can achieve close to 1 if we increase =res= option to =r.fuzzy.system=
Output label = [sad=1 happy=0; sad=0 happy=1]
  Optionally, output label = [sad=<near 1> happy=<near 0>; sad=<near 0> happy=<near 1>]

Any suggestions will be greatly appreciated.

Regards,

  -k.

Hi GRASS List,

Following up on the previous message regarding fuzzy logic and GRASS - The scikit-fuzzy toolbox https://pythonhosted.org/scikit-fuzzy/ is very easy to use and it looks like it supports a super-set of the functionality provided by the GRASS addon. The GRASS addon does appear to have some issues, but thanks to grass-session and the general ease of getting GRASS data into Numpy arrays, it's easy to work with scikit-fuzzy instead.

Pro's to scikit-fuzzy: maintained, more complete, simpler interface, better documentation.

Cons: Must leave GRASS, Orders of magnitude slower.

  -k.

On 2020-08-31 at 12:12 -07, Ken Mankoff <mankoff@gmail.com> wrote...

Hello,

https://grass.osgeo.org/grass78/manuals/addons/r.fuzzy.system.html

I'd like to use the =r.fuzzy.system= addons for GRASS, but am having
trouble understanding the output. I'm concerned there is a bug. Below
is a minimum example I've created to demonstrate the issue. If anyone
on this list has experience with these modules or interest in helping
getting their documentation improved so that they are easier to use, I
can take the lead but would benefit from some help with this.

I have already improved some of the incorrect docs for these addons
(see https://github.com/OSGeo/grass-addons/pull/175 ) but am now
returning to a bug I opened a few months ago here
https://github.com/OSGeo/grass-addons/issues/176

I'm not 100 % certain there is a bug - I could be using or
interpreting the results incorrectly. I hope that is the case and this
is a simple fix. If code changes are required, I will try to implement
them, but would be grateful for pointers about what/where if someone
else sees something I have not yet noticed. I am open to including
collaborators as co-authors on a paper I'm writing if the effort
needed to get this working and the contribution are significant.

Here (and the GitHub issue above) is the best way I can demonstrate
the issue:

* GRASS Fuzzy Code Test

+ Four-cell raster map foo = [1, 2, 3, 4]
  + Foo is "low" when 1, "hi" when 4, and linear change between +
  foo_lo = [1, 0.66, 0.33, 0] + foo_hi = [0, 0.33, 0.66, 1]
+ Output is "sad" when foo is "lo", "happy" when foo is "hi", and
linear between
  + Expected output:
    + out values = [1, 0.66, 0.33, 0] + out label: [sad=1 happy=0;
    sad=0.66 happy=0.33; sad=0.33 happy=0.66; sad=0 happy=1]

** Summary

Results from #+BEGIN_SRC bash r.fuzzy.system -m maps=fuzzy.maps
rules=fuzzy.rules output=out res=10 r.stats -1l out #+END_SRC

Are:

#+RESULTS:
| 0.63636363 | sad=1.00 | happy=1.00 | 0.54545456 | sad=1.00 |
| happy=1.00 | 0.36363637 | sad=1.00 | happy=1.00 | 0.27272728 |
| sad=1.00 | happy=1.00 |

I can see that I've encoded sadness, presumably because that was
listed first in the fuzzy.maps __OUTPUT__ (that file contents is shown
below), but both sad=1.0 and happy=1.0 seems incorrect to me.

** Set up domain and helper functions

#+BEGIN_SRC bash :results verbatim grass -c ./G_fuzzy

export GRASS_OVERWRITE=1 export GRASS_VERBOSE=0 g.region w=0 s=0 e=4
n=1 res=1 -pa -s #+END_SRC

** Define data

#+BEGIN_SRC bash r.mapcalc "foo = float(col())" r.stats -1 foo
#+END_SRC

#+RESULTS:
| 1 | 2 | 3 | 4 |

** Set up rules

#+BEGIN_SRC conf :tangle fuzzy.maps % foo $ lo {right; 1,4; linear; 0;
1} $ hi {left; 1,4; linear; 0; 1}

% _OUTPUT_ $ sad {left; 0,1; linear; 0;1} $ happy {right; 0,1; linear;
0;1} #+END_SRC

#+BEGIN_SRC conf :tangle fuzzy.rules $ happy { foo = hi } $ sad { foo
= lo } #+END_SRC

** Run the fuzzy system with pixel-level debug output

#+BEGIN_SRC bash :results verbatim r.fuzzy.system -m maps=fuzzy.maps
rules=fuzzy.rules output=out res=10 coors=0.5,0.5 echo " "
r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules output=out res=10x
coors=3.5,0.5 #+END_SRC

#+RESULTS: #+begin_example ANTECEDENT happy: 0.000 ANTECEDENT sad:
1.000 RESULT (defuzzified): 0.636 UNIVERSE,happy,sad,AGREGATE
0.000,0.000,0.000,0.000 0.091,0.000,0.091,0.091
0.182,0.000,0.182,0.182 0.273,0.000,0.273,0.273
0.364,0.000,0.364,0.364 0.455,0.000,0.455,0.455
0.545,0.000,0.545,0.545 0.636,0.000,0.636,0.636
0.727,0.000,0.727,0.727 0.818,0.000,0.818,0.818
0.909,0.000,0.909,0.909

ANTECEDENT happy: 1.000 ANTECEDENT sad: 0.000 RESULT (defuzzified):
0.273 UNIVERSE,happy,sad,AGREGATE 0.000,1.000,0.000,1.000
0.091,0.909,0.000,0.909 0.182,0.818,0.000,0.818
0.273,0.727,0.000,0.727 0.364,0.636,0.000,0.636
0.455,0.545,0.000,0.545 0.545,0.455,0.000,0.455
0.636,0.364,0.000,0.364 0.727,0.273,0.000,0.273
0.818,0.182,0.000,0.182 0.909,0.091,0.000,0.091 #+end_example

** Run the fuzzy system to get raster output

#+BEGIN_SRC bash r.fuzzy.system -m maps=fuzzy.maps rules=fuzzy.rules
output=out res=10 #+END_SRC

#+RESULTS:

Test the intermediate result from =-m= flag.

#+BEGIN_SRC bash r.stats -1 out_sad #+END_SRC

#+RESULTS:
| 1 | 0.66666669 | 0.33333334 |
| 0 |

#+BEGIN_SRC bash r.stats -1 out_happy #+END_SRC

#+RESULTS:
| 0 | 0.33333334 | 0.66666669 |
| 1 |

Now inspect the final result

#+BEGIN_SRC bash :results verbatim r.stats -1l out #+END_SRC

#+RESULTS: : 0.63636363 sad=1.00 happy=1.00 : 0.54545456 sad=1.00
happy=1.00 : 0.36363637 sad=1.00 happy=1.00 : 0.27272728 sad=1.00
happy=1.00

+ The intermediate results, =out_sad= and =out_happy= make sense, but
the final result does not. + This suggests there is an issue with the
defuzzification step. Let's try other methods.

#+BEGIN_SRC bash :results verbatim r.fuzzy.system -m maps=fuzzy.maps
rules=fuzzy.rules output=out res=10 defuz=bisector imp=minimum r.stats
-1l out #+END_SRC

#+RESULTS: : : 0.63636363 sad=1.00 happy=1.00 : 0.54545456 sad=1.00
happy=1.00 : 0.36363637 sad=1.00 happy=1.00 : 0.27272728 sad=1.00
happy=1.00

Expected results:

Output value = [1,0.6, 0.3, 0] # can achieve close to 1 if we increase
=res= option to =r.fuzzy.system= Output label = [sad=1 happy=0; sad=0
happy=1]
  Optionally, output label = [sad=<near 1> happy=<near 0>; sad=<near
  0> happy=<near 1>]

Any suggestions will be greatly appreciated.

Regards,

  -k.