Console.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801
  1. /*
  2. Author: Juan Rada-Vilela, Ph.D.
  3. Copyright (C) 2010-2014 FuzzyLite Limited
  4. All rights reserved
  5. This file is part of fuzzylite.
  6. fuzzylite is free software: you can redistribute it and/or modify it under
  7. the terms of the GNU Lesser General Public License as published by the Free
  8. Software Foundation, either version 3 of the License, or (at your option)
  9. any later version.
  10. fuzzylite is distributed in the hope that it will be useful, but WITHOUT
  11. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  13. for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with fuzzylite. If not, see <http://www.gnu.org/licenses/>.
  16. fuzzylite™ is a trademark of FuzzyLite Limited.
  17. */
  18. #include "fl/Console.h"
  19. #include "fl/Headers.h"
  20. #include <algorithm>
  21. #include <cctype>
  22. #include <fstream>
  23. #include <stdlib.h>
  24. #include <utility>
  25. #include <vector>
  26. #ifdef FL_UNIX
  27. #include <time.h> //only for benchmarks
  28. #include <termios.h>
  29. #include <unistd.h>
  30. #elif defined(FL_WINDOWS)
  31. #include <conio.h>
  32. #endif
  33. namespace fl {
  34. const std::string Console::KW_INPUT_FILE = "-i";
  35. const std::string Console::KW_INPUT_FORMAT = "-if";
  36. const std::string Console::KW_OUTPUT_FILE = "-o";
  37. const std::string Console::KW_OUTPUT_FORMAT = "-of";
  38. const std::string Console::KW_EXAMPLE = "-example";
  39. const std::string Console::KW_DECIMALS = "-decimals";
  40. const std::string Console::KW_DATA_INPUT = "-d";
  41. const std::string Console::KW_DATA_MAXIMUM = "-dmaximum";
  42. const std::string Console::KW_DATA_EXPORT_HEADER = "-dheader";
  43. const std::string Console::KW_DATA_EXPORT_INPUTS = "-dinputs";
  44. std::vector<Console::Option> Console::availableOptions() {
  45. std::vector<Console::Option> options;
  46. options.push_back(Option(KW_INPUT_FILE, "inputfile", "file to import your engine from"));
  47. options.push_back(Option(KW_INPUT_FORMAT, "format", "format of the file to import (fll | fis | fcl)"));
  48. options.push_back(Option(KW_OUTPUT_FILE, "outputfile", "file to export your engine to"));
  49. options.push_back(Option(KW_OUTPUT_FORMAT, "format", "format of the file to export (fll | fld | cpp | java | fis | fcl)"));
  50. options.push_back(Option(KW_EXAMPLE, "letter", "if not inputfile, built-in example to use as engine: (m)amdani or (t)akagi-sugeno"));
  51. options.push_back(Option(KW_DECIMALS, "number", "number of decimals to write floating-poing values"));
  52. options.push_back(Option(KW_DATA_INPUT, "datafile", "if exporting to fld, file of input values to evaluate your engine on"));
  53. options.push_back(Option(KW_DATA_MAXIMUM, "number", "if exporting to fld without datafile, maximum number of results to export"));
  54. options.push_back(Option(KW_DATA_EXPORT_HEADER, "boolean", "if true and exporting to fld, include headers"));
  55. options.push_back(Option(KW_DATA_EXPORT_INPUTS, "boolean", "if true and exporting to fld, include input values"));
  56. return options;
  57. }
  58. std::string Console::usage() {
  59. std::vector<Console::Option> options = availableOptions();
  60. std::ostringstream ss;
  61. ss << "Copyright (C) 2010-2014 FuzzyLite Limited\n";
  62. ss << "All rights reserved\n";
  63. ss << "==================================================\n";
  64. ss << "fuzzylite: a fuzzy logic control library\n";
  65. ss << "version: " << fuzzylite::longVersion() << "\n";
  66. ss << "author: " << fuzzylite::author() << "\n";
  67. ss << "license: " << fuzzylite::license() << "\n";
  68. ss << "==================================================\n";
  69. ss << "usage: fuzzylite inputfile outputfile\n";
  70. ss << " or: fuzzylite ";
  71. for (std::size_t i = 0; i < options.size(); ++i) {
  72. ss << "[" << options.at(i).key << " " << options.at(i).value << "] ";
  73. }
  74. ss << "\n\nwhere:\n";
  75. for (std::size_t i = 0; i < options.size(); ++i) {
  76. std::string spacedKey(12, ' ');
  77. std::string key = options.at(i).key;
  78. std::copy(key.begin(), key.end(), spacedKey.begin());
  79. std::string spacedValue(13, ' ');
  80. std::string value = options.at(i).value;
  81. std::copy(value.begin(), value.end(), spacedValue.begin());
  82. std::string description = options.at(i).description;
  83. ss << spacedKey << spacedValue << description << "\n";
  84. }
  85. ss << "\n";
  86. ss << "Visit http://www.fuzzylite.com for more information.";
  87. return ss.str();
  88. }
  89. std::map<std::string, std::string> Console::parse(int argc, char** argv) {
  90. if ((argc - 1) % 2 != 0) {
  91. throw fl::Exception("[option error] incomplete number of parameters [key value]", FL_AT);
  92. }
  93. std::map<std::string, std::string> options;
  94. for (int i = 1; i < argc - 1; i += 2) {
  95. std::string key = std::string(argv[i]);
  96. std::string value = std::string(argv[i + 1]);
  97. options[key] = value;
  98. }
  99. if (options.size() == 1) {
  100. std::map<std::string, std::string>::const_iterator it = options.begin();
  101. if (it->first.at(0) != '-') {
  102. options[KW_INPUT_FILE] = it->first;
  103. options[KW_OUTPUT_FILE] = it->second;
  104. }
  105. } else {
  106. std::vector<Console::Option> validOptions = availableOptions();
  107. for (std::map<std::string, std::string>::const_iterator it = options.begin();
  108. it != options.end(); ++it) {
  109. bool isValid = false;
  110. for (std::size_t i = 0; i < validOptions.size(); ++i) {
  111. std::string key = validOptions.at(i).key;
  112. if (key == it->first) {
  113. isValid = true;
  114. break;
  115. }
  116. }
  117. if (not isValid) {
  118. throw fl::Exception("[option error] option <" + it->first + "> not recognized", FL_AT);
  119. }
  120. }
  121. }
  122. return options;
  123. }
  124. void Console::process(const std::map<std::string, std::string>& options) {
  125. std::map<std::string, std::string>::const_iterator it;
  126. it = options.find(KW_DECIMALS);
  127. if (it != options.end()) {
  128. fl::fuzzylite::setDecimals((int) fl::Op::toScalar(it->second));
  129. }
  130. std::string example;
  131. std::string inputFormat;
  132. std::ostringstream textEngine;
  133. it = options.find(KW_EXAMPLE);
  134. bool isExample = (it != options.end());
  135. if (isExample) {
  136. example = it->second;
  137. Engine* engine;
  138. if (example == "m" or example == "mamdani") {
  139. engine = mamdani();
  140. } else if (example == "t" or example == "ts" or example == "takagi-sugeno") {
  141. engine = takagiSugeno();
  142. } else {
  143. throw fl::Exception("[option error] example <" + example + "> not available", FL_AT);
  144. }
  145. inputFormat = "fll";
  146. textEngine << FllExporter().toString(engine);
  147. delete engine;
  148. } else {
  149. it = options.find(KW_INPUT_FILE);
  150. if (it == options.end()) {
  151. throw fl::Exception("[option error] no input file specified", FL_AT);
  152. }
  153. std::string inputFilename = it->second;
  154. std::ifstream inputFile(inputFilename.c_str());
  155. if (not inputFile.is_open()) {
  156. throw fl::Exception("[file error] file <" + inputFilename + "> could not be opened", FL_AT);
  157. }
  158. std::string line;
  159. while (std::getline(inputFile, line)) {
  160. textEngine << line << std::endl;
  161. }
  162. inputFile.close();
  163. it = options.find(KW_INPUT_FORMAT);
  164. if (it != options.end()) {
  165. inputFormat = it->second;
  166. } else {
  167. std::size_t extensionIndex = inputFilename.find_last_of(".");
  168. if (extensionIndex != std::string::npos) {
  169. inputFormat = inputFilename.substr(extensionIndex + 1);
  170. } else {
  171. throw fl::Exception("[format error] unspecified format of input file", FL_AT);
  172. }
  173. }
  174. }
  175. std::string outputFilename;
  176. it = options.find(KW_OUTPUT_FILE);
  177. if (it != options.end()) {
  178. outputFilename = it->second;
  179. }
  180. std::string outputFormat;
  181. it = options.find(KW_OUTPUT_FORMAT);
  182. if (it != options.end()) {
  183. outputFormat = it->second;
  184. } else {
  185. std::size_t extensionIndex = outputFilename.find_last_of(".");
  186. if (extensionIndex != std::string::npos) {
  187. outputFormat = outputFilename.substr(extensionIndex + 1);
  188. } else {
  189. throw fl::Exception("[format error] unspecified format of output file", FL_AT);
  190. }
  191. }
  192. if (outputFilename.empty()) {
  193. process(textEngine.str(), std::cout, inputFormat, outputFormat, options);
  194. } else {
  195. std::ofstream writer(outputFilename.c_str());
  196. if (not writer.is_open()) {
  197. throw fl::Exception("[file error] file <" + outputFilename + "> could not be created", FL_AT);
  198. }
  199. process(textEngine.str(), writer, inputFormat, outputFormat, options);
  200. writer.flush();
  201. writer.close();
  202. }
  203. }
  204. void Console::process(const std::string& input, std::ostream& writer,
  205. const std::string& inputFormat, const std::string& outputFormat,
  206. const std::map<std::string, std::string>& options) {
  207. FL_unique_ptr<Importer> importer;
  208. FL_unique_ptr<Exporter> exporter;
  209. FL_unique_ptr<Engine> engine;
  210. if ("fll" == inputFormat) {
  211. importer.reset(new FllImporter);
  212. } else if ("fcl" == inputFormat) {
  213. importer.reset(new FclImporter);
  214. } else if ("fis" == inputFormat) {
  215. importer.reset(new FisImporter);
  216. } else {
  217. throw fl::Exception("[import error] format <" + inputFormat + "> "
  218. "not supported", FL_AT);
  219. }
  220. engine.reset(importer->fromString(input));
  221. if ("fld" == outputFormat) {
  222. std::map<std::string, std::string>::const_iterator it;
  223. FldExporter fldExporter;
  224. fldExporter.setSeparator("\t");
  225. bool exportHeaders = true;
  226. if ((it = options.find(KW_DATA_EXPORT_HEADER)) != options.end()) {
  227. exportHeaders = ("true" == it->second);
  228. }
  229. fldExporter.setExportHeader(exportHeaders);
  230. bool exportInputValues = true;
  231. if ((it = options.find(KW_DATA_EXPORT_INPUTS)) != options.end()) {
  232. exportInputValues = ("true" == it->second);
  233. }
  234. fldExporter.setExportInputValues(exportInputValues);
  235. if ((it = options.find(KW_DATA_INPUT)) != options.end()) {
  236. std::ifstream dataFile(it->second.c_str());
  237. if (not dataFile.is_open()) {
  238. throw fl::Exception("[export error] file <" + it->second + "> could not be opened", FL_AT);
  239. }
  240. try {
  241. fldExporter.write(engine.get(), writer, dataFile);
  242. } catch (std::exception& ex) {
  243. (void) ex;
  244. dataFile.close();
  245. throw;
  246. }
  247. } else {
  248. if ((it = options.find(KW_DATA_MAXIMUM)) != options.end()) {
  249. fldExporter.write(engine.get(), writer, (int) fl::Op::toScalar(it->second));
  250. } else {
  251. std::ostringstream buffer;
  252. buffer << "#FuzzyLite Interactive Console (press H for help)\n";
  253. buffer << fldExporter.header(engine.get()) << "\n";
  254. bool showCout = &writer != &std::cout;
  255. writer << buffer.str();
  256. if (showCout) std::cout << buffer.str();
  257. else writer.flush();
  258. interactive(writer, engine.get());
  259. }
  260. }
  261. } else {
  262. if ("fll" == outputFormat) {
  263. exporter.reset(new FllExporter);
  264. } else if ("fcl" == outputFormat) {
  265. exporter.reset(new FclExporter);
  266. } else if ("fis" == outputFormat) {
  267. exporter.reset(new FisExporter);
  268. } else if ("cpp" == outputFormat) {
  269. exporter.reset(new CppExporter);
  270. } else if ("java" == outputFormat) {
  271. exporter.reset(new JavaExporter);
  272. } else throw fl::Exception("[export error] format <" + outputFormat + "> "
  273. "not supported", FL_AT);
  274. writer << exporter->toString(engine.get());
  275. }
  276. }
  277. int Console::readCharacter() {
  278. int ch = 0;
  279. #ifdef FL_UNIX
  280. struct termios oldt, newt;
  281. tcgetattr(STDIN_FILENO, &oldt);
  282. newt = oldt;
  283. newt.c_lflag &= ~(ICANON | ECHO);
  284. tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  285. ch = getchar();
  286. tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  287. #elif defined(FL_WINDOWS)
  288. ch = _getch();
  289. #endif
  290. return ch;
  291. }
  292. void Console::interactive(std::ostream& writer, Engine* engine) {
  293. std::ostringstream buffer;
  294. buffer << ">";
  295. bool showCout = &writer != &std::cout;
  296. const std::string space("\t");
  297. std::vector<scalar> inputValues;
  298. std::ostringstream inputValue;
  299. int ch = 0;
  300. do {
  301. writer << buffer.str();
  302. if (showCout) std::cout << buffer.str();
  303. else writer.flush();
  304. buffer.str("");
  305. ch = readCharacter();
  306. if (std::isspace(ch)) {
  307. scalar value = engine->getInputVariable(inputValues.size())->getInputValue();
  308. try {
  309. value = fl::Op::toScalar(inputValue.str());
  310. } catch (std::exception& ex) {
  311. (void) ex;
  312. buffer << "[" << fl::Op::str(value) << "]";
  313. }
  314. buffer << space;
  315. inputValue.str("");
  316. inputValues.push_back(value);
  317. if (inputValues.size() == engine->inputVariables().size()) {
  318. ch = 'P'; //fall through to process;
  319. } else continue;
  320. }
  321. if (not std::isgraph(ch)) continue;
  322. switch (ch) {
  323. default:
  324. inputValue << char(ch);
  325. buffer << char(ch);
  326. break;
  327. case 'r':
  328. case 'R': engine->restart();
  329. buffer << "#[Restart]";
  330. //fall through
  331. case 'd':
  332. case 'D': inputValues.clear();
  333. buffer << "#[Discard]\n>";
  334. inputValue.str("");
  335. break;
  336. case 'p':
  337. case 'P': //Process
  338. {
  339. inputValue.str("");
  340. for (std::size_t i = 0; i < inputValues.size(); ++i) {
  341. InputVariable* inputVariable = engine->inputVariables().at(i);
  342. inputVariable->setInputValue(inputValues.at(i));
  343. }
  344. std::vector<scalar> missingInputs;
  345. for (std::size_t i = inputValues.size(); i < engine->inputVariables().size(); ++i) {
  346. InputVariable* inputVariable = engine->inputVariables().at(i);
  347. missingInputs.push_back(inputVariable->getInputValue());
  348. }
  349. inputValues.clear();
  350. buffer << fl::Op::join(missingInputs, space);
  351. if (not missingInputs.empty()) buffer << space;
  352. buffer << "=" << space;
  353. try {
  354. engine->process();
  355. std::vector<scalar> outputValues;
  356. for (std::size_t i = 0; i < engine->outputVariables().size(); ++i) {
  357. OutputVariable* outputVariable = engine->outputVariables().at(i);
  358. outputVariable->defuzzify();
  359. outputValues.push_back(outputVariable->getOutputValue());
  360. }
  361. buffer << fl::Op::join(outputValues, space) << "\n>";
  362. } catch (std::exception& ex) {
  363. buffer << "#[Error: " << ex.what() << "]";
  364. }
  365. break;
  366. }
  367. case 'q':
  368. case 'Q': buffer << "#[Quit]\n";
  369. break;
  370. case 'h':
  371. case 'H': buffer << "\n>" << interactiveHelp() << "\n>";
  372. inputValue.str("");
  373. break;
  374. }
  375. } while (not (ch == 'Q' or ch == 'q'));
  376. writer << std::endl;
  377. }
  378. std::string Console::interactiveHelp() {
  379. return
  380. "#Special Keys\n"
  381. "#=============\n"
  382. "#\tR\tRestart engine and discard current inputs\n"
  383. "#\tD\tDiscard current inputs\n"
  384. "#\tP\tProcess engine\n"
  385. "#\tQ\tQuit interactive console\n"
  386. "#\tH\tShow this help\n"
  387. "#=============\n";
  388. }
  389. Engine* Console::mamdani() {
  390. Engine* engine = new Engine("simple-dimmer");
  391. InputVariable* ambient = new InputVariable("Ambient", 0, 1);
  392. ambient->addTerm(new Triangle("DARK", .0, .25, .5));
  393. ambient->addTerm(new Triangle("MEDIUM", .25, .5, .75));
  394. ambient->addTerm(new Triangle("BRIGHT", .5, .75, 1));
  395. engine->addInputVariable(ambient);
  396. OutputVariable* power = new OutputVariable("Power", 0, 2);
  397. power->setDefaultValue(fl::nan);
  398. power->addTerm(new Triangle("LOW", 0.0, 0.5, 1));
  399. power->addTerm(new Triangle("MEDIUM", 0.5, 1, 1.5));
  400. power->addTerm(new Triangle("HIGH", 1, 1.5, 2));
  401. engine->addOutputVariable(power);
  402. RuleBlock* ruleblock = new RuleBlock();
  403. ruleblock->addRule(Rule::parse("if Ambient is DARK then Power is HIGH", engine));
  404. ruleblock->addRule(Rule::parse("if Ambient is MEDIUM then Power is MEDIUM", engine));
  405. ruleblock->addRule(Rule::parse("if Ambient is BRIGHT then Power is LOW", engine));
  406. engine->addRuleBlock(ruleblock);
  407. engine->configure("", "", "Minimum", "Maximum", "Centroid");
  408. return engine;
  409. }
  410. Engine* Console::takagiSugeno() {
  411. Engine* engine = new Engine("approximation of sin(x)/x");
  412. fl::InputVariable* inputX = new fl::InputVariable("inputX");
  413. inputX->setRange(0, 10);
  414. inputX->addTerm(new fl::Triangle("NEAR_1", 0, 1, 2));
  415. inputX->addTerm(new fl::Triangle("NEAR_2", 1, 2, 3));
  416. inputX->addTerm(new fl::Triangle("NEAR_3", 2, 3, 4));
  417. inputX->addTerm(new fl::Triangle("NEAR_4", 3, 4, 5));
  418. inputX->addTerm(new fl::Triangle("NEAR_5", 4, 5, 6));
  419. inputX->addTerm(new fl::Triangle("NEAR_6", 5, 6, 7));
  420. inputX->addTerm(new fl::Triangle("NEAR_7", 6, 7, 8));
  421. inputX->addTerm(new fl::Triangle("NEAR_8", 7, 8, 9));
  422. inputX->addTerm(new fl::Triangle("NEAR_9", 8, 9, 10));
  423. engine->addInputVariable(inputX);
  424. fl::OutputVariable* outputFx = new fl::OutputVariable("outputFx");
  425. outputFx->setRange(-1, 1);
  426. outputFx->setDefaultValue(fl::nan);
  427. outputFx->setLockPreviousOutputValue(true); //To use its value with diffFx
  428. outputFx->addTerm(new Constant("f1", 0.84));
  429. outputFx->addTerm(new Constant("f2", 0.45));
  430. outputFx->addTerm(new Constant("f3", 0.04));
  431. outputFx->addTerm(new Constant("f4", -0.18));
  432. outputFx->addTerm(new Constant("f5", -0.19));
  433. outputFx->addTerm(new Constant("f6", -0.04));
  434. outputFx->addTerm(new Constant("f7", 0.09));
  435. outputFx->addTerm(new Constant("f8", 0.12));
  436. outputFx->addTerm(new Constant("f9", 0.04));
  437. engine->addOutputVariable(outputFx);
  438. fl::OutputVariable* trueFx = new fl::OutputVariable("trueFx");
  439. trueFx->setRange(fl::nan, fl::nan);
  440. trueFx->setLockPreviousOutputValue(true); //To use its value with diffFx
  441. trueFx->addTerm(fl::Function::create("fx", "sin(inputX)/inputX", engine));
  442. engine->addOutputVariable(trueFx);
  443. fl::OutputVariable* diffFx = new fl::OutputVariable("diffFx");
  444. diffFx->addTerm(fl::Function::create("diff", "fabs(outputFx-trueFx)", engine));
  445. diffFx->setRange(fl::nan, fl::nan);
  446. // diffFx->setLockValidOutput(true); //To use in input diffPreviousFx
  447. engine->addOutputVariable(diffFx);
  448. fl::RuleBlock* block = new fl::RuleBlock();
  449. block->addRule(fl::Rule::parse("if inputX is NEAR_1 then outputFx is f1", engine));
  450. block->addRule(fl::Rule::parse("if inputX is NEAR_2 then outputFx is f2", engine));
  451. block->addRule(fl::Rule::parse("if inputX is NEAR_3 then outputFx is f3", engine));
  452. block->addRule(fl::Rule::parse("if inputX is NEAR_4 then outputFx is f4", engine));
  453. block->addRule(fl::Rule::parse("if inputX is NEAR_5 then outputFx is f5", engine));
  454. block->addRule(fl::Rule::parse("if inputX is NEAR_6 then outputFx is f6", engine));
  455. block->addRule(fl::Rule::parse("if inputX is NEAR_7 then outputFx is f7", engine));
  456. block->addRule(fl::Rule::parse("if inputX is NEAR_8 then outputFx is f8", engine));
  457. block->addRule(fl::Rule::parse("if inputX is NEAR_9 then outputFx is f9", engine));
  458. block->addRule(fl::Rule::parse("if inputX is any then trueFx is fx and diffFx is diff", engine));
  459. engine->addRuleBlock(block);
  460. engine->configure("", "", "AlgebraicProduct", "AlgebraicSum", "WeightedAverage");
  461. return engine;
  462. }
  463. void Console::exportAllExamples(const std::string& from, const std::string& to) {
  464. std::vector<std::string> examples;
  465. examples.push_back("/mamdani/AllTerms");
  466. // examples.push_back("/mamdani/Laundry");
  467. examples.push_back("/mamdani/SimpleDimmer");
  468. // examples.push_back("/mamdani/SimpleDimmerInverse");
  469. examples.push_back("/mamdani/matlab/mam21");
  470. examples.push_back("/mamdani/matlab/mam22");
  471. examples.push_back("/mamdani/matlab/shower");
  472. examples.push_back("/mamdani/matlab/tank");
  473. examples.push_back("/mamdani/matlab/tank2");
  474. examples.push_back("/mamdani/matlab/tipper");
  475. examples.push_back("/mamdani/matlab/tipper1");
  476. examples.push_back("/mamdani/octave/investment_portfolio");
  477. examples.push_back("/mamdani/octave/mamdani_tip_calculator");
  478. examples.push_back("/takagi-sugeno/approximation");
  479. examples.push_back("/takagi-sugeno/SimpleDimmer");
  480. examples.push_back("/takagi-sugeno/matlab/fpeaks");
  481. examples.push_back("/takagi-sugeno/matlab/invkine1");
  482. examples.push_back("/takagi-sugeno/matlab/invkine2");
  483. examples.push_back("/takagi-sugeno/matlab/juggler");
  484. examples.push_back("/takagi-sugeno/matlab/membrn1");
  485. examples.push_back("/takagi-sugeno/matlab/membrn2");
  486. examples.push_back("/takagi-sugeno/matlab/slbb");
  487. examples.push_back("/takagi-sugeno/matlab/slcp");
  488. examples.push_back("/takagi-sugeno/matlab/slcp1");
  489. examples.push_back("/takagi-sugeno/matlab/slcpp1");
  490. examples.push_back("/takagi-sugeno/matlab/sltbu_fl");
  491. examples.push_back("/takagi-sugeno/matlab/sugeno1");
  492. examples.push_back("/takagi-sugeno/matlab/tanksg");
  493. examples.push_back("/takagi-sugeno/matlab/tippersg");
  494. examples.push_back("/takagi-sugeno/octave/cubic_approximator");
  495. examples.push_back("/takagi-sugeno/octave/heart_disease_risk");
  496. examples.push_back("/takagi-sugeno/octave/linear_tip_calculator");
  497. examples.push_back("/takagi-sugeno/octave/sugeno_tip_calculator");
  498. examples.push_back("/tsukamoto/tsukamoto");
  499. std::string sourceBase = "/home/jcrada/Development/fl/fuzzylite/examples/original";
  500. std::string targetBase = "/tmp/fl/";
  501. FL_unique_ptr<Importer> importer;
  502. if (from == "fll") importer.reset(new FllImporter);
  503. else if (from == "fis") importer.reset(new FisImporter);
  504. else if (from == "fcl") importer.reset(new FclImporter);
  505. else throw fl::Exception("[examples error] unrecognized format <" + from + "> to import", FL_AT);
  506. FL_unique_ptr<Exporter> exporter;
  507. if (to == "fll") exporter.reset(new FllExporter);
  508. else if (to == "fld") exporter.reset(new FldExporter(" "));
  509. else if (to == "fcl") exporter.reset(new FclExporter);
  510. else if (to == "fis") exporter.reset(new FisExporter);
  511. else if (to == "cpp") exporter.reset(new CppExporter);
  512. else if (to == "java") exporter.reset(new JavaExporter);
  513. else throw fl::Exception("[examples error] unrecognized format <" + to + "> to export", FL_AT);
  514. std::vector<std::pair<Exporter*, Importer*> > tests;
  515. tests.push_back(std::pair<Exporter*, Importer*>(new FllExporter, new FllImporter));
  516. tests.push_back(std::pair<Exporter*, Importer*>(new FisExporter, new FisImporter));
  517. tests.push_back(std::pair<Exporter*, Importer*>(new FclExporter, new FclImporter));
  518. for (std::size_t i = 0; i < examples.size(); ++i) {
  519. FL_LOG("Processing " << (i + 1) << "/" << examples.size() << ": " << examples.at(i));
  520. std::ostringstream ss;
  521. std::string input = sourceBase + examples.at(i) + "." + from;
  522. std::ifstream source(input.c_str());
  523. if (source.is_open()) {
  524. std::string line;
  525. while (source.good()) {
  526. std::getline(source, line);
  527. ss << line << "\n";
  528. }
  529. source.close();
  530. } else throw fl::Exception("[examples error] file not found: " + input, FL_AT);
  531. FL_unique_ptr<Engine> engine(importer->fromString(ss.str()));
  532. for (std::size_t t = 0; t < tests.size(); ++t) {
  533. std::string out = tests.at(t).first->toString(engine.get());
  534. FL_unique_ptr<Engine> copy(tests.at(t).second->fromString(out));
  535. std::string out_copy = tests.at(t).first->toString(copy.get());
  536. if (out != out_copy) {
  537. std::ostringstream ss;
  538. ss << "[imex error] different results <"
  539. << importer->name() << "," << exporter->name() << "> "
  540. "at " + examples.at(t) + "." + from + ":\n";
  541. ss << "<Engine A>\n" << out << "\n\n" <<
  542. "================================\n\n" <<
  543. "<Engine B>\n" << out_copy;
  544. throw fl::Exception(ss.str(), FL_AT);
  545. }
  546. }
  547. std::string output = targetBase + examples.at(i) + "." + to;
  548. std::ofstream target(output.c_str());
  549. if (target.is_open()) {
  550. if (to == "cpp") {
  551. target << "#include <fl/Headers.h>\n\n"
  552. << "int main(int argc, char** argv){\n"
  553. << exporter->toString(engine.get())
  554. << "\n}\n";
  555. } else if (to == "java") {
  556. std::string className = examples.at(i).substr(examples.at(i).find_last_of('/') + 1);
  557. target << "import com.fuzzylite.*;\n"
  558. << "import com.fuzzylite.defuzzifier.*;\n"
  559. << "import com.fuzzylite.factory.*;\n"
  560. << "import com.fuzzylite.hedge.*;\n"
  561. << "import com.fuzzylite.imex.*;\n"
  562. << "import com.fuzzylite.norm.*;\n"
  563. << "import com.fuzzylite.norm.s.*;\n"
  564. << "import com.fuzzylite.norm.t.*;\n"
  565. << "import com.fuzzylite.rule.*;\n"
  566. << "import com.fuzzylite.term.*;\n"
  567. << "import com.fuzzylite.variable.*;\n\n"
  568. << "public class " << Op::validName(className) << "{\n"
  569. << "public static void main(String[] args){\n"
  570. << exporter->toString(engine.get())
  571. << "\n}\n}\n";
  572. } else {
  573. target << exporter->toString(engine.get());
  574. }
  575. target.close();
  576. }
  577. Engine copyConstructor(*engine.get());
  578. (void) copyConstructor;
  579. Engine assignmentOperator = *engine.get();
  580. (void) assignmentOperator;
  581. }
  582. for (std::size_t i = 0; i < tests.size(); ++i) {
  583. delete tests.at(i).first;
  584. delete tests.at(i).second;
  585. }
  586. }
  587. #if defined(FL_UNIX) && ! defined(FL_APPLE)
  588. void Console::benchmarkExamples(int runs) {
  589. std::string sourceBase = "/home/jcrada/Development/fl/fuzzylite/examples/original";
  590. typedef std::pair<std::string, int > Example;
  591. std::vector<Example> examples;
  592. examples.push_back(Example("/mamdani/AllTerms", 1e4));
  593. examples.push_back(Example("/mamdani/SimpleDimmer", 1e5));
  594. examples.push_back(Example("/mamdani/matlab/mam21", 128));
  595. examples.push_back(Example("/mamdani/matlab/mam22", 128));
  596. examples.push_back(Example("/mamdani/matlab/shower", 256));
  597. examples.push_back(Example("/mamdani/matlab/tank", 256));
  598. examples.push_back(Example("/mamdani/matlab/tank2", 512));
  599. examples.push_back(Example("/mamdani/matlab/tipper", 256));
  600. examples.push_back(Example("/mamdani/matlab/tipper1", 1e5));
  601. examples.push_back(Example("/mamdani/octave/investment_portfolio", 256));
  602. examples.push_back(Example("/mamdani/octave/mamdani_tip_calculator", 256));
  603. examples.push_back(Example("/takagi-sugeno/approximation", 1e6));
  604. examples.push_back(Example("/takagi-sugeno/SimpleDimmer", 2e6));
  605. examples.push_back(Example("/takagi-sugeno/matlab/fpeaks", 512));
  606. examples.push_back(Example("/takagi-sugeno/matlab/invkine1", 256));
  607. examples.push_back(Example("/takagi-sugeno/matlab/invkine2", 256));
  608. examples.push_back(Example("/takagi-sugeno/matlab/juggler", 512));
  609. examples.push_back(Example("/takagi-sugeno/matlab/membrn1", 1024));
  610. examples.push_back(Example("/takagi-sugeno/matlab/membrn2", 512));
  611. examples.push_back(Example("/takagi-sugeno/matlab/slbb", 20));
  612. examples.push_back(Example("/takagi-sugeno/matlab/slcp", 20));
  613. examples.push_back(Example("/takagi-sugeno/matlab/slcp1", 15));
  614. examples.push_back(Example("/takagi-sugeno/matlab/slcpp1", 9));
  615. examples.push_back(Example("/takagi-sugeno/matlab/sltbu_fl", 128));
  616. examples.push_back(Example("/takagi-sugeno/matlab/sugeno1", 2e6));
  617. examples.push_back(Example("/takagi-sugeno/matlab/tanksg", 1024));
  618. examples.push_back(Example("/takagi-sugeno/matlab/tippersg", 1024));
  619. examples.push_back(Example("/takagi-sugeno/octave/cubic_approximator", 2e6));
  620. examples.push_back(Example("/takagi-sugeno/octave/heart_disease_risk", 1024));
  621. examples.push_back(Example("/takagi-sugeno/octave/linear_tip_calculator", 1024));
  622. examples.push_back(Example("/takagi-sugeno/octave/sugeno_tip_calculator", 512));
  623. examples.push_back(Example("/tsukamoto/tsukamoto", 1e6));
  624. for (std::size_t i = 0; i < examples.size(); ++i) {
  625. FL_LOG(examples.at(i).first << "\t" << examples.at(i).second);
  626. }
  627. FllImporter importer;
  628. FldExporter exporter;
  629. exporter.setExportHeader(false);
  630. exporter.setExportInputValues(false);
  631. exporter.setExportOutputValues(false);
  632. std::ostream dummy(0);
  633. for (std::size_t e = 0; e < examples.size(); ++e) {
  634. std::string filename(sourceBase + examples.at(e).first + ".fll");
  635. std::ifstream file(filename.c_str());
  636. std::ostringstream fll;
  637. if (file.is_open()) {
  638. std::string line;
  639. while (file.good()) {
  640. std::getline(file, line);
  641. fll << line << "\n";
  642. }
  643. file.close();
  644. } else throw fl::Exception("[examples error] file not found: " + filename, FL_AT);
  645. FL_unique_ptr<Engine> engine(importer.fromString(fll.str()));
  646. std::vector<scalar> seconds;
  647. timespec start, now;
  648. int results = std::pow(1.0 * examples.at(e).second, engine->numberOfInputVariables());
  649. for (int r = 0; r < runs; ++r) {
  650. clock_gettime(CLOCK_REALTIME, &start);
  651. exporter.write(engine.get(), dummy, results);
  652. clock_gettime(CLOCK_REALTIME, &now);
  653. time_t elapsed = now.tv_sec - start.tv_sec;
  654. scalar a = elapsed + start.tv_nsec / 1e9f;
  655. scalar b = elapsed + now.tv_nsec / 1e9f;
  656. seconds.push_back((b - a) + elapsed);
  657. }
  658. scalar mean = Op::mean(seconds);
  659. scalar stdev = Op::standardDeviation(seconds, mean);
  660. FL_LOG(examples.at(e).first << ":\t" <<
  661. fl::Op::str(mean) << "\t" << fl::Op::str(stdev) << "\t" <<
  662. Op::join(seconds, "\t"));
  663. }
  664. }
  665. #endif
  666. int Console::main(int argc, char** argv) {
  667. (void) argc;
  668. (void) argv;
  669. if (argc <= 1) {
  670. std::cout << usage() << std::endl;
  671. return EXIT_SUCCESS;
  672. }
  673. if (argc == 2) {
  674. if ("export-examples" == std::string(argv[1])) {
  675. try {
  676. fuzzylite::setDecimals(3);
  677. FL_LOG("Processing fll->fll");
  678. exportAllExamples("fll", "fll");
  679. FL_LOG("Processing fll->fcl");
  680. exportAllExamples("fll", "fcl");
  681. FL_LOG("Processing fll->fis");
  682. exportAllExamples("fll", "fis");
  683. FL_LOG("Processing fll->cpp");
  684. exportAllExamples("fll", "cpp");
  685. FL_LOG("Processing fll->java");
  686. exportAllExamples("fll", "java");
  687. fuzzylite::setDecimals(8);
  688. fuzzylite::setMachEps(1e-6);
  689. FL_LOG("Processing fll->fld");
  690. exportAllExamples("fll", "fld");
  691. } catch (std::exception& ex) {
  692. std::cout << ex.what() << "\nBACKTRACE:\n" <<
  693. fl::Exception::btCallStack() << std::endl;
  694. return EXIT_FAILURE;
  695. }
  696. return EXIT_SUCCESS;
  697. } else if ("benchmarks" == std::string(argv[1])) {
  698. #if defined(FL_UNIX) && ! defined(FL_APPLE)
  699. fuzzylite::setDecimals(3);
  700. Console::benchmarkExamples(10);
  701. return EXIT_SUCCESS;
  702. #else
  703. throw fl::Exception("[benchmarks error] implementation available only for Unix-based OS", FL_AT);
  704. #endif
  705. }
  706. }
  707. try {
  708. std::map<std::string, std::string> options = parse(argc, argv);
  709. process(options);
  710. } catch (std::exception& ex) {
  711. std::cout << ex.what() << "\n" << std::endl;
  712. // std::cout << fl::Exception::btCallStack() << std::endl;
  713. return EXIT_FAILURE;
  714. }
  715. return EXIT_SUCCESS;
  716. }
  717. }