Hi,
Here is a program that permits to create fuzzy systems.
Save this program as "fuzzy.fs" and include it in the programs where the fuzzy systems will be created.
Notice that you can create several fuzzy systems in the same program.
\ the code begins here:
\ Mamdani type fuzzy system with normalized output (in [-1, 1])
variable tnorm
variable tconorm
variable (in_fuzzify)
variable (out_fuzzify)
variable (rules)
: tnorm: ' tnorm ! ;
: tconorm: ' tconorm ! ;
: in_fuzzify: ' (in_fuzzify) ! ;
: out_fuzzify: ' (out_fuzzify) ! ;
: rules: ' (rules) ! ;
fvariable fs_output
: output: fs_output create , does> @ ;
: inputs: 0 ?do fvariable loop ;
\ we use membership functions: gaussian, triangular, trapezoidal, ... Just define them
\ gaussian membership function mf = mf_gauss(x;m,s) = exp(-0.5*((x-m)/s)^2) : mf_gauss ( f: x m s -- f: md ) frot frot f- fswap f/ fdup f* 0.5e f* fnegate fexp ;
\ using prod as tnorm and probabilistic sum as tconorm,
\ we can use fmin and fmax for tnorm and tconorm respectively
: prod f* ;
: prob_sum fover fover f* f- f+ ; \ (u,v)---> u+v-u*v
\ use fmin or fmax already defined directly
\ : fmin fmin ;
\ : fmax fmax ;
\ to write rulesHi again,
: fuzzy_propositions: 0 ?do 0e fvalue loop ;
: .and. tnorm @ execute ;
: .or. tconorm @ execute ;
: .if. 1e ;
: .then. tnorm @ execute ;
: )r tnorm @ execute ;
: r( ; immediate
: rt( 0e ;
: )rt tconorm @ execute ;
: .is. f@ ;
: infere (out_fuzzify) @ execute (rules) @ execute ;
10 value N/2
N/2 negate value N_begin
N/2 1+ value N_end
N/2 s>f 1/f fvalue out_step
: infere_defuzz ( f: -- z* )
0e 0e ( f: s_mfz s_mf )
N_end N_begin
do
fswap ( f: s_mf s_mfz )
i s>f out_step f* ( f: s_mf s_mfz z )
fs_output f! ( f: s_mf s_mfz )
infere ( f: s_mf s_mfz mf)
ftuck fs_output f@ f* f+ ( f: s_mf mf s_mfz)
frot frot f+ ( f: s_mfz s_mf)
loop
f/ ;
: (fuzzy_system) (in_fuzzify) @ execute infere_defuzz fs_output f! ;
: fuzzy_system: ['] (fuzzy_system)
create , tnorm @ , tconorm @ , (in_fuzzify) @ , (out_fuzzify) @ , (rules) @ ,
does> dup
cell+ dup @ tnorm !
cell+ dup @ tconorm !
cell+ dup @ (in_fuzzify) !
cell+ dup @ (out_fuzzify) !
cell+ @ (rules) !
@ execute ;
\ the code finishes here.
Enjoy,
Bye
Le vendredi 15 septembre 2023 à 11:39:45 UTC, Ahmed MELAHI a écrit :[..]
The program was tested with gforth, vfxforth and iforth version 4.0
the timing was interesting:
gforth:
FS1: 20 micro seconds
FS2: 06 micro seconds
vfxforth:
FS1: 11 micro seconds
FS2: 9.5 micro seconds
iForth:
FS1: 14 micro seconds
FS2: 05 micro seconds
Notice that FS1 and FS2 works in the same program.
I was having fun learning FL, still do, and thought to share what I understood till now. so here is my take as a newbie to FL. I hope i did not make too many mistakes (especially any conceptual ones :) ). The formatting my be messed up.
VOCABULARY FuzzyLogic21 ALSO FuzzyLogic21 DEFINITIONS
\ Assume trapizoidal inputs
\ Assume range is bounded by p1 and p4
\ Assume singleton outputs
\ no verification of rules being complete (covering all cases) is done in this implementation
: lingvar VARIABLE ; \ lingustic variable (input or output is a variable here)
: member ( p1 p2 p3 p3 --) CREATE >R SWAP ROT , , , R> , ; \ define input m.ship. function, simple without linking lingvar
: p1 @ ; : p2 CELL+ @ ; : p3 2 CELLS + @ ; : p4 3 CELLS + @ ;
: pts ( mem -- p1 p2 p3 p4 ) >R R@ p1 R@ p2 R@ p3 R> p4 ;
: singleton ( val -- ) CONSTANT ; \ 'member' word could be used with p1, but seemed a waste!
: seg1 ( mem -- p1 p2 ) >R R@ p1 1+ R> p2 1- ; \ ascending line
: seg2 ( mem -- p2 p3 ) >R R@ p2 R> p3 ; \ horizontal line
: seg3 ( mem -- p3 p4 ) >R R@ p3 1+ R> p4 1- ; \ desc. line
1000 VALUE res \ resolution of the 1==1000 value membership
: interpo ( xm y1 y2 -- ym ) >R TUCK - res * SWAP R> - / ABS ; \ interpolate. used for both asc. and desc. lines.
: ]clip[ ( val p1 p2 -- clipped ) ROT DUP >R -ROT 1+ WITHIN ABS R> * ; \ val or zero if out of range
: fuzz ( crisp mem -- fz1 fz2 fz3 ) \ trapizoidal interpolation. is it possible to improve this?
2DUP seg1 ]clip[ IF 2DUP seg1 interpo ELSE 0 THEN -ROT
2DUP seg2 ]clip[ IF res ELSE 0 THEN -ROT
2DUP seg3 ]clip[ IF seg3 SWAP interpo ELSE 2DROP 0 THEN ;
DEFER aggregate
: maximize ( val var -- ) TUCK @ MAX SWAP ! ;
: minimize ( val var -- ) TUCK @ MIN SWAP ! ;
: sum ( val var -- ) +! ;
' maximize IS aggregate
: defuz ( fuz-val lingvar singleton -- ) ROT res */ SWAP aggregate ;
\ Rules compilation
SYNONYM ` POSTPONE
DEFER <IS> IMMEDIATE
DEFER <AND> IMMEDIATE
: nop ;
: compile-at ` @ ;
: compile-fuzz-min ` fuzz ` + ` + ` min ; ' compile-fuzz-min IS <AND>
: compile-<and>-defuz ` defuz ` DUP ;
: antecedent-scope ['] compile-at IS <IS> ['] compile-fuzz-min IS <AND> ;
: consequence-scope ['] nop IS <IS> ['] compile-<and>-defuz IS <AND> ;
: <IF> ` res ` 1+ antecedent-scope ; IMMEDIATE \ max fuz is res, thus 'res 1+' will do with MIN
: <THEN> ` <AND> ` DUP ` IF ` DUP consequence-scope ; IMMEDIATE
: <END> ` defuz ` THEN ` DROP ; IMMEDIATE
: .fired ." Rule " . ." fired! " ;
\
\ Example - car brakes
\
lingvar speed \ in KM\H
0 10 40 50 member low
40 60 80 100 member medium
80 100 320 325 member high
lingvar distance \ in meters
-1 0 20 50 member close
30 60 80 100 member near
80 110 1000 1005 member far
lingvar brake \ measured in N or poundal (this example is illustrative rather than giving experience/measured forces)
0 singleton light
10 singleton moderate
30 singleton hard
: brake-rules
0 brake !
<IF> distance <IS> close <AND> speed <IS> high <THEN> 1 .fired brake <IS> hard <END>
<IF> distance <IS> close <AND> speed <IS> medium <THEN> 2 .fired brake <IS> hard <END>
<IF> distance <IS> close <AND> speed <IS> low <THEN> 3 .fired brake <IS> moderate <END>
<IF> distance <IS> near <AND> speed <IS> high <THEN> 4 .fired brake <IS> hard <END>
<IF> distance <IS> near <AND> speed <IS> medium <THEN> 5 .fired brake <IS> moderate <END>
<IF> distance <IS> near <AND> speed <IS> low <THEN> 6 .fired brake <IS> light <END>
<IF> distance <IS> far <THEN> 7 .fired brake <IS> light <END>
;
: control-brake ( -- b ) brake-rules brake @ ;
CR CR .( Car Brakes example) CR
2 distance !
CR 15 speed ! control-brake .
CR 70 speed ! control-brake .
CR 100 speed ! control-brake .
CR
50 distance !
CR 45 speed ! control-brake .
CR 90 speed ! control-brake .
CR
50 distance !
CR 15 speed ! control-brake .
CR 70 speed ! control-brake .
CR 100 speed ! control-brake .
CR
200 distance !
CR 15 speed ! control-brake .
CR 70 speed ! control-brake .
CR 100 speed ! control-brake .
\
\ Tipping Examples
\
lingvar service \ level
-2 -1 0 5 member poor
0 5 5 10 member acceptable
5 10 11 12 member amazing
lingvar quality \ of food
-2 -1 0 5 member bad
0 5 5 10 member decent
5 10 11 12 member great
lingvar tip \ percentage
0 singleton low
13 singleton medium
25 singleton high
variable count
: tipping-rules
0 tip ! 0 count !
<IF> service <IS> amazing <THEN> 1 .fired count ++ tip <IS> high <END> quality <IS> great <THEN> 2 .fired count ++ tip <IS> high <END>
<IF> service <IS> acceptable <THEN> 3 .fired count ++ tip <IS> medium <END> service <IS> poor <AND> quality <IS> poor <THEN> 4 .fired count ++ tip <IS> low <END>
;
' sum is aggregate
: calc-tip tipping-rules tip @ count @ / ;
CR CR .( Tipping example)
CR 6 quality ! 9 service ! calc-tip .
CR 6 quality ! 8 service ! calc-tip .
CR 9 quality ! 4 service ! calc-tip .
CR 3 quality ! 3 service ! calc-tip .
\
\ Example - fan control
\
lingvar temperature
-21 -20 20 40 member cool
20 40 40 50 member warm
40 60 120 121 member hot
lingvar fan-speed
30 singleton slow
60 singleton medium
90 singleton fast
: fan-rules
0 fan-speed !
<IF> temperature <IS> cool <THEN> 1 .fired fan-speed <IS> slow <END> temperature <IS> warm <THEN> 2 .fired fan-speed <IS> medium <END> temperature <IS> hot <THEN> 3 .fired fan-speed <IS> fast <END>
;
: control-fan fan-rules fan-speed @ ;
: clip-input cool p1 hot p4 WITHIN NOT ABORT" Input out of range!" ;
: control2 clip-input temperature ! control-fan ;
CR CR .( Fan Speed control)
: test 80 0 DO CR I 3 .r space I temperature ! control-fan space 3 .r LOOP ; test
Le mercredi 11 octobre 2023 à 16:45:36 UTC, Ala'a a écrit :
I tried to read your program. I see that you have used integers. Me I prefer floats.
Ahmed MELAHI schrieb am Mittwoch, 11. Oktober 2023 um 20:50:53 UTC+2:Agreed.
Le mercredi 11 octobre 2023 à 16:45:36 UTC, Ala'a a écrit :Practically all real-life applications of fuzzy logic are in control of technical systems,
I tried to read your program. I see that you have used integers. Me I prefer floats.
eg motors or chemical reactors.
There you often don't have floats available. So binary FL has its important place.
Le jeudi 12 octobre 2023 à 08:02:07 UTC, minforth a écrit :
Ahmed MELAHI schrieb am Mittwoch, 11. Oktober 2023 um 20:50:53 UTC+2:
Le mercredi 11 octobre 2023 à 16:45:36 UTC, Ala'a a écrit :Practically all real-life applications of fuzzy logic are in control of technical systems,
I tried to read your program. I see that you have used integers. Me I prefer floats.
eg motors or chemical reactors.
There you often don't have floats available. So binary FL has its important place.Agreed.
But for simulations of fuzzy logic control systems, I prefer floats.
On Thursday, October 12, 2023 at 12:20:27 PM UTC+4, Ahmed MELAHI wrote:
Le jeudi 12 octobre 2023 à 08:02:07 UTC, minforth a écrit :
Ahmed MELAHI schrieb am Mittwoch, 11. Oktober 2023 um 20:50:53 UTC+2:
Le mercredi 11 octobre 2023 à 16:45:36 UTC, Ala'a a écrit :Practically all real-life applications of fuzzy logic are in control of technical systems,
I tried to read your program. I see that you have used integers. Me I prefer floats.
eg motors or chemical reactors.
There you often don't have floats available. So binary FL has its important place.Agreed.
But for simulations of fuzzy logic control systems, I prefer floats.Hi,
sure both are fine. my goal was concept realization without distraction with FP details. Moreover, if you dabble with Forth in micro controllers, most are FP-less (if that was a word!) but again on PC it is doable in both.
++ word is incrementing by one
: ++ ( a -- ) 1 SWAP +! ;
Regards,Salutations
I was having fun learning FL, still do, and thought to share what I understood till now. so here is my take as a newbie to FL. I hope i did not make too many mistakes (especially any conceptual ones :) ). The formatting my be messed up.
VOCABULARY FuzzyLogic21 ALSO FuzzyLogic21 DEFINITIONS
\ Assume trapizoidal inputs
\ Assume range is bounded by p1 and p4
\ Assume singleton outputs
\ no verification of rules being complete (covering all cases) is done in this implementation
: lingvar VARIABLE ; \ lingustic variable (input or output is a variable here)
: member ( p1 p2 p3 p3 --) CREATE >R SWAP ROT , , , R> , ; \ define input m.ship. function, simple without linking lingvar
: p1 @ ; : p2 CELL+ @ ; : p3 2 CELLS + @ ; : p4 3 CELLS + @ ;
: pts ( mem -- p1 p2 p3 p4 ) >R R@ p1 R@ p2 R@ p3 R> p4 ;
: singleton ( val -- ) CONSTANT ; \ 'member' word could be used with p1, but seemed a waste!
: seg1 ( mem -- p1 p2 ) >R R@ p1 1+ R> p2 1- ; \ ascending line
: seg2 ( mem -- p2 p3 ) >R R@ p2 R> p3 ; \ horizontal line
: seg3 ( mem -- p3 p4 ) >R R@ p3 1+ R> p4 1- ; \ desc. line
1000 VALUE res \ resolution of the 1==1000 value membership
: interpo ( xm y1 y2 -- ym ) >R TUCK - res * SWAP R> - / ABS ; \ interpolate. used for both asc. and desc. lines.
: ]clip[ ( val p1 p2 -- clipped ) ROT DUP >R -ROT 1+ WITHIN ABS R> * ; \ val or zero if out of range
: fuzz ( crisp mem -- fz1 fz2 fz3 ) \ trapizoidal interpolation. is it possible to improve this?
2DUP seg1 ]clip[ IF 2DUP seg1 interpo ELSE 0 THEN -ROT
2DUP seg2 ]clip[ IF res ELSE 0 THEN -ROT
2DUP seg3 ]clip[ IF seg3 SWAP interpo ELSE 2DROP 0 THEN ;
DEFER aggregate
: maximize ( val var -- ) TUCK @ MAX SWAP ! ;
: minimize ( val var -- ) TUCK @ MIN SWAP ! ;
: sum ( val var -- ) +! ;
' maximize IS aggregate
: defuz ( fuz-val lingvar singleton -- ) ROT res */ SWAP aggregate ;
\ Rules compilation
SYNONYM ` POSTPONE
DEFER <IS> IMMEDIATE
DEFER <AND> IMMEDIATE
: nop ;
: compile-at ` @ ;
: compile-fuzz-min ` fuzz ` + ` + ` min ; ' compile-fuzz-min IS <AND>
: compile-<and>-defuz ` defuz ` DUP ;
: antecedent-scope ['] compile-at IS <IS> ['] compile-fuzz-min IS <AND> ;
: consequence-scope ['] nop IS <IS> ['] compile-<and>-defuz IS <AND> ;
: <IF> ` res ` 1+ antecedent-scope ; IMMEDIATE \ max fuz is res, thus 'res 1+' will do with MIN
: <THEN> ` <AND> ` DUP ` IF ` DUP consequence-scope ; IMMEDIATE
: <END> ` defuz ` THEN ` DROP ; IMMEDIATE
: .fired ." Rule " . ." fired! " ;
\
\ Example - car brakes
\
lingvar speed \ in KM\H
0 10 40 50 member low
40 60 80 100 member medium
80 100 320 325 member high
lingvar distance \ in meters
-1 0 20 50 member close
30 60 80 100 member near
80 110 1000 1005 member far
lingvar brake \ measured in N or poundal (this example is illustrative rather than giving experience/measured forces)
0 singleton light
10 singleton moderate
30 singleton hard
: brake-rules
0 brake !
<IF> distance <IS> close <AND> speed <IS> high <THEN> 1 .fired brake <IS> hard <END>
<IF> distance <IS> close <AND> speed <IS> medium <THEN> 2 .fired brake <IS> hard <END>
<IF> distance <IS> close <AND> speed <IS> low <THEN> 3 .fired brake <IS> moderate <END>
<IF> distance <IS> near <AND> speed <IS> high <THEN> 4 .fired brake <IS> hard <END>
<IF> distance <IS> near <AND> speed <IS> medium <THEN> 5 .fired brake <IS> moderate <END>
<IF> distance <IS> near <AND> speed <IS> low <THEN> 6 .fired brake <IS> light <END>
<IF> distance <IS> far <THEN> 7 .fired brake <IS> light <END>
;
: control-brake ( -- b ) brake-rules brake @ ;
CR CR .( Car Brakes example) CR
2 distance !
CR 15 speed ! control-brake .
CR 70 speed ! control-brake .
CR 100 speed ! control-brake .
CR
50 distance !
CR 45 speed ! control-brake .
CR 90 speed ! control-brake .
CR
50 distance !
CR 15 speed ! control-brake .
CR 70 speed ! control-brake .
CR 100 speed ! control-brake .
CR
200 distance !
CR 15 speed ! control-brake .
CR 70 speed ! control-brake .
CR 100 speed ! control-brake .
\
\ Tipping Examples
\
lingvar service \ level
-2 -1 0 5 member poor
0 5 5 10 member acceptable
5 10 11 12 member amazing
lingvar quality \ of food
-2 -1 0 5 member bad
0 5 5 10 member decent
5 10 11 12 member great
lingvar tip \ percentage
0 singleton low
13 singleton medium
25 singleton high
variable count
: tipping-rules
0 tip ! 0 count !
<IF> service <IS> amazing <THEN> 1 .fired count ++ tip <IS> high <END> quality <IS> great <THEN> 2 .fired count ++ tip <IS> high <END>
<IF> service <IS> acceptable <THEN> 3 .fired count ++ tip <IS> medium <END> service <IS> poor <AND> quality <IS> poor <THEN> 4 .fired count ++ tip <IS> low <END>
;
' sum is aggregate
: calc-tip tipping-rules tip @ count @ / ;
CR CR .( Tipping example)
CR 6 quality ! 9 service ! calc-tip .
CR 6 quality ! 8 service ! calc-tip .
CR 9 quality ! 4 service ! calc-tip .
CR 3 quality ! 3 service ! calc-tip .
\
\ Example - fan control
\
lingvar temperature
-21 -20 20 40 member cool
20 40 40 50 member warm
40 60 120 121 member hot
lingvar fan-speed
30 singleton slow
60 singleton medium
90 singleton fast
: fan-rules
0 fan-speed !
<IF> temperature <IS> cool <THEN> 1 .fired fan-speed <IS> slow <END> temperature <IS> warm <THEN> 2 .fired fan-speed <IS> medium <END> temperature <IS> hot <THEN> 3 .fired fan-speed <IS> fast <END>
;
: control-fan fan-rules fan-speed @ ;
: clip-input cool p1 hot p4 WITHIN NOT ABORT" Input out of range!" ;
: control2 clip-input temperature ! control-fan ;
CR CR .( Fan Speed control)
: test 80 0 DO CR I 3 .r space I temperature ! control-fan space 3 .r LOOP ; test
Hi Ahmed,the deffered 'aggregate' is 'maximize'. however, for the tipping example it was 'sum' and then with the help of 'count' variable I cheated and did (my) average by dividing by the sum of count rather than sum of fired rules' antecedents values.
Your observation about the missing division is a near hit :)
Kindly correct me if I am wrong. There is aggregation and then Defuzzification. Aggregation result is sets, Defuzzification result is crisp values. Both of these are kind of intermingled (implemented) in 'defuz' and 'aggregate' words. The default of
Regards,
Sysop: | Keyop |
---|---|
Location: | Huddersfield, West Yorkshire, UK |
Users: | 475 |
Nodes: | 16 (2 / 14) |
Uptime: | 19:38:50 |
Calls: | 9,487 |
Calls today: | 6 |
Files: | 13,617 |
Messages: | 6,121,093 |