diff options
Diffstat (limited to 'fuzzylite/src/imex/FllImporter.cpp')
-rw-r--r-- | fuzzylite/src/imex/FllImporter.cpp | 193 |
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); } - } |