summaryrefslogtreecommitdiff
path: root/fuzzylite/src/imex/FllImporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/imex/FllImporter.cpp')
-rw-r--r--fuzzylite/src/imex/FllImporter.cpp317
1 files changed, 317 insertions, 0 deletions
diff --git a/fuzzylite/src/imex/FllImporter.cpp b/fuzzylite/src/imex/FllImporter.cpp
new file mode 100644
index 0000000..2443d10
--- /dev/null
+++ b/fuzzylite/src/imex/FllImporter.cpp
@@ -0,0 +1,317 @@
+/*
+ Author: Juan Rada-Vilela, Ph.D.
+ Copyright (C) 2010-2014 FuzzyLite Limited
+ All rights reserved
+
+ This file is part of fuzzylite.
+
+ fuzzylite is free software: you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ fuzzylite is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with fuzzylite. If not, see <http://www.gnu.org/licenses/>.
+
+ fuzzyliteâ„¢ is a trademark of FuzzyLite Limited.
+
+ */
+
+#include "fl/imex/FllImporter.h"
+
+#include "fl/Headers.h"
+
+#include <queue>
+
+namespace fl {
+
+ FllImporter::FllImporter(const std::string& separator) : Importer(),
+ _separator(separator) {
+ }
+
+ FllImporter::~FllImporter() {
+
+ }
+
+ std::string FllImporter::name() const {
+ return "FllImporter";
+ }
+
+ void FllImporter::setSeparator(const std::string& separator) {
+ this->_separator = separator;
+ }
+
+ std::string FllImporter::getSeparator() const {
+ return this->_separator;
+ }
+
+ Engine* FllImporter::fromString(const std::string& fll) const {
+ FL_unique_ptr<Engine> engine(new Engine);
+
+ std::string tag;
+ std::ostringstream block;
+ std::istringstream fclReader(fll);
+ std::string line;
+ std::queue<std::string> lineQueue;
+
+ bool processPending = false;
+ int lineNumber = 0;
+ while (not lineQueue.empty() or std::getline(fclReader, line)) {
+ if (not lineQueue.empty()) {
+ line = lineQueue.front();
+ lineQueue.pop();
+ } else {
+ line = clean(line);
+ if (line.empty()) continue;
+ std::vector<std::string> split = Op::split(line, _separator);
+ line = clean(split.front());
+ for (std::size_t i = 1; i < split.size(); ++i) {
+ lineQueue.push(clean(split.at(i)));
+ }
+ ++lineNumber;
+ }
+ if (line.empty()) continue;
+ std::size_t colon = line.find_first_of(':');
+ if (colon == std::string::npos) {
+ throw fl::Exception("[import error] expected a colon at line " +
+ Op::str(lineNumber) + ": " + line, FL_AT);
+ }
+ std::string key = Op::trim(line.substr(0, colon));
+ std::string value = Op::trim(line.substr(colon + 1));
+ if ("Engine" == key) {
+ engine->setName(value);
+ continue;
+ } else {
+ processPending = (key == "InputVariable"
+ or key == "OutputVariable"
+ or key == "RuleBlock");
+ }
+ if (processPending) {
+ process(tag, block.str(), engine.get());
+ block.str(""); //clear buffer
+ block.clear(); //clear error flags
+ processPending = false;
+ tag = key;
+ }
+ block << key << ":" << value << "\n";
+ }
+ process(tag, block.str(), engine.get());
+ return engine.release();
+ }
+
+ void FllImporter::process(const std::string& tag, const std::string& block, Engine* engine) const {
+ if (tag.empty()) return;
+ if ("InputVariable" == tag) {
+ processInputVariable(block, engine);
+ } else if ("OutputVariable" == tag) {
+ processOutputVariable(block, engine);
+ } else if ("RuleBlock" == tag) {
+ processRuleBlock(block, engine);
+ } else {
+ throw fl::Exception("[import error] block tag <" + tag + "> not recognized", FL_AT);
+ }
+ }
+
+ void FllImporter::processInputVariable(const std::string& block, Engine* engine) const {
+ std::istringstream reader(block);
+ std::string line;
+ InputVariable* inputVariable = new InputVariable;
+ engine->addInputVariable(inputVariable);
+ while (std::getline(reader, line)) {
+ std::pair<std::string, std::string> keyValue = parseKeyValue(line, ':');
+ if ("InputVariable" == keyValue.first) {
+ inputVariable->setName(Op::validName(keyValue.second));
+ } else if ("enabled" == keyValue.first) {
+ inputVariable->setEnabled(parseBoolean(keyValue.second));
+ } else if ("range" == keyValue.first) {
+ std::pair<scalar, scalar> range = parseRange(keyValue.second);
+ inputVariable->setRange(range.first, range.second);
+ } else if ("term" == keyValue.first) {
+ inputVariable->addTerm(parseTerm(keyValue.second, engine));
+ } else {
+ throw fl::Exception("[import error] key <" + keyValue.first + "> not "
+ "recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
+ }
+ }
+ }
+
+ void FllImporter::processOutputVariable(const std::string& block, Engine* engine) const {
+ std::istringstream reader(block);
+ std::string line;
+ OutputVariable* outputVariable = new OutputVariable;
+ engine->addOutputVariable(outputVariable);
+ while (std::getline(reader, line)) {
+ std::pair<std::string, std::string> keyValue = parseKeyValue(line, ':');
+ if ("OutputVariable" == keyValue.first) {
+ outputVariable->setName(Op::validName(keyValue.second));
+ } else if ("enabled" == keyValue.first) {
+ outputVariable->setEnabled(parseBoolean(keyValue.second));
+ } else if ("range" == keyValue.first) {
+ std::pair<scalar, scalar> range = parseRange(keyValue.second);
+ outputVariable->setRange(range.first, range.second);
+ } else if ("default" == keyValue.first) {
+ outputVariable->setDefaultValue(Op::toScalar(keyValue.second));
+ } else if ("lock-previous" == keyValue.first or "lock-valid" == keyValue.first) {
+ outputVariable->setLockPreviousOutputValue(parseBoolean(keyValue.second));
+ } else if ("lock-range" == keyValue.first) {
+ outputVariable->setLockOutputValueInRange(parseBoolean(keyValue.second));
+ } else if ("defuzzifier" == keyValue.first) {
+ outputVariable->setDefuzzifier(parseDefuzzifier(keyValue.second));
+ } else if ("accumulation" == keyValue.first) {
+ outputVariable->fuzzyOutput()->setAccumulation(parseSNorm(keyValue.second));
+ } else if ("term" == keyValue.first) {
+ outputVariable->addTerm(parseTerm(keyValue.second, engine));
+ } else {
+ throw fl::Exception("[import error] key <" + keyValue.first + "> not "
+ "recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
+ }
+ }
+ }
+
+ void FllImporter::processRuleBlock(const std::string& block, Engine* engine) const {
+ std::istringstream reader(block);
+ std::string line;
+ RuleBlock* ruleBlock = new RuleBlock;
+ engine->addRuleBlock(ruleBlock);
+ while (std::getline(reader, line)) {
+ std::pair<std::string, std::string> keyValue = parseKeyValue(line, ':');
+ if ("RuleBlock" == keyValue.first) {
+ ruleBlock->setName(keyValue.second);
+ } else if ("enabled" == keyValue.first) {
+ ruleBlock->setEnabled(parseBoolean(keyValue.second));
+ } else if ("conjunction" == keyValue.first) {
+ ruleBlock->setConjunction(parseTNorm(keyValue.second));
+ } else if ("disjunction" == keyValue.first) {
+ ruleBlock->setDisjunction(parseSNorm(keyValue.second));
+ } else if ("activation" == keyValue.first) {
+ ruleBlock->setActivation(parseTNorm(keyValue.second));
+ } else if ("rule" == keyValue.first) {
+ Rule* rule = new Rule;
+ rule->setText(keyValue.second);
+ try {
+ rule->load(engine);
+ } catch (std::exception& ex) {
+ FL_LOG(ex.what());
+ }
+ ruleBlock->addRule(rule);
+ } else {
+ throw fl::Exception("[import error] key <" + keyValue.first + "> not "
+ "recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
+ }
+ }
+ }
+
+ Term* FllImporter::parseTerm(const std::string& text, Engine* engine) const {
+ std::vector<std::string> tokens = Op::split(text, " ");
+
+ //MEDIUM Triangle 0.500 1.000 1.500
+
+ if (tokens.size() < 2) {
+ throw fl::Exception("[syntax error] expected a term in format <name class parameters>, "
+ "but found <" + text + ">", FL_AT);
+ }
+ FL_unique_ptr<Term> term;
+ term.reset(FactoryManager::instance()->term()->constructObject(tokens.at(1)));
+ Term::updateReference(term.get(), engine);
+ term->setName(Op::validName(tokens.at(0)));
+ std::ostringstream parameters;
+ for (std::size_t i = 2; i < tokens.size(); ++i) {
+ parameters << tokens.at(i);
+ if (i + 1 < tokens.size()) parameters << " ";
+ }
+ term->configure(parameters.str());
+ return term.release();
+ }
+
+ TNorm* FllImporter::parseTNorm(const std::string& name) const {
+ if (name == "none") return FactoryManager::instance()->tnorm()->constructObject("");
+ return FactoryManager::instance()->tnorm()->constructObject(name);
+ }
+
+ SNorm* FllImporter::parseSNorm(const std::string& name) const {
+ if (name == "none") return FactoryManager::instance()->snorm()->constructObject("");
+ return FactoryManager::instance()->snorm()->constructObject(name);
+ }
+
+ Defuzzifier* FllImporter::parseDefuzzifier(const std::string& text) const {
+ std::vector<std::string> parameters = Op::split(text, " ");
+ std::string name = parameters.at(0);
+ if (name == "none") return FactoryManager::instance()->defuzzifier()->constructObject("");
+ Defuzzifier* defuzzifier = FactoryManager::instance()->defuzzifier()->constructObject(name);
+ if (parameters.size() > 1) {
+ std::string parameter(parameters.at(1));
+ if (IntegralDefuzzifier * integralDefuzzifier = dynamic_cast<IntegralDefuzzifier*> (defuzzifier)) {
+ integralDefuzzifier->setResolution((int) Op::toScalar(parameter));
+ } else if (WeightedDefuzzifier * weightedDefuzzifier = dynamic_cast<WeightedDefuzzifier*> (defuzzifier)) {
+ WeightedDefuzzifier::Type type = WeightedDefuzzifier::Automatic;
+ if (parameter == "Automatic") type = WeightedDefuzzifier::Automatic;
+ else if (parameter == "TakagiSugeno") type = WeightedDefuzzifier::TakagiSugeno;
+ else if (parameter == "Tsukamoto") type = WeightedDefuzzifier::Tsukamoto;
+ else throw fl::Exception("[syntax error] unknown parameter of WeightedDefuzzifier <" + parameter + ">", FL_AT);
+ weightedDefuzzifier->setType(type);
+ }
+ }
+ return defuzzifier;
+ }
+
+ std::pair<scalar, scalar> FllImporter::parseRange(const std::string& text) const {
+ std::pair<std::string, std::string> range = parseKeyValue(text, ' ');
+ return std::pair<scalar, scalar>(Op::toScalar(range.first), Op::toScalar(range.second));
+ }
+
+ bool FllImporter::parseBoolean(const std::string& boolean) const {
+ if ("true" == boolean) return true;
+ if ("false" == boolean) return false;
+ throw fl::Exception("[syntax error] expected boolean <true|false>, "
+ "but found <" + boolean + ">", FL_AT);
+ }
+
+ std::pair<std::string, std::string> FllImporter::parseKeyValue(const std::string& text,
+ char separator) const {
+ std::size_t half = text.find_first_of(separator);
+ if (half == std::string::npos) {
+ std::ostringstream ex;
+ ex << "[syntax error] expected pair in the form "
+ "<key" << separator << "value>, but found <" << text << ">";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ std::pair<std::string, std::string> result;
+ result.first = text.substr(0, half);
+ result.second = text.substr(half + 1);
+ return result;
+ }
+
+ std::string FllImporter::clean(const std::string& line) const {
+ if (line.empty()) return line;
+ if (line.size() == 1) return isspace(line.at(0)) ? "" : line;
+ int start = 0, end = line.size() - 1;
+ while (start <= end and isspace(line.at(start))) {
+ ++start;
+ }
+ int sharp = start;
+ while (sharp <= end) {
+ if (line.at(sharp) == '#') {
+ end = sharp - 1;
+ break;
+ }
+ ++sharp;
+ }
+ while (end >= start and (line.at(end) == '#' or isspace(line.at(end)))) {
+ --end;
+ }
+
+ int length = end - start + 1;
+ return line.substr(start, length);
+ }
+
+ FllImporter* FllImporter::clone() const {
+ return new FllImporter(*this);
+ }
+
+
+}