summaryrefslogtreecommitdiff
path: root/fuzzylite/src/imex/FisImporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/imex/FisImporter.cpp')
-rw-r--r--fuzzylite/src/imex/FisImporter.cpp235
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())) {