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.cpp193
1 files changed, 96 insertions, 97 deletions
diff --git a/fuzzylite/src/imex/FllImporter.cpp b/fuzzylite/src/imex/FllImporter.cpp
index 2443d10..ac9d1fc 100644
--- a/fuzzylite/src/imex/FllImporter.cpp
+++ b/fuzzylite/src/imex/FllImporter.cpp
@@ -1,25 +1,17 @@
/*
- Author: Juan Rada-Vilela, Ph.D.
- Copyright (C) 2010-2014 FuzzyLite Limited
- All rights reserved
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
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.
+ the terms of the FuzzyLite License included with the software.
- 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.
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+ fuzzylite is a registered trademark of FuzzyLite Limited.
*/
#include "fl/imex/FllImporter.h"
@@ -31,12 +23,9 @@
namespace fl {
FllImporter::FllImporter(const std::string& separator) : Importer(),
- _separator(separator) {
- }
-
- FllImporter::~FllImporter() {
+ _separator(separator) { }
- }
+ FllImporter::~FllImporter() { }
std::string FllImporter::name() const {
return "FllImporter";
@@ -50,62 +39,48 @@ namespace fl {
return this->_separator;
}
- Engine* FllImporter::fromString(const std::string& fll) const {
+ Engine* FllImporter::fromString(const std::string& code) const {
FL_unique_ptr<Engine> engine(new Engine);
+ const std::string fll = Op::join(Op::split(code, _separator), "\n");
std::string tag;
- std::ostringstream block;
- std::istringstream fclReader(fll);
+ std::vector<std::string> block;
+ std::istringstream fllReader(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;
- }
+
+ while (std::getline(fllReader, line)) {
+ line = Op::trim(Op::split(line, "#", false).front()); //remove comments
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);
+ throw Exception("[import error] expected a colon here: " + 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
+ } else if (key == "description" and block.empty()){
+ engine->setDescription(value);
+ continue;
+ } else if (key == "InputVariable"
+ or key == "OutputVariable"
+ or key == "RuleBlock") {
+ process(tag, Op::join(block, "\n"), engine.get());
block.clear(); //clear error flags
- processPending = false;
tag = key;
+ } else if (tag.empty()) {
+ throw Exception("[import error] unexpected block: " + line, FL_AT);
}
- block << key << ":" << value << "\n";
+ block.push_back(key + ":" + value);
}
- process(tag, block.str(), engine.get());
+ process(tag, Op::join(block, "\n"), engine.get());
return engine.release();
}
void FllImporter::process(const std::string& tag, const std::string& block, Engine* engine) const {
if (tag.empty()) return;
+ // FL_LOG("Processing " << tag << "\n" << block);
if ("InputVariable" == tag) {
processInputVariable(block, engine);
} else if ("OutputVariable" == tag) {
@@ -113,42 +88,47 @@ namespace fl {
} else if ("RuleBlock" == tag) {
processRuleBlock(block, engine);
} else {
- throw fl::Exception("[import error] block tag <" + tag + "> not recognized", FL_AT);
+ throw 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);
+ FL_unique_ptr<InputVariable> inputVariable(new 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 ("description" == keyValue.first) {
+ inputVariable->setDescription(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 ("lock-range" == keyValue.first) {
+ inputVariable->setLockValueInRange(parseBoolean(keyValue.second));
} else if ("term" == keyValue.first) {
inputVariable->addTerm(parseTerm(keyValue.second, engine));
} else {
- throw fl::Exception("[import error] key <" + keyValue.first + "> not "
+ throw Exception("[import error] key <" + keyValue.first + "> not "
"recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
}
}
+ engine->addInputVariable(inputVariable.release());
}
void FllImporter::processOutputVariable(const std::string& block, Engine* engine) const {
std::istringstream reader(block);
std::string line;
- OutputVariable* outputVariable = new OutputVariable;
- engine->addOutputVariable(outputVariable);
+ FL_unique_ptr<OutputVariable> outputVariable(new 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 ("description" == keyValue.first) {
+ outputVariable->setDescription(keyValue.second);
} else if ("enabled" == keyValue.first) {
outputVariable->setEnabled(parseBoolean(keyValue.second));
} else if ("range" == keyValue.first) {
@@ -157,39 +137,64 @@ namespace fl {
} 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));
+ outputVariable->setLockPreviousValue(parseBoolean(keyValue.second));
} else if ("lock-range" == keyValue.first) {
- outputVariable->setLockOutputValueInRange(parseBoolean(keyValue.second));
+ outputVariable->setLockValueInRange(parseBoolean(keyValue.second));
} else if ("defuzzifier" == keyValue.first) {
outputVariable->setDefuzzifier(parseDefuzzifier(keyValue.second));
+ } else if ("aggregation" == keyValue.first) {
+ outputVariable->fuzzyOutput()->setAggregation(parseSNorm(keyValue.second));
} else if ("accumulation" == keyValue.first) {
- outputVariable->fuzzyOutput()->setAccumulation(parseSNorm(keyValue.second));
+ outputVariable->fuzzyOutput()->setAggregation(parseSNorm(keyValue.second));
+ FL_LOG("[warning] obsolete usage of identifier <accumulation: SNorm> in OutputVariable");
+ FL_LOG("[information] from version 6.0, the identifier <aggregation: SNorm> should be used");
+ FL_LOG("[backward compatibility] assumed "
+ "<aggregation: " << keyValue.second << "> "
+ "instead of <accumulation: " << keyValue.second << ">");
} else if ("term" == keyValue.first) {
outputVariable->addTerm(parseTerm(keyValue.second, engine));
} else {
- throw fl::Exception("[import error] key <" + keyValue.first + "> not "
+ throw Exception("[import error] key <" + keyValue.first + "> not "
"recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
}
}
+ engine->addOutputVariable(outputVariable.release());
}
void FllImporter::processRuleBlock(const std::string& block, Engine* engine) const {
std::istringstream reader(block);
std::string line;
- RuleBlock* ruleBlock = new RuleBlock;
- engine->addRuleBlock(ruleBlock);
+ FL_unique_ptr<RuleBlock> ruleBlock(new 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 ("description" == keyValue.first) {
+ ruleBlock->setDescription(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 ("implication" == keyValue.first) {
+ ruleBlock->setImplication(parseTNorm(keyValue.second));
} else if ("activation" == keyValue.first) {
- ruleBlock->setActivation(parseTNorm(keyValue.second));
+ TNormFactory* tnorm = FactoryManager::instance()->tnorm();
+ //@todo remove backwards compatibility in version 7.0
+ if (tnorm->hasConstructor(keyValue.second)) {
+ ruleBlock->setImplication(parseTNorm(keyValue.second));
+ FL_LOG("[warning] obsolete usage of identifier <activation: TNorm> "
+ "in RuleBlock");
+ FL_LOG("[information] from version 6.0, the identifiers are "
+ "<activation: Activation> for Activation methods "
+ "and <implication: TNorm> for T-Norms");
+ FL_LOG("[backward compatibility] assumed "
+ "<implication: " << keyValue.second << "> "
+ "instead of <activation: " << keyValue.second << ">");
+ } else {
+ ruleBlock->setActivation(parseActivation(keyValue.second));
+ }
} else if ("rule" == keyValue.first) {
Rule* rule = new Rule;
rule->setText(keyValue.second);
@@ -200,10 +205,14 @@ namespace fl {
}
ruleBlock->addRule(rule);
} else {
- throw fl::Exception("[import error] key <" + keyValue.first + "> not "
+ throw Exception("[import error] key <" + keyValue.first + "> not "
"recognized in pair <" + keyValue.first + ":" + keyValue.second + ">", FL_AT);
}
}
+ if (not ruleBlock->getActivation()){
+ ruleBlock->setActivation(new General);
+ }
+ engine->addRuleBlock(ruleBlock.release());
}
Term* FllImporter::parseTerm(const std::string& text, Engine* engine) const {
@@ -212,12 +221,12 @@ namespace fl {
//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>, "
+ throw 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->updateReference(engine);
term->setName(Op::validName(tokens.at(0)));
std::ostringstream parameters;
for (std::size_t i = 2; i < tokens.size(); ++i) {
@@ -238,6 +247,20 @@ namespace fl {
return FactoryManager::instance()->snorm()->constructObject(name);
}
+ Activation* FllImporter::parseActivation(const std::string& name) const {
+ if (name == "none") return FactoryManager::instance()->activation()->constructObject("");
+ std::vector<std::string> tokens = Op::split(name, " ");
+ Activation* result = FactoryManager::instance()->activation()->constructObject(tokens.front());
+
+ std::ostringstream parameters;
+ for (std::size_t i = 1; i < tokens.size(); ++i) {
+ parameters << tokens.at(i);
+ if (i + 1 < tokens.size()) parameters << " ";
+ }
+ result->configure(parameters.str());
+ return result;
+ }
+
Defuzzifier* FllImporter::parseDefuzzifier(const std::string& text) const {
std::vector<std::string> parameters = Op::split(text, " ");
std::string name = parameters.at(0);
@@ -252,7 +275,7 @@ namespace fl {
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);
+ else throw Exception("[syntax error] unknown parameter of WeightedDefuzzifier <" + parameter + ">", FL_AT);
weightedDefuzzifier->setType(type);
}
}
@@ -267,7 +290,7 @@ namespace fl {
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>, "
+ throw Exception("[syntax error] expected boolean <true|false>, "
"but found <" + boolean + ">", FL_AT);
}
@@ -278,7 +301,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected pair in the form "
"<key" << separator << "value>, but found <" << text << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
std::pair<std::string, std::string> result;
result.first = text.substr(0, half);
@@ -286,32 +309,8 @@ namespace fl {
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);
}
-
}