Recent

Author Topic: more logics and an erratum for Zadeh.  (Read 694 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 18695
  • To Europe: simply sell USA bonds: dollar collapses
more logics and an erratum for Zadeh.
« on: January 02, 2026, 10:17:23 am »
There is quite a lot of interest in logics lately so I added the important Lukasiwicz Logic and the equally interesting Kleene/Dienes logic to my compendium.
Both of these are related to Zadeh logic being continuously valued.
At the same time I discovered - well, Claude did - a small inconsistency in my Zadeh logic where I preferred a Kleene/Dienes implementation for imp() over Zadeh's original (this is common), so I changed it to Zadeh's original, with comment. That was not a bug perse, but needed the change to keep it in line with the publication.
This time I used AI, Claude and DeepSeek to verify both theory and implementation.

LukasiwiczLogic:
Code: Pascal  [Select][+][-]
  1. unit LukasiwiczLogic;
  2. {
  3.   Thaddy de Koning, (c) 2021-2025. Creative commons V3.}
  4. }
  5. {$mode objfpc}{$H+}
  6. {$R-}{$Q-}// No range or overflow checks for performance
  7.  
  8. interface
  9. uses
  10.   sysutils;
  11.  
  12. type
  13.   { Łukasiewicz truth values in [0,1] }
  14.   TLukasiewiczValue = single;
  15.  
  16.   { Basic Łukasiewicz operations }
  17.   function LukNot(const A: TLukasiewiczValue): TLukasiewiczValue; inline;
  18.   function LukAnd(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  19.   function LukOr(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  20.   {Note: default conform theory, but two common alternatives as comments below }
  21.   function LukXor(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  22.   function LukImplies(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  23.   function LukEquiv(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  24.  
  25.   { Operators AND/OR/NOT/XOR }
  26.   operator not(const A: TLukasiewiczValue): TLukasiewiczValue; inline;
  27.   operator and(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  28.   operator or(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  29.   {Note: default conform theory, but two common alternatives as comments below }
  30.   operator xor(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  31.  
  32.   { Additional Łukasiewicz operations }
  33.   function LukStrongConjunction(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  34.   function LukStrongDisjunction(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  35.   function LukDelta(const A: TLukasiewiczValue): TLukasiewiczValue; inline; { Delta operator }
  36.   function LukNabla(const A: TLukasiewiczValue): TLukasiewiczValue; inline; { Nabla operator }
  37.  
  38.   { Łukasiewicz T-norm and T-conorm }
  39.   function LukTNorm(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  40.   function LukTConorm(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  41.  
  42.   { Threshold functions }
  43.   function LukIsTrue(const A: TLukasiewiczValue; const Threshold: TLukasiewiczValue = 1.0): Boolean; inline;
  44.   function LukIsFalse(const A: TLukasiewiczValue; const Threshold: TLukasiewiczValue = 0.0): Boolean; inline;
  45.  
  46.   { Aggregation operators }
  47.   function LukWeightedAverage(const Values: array of TLukasiewiczValue;
  48.     const Weights: array of TLukasiewiczValue): TLukasiewiczValue;
  49.   function LukGeneralizedAnd(const Values: array of TLukasiewiczValue): TLukasiewiczValue;
  50.   function LukGeneralizedOr(const Values: array of TLukasiewiczValue): TLukasiewiczValue;
  51.  
  52. implementation
  53.  
  54. uses
  55.   Math;
  56.  
  57. { Łukasiewicz Negation: ¬A = 1 - A }
  58. function LukNot(const A: TLukasiewiczValue): TLukasiewiczValue; inline;
  59. begin
  60.   Result := 1.0 - A;
  61. end;
  62.  
  63. { Łukasiewicz Conjunction: A ⊗ B = max(0, A + B - 1) }
  64. function LukAnd(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  65. begin
  66.   Result := Max(0.0, A + B - 1.0);
  67. end;
  68.  
  69. { Łukasiewicz Disjunction: A ⊕ B = min(1, A + B) }
  70. function LukOr(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  71. begin
  72.   Result := Min(1.0, A + B);
  73. end;
  74.  
  75. { Łukasiewicz Implication: A → B = min(1, 1 - A + B) }
  76. function LukImplies(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  77. begin
  78.   Result := Min(1.0, 1.0 - A + B);
  79. end;
  80.  
  81. { Łukasiewicz Equivalence: A ↔ B = 1 - |A - B| }
  82. function LukEquiv(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  83. begin
  84.   Result := 1.0 - Abs(A - B);
  85. end;
  86.  
  87. { Łukasiewicz XOR - Three common definitions }
  88. function LukXor(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  89. begin
  90.   { Definition 1: A ⊕ B = max(min(A, 1-B), min(1-A, B))
  91.      This is Łukasiewicz interpretation of exclusive or }
  92.   Result := Max(Min(A, 1.0 - B), Min(1.0 - A, B));
  93.  
  94.   { Alternative definitions (comment out the above and uncomment one below): }
  95.  
  96.   { Definition 2: A ⊕ B = |A - B| }
  97.   // Result := Abs(A - B);
  98.  
  99.   { Definition 3: A ⊕ B = min(max(A, B), max(1-A, 1-B)) - Standard fuzzy XOR }
  100.   // Result := Min(Max(A, B), Max(1.0 - A, 1.0 - B));
  101. end;
  102.  
  103. { Operators }
  104. operator not(const A: TLukasiewiczValue): TLukasiewiczValue; inline;
  105. begin
  106.   Result := 1.0 - A;
  107. end;
  108.  
  109. operator and(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  110. begin
  111.   Result := Max(0.0, A + B - 1.0);
  112. end;
  113.  
  114. operator or(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  115. begin
  116.   Result := Min(1.0, A + B);
  117. end;
  118.  
  119. operator xor(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  120. begin
  121.   { Using Definition 1 for the operator }
  122.   Result := Max(Min(A, 1.0 - B), Min(1.0 - A, B));
  123. end;
  124.  
  125. { Strong Conjunction: A ⊙ B = max(0, A + B - 1) (same as ∧ in Łukasiewicz) }
  126. function LukStrongConjunction(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  127. begin
  128.   Result := Max(0.0, A + B - 1.0);
  129. end;
  130.  
  131. { Strong Disjunction: A ⊞ B = min(1, A + B) (same as ∨ in Łukasiewicz) }
  132. function LukStrongDisjunction(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  133. begin
  134.   Result := Min(1.0, A + B);
  135. end;
  136.  
  137. { Delta operator: ΔA = 1 if A = 1, 0 otherwise }
  138. function LukDelta(const A: TLukasiewiczValue): TLukasiewiczValue; inline;
  139. begin
  140.   if A = 1.0 then
  141.     Result := 1.0
  142.   else
  143.     Result := 0.0;
  144. end;
  145.  
  146. { Nabla operator: ∇A = 1 if A > 0, 0 otherwise }
  147. function LukNabla(const A: TLukasiewiczValue): TLukasiewiczValue; inline;
  148. begin
  149.   { Use Sign function for faster check }
  150.   if Sign(A) > 0 then
  151.     Result := 1.0
  152.   else
  153.     Result := 0.0;
  154. end;
  155.  
  156. { T-norm: Łukasiewicz T-norm (same as conjunction) }
  157. function LukTNorm(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  158. begin
  159.   Result := Max(0.0, A + B - 1.0);
  160. end;
  161.  
  162. { T-conorm: Łukasiewicz T-conorm (same as disjunction) }
  163. function LukTConorm(const A, B: TLukasiewiczValue): TLukasiewiczValue; inline;
  164. begin
  165.   Result := Min(1.0, A + B);
  166. end;
  167.  
  168. { Check if value is considered true (>= threshold) }
  169. function LukIsTrue(const A: TLukasiewiczValue; const Threshold: TLukasiewiczValue = 1.0): Boolean; inline;
  170. begin
  171.   Result := A >= Threshold;
  172. end;
  173.  
  174. { Check if value is considered false (<= threshold) }
  175. function LukIsFalse(const A: TLukasiewiczValue; const Threshold: TLukasiewiczValue = 0.0): Boolean; inline;
  176. begin
  177.   Result := A <= Threshold;
  178. end;
  179.  
  180. { Weighted average aggregation }
  181. function LukWeightedAverage(const Values: array of TLukasiewiczValue;
  182.   const Weights: array of TLukasiewiczValue): TLukasiewiczValue;
  183. var
  184.   i: Integer;
  185.   sumValues, sumWeights: TLukasiewiczValue;
  186. begin
  187.   if Length(Values) = 0 then
  188.     Exit(0.5); { Default middle value }
  189.    
  190.   if Length(Weights) <> Length(Values) then
  191.     raise Exception.Create('Number of weights must match number of values');
  192.  
  193.   sumValues := 0.0;
  194.   sumWeights := 0.0;
  195.  
  196.   for i := 0 to High(Values) do
  197.   begin
  198.     sumValues := sumValues + Values[i] * Weights[i];
  199.     sumWeights := sumWeights + Weights[i];
  200.   end;
  201.  
  202.   if sumWeights = 0 then
  203.     Result := 0.5
  204.   else
  205.     Result := sumValues / sumWeights;
  206. end;
  207.  
  208. { Generalized conjunction (minimum for all values) }
  209. function LukGeneralizedAnd(const Values: array of TLukasiewiczValue): TLukasiewiczValue;
  210. var
  211.   i: Integer;
  212. begin
  213.   if Length(Values) = 0 then
  214.     Exit(1.0); { Empty conjunction is true }
  215.  
  216.   Result := Values[0];
  217.   for i := 1 to High(Values) do
  218.     Result := Max(0.0, Result + Values[i] - 1.0);
  219. end;
  220.  
  221. { Generalized disjunction (maximum for all values) }
  222. function LukGeneralizedOr(const Values: array of TLukasiewiczValue): TLukasiewiczValue;
  223. var
  224.   i: Integer;
  225. begin
  226.   if Length(Values) = 0 then
  227.     Exit(0.0); { Empty disjunction is false }
  228.  
  229.   Result := Values[0];
  230.   for i := 1 to High(Values) do
  231.     Result := Min(1.0, Result + Values[i]);
  232. end;
  233.  
  234. end.
Demo for the above:
Code: Pascal  [Select][+][-]
  1. program LukasiewiczDemo;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   LukasiwiczLogic, SysUtils;
  7.  
  8. procedure DemonstrateBasicOperations;
  9. var
  10.   A, B: TLukasiewiczValue;
  11. begin
  12.   WriteLn('=== Łukasiewicz Logic Demo ===');
  13.   WriteLn;
  14.  
  15.   A := 0.7;
  16.   B := 0.4;
  17.  
  18.   WriteLn(Format('A = %.1f, B = %.1f', [A, B]));
  19.   WriteLn(Format('¬A = %.1f', [LukNot(A)]));
  20.   WriteLn(Format('A ∧ B = %.1f', [LukAnd(A, B)]));
  21.   WriteLn(Format('A ∨ B = %.1f', [LukOr(A, B)]));
  22.   WriteLn(Format('A → B = %.1f', [LukImplies(A, B)]));
  23.   WriteLn(Format('A ↔ B = %.1f', [LukEquiv(A, B)]));
  24.   WriteLn;
  25.  
  26.   { Compare with Boolean logic boundaries }
  27.   WriteLn('=== Boundary Cases ===');
  28.   WriteLn(Format('LukAnd(1.0, 1.0) = %.1f (like Boolean AND)', [LukAnd(1.0, 1.0)]));
  29.   WriteLn(Format('LukOr(0.0, 0.0) = %.1f (like Boolean OR)', [LukOr(0.0, 0.0)]));
  30.   WriteLn(Format('LukNot(1.0) = %.1f (like Boolean NOT)', [LukNot(1.0)]));
  31. end;
  32.  
  33. procedure DemonstrateProperties;
  34. var
  35.   A, B, C: TLukasiewiczValue;
  36. begin
  37.   WriteLn;
  38.   WriteLn('=== Key Łukasiewicz Properties ===');
  39.  
  40.   A := 0.6;
  41.   B := 0.3;
  42.   C := 0.8;
  43.  
  44.   { Law of excluded middle: A ∨ ¬A = 1 }
  45.   WriteLn(Format('Law of excluded middle: %.1f ∨ ¬%.1f = %.1f',
  46.     [A, A, LukOr(A, LukNot(A))]));
  47.  
  48.   { Law of non-contradiction: A ∧ ¬A = 0 }
  49.   WriteLn(Format('Law of non-contradiction: %.1f ∧ ¬%.1f = %.1f',
  50.     [A, A, LukAnd(A, LukNot(A))]));
  51.  
  52.   { De Morgan's laws }
  53.   WriteLn(Format('De Morgan 1: ¬(%.1f ∧ %.1f) = %.1f, ¬%.1f ∨ ¬%.1f = %.1f',
  54.     [A, B, LukNot(LukAnd(A, B)), A, B, LukOr(LukNot(A), LukNot(B))]));
  55.  
  56.   WriteLn(Format('De Morgan 2: ¬(%.1f ∨ %.1f) = %.1f, ¬%.1f ∧ ¬%.1f = %.1f',
  57.     [A, B, LukNot(LukOr(A, B)), A, B, LukAnd(LukNot(A), LukNot(B))]));
  58. end;
  59.  
  60. procedure DemonstrateAggregation;
  61. var
  62.   values: array[0..2] of TLukasiewiczValue;
  63.   weights: array[0..2] of Single;
  64. begin
  65.   WriteLn;
  66.   WriteLn('=== Aggregation Operators ===');
  67.  
  68.   values[0] := 0.8;
  69.   values[1] := 0.4;
  70.   values[2] := 0.6;
  71.  
  72.   weights[0] := 0.5;
  73.   weights[1] := 0.3;
  74.   weights[2] := 0.2;
  75.  
  76.   WriteLn(Format('Weighted average: %.3f',
  77.     [LukWeightedAverage(values, weights)]));
  78.   WriteLn(Format('Generalized AND: %.1f',
  79.     [LukGeneralizedAnd(values)]));
  80.   WriteLn(Format('Generalized OR: %.1f',
  81.     [LukGeneralizedOr(values)]));
  82. end;
  83.  
  84. begin
  85.   DemonstrateBasicOperations;
  86.   DemonstrateProperties;
  87.   DemonstrateAggregation;
  88.  
  89.   WriteLn;
  90.   WriteLn('Press Enter to exit...');
  91.   ReadLn;
  92. end.


Kleene-Dienes:
Code: Pascal  [Select][+][-]
  1. program kleenedieneslogic;
  2. {$mode objfpc}{$notes off}
  3. { Kleene-Dienes fuzzy logic operators
  4.  
  5.   Key differences from Zadeh logic:
  6.   - AND uses algebraic product: a * b
  7.   - OR uses algebraic sum: a + b - a*b
  8.   - NOT remains the same: 1 - a
  9.   - XOR derived from the above
  10.  
  11.   Named after Stephen Cole Kleene and Jan Dienes.
  12.  
  13.   Thaddy de Koning, (c) 2021-2025. Creative commons V3.}
  14. type
  15.   { Fuzz is a double in the inclusive range 0..1
  16.     The programmer is responsible for valid input.
  17.     (You can use EnsureRange from the math unit.) }
  18.   Fuzz = type double;
  19.  
  20. { the basic logic }
  21.  
  22.   { AND is defined as algebraic product a * b }
  23.   operator and (const a,b:Fuzz):Fuzz;inline;
  24.   begin
  25.     Result := a * b
  26.   end;
  27.  
  28.   { OR is defined as algebraic sum a + b - a*b }
  29.   operator or (const a,b:Fuzz):Fuzz;inline;
  30.   begin
  31.     Result := a + b - a * b
  32.   end;
  33.  
  34.   { NOT is the inverse, same as Zadeh }
  35.   operator not (const a:Fuzz):Fuzz;inline;
  36.   begin
  37.     Result := 1 - a
  38.   end;
  39.  
  40.   { XOR derived from OR and AND: (a OR b) AND NOT(a AND b)
  41.     Which expands to: a + b - 2*a*b }
  42.   operator xor (const a,b:Fuzz):Fuzz;inline;
  43.   begin
  44.     Result := a + b - 2 * a * b
  45.   end;
  46.  
  47. { derived logic as functions }
  48.  
  49.   { IMP - Kleene-Dienes implication: NOT a OR b = 1 - a + a*b }
  50.   function imp(const a,b:Fuzz):Fuzz;inline;
  51.   begin
  52.     Result := (not a) or b
  53.   end;
  54.  
  55.   { NAND }
  56.   function nand(const a,b:Fuzz):Fuzz;inline;
  57.   begin
  58.     Result := not (a and b)
  59.   end;
  60.  
  61.   { NOR }
  62.   function nor(const a,b:Fuzz):Fuzz;inline;
  63.   begin
  64.     Result := not (a or b)
  65.   end;
  66.  
  67.   { NXR (XNOR) }
  68.   function nxr(const a,b:Fuzz):Fuzz;inline;
  69.   begin
  70.     Result := not (a xor b)
  71.   end;
  72.  
  73.   { Inhibition: a AND NOT b }
  74.   function inhibition(const a,b:Fuzz):Fuzz;inline;
  75.   begin
  76.     Result := a and (not b)
  77.   end;
  78.  
  79. begin
  80. end.

Corrected Zadeh for Imp():
Code: Pascal  [Select][+][-]
  1. program zadehlogic;
  2. {$mode objfpc}{$notes off}
  3. { Zadeh's standard fuzzy logic operators
  4.  See:
  5.    https://commons.wikimedia.org/wiki/Fuzzy_operator
  6.  
  7.  Don't let your eyes fool you, these are not integer or boolean
  8.  calculations, but floating point calculations!.
  9.  
  10.  Enjoy,
  11.  
  12.  Thaddy de Koning, (c) 2021. Creatve commons V3.}
  13. type
  14.   { Fuzz is a double in the inclusive range 0..1
  15.     The programmer is responsible for valid input.
  16.     (You can use EnsureRange from the math unit.) }
  17.   Fuzz = type double;  
  18.  
  19. { helpers }  
  20.   function min(const a,b:Fuzz):Fuzz;inline;
  21.   begin    
  22.     if a > b then result := b else result := a;
  23.   end;
  24.  
  25.   function max(const a,b:Fuzz):Fuzz;inline;
  26.   begin    
  27.     if b > a then result := b else result := a;
  28.   end;
  29.  
  30. { the basic logic }
  31.  
  32.   { AND is defined as min(a, b) in standard fuzzy logic }
  33.   operator and (const a,b:Fuzz):Fuzz;inline;
  34.   begin
  35.     Result:=min(a,b);
  36.   end;
  37.  
  38.   { OR is defined as max(a,b) in standard fuzzy logic }
  39.   operator or (const a,b:Fuzz):Fuzz;inline;
  40.   begin
  41.     Result:=max(a, b);
  42.   end;
  43.  
  44.   { NOT is simply the inverse, given a range of 0..1. Comparable to Boolean}
  45.   operator not (const a:Fuzz):Fuzz;inline;
  46.   begin
  47.     result := 1 - a;
  48.   end;
  49.  
  50.   { XOR. See AND how this reflects: the bias to either a or b gets amplified  }
  51.   operator xor (const a,b:Fuzz):Fuzz;inline;
  52.   begin
  53.     result := a + b - 2 * (a and b);
  54.   end;
  55.  
  56.  { not overloaded logic as functions: all can be derived from the above four }
  57.  
  58.   { IMP }
  59.   function imp(const a,b:Fuzz):Fuzz;inline;
  60.   begin
  61.     // Result := not (a and not b) // Kleene-Dienes implication
  62.     Result := max(1-a, min(a,b));  // Zadeh implication
  63.   end;  
  64.  
  65.   { NAND }
  66.   function nand(const a,b:Fuzz):Fuzz;inline;
  67.   begin
  68.     Result := not (a and b);
  69.   end;
  70.  
  71.   { NOR }
  72.   function nor(const a,b:Fuzz):Fuzz;inline;
  73.   begin
  74.     Result := not (a or b);
  75.   end;
  76.  
  77.   { NXR }
  78.   function nxr(const a,b:Fuzz):Fuzz;inline;
  79.   begin
  80.     Result := not (a xor b);
  81.   end;
  82.  
  83.   { MNIMP material non-implication}
  84.   function mnimp(const a,b:Fuzz):Fuzz;inline;
  85.   begin
  86.     Result := a and not b;
  87.   end;  
  88.  
  89.   { NIMP}
  90.   function nimp(const a,b:Fuzz):Fuzz;inline;
  91.   begin
  92.     Result := not imp(a,b);
  93.   end;  
  94.  
  95. begin
  96. end.

There are also versions available as units where I just gave the code for some here.
Claude is good in writing examples, btw!! Just feed it your code.




« Last Edit: January 02, 2026, 10:28:15 am by Thaddy »
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

d2010

  • Full Member
  • ***
  • Posts: 246
Re: more logics and an erratum for Zadeh.
« Reply #1 on: January 03, 2026, 01:54:34 pm »
Many thanks, God bless you.
Thanks , thanks

Thaddy

  • Hero Member
  • *****
  • Posts: 18695
  • To Europe: simply sell USA bonds: dollar collapses
Re: more logics and an erratum for Zadeh.
« Reply #2 on: January 04, 2026, 08:02:20 am »
Glad you like it.
I am still working on it to use more overloads because some of the functions can be expressed in Pascal set notation. I don't think it is feasable to have the complete underlying algebras implemented that way: some functions can not be replaced by meaningful operators.
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

VisualLab

  • Hero Member
  • *****
  • Posts: 708
Re: more logics and an erratum for Zadeh.
« Reply #3 on: January 04, 2026, 11:59:28 pm »
There is quite a lot of interest in logics lately so I added the important Lukasiwicz Logic and the equally interesting Kleene/Dienes logic to my compendium.
Both of these are related to Zadeh logic being continuously valued.
At the same time I discovered - well, Claude did - a small inconsistency in my Zadeh logic where I preferred a Kleene/Dienes implementation for imp() over Zadeh's original (this is common), so I changed it to Zadeh's original, with comment. That was not a bug perse, but needed the change to keep it in line with the publication.

Do you plan to publish your work? And will it be a library?

 

TinyPortal © 2005-2018