diff options
Diffstat (limited to 'fuzzylite/src/imex/FisImporter.cpp')
-rw-r--r-- | fuzzylite/src/imex/FisImporter.cpp | 235 |
1 files changed, 109 insertions, 126 deletions
diff --git a/fuzzylite/src/imex/FisImporter.cpp b/fuzzylite/src/imex/FisImporter.cpp index 741719c..f846469 100644 --- a/fuzzylite/src/imex/FisImporter.cpp +++ b/fuzzylite/src/imex/FisImporter.cpp @@ -1,42 +1,28 @@ /* - 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/FisImporter.h" #include "fl/Headers.h" -#include <sstream> -#include <iostream> -#include <cctype> - namespace fl { - FisImporter::FisImporter() : Importer() { - } + FisImporter::FisImporter() : Importer() { } - FisImporter::~FisImporter() { - } + FisImporter::~FisImporter() { } std::string FisImporter::name() const { return "FisImporter"; @@ -47,27 +33,20 @@ namespace fl { std::istringstream fisReader(fis); std::string line; - int lineNumber = 0; + std::size_t lineNumber = 0; std::vector<std::string> sections; while (std::getline(fisReader, line)) { ++lineNumber; - std::vector<std::string> comments; - comments = Op::split(line, "//"); - if (comments.size() > 1) { - line = comments.front(); - } - comments = Op::split(line, "#"); - if (comments.size() > 1) { - line = comments.front(); - } + //remove comments + line = Op::split(line, "//", false).front(); + line = Op::split(line, "#", false).front(); line = Op::trim(line); - if (line.empty() or line.at(0) == '%' or line.at(0) == '#' - or (line.substr(0, 2) == "//")) { + if (line.empty() or line.at(0) == '%') { continue; } - line = fl::Op::findReplace(line, "'", ""); + line = Op::findReplace(line, "'", ""); if ("[System]" == line.substr(0, std::string("[System]").size()) or "[Input" == line.substr(0, std::string("[Input").size()) @@ -79,9 +58,9 @@ namespace fl { sections.at(sections.size() - 1) += "\n" + line; } else { std::ostringstream ss; - ss << "[import error] line " << lineNumber << " <" << line + "> " + ss << "[import error] line " << lineNumber << " <" << line << "> " "does not belong to any section"; - throw fl::Exception(ss.str(), FL_AT); + throw Exception(ss.str(), FL_AT); } } } @@ -96,12 +75,12 @@ namespace fl { importOutput(sections.at(i), engine.get()); else if ("[Rules]" == sections.at(i).substr(0, std::string("[Rules]").size())) importRules(sections.at(i), engine.get()); - else throw fl::Exception("[import error] section <" + else throw Exception("[import error] section <" + sections.at(i) + "> not recognized", FL_AT); } - engine->configure(extractTNorm(andMethod), extractSNorm(orMethod), - extractTNorm(impMethod), extractSNorm(aggMethod), - extractDefuzzifier(defuzzMethod)); + engine->configure(translateTNorm(andMethod), translateSNorm(orMethod), + translateTNorm(impMethod), translateSNorm(aggMethod), + translateDefuzzifier(defuzzMethod), General().className()); return engine.release(); } @@ -113,14 +92,14 @@ namespace fl { std::string line; std::getline(reader, line); //ignore first line [System] while (std::getline(reader, line)) { - std::vector<std::string> keyValue = fl::Op::split(line, "="); + std::vector<std::string> keyValue = Op::split(line, "="); - std::string key = fl::Op::trim(keyValue.at(0)); + std::string key = Op::trim(keyValue.at(0)); std::string value; for (std::size_t i = 1; i < keyValue.size(); ++i) { value += keyValue.at(i); } - value = fl::Op::trim(value); + value = Op::trim(value); if (key == "Name") engine->setName(value); else if (key == "AndMethod") andMethod = value; else if (key == "OrMethod") orMethod = value; @@ -131,7 +110,7 @@ namespace fl { or key == "NumInputs" or key == "NumOutputs" or key == "NumRules" or key == "NumMFs") { //ignore because are redundant. - } else throw fl::Exception("[import error] token <" + key + "> not recognized", FL_AT); + } else throw Exception("[import error] token <" + key + "> not recognized", FL_AT); } } @@ -144,18 +123,19 @@ namespace fl { engine->addInputVariable(input); while (std::getline(reader, line)) { - std::vector<std::string> keyValue = fl::Op::split(line, "="); + std::vector<std::string> keyValue = Op::split(line, "="); if (keyValue.size() != 2) - throw fl::Exception("[syntax error] expected a property of type " + throw Exception("[syntax error] expected a property of type " "'key=value', but found <" + line + ">", FL_AT); - std::string key = fl::Op::trim(keyValue.at(0)); - std::string value = fl::Op::trim(keyValue.at(1)); + std::string key = Op::trim(keyValue.at(0)); + std::string value = Op::trim(keyValue.at(1)); - if (key == "Name") input->setName(fl::Op::validName(value)); - else if (key == "Enabled") { + if (key == "Name") { + input->setName(Op::validName(value)); + } else if (key == "Enabled") { input->setEnabled(Op::isEq(Op::toScalar(value), 1.0)); } else if (key == "Range") { - std::pair<scalar, scalar> minmax = range(value); + std::pair<scalar, scalar> minmax = parseRange(value); input->setMinimum(minmax.first); input->setMaximum(minmax.second); } else if (key.substr(0, 2) == "MF") { @@ -163,7 +143,7 @@ namespace fl { } else if (key == "NumMFs") { //ignore } else { - throw fl::Exception("[import error] token <" + key + "> not recognized", FL_AT); + throw Exception("[import error] token <" + key + "> not recognized", FL_AT); } } } @@ -178,32 +158,33 @@ namespace fl { while (std::getline(reader, line)) { - std::vector<std::string> keyValue = fl::Op::split(line, "="); + std::vector<std::string> keyValue = Op::split(line, "="); if (keyValue.size() != 2) - throw fl::Exception("[syntax error] expected a property of type " + throw Exception("[syntax error] expected a property of type " "'key=value', but found < " + line + ">", FL_AT); - std::string key = fl::Op::trim(keyValue.at(0)); - std::string value = fl::Op::trim(keyValue.at(1)); + std::string key = Op::trim(keyValue.at(0)); + std::string value = Op::trim(keyValue.at(1)); - if (key == "Name") output->setName(fl::Op::validName(value)); - else if (key == "Enabled") { + if (key == "Name") { + output->setName(Op::validName(value)); + } else if (key == "Enabled") { output->setEnabled(Op::isEq(Op::toScalar(value), 1.0)); } else if (key == "Range") { - std::pair<scalar, scalar> minmax = range(value); + std::pair<scalar, scalar> minmax = parseRange(value); output->setMinimum(minmax.first); output->setMaximum(minmax.second); } else if (key.substr(0, 2) == "MF") { output->addTerm(parseTerm(value, engine)); } else if (key == "Default") { - output->setDefaultValue(fl::Op::toScalar(value)); + output->setDefaultValue(Op::toScalar(value)); } else if (key == "LockPrevious") { - output->setLockPreviousOutputValue(fl::Op::isEq(fl::Op::toScalar(value), 1.0)); + output->setLockPreviousValue(Op::isEq(Op::toScalar(value), 1.0)); } else if (key == "LockRange") { - output->setLockOutputValueInRange(fl::Op::isEq(fl::Op::toScalar(value), 1.0)); + output->setLockValueInRange(Op::isEq(Op::toScalar(value), 1.0)); } else if (key == "NumMFs") { //ignore } else { - throw fl::Exception("[import error] token <" + key + "> not recognized", FL_AT); + throw Exception("[import error] token <" + key + "> not recognized", FL_AT); } } } @@ -217,78 +198,78 @@ namespace fl { engine->addRuleBlock(ruleblock); while (std::getline(reader, line)) { - std::vector<std::string> inputsAndRest = fl::Op::split(line, ","); + std::vector<std::string> inputsAndRest = Op::split(line, ","); if (inputsAndRest.size() != 2) - throw fl::Exception("[syntax error] expected rule to match pattern " + throw Exception("[syntax error] expected rule to match pattern " "<'i '+, 'o '+ (w) : '1|2'>, but found instead <" + line + ">", FL_AT); - std::vector <std::string> outputsAndRest = fl::Op::split(inputsAndRest.at(1), ":"); + std::vector <std::string> outputsAndRest = Op::split(inputsAndRest.at(1), ":"); if (outputsAndRest.size() != 2) - throw fl::Exception("[syntax error] expected rule to match pattern " + throw Exception("[syntax error] expected rule to match pattern " "<'i '+, 'o '+ (w) : '1|2'>, but found instead <" + line + ">", FL_AT); - std::vector<std::string> inputs = fl::Op::split(inputsAndRest.at(0), " "); - std::vector<std::string> outputs = fl::Op::split(outputsAndRest.at(0), " "); + std::vector<std::string> inputs = Op::split(inputsAndRest.at(0), " "); + std::vector<std::string> outputs = Op::split(outputsAndRest.at(0), " "); std::string weightInParenthesis = outputs.at(outputs.size() - 1); outputs.erase(outputs.begin() + outputs.size() - 1); - std::string connector = fl::Op::trim(outputsAndRest.at(1)); + std::string connector = Op::trim(outputsAndRest.at(1)); - if ((int) inputs.size() != engine->numberOfInputVariables()) { + if (inputs.size() != engine->numberOfInputVariables()) { std::ostringstream ss; ss << "[syntax error] expected <" << engine->numberOfInputVariables() << ">" " input variables, but found <" << inputs.size() << ">" " input variables in rule <" << line << ">"; - throw fl::Exception(ss.str(), FL_AT); + throw Exception(ss.str(), FL_AT); } - if ((int) outputs.size() != engine->numberOfOutputVariables()) { + if (outputs.size() != engine->numberOfOutputVariables()) { std::ostringstream ss; ss << "[syntax error] expected <" << engine->numberOfOutputVariables() << ">" " output variables, but found <" << outputs.size() << ">" " output variables in rule <" << line << ">"; - throw fl::Exception(ss.str(), FL_AT); + throw Exception(ss.str(), FL_AT); } std::vector<std::string> antecedent, consequent; for (std::size_t i = 0; i < inputs.size(); ++i) { - scalar inputCode = fl::Op::toScalar(inputs.at(i)); - if (fl::Op::isEq(inputCode, 0.0)) continue; + scalar inputCode = Op::toScalar(inputs.at(i)); + if (Op::isEq(inputCode, 0.0)) continue; std::ostringstream ss; ss << engine->getInputVariable(i)->getName() << " " - << fl::Rule::isKeyword() << " " + << Rule::isKeyword() << " " << translateProposition(inputCode, engine->getInputVariable(i)); antecedent.push_back(ss.str()); } for (std::size_t i = 0; i < outputs.size(); ++i) { - scalar outputCode = fl::Op::toScalar(outputs.at(i)); - if (fl::Op::isEq(outputCode, 0.0)) continue; + scalar outputCode = Op::toScalar(outputs.at(i)); + if (Op::isEq(outputCode, 0.0)) continue; std::ostringstream ss; ss << engine->getOutputVariable(i)->getName() << " " - << fl::Rule::isKeyword() << " " + << Rule::isKeyword() << " " << translateProposition(outputCode, engine->getOutputVariable(i)); consequent.push_back(ss.str()); } std::ostringstream ruleText; - ruleText << fl::Rule::ifKeyword() << " "; + ruleText << Rule::ifKeyword() << " "; for (std::size_t i = 0; i < antecedent.size(); ++i) { ruleText << antecedent.at(i); if (i + 1 < antecedent.size()) { ruleText << " "; - if (connector == "1") ruleText << fl::Rule::andKeyword() << " "; - else if (connector == "2") ruleText << fl::Rule::orKeyword() << " "; - else throw fl::Exception("[syntax error] connector <" + if (connector == "1") ruleText << Rule::andKeyword() << " "; + else if (connector == "2") ruleText << Rule::orKeyword() << " "; + else throw Exception("[syntax error] connector <" + connector + "> not recognized", FL_AT); } } - ruleText << " " << fl::Rule::thenKeyword() << " "; + ruleText << " " << Rule::thenKeyword() << " "; for (std::size_t i = 0; i < consequent.size(); ++i) { ruleText << consequent.at(i); if (i + 1 < consequent.size()) { - ruleText << " " << fl::Rule::andKeyword() << " "; + ruleText << " " << Rule::andKeyword() << " "; } } @@ -300,9 +281,9 @@ namespace fl { ss << weightInParenthesis.at(i); } - scalar weight = fl::Op::toScalar(ss.str()); - if (not fl::Op::isEq(weight, 1.0)) - ruleText << " " << fl::Rule::withKeyword() << " " << Op::str(weight); + scalar weight = Op::toScalar(ss.str()); + if (not Op::isEq(weight, 1.0)) + ruleText << " " << Rule::withKeyword() << " " << Op::str(weight); Rule* rule = new Rule(ruleText.str()); try { rule->load(engine); @@ -314,34 +295,34 @@ namespace fl { } std::string FisImporter::translateProposition(scalar code, Variable* variable) const { - int intPart = (int) std::floor(std::fabs(code)) - 1; - scalar fracPart = std::fmod(std::fabs(code), 1.0); - if (intPart >= variable->numberOfTerms()) { + int intPart = (int) std::floor(std::abs(code)) - 1; + scalar fracPart = std::fmod(std::abs(code), scalar(1.0)); + if (intPart >= static_cast<int> (variable->numberOfTerms())) { std::ostringstream ex; ex << "[syntax error] the code <" << code << "> refers to a term " "out of range from variable <" << variable->getName() << ">"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } bool isAny = intPart < 0; std::ostringstream ss; if (code < 0) ss << Not().name() << " "; - if (fl::Op::isEq(fracPart, 0.01)) ss << Seldom().name() << " "; - else if (fl::Op::isEq(fracPart, 0.05)) ss << Somewhat().name() << " "; - else if (fl::Op::isEq(fracPart, 0.2)) ss << Very().name() << " "; - else if (fl::Op::isEq(fracPart, 0.3)) ss << Extremely().name() << " "; - else if (fl::Op::isEq(fracPart, 0.4)) ss << Very().name() << " " << Very().name() << " "; - else if (fl::Op::isEq(fracPart, 0.99)) ss << Any().name() << " "; - else if (not fl::Op::isEq(fracPart, 0)) - throw fl::Exception("[syntax error] no hedge defined in FIS format for <" - + fl::Op::str(fracPart) + ">", FL_AT); + if (Op::isEq(fracPart, 0.01)) ss << Seldom().name() << " "; + else if (Op::isEq(fracPart, 0.05)) ss << Somewhat().name() << " "; + else if (Op::isEq(fracPart, 0.2)) ss << Very().name() << " "; + else if (Op::isEq(fracPart, 0.3)) ss << Extremely().name() << " "; + else if (Op::isEq(fracPart, 0.4)) ss << Very().name() << " " << Very().name() << " "; + else if (Op::isEq(fracPart, 0.99)) ss << Any().name() << " "; + else if (not Op::isEq(fracPart, 0.0)) + throw Exception("[syntax error] no hedge defined in FIS format for <" + + Op::str(fracPart) + ">", FL_AT); if (not isAny) { ss << variable->getTerm(intPart)->getName(); } return ss.str(); } - std::string FisImporter::extractTNorm(const std::string & name) const { + std::string FisImporter::translateTNorm(const std::string& name) const { if (name.empty()) return ""; if (name == "min") return Minimum().className(); if (name == "prod") return AlgebraicProduct().className(); @@ -353,20 +334,21 @@ namespace fl { return name; } - std::string FisImporter::extractSNorm(const std::string & name) const { + std::string FisImporter::translateSNorm(const std::string& name) const { if (name.empty()) return ""; if (name == "max") return Maximum().className(); - if (name == "sum" or name == "probor") return AlgebraicSum().className(); + if (name == "probor") return AlgebraicSum().className(); if (name == "bounded_sum") return BoundedSum().className(); if (name == "normalized_sum") return NormalizedSum().className(); if (name == "drastic_sum") return DrasticSum().className(); if (name == "einstein_sum") return EinsteinSum().className(); if (name == "hamacher_sum") return HamacherSum().className(); if (name == "nilpotent_maximum") return NilpotentMaximum().className(); + if (name == "sum") return UnboundedSum().className(); return name; } - std::string FisImporter::extractDefuzzifier(const std::string & name) const { + std::string FisImporter::translateDefuzzifier(const std::string& name) const { if (name.empty()) return ""; if (name == "centroid") return Centroid().className(); if (name == "bisector") return Bisector().className(); @@ -378,22 +360,22 @@ namespace fl { return name; } - std::pair<scalar, scalar> FisImporter::range(const std::string& range) const { - std::vector<std::string> parts = fl::Op::split(range, " "); + std::pair<scalar, scalar> FisImporter::parseRange(const std::string& range) const { + std::vector<std::string> parts = Op::split(range, " "); if (parts.size() != 2) - throw fl::Exception("[syntax error] expected range in format '[begin end]'," + throw Exception("[syntax error] expected range in format '[begin end]'," " but found <" + range + ">", FL_AT); std::string begin = parts.at(0), end = parts.at(1); if (begin.at(0) != '[' or end.at(end.size() - 1) != ']') - throw fl::Exception("[syntax error] expected range in format '[begin end]'," + throw Exception("[syntax error] expected range in format '[begin end]'," " but found <" + range + ">", FL_AT); std::pair<scalar, scalar> result; - result.first = fl::Op::toScalar(begin.substr(1)); - result.second = fl::Op::toScalar(end.substr(0, end.size() - 1)); + result.first = Op::toScalar(begin.substr(1)); + result.second = Op::toScalar(end.substr(0, end.size() - 1)); return result; } - Term * FisImporter::parseTerm(const std::string & fis, const Engine* engine) const { + Term * FisImporter::parseTerm(const std::string& fis, const Engine* engine) const { std::ostringstream ss; for (std::size_t i = 0; i < fis.size(); ++i) { if (not (fis.at(i) == '[' or fis.at(i) == ']')) { @@ -402,35 +384,36 @@ namespace fl { } std::string line = ss.str(); - std::vector<std::string> nameTerm = fl::Op::split(line, ":"); + std::vector<std::string> nameTerm = Op::split(line, ":"); if (nameTerm.size() != 2) { - throw fl::Exception("[syntax error] expected term in format 'name':'class',[params], " + throw Exception("[syntax error] expected term in format 'name':'class',[params], " "but found <" + line + ">", FL_AT); } - std::vector<std::string> termParams = fl::Op::split(nameTerm.at(1), ","); + std::vector<std::string> termParams = Op::split(nameTerm.at(1), ","); if (termParams.size() != 2) { - throw fl::Exception("[syntax error] expected term in format 'name':'class',[params], " + throw Exception("[syntax error] expected term in format 'name':'class',[params], " "but found " + line, FL_AT); } - std::vector<std::string> parameters = fl::Op::split(termParams.at(1), " "); + std::vector<std::string> parameters = Op::split(termParams.at(1), " "); for (std::size_t i = 0; i < parameters.size(); ++i) { - parameters.at(i) = fl::Op::trim(parameters.at(i)); + parameters.at(i) = Op::trim(parameters.at(i)); } return createInstance( - fl::Op::trim(termParams.at(0)), - fl::Op::trim(nameTerm.at(0)), + Op::trim(termParams.at(0)), + Op::trim(nameTerm.at(0)), parameters, engine); } - Term * FisImporter::createInstance(const std::string& mClass, + Term* FisImporter::createInstance(const std::string& mClass, const std::string& name, const std::vector<std::string>& params, const Engine* engine) const { std::map<std::string, std::string> mapping; - mapping["discretemf"] = Discrete().className(); + mapping["binarymf"] = Binary().className(); mapping["concavemf"] = Concave().className(); mapping["constant"] = Constant().className(); mapping["cosinemf"] = Cosine().className(); + mapping["discretemf"] = Discrete().className(); mapping["function"] = Function().className(); mapping["gbellmf"] = Bell().className(); mapping["gaussmf"] = Gaussian().className(); @@ -484,7 +467,7 @@ namespace fl { FL_unique_ptr<Term> term; term.reset(FactoryManager::instance()->term()->constructObject(flClass)); - Term::updateReference(term.get(), engine); + term->updateReference(engine); term->setName(Op::validName(name)); std::string separator; if (not dynamic_cast<Function*> (term.get())) { |