test.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /* Copyright 2010 Juan Rada-Vilela
  2. Licensed under the Apache License, Version 2.0 (the "License");
  3. you may not use this file except in compliance with the License.
  4. You may obtain a copy of the License at
  5. http://www.apache.org/licenses/LICENSE-2.0
  6. Unless required by applicable law or agreed to in writing, software
  7. distributed under the License is distributed on an "AS IS" BASIS,
  8. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  9. See the License for the specific language governing permissions and
  10. limitations under the License.
  11. */
  12. #include "test.h"
  13. #include "FuzzyLite.h"
  14. #include <limits>
  15. #include "FunctionTerm.h"
  16. namespace fl {
  17. void Test::SimpleMamdani() {
  18. FuzzyOperator& op = FuzzyOperator::DefaultFuzzyOperator();
  19. FuzzyEngine engine("simple-mamdani", op);
  20. engine.hedgeSet().add(new fl::HedgeNot);
  21. engine.hedgeSet().add(new fl::HedgeSomewhat);
  22. engine.hedgeSet().add(new fl::HedgeVery);
  23. fl::InputLVar* energy = new fl::InputLVar("Energy");
  24. energy->addTerm(new fl::ShoulderTerm("LOW", 0.25, 0.5, true));
  25. energy->addTerm(new fl::TriangularTerm("MEDIUM", 0.25, 0.75));
  26. energy->addTerm(new fl::ShoulderTerm("HIGH", 0.50, 0.75, false));
  27. engine.addInputLVar(energy);
  28. fl::OutputLVar* health = new fl::OutputLVar("Health");
  29. health->addTerm(new fl::TriangularTerm("BAD", 0.0, 0.50));
  30. health->addTerm(new fl::TriangularTerm("REGULAR", 0.25, 0.75));
  31. health->addTerm(new fl::TriangularTerm("GOOD", 0.50, 1.00));
  32. engine.addOutputLVar(health);
  33. fl::RuleBlock* block = new fl::RuleBlock();
  34. block->addRule(new fl::MamdaniRule("if Energy is LOW then Health is BAD", engine));
  35. block->addRule(new fl::MamdaniRule("if Energy is MEDIUM then Health is REGULAR", engine));
  36. block->addRule(new fl::MamdaniRule("if Energy is HIGH then Health is GOOD", engine));
  37. engine.addRuleBlock(block);
  38. for (fl::flScalar in = 0.0; in < 1.1; in += 0.1) {
  39. energy->setInput(in);
  40. engine.process();
  41. fl::flScalar out = health->output().defuzzify();
  42. (void)out; //Just to avoid warning when building
  43. FL_LOG("Energy=" << in);
  44. FL_LOG("Energy is " << energy->fuzzify(in));
  45. FL_LOG("Health=" << out);
  46. FL_LOG("Health is " << health->fuzzify(out));
  47. FL_LOG("--");
  48. }
  49. }
  50. void Test::ComplexMamdani() {
  51. FuzzyOperator& op = FuzzyOperator::DefaultFuzzyOperator();
  52. FuzzyEngine engine("complex-mamdani", op);
  53. engine.hedgeSet().add(new fl::HedgeNot);
  54. engine.hedgeSet().add(new fl::HedgeSomewhat);
  55. engine.hedgeSet().add(new fl::HedgeVery);
  56. fl::InputLVar* energy = new fl::InputLVar("Energy");
  57. energy->addTerm(new fl::TriangularTerm("LOW", 0.0, 0.50));
  58. energy->addTerm(new fl::TriangularTerm("MEDIUM", 0.25, 0.75));
  59. energy->addTerm(new fl::TriangularTerm("HIGH", 0.50, 1.00));
  60. engine.addInputLVar(energy);
  61. fl::InputLVar* distance = new fl::InputLVar("Distance");
  62. distance->addTerm(new fl::TriangularTerm("NEAR", 0, 500));
  63. distance->addTerm(new fl::TriangularTerm("FAR", 250, 750));
  64. distance->addTerm(new fl::TriangularTerm("FAR_AWAY", 500, 1000));
  65. engine.addInputLVar(distance);
  66. fl::OutputLVar* power = new fl::OutputLVar("Power");
  67. power->addTerm(new fl::ShoulderTerm("LOW", 0.25, 0.5, true));
  68. power->addTerm(new fl::TriangularTerm("MEDIUM", 0.25, 0.75));
  69. power->addTerm(new fl::ShoulderTerm("HIGH", 0.50, 0.75, false));
  70. engine.addOutputLVar(power);
  71. fl::RuleBlock* block = new fl::RuleBlock();
  72. block->addRule(new fl::MamdaniRule("if Energy is LOW and Distance is FAR_AWAY then Power is LOW", engine));
  73. block->addRule(new fl::MamdaniRule("if Energy is LOW and Distance is FAR then Power is very MEDIUM", engine));
  74. block->addRule(new fl::MamdaniRule("if Energy is LOW and Distance is NEAR then Power is HIGH", engine));
  75. block->addRule(new fl::MamdaniRule("if Energy is MEDIUM and Distance is FAR_AWAY then Power is LOW with 0.8", engine));
  76. block->addRule(new fl::MamdaniRule("if Energy is MEDIUM and Distance is FAR then Power is MEDIUM with 1.0", engine));
  77. block->addRule(new fl::MamdaniRule("if Energy is MEDIUM and Distance is NEAR then Power is HIGH with 0.3", engine));
  78. block->addRule(new fl::MamdaniRule("if Energy is HIGH and Distance is FAR_AWAY then Power is LOW with 0.43333", engine));
  79. block->addRule(new fl::MamdaniRule("if Energy is HIGH and Distance is FAR then Power is MEDIUM", engine));
  80. block->addRule(new fl::MamdaniRule("if Energy is HIGH and Distance is NEAR then Power is HIGH", engine));
  81. engine.addRuleBlock(block);
  82. for (int i = 0; i < block->numberOfRules(); ++i) {
  83. FL_LOG(block->rule(i)->toString());
  84. }
  85. return;
  86. for (fl::flScalar in = 0.0; in < 1.1; in += 0.1) {
  87. energy->setInput(in);
  88. distance->setInput(500);
  89. engine.process();
  90. fl::flScalar out = power->output().defuzzify();
  91. (void)out; //Just to avoid warning when building
  92. FL_LOG("Energy=" << in);
  93. FL_LOG("Energy is " << power->fuzzify(in));
  94. FL_LOG("Health=" << out);
  95. FL_LOG("Health is " << energy->fuzzify(out));
  96. FL_LOG("--");
  97. }
  98. }
  99. void Test::SimpleTakagiSugeno() {
  100. FuzzyOperator& op = FuzzyOperator::DefaultFuzzyOperator();
  101. op.setDefuzzifier(new TakagiSugenoDefuzzifier);
  102. FuzzyEngine engine("takagi-sugeno", op);
  103. fl::InputLVar* x = new fl::InputLVar("x");
  104. x->addTerm(new fl::TriangularTerm("NEAR_1", 0, 2));
  105. x->addTerm(new fl::TriangularTerm("NEAR_2", 1, 3));
  106. x->addTerm(new fl::TriangularTerm("NEAR_3", 2, 4));
  107. x->addTerm(new fl::TriangularTerm("NEAR_4", 3, 5));
  108. x->addTerm(new fl::TriangularTerm("NEAR_5", 4, 6));
  109. x->addTerm(new fl::TriangularTerm("NEAR_6", 5, 7));
  110. x->addTerm(new fl::TriangularTerm("NEAR_7", 6, 8));
  111. x->addTerm(new fl::TriangularTerm("NEAR_8", 7, 9));
  112. x->addTerm(new fl::TriangularTerm("NEAR_9", 8, 10));
  113. engine.addInputLVar(x);
  114. fl::OutputLVar* f_x = new fl::OutputLVar("f_x");
  115. f_x->addTerm(new fl::FunctionTerm("function", "(sin x) / x", 0, 10));
  116. engine.addOutputLVar(f_x);
  117. fl::RuleBlock* block = new fl::RuleBlock();
  118. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_1 then f_x=0.84", engine));
  119. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_2 then f_x=0.45", engine));
  120. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_3 then f_x=0.04", engine));
  121. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_4 then f_x=-0.18", engine));
  122. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_5 then f_x=-0.19", engine));
  123. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_6 then f_x=-0.04", engine));
  124. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_7 then f_x=0.09", engine));
  125. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_8 then f_x=0.12", engine));
  126. block->addRule(new fl::TakagiSugenoRule("if x is NEAR_9 then f_x=0.04", engine));
  127. engine.addRuleBlock(block);
  128. int n = 40;
  129. flScalar mse = 0;
  130. for (fl::flScalar in = x->minimum(); in < x->maximum() ;
  131. in += (x->minimum() + x->maximum()) / n) {
  132. x->setInput(in);
  133. engine.process();
  134. flScalar expected = f_x->term(0)->membership(in);
  135. flScalar obtained = f_x->output().defuzzify();
  136. flScalar se = (expected - obtained) * (expected - obtained);
  137. mse += isnan(se) ? 0 : se;
  138. FL_LOG("x=" << in << "\texpected_out=" << expected << "\tobtained_out=" << obtained
  139. << "\tse=" << se);
  140. }
  141. FL_LOG("MSE=" << mse / n);
  142. }
  143. void Test::SimplePendulum() {
  144. FuzzyOperator& op = FuzzyOperator::DefaultFuzzyOperator();
  145. FuzzyEngine engine("pendulum-3d",op);
  146. InputLVar* anglex = new InputLVar("AngleX");
  147. std::vector<std::string> labels;
  148. labels.push_back("NEAR_0");
  149. labels.push_back("NEAR_45");
  150. labels.push_back("NEAR_90");
  151. labels.push_back("NEAR_135");
  152. labels.push_back("NEAR_180");
  153. anglex->createTerms(5, LinguisticTerm::MF_SHOULDER, 0, 180, labels);
  154. engine.addInputLVar(anglex);
  155. InputLVar* anglez = new InputLVar("AngleZ");
  156. labels.clear();
  157. labels.push_back("NEAR_0");
  158. labels.push_back("NEAR_45");
  159. labels.push_back("NEAR_90");
  160. labels.push_back("NEAR_135");
  161. labels.push_back("NEAR_180");
  162. anglez->createTerms(5, LinguisticTerm::MF_SHOULDER, 0, 180, labels);
  163. engine.addInputLVar(anglez);
  164. OutputLVar* forcex = new OutputLVar("ForceX");
  165. labels.clear();
  166. labels.push_back("NL");
  167. labels.push_back("NS");
  168. labels.push_back("ZR");
  169. labels.push_back("PS");
  170. labels.push_back("PL");
  171. forcex->createTerms(5, LinguisticTerm::MF_TRIANGULAR, -1, 1, labels);
  172. engine.addOutputLVar(forcex);
  173. OutputLVar* forcez = new OutputLVar("ForceZ");
  174. labels.clear();
  175. labels.push_back("NL");
  176. labels.push_back("NS");
  177. labels.push_back("ZR");
  178. labels.push_back("PS");
  179. labels.push_back("PL");
  180. forcez->createTerms(5, LinguisticTerm::MF_TRIANGULAR, -1, 1, labels);
  181. engine.addOutputLVar(forcez);
  182. RuleBlock* ruleblock = new RuleBlock("Rules");
  183. ruleblock->addRule(new MamdaniRule("if AngleX is NEAR_180 then ForceX is NL", engine));
  184. ruleblock->addRule(new MamdaniRule("if AngleX is NEAR_135 then ForceX is NS", engine));
  185. ruleblock->addRule(new MamdaniRule("if AngleX is NEAR_90 then ForceX is ZR", engine));
  186. ruleblock->addRule(new MamdaniRule("if AngleX is NEAR_45 then ForceX is PS", engine));
  187. ruleblock->addRule(new MamdaniRule("if AngleX is NEAR_0 then ForceX is PL", engine));
  188. ruleblock->addRule(new MamdaniRule("if AngleZ is NEAR_180 then ForceZ is NL", engine));
  189. ruleblock->addRule(new MamdaniRule("if AngleZ is NEAR_135 then ForceZ is NS", engine));
  190. ruleblock->addRule(new MamdaniRule("if AngleZ is NEAR_90 then ForceZ is ZR", engine));
  191. ruleblock->addRule(new MamdaniRule("if AngleZ is NEAR_45 then ForceZ is PS", engine));
  192. ruleblock->addRule(new MamdaniRule("if AngleZ is NEAR_0 then ForceZ is PL", engine));
  193. engine.addRuleBlock(ruleblock);
  194. FL_LOG(engine.toString());
  195. for (int i = 0; i < 180; i += 20) {
  196. engine.setInput("AngleX", i);
  197. engine.process();
  198. FL_LOG("angle=" << i << "\tforce=" << engine.output("ForceX"));
  199. }
  200. }
  201. void Test::main(int args, char** argv) {
  202. FL_LOG("Starting in 2 second");
  203. FL_LOG("Example: Simple Mamdani");
  204. FL_LOG("=======================");
  205. #ifdef _MSC_VER
  206. //Sleep(2);
  207. #else
  208. sleep(2);
  209. #endif
  210. SimpleMamdani();
  211. FL_LOG("=======================\n");
  212. FL_LOG("Starting in 2 second");
  213. FL_LOG("Example: Complex Mamdani");
  214. FL_LOG("========================");
  215. #ifdef _MSC_VER
  216. //Sleep(2);
  217. #else
  218. sleep(2);
  219. #endif
  220. ComplexMamdani();
  221. FL_LOG("=======================\n");
  222. FL_LOG("Starting in 2 second");
  223. FL_LOG("Example: Simple Pendulum");
  224. FL_LOG("========================");
  225. #ifdef _MSC_VER
  226. //Sleep(2);
  227. #else
  228. sleep(2);
  229. #endif
  230. SimplePendulum();
  231. FL_LOG("=======================\n");
  232. FL_LOG("Starting in 2 second");
  233. FL_LOG("Example: Simple Takagi-Sugeno");
  234. FL_LOG("========================");
  235. #ifdef _MSC_VER
  236. //Sleep(2);
  237. #else
  238. sleep(2);
  239. #endif
  240. SimpleTakagiSugeno();
  241. FL_LOG("=======================\n");
  242. FL_LOG("For further examples build the GUI...");
  243. }
  244. }