summaryrefslogtreecommitdiff
path: root/fuzzylite/src/imex
diff options
context:
space:
mode:
authorJohannes 'josch' Schauer <josch@debian.org>2019-01-27 13:56:24 +0100
committerJohannes 'josch' Schauer <josch@debian.org>2019-01-27 13:56:33 +0100
commit6ce553563bc795f389f639a3a8cdfe356de71441 (patch)
treeda4c9ede3087ca534d93bc1ac5a14f044f036600 /fuzzylite/src/imex
parentbbefa170378553e5a6e0d72e4d52328b61f3e8ac (diff)
new upstream version 6.0
Diffstat (limited to 'fuzzylite/src/imex')
-rw-r--r--fuzzylite/src/imex/CppExporter.cpp181
-rw-r--r--fuzzylite/src/imex/Exporter.cpp32
-rw-r--r--fuzzylite/src/imex/FclExporter.cpp126
-rw-r--r--fuzzylite/src/imex/FclImporter.cpp164
-rw-r--r--fuzzylite/src/imex/FisExporter.cpp180
-rw-r--r--fuzzylite/src/imex/FisImporter.cpp235
-rw-r--r--fuzzylite/src/imex/FldExporter.cpp246
-rw-r--r--fuzzylite/src/imex/FllExporter.cpp85
-rw-r--r--fuzzylite/src/imex/FllImporter.cpp193
-rw-r--r--fuzzylite/src/imex/Importer.cpp32
-rw-r--r--fuzzylite/src/imex/JavaExporter.cpp157
-rw-r--r--fuzzylite/src/imex/RScriptExporter.cpp234
12 files changed, 1042 insertions, 823 deletions
diff --git a/fuzzylite/src/imex/CppExporter.cpp b/fuzzylite/src/imex/CppExporter.cpp
index 7b21087..8a77c0c 100644
--- a/fuzzylite/src/imex/CppExporter.cpp
+++ b/fuzzylite/src/imex/CppExporter.cpp
@@ -1,75 +1,73 @@
/*
- 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/CppExporter.h"
#include "fl/Headers.h"
-#include <algorithm>
-
namespace fl {
- CppExporter::CppExporter(bool prefixNamespace) : Exporter(),
- _prefixNamespace(prefixNamespace) {
- }
+ CppExporter::CppExporter(bool prefixNamespace, bool usingVariableNames) : Exporter(),
+ _usingNamespace(prefixNamespace), _usingVariableNames(usingVariableNames) { }
- CppExporter::~CppExporter() {
- }
+ CppExporter::~CppExporter() { }
std::string CppExporter::name() const {
return "CppExporter";
}
std::string CppExporter::fl(const std::string& clazz) const {
- return _prefixNamespace ? "fl::" + clazz : clazz;
+ return _usingNamespace ? "fl::" + clazz : clazz;
+ }
+
+ void CppExporter::setUsingNamespace(bool usingNamespace) {
+ this->_usingNamespace = usingNamespace;
}
- void CppExporter::setPrefixNamespace(bool prefixNamespace){
- this->_prefixNamespace = prefixNamespace;
+ bool CppExporter::isUsingNamespace() const {
+ return this->_usingNamespace;
}
- bool CppExporter::isPrefixNamespace() const{
- return this->_prefixNamespace;
+ void CppExporter::setUsingVariableNames(bool usingVariableNames) {
+ this->_usingVariableNames = usingVariableNames;
+ }
+
+ bool CppExporter::isUsingVariableNames() const {
+ return this->_usingVariableNames;
}
std::string CppExporter::toString(const Engine* engine) const {
std::ostringstream cpp;
- if (not _prefixNamespace) cpp << "using namespace fl;\n\n";
+ cpp << "//Code automatically generated with " << fuzzylite::library() << ".\n\n";
+ if (not isUsingNamespace()) cpp << "using namespace fl;\n\n";
cpp << fl("Engine* ") << "engine = new " << fl("Engine;\n");
cpp << "engine->setName(\"" << engine->getName() << "\");\n";
+ cpp << "engine->setDescription(\"" << engine->getDescription() << "\");\n";
cpp << "\n";
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
cpp << toString(engine->getInputVariable(i), engine) << "\n";
}
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
cpp << toString(engine->getOutputVariable(i), engine) << "\n";
}
- for (int i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
cpp << toString(engine->getRuleBlock(i), engine) << "\n";
}
@@ -77,21 +75,28 @@ namespace fl {
}
std::string CppExporter::toString(const InputVariable* inputVariable, const Engine* engine) const {
- std::ostringstream ss;
- std::string name = "inputVariable";
- if (engine->numberOfInputVariables() > 1) {
- int index = std::distance(engine->inputVariables().begin(),
- std::find(engine->inputVariables().begin(),
- engine->inputVariables().end(), inputVariable));
- name += Op::str<int>(index + 1);
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(inputVariable->getName());
+ } else {
+ name = "inputVariable";
+ if (engine->numberOfInputVariables() > 1) {
+ std::size_t index = std::distance(engine->inputVariables().begin(),
+ std::find(engine->inputVariables().begin(),
+ engine->inputVariables().end(), inputVariable));
+ name += Op::str(index + 1);
+ }
}
+ std::ostringstream ss;
ss << fl("InputVariable* ") << name << " = new " << fl("InputVariable;\n");
- ss << name << "->setEnabled(" << (inputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << "->setName(\"" << inputVariable->getName() << "\");\n";
+ ss << name << "->setDescription(\"" << inputVariable->getDescription() << "\");\n";
+ ss << name << "->setEnabled(" << (inputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << "->setRange(" <<
toString(inputVariable->getMinimum()) << ", " <<
toString(inputVariable->getMaximum()) << ");\n";
- for (int t = 0; t < inputVariable->numberOfTerms(); ++t) {
+ ss << name << "->setLockValueInRange(" << (inputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ for (std::size_t t = 0; t < inputVariable->numberOfTerms(); ++t) {
ss << name << "->addTerm(" << toString(inputVariable->getTerm(t)) << ");\n";
}
ss << "engine->addInputVariable(" << name << ");\n";
@@ -99,58 +104,73 @@ namespace fl {
}
std::string CppExporter::toString(const OutputVariable* outputVariable, const Engine* engine) const {
- std::ostringstream ss;
- std::string name = "outputVariable";
- if (engine->numberOfOutputVariables() > 1) {
- int index = std::distance(engine->outputVariables().begin(),
- std::find(engine->outputVariables().begin(),
- engine->outputVariables().end(), outputVariable));
- name += Op::str<int>(index + 1);
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(outputVariable->getName());
+ } else {
+ name = "outputVariable";
+ if (engine->numberOfOutputVariables() > 1) {
+ std::size_t index = std::distance(engine->outputVariables().begin(),
+ std::find(engine->outputVariables().begin(),
+ engine->outputVariables().end(), outputVariable));
+ name += Op::str(index + 1);
+ }
}
+ std::ostringstream ss;
ss << fl("OutputVariable* ") << name << " = new " << fl("OutputVariable;\n");
- ss << name << "->setEnabled(" << (outputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << "->setName(\"" << outputVariable->getName() << "\");\n";
+ ss << name << "->setDescription(\"" << outputVariable->getDescription() << "\");\n";
+ ss << name << "->setEnabled(" << (outputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << "->setRange(" <<
toString(outputVariable->getMinimum()) << ", " <<
toString(outputVariable->getMaximum()) << ");\n";
- ss << name << "->fuzzyOutput()->setAccumulation(" <<
- toString(outputVariable->fuzzyOutput()->getAccumulation()) << ");\n";
+ ss << name << "->setLockValueInRange(" <<
+ (outputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ ss << name << "->setAggregation(" <<
+ toString(outputVariable->fuzzyOutput()->getAggregation()) << ");\n";
ss << name << "->setDefuzzifier(" <<
toString(outputVariable->getDefuzzifier()) << ");\n";
ss << name << "->setDefaultValue(" <<
toString(outputVariable->getDefaultValue()) << ");\n";
- ss << name << "->setLockPreviousOutputValue(" <<
- (outputVariable->isLockedPreviousOutputValue() ? "true" : "false") << ");\n";
- ss << name << "->setLockOutputValueInRange(" <<
- (outputVariable->isLockedOutputValueInRange() ? "true" : "false") << ");\n";
- for (int t = 0; t < outputVariable->numberOfTerms(); ++t) {
+ ss << name << "->setLockPreviousValue(" <<
+ (outputVariable->isLockPreviousValue() ? "true" : "false") << ");\n";
+ for (std::size_t t = 0; t < outputVariable->numberOfTerms(); ++t) {
ss << name << "->addTerm(" << toString(outputVariable->getTerm(t)) << ");\n";
}
ss << "engine->addOutputVariable(" << name << ");\n";
return ss.str();
}
- //TODO: addRules using `new Rule` instead of `Rule::parse` in version 6.0
std::string CppExporter::toString(const RuleBlock* ruleBlock, const Engine* engine) const {
- std::ostringstream ss;
- std::string name = "ruleBlock";
- if (engine->numberOfRuleBlocks() > 1) {
- int index = std::distance(engine->ruleBlocks().begin(),
- std::find(engine->ruleBlocks().begin(),
- engine->ruleBlocks().end(), ruleBlock));
- name += Op::str<int>(index + 1);
+ std::string name;
+
+ if (isUsingVariableNames() and not ruleBlock->getName().empty()) {
+ name = Op::validName(ruleBlock->getName());
+ } else {
+ name = "ruleBlock";
+ if (engine->numberOfRuleBlocks() > 1) {
+ std::size_t index = std::distance(engine->ruleBlocks().begin(),
+ std::find(engine->ruleBlocks().begin(),
+ engine->ruleBlocks().end(), ruleBlock));
+ name += Op::str(index + 1);
+ }
}
+
+ std::ostringstream ss;
ss << fl("RuleBlock* ") << name << " = new " << fl("RuleBlock;\n");
- ss << name << "->setEnabled(" << (ruleBlock->isEnabled() ? "true" : "false") << ");\n";
ss << name << "->setName(\"" << ruleBlock->getName() << "\");\n";
+ ss << name << "->setDescription(\"" << ruleBlock->getDescription() << "\");\n";
+ ss << name << "->setEnabled(" << (ruleBlock->isEnabled() ? "true" : "false") << ");\n";
ss << name << "->setConjunction(" <<
toString(ruleBlock->getConjunction()) << ");\n";
ss << name << "->setDisjunction("
<< toString(ruleBlock->getDisjunction()) << ");\n";
+ ss << name << "->setImplication("
+ << toString(ruleBlock->getImplication()) << ");\n";
ss << name << "->setActivation("
<< toString(ruleBlock->getActivation()) << ");\n";
- for (int r = 0; r < ruleBlock->numberOfRules(); ++r) {
- ss << name << "->addRule(" << "fl::Rule::parse(\"" <<
+ for (std::size_t r = 0; r < ruleBlock->numberOfRules(); ++r) {
+ ss << name << "->addRule(" << fl("Rule") << "::parse(\"" <<
ruleBlock->getRule(r)->getText() << "\", engine));\n";
}
ss << "engine->addRuleBlock(" << name << ");\n";
@@ -158,12 +178,12 @@ namespace fl {
}
std::string CppExporter::toString(scalar value) const {
- if (fl::Op::isNaN(value))
+ if (Op::isNaN(value))
return "fl::nan";
- if (fl::Op::isInf(value)){
- return (value > 0 ? "fl::inf" : "-fl::inf");
+ if (Op::isInf(value)) {
+ return (value > 0 ? "fl::inf" : "-fl::inf");
}
- return fl::Op::str(value);
+ return Op::str(value);
}
std::string CppExporter::toString(const Term* term) const {
@@ -172,8 +192,8 @@ namespace fl {
if (const Discrete * discrete = dynamic_cast<const Discrete*> (term)) {
std::ostringstream ss;
ss << fl(term->className()) << "::create(\"" << term->getName() << "\", "
- << discrete->xy().size() * 2 << ", "
- << fl::Op::join(Discrete::toVector(discrete->xy()), ", ") << ")";
+ << (discrete->xy().size() * 2) << ", "
+ << Op::join(Discrete::toVector(discrete->xy()), ", ") << ")";
return ss.str();
}
@@ -187,7 +207,7 @@ namespace fl {
if (const Linear * linear = dynamic_cast<const Linear*> (term)) {
std::ostringstream ss;
ss << fl(term->className()) << "::create(\"" << term->getName() << "\", "
- << "engine, " << fl::Op::join(linear->coefficients(), ", ") << ")";
+ << "engine, " << Op::join(linear->coefficients(), ", ") << ")";
return ss.str();
}
@@ -217,7 +237,7 @@ namespace fl {
if (const IntegralDefuzzifier * integralDefuzzifier =
dynamic_cast<const IntegralDefuzzifier*> (defuzzifier)) {
return "new " + fl(integralDefuzzifier->className()) + "("
- + fl::Op::str(integralDefuzzifier->getResolution()) + ")";
+ + Op::str(integralDefuzzifier->getResolution()) + ")";
}
if (const WeightedDefuzzifier * weightedDefuzzifier =
dynamic_cast<const WeightedDefuzzifier*> (defuzzifier)) {
@@ -227,6 +247,19 @@ namespace fl {
return "new " + fl(defuzzifier->className());
}
+ std::string CppExporter::toString(const Activation* activation) const {
+ if (not activation) return "fl::null";
+ std::string parameters = Op::trim(activation->parameters());
+ if (parameters.empty()) return "new " + fl(activation->className());
+
+ std::vector<std::string> values = Op::split(parameters, " ");
+ for (std::size_t i = 0; i < values.size(); ++i) {
+ std::string parameter = values.at(i);
+ values.at(i) = (Op::isNumeric(parameter) ? parameter : ("\"" + parameter + "\""));
+ }
+ return "new " + fl(activation->className()) + "(" + Op::join(values, ", ") + ")";
+ }
+
CppExporter* CppExporter::clone() const {
return new CppExporter(*this);
}
diff --git a/fuzzylite/src/imex/Exporter.cpp b/fuzzylite/src/imex/Exporter.cpp
index 5b0fe1b..1aaf24e 100644
--- a/fuzzylite/src/imex/Exporter.cpp
+++ b/fuzzylite/src/imex/Exporter.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/Exporter.h"
@@ -29,18 +21,14 @@
namespace fl {
- Exporter::Exporter() {
-
- }
-
- Exporter::~Exporter() {
+ Exporter::Exporter() { }
- }
+ Exporter::~Exporter() { }
void Exporter::toFile(const std::string& path, const Engine* engine) const {
std::ofstream writer(path.c_str());
if (not writer.is_open()) {
- throw fl::Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
}
writer << toString(engine) << std::endl;
writer.close();
diff --git a/fuzzylite/src/imex/FclExporter.cpp b/fuzzylite/src/imex/FclExporter.cpp
index cf8ffb0..98f1177 100644
--- a/fuzzylite/src/imex/FclExporter.cpp
+++ b/fuzzylite/src/imex/FclExporter.cpp
@@ -1,39 +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/FclExporter.h"
#include "fl/Headers.h"
-#include <sstream>
-
namespace fl {
- FclExporter::FclExporter(const std::string& indent) : Exporter(), _indent(indent) {
- }
+ FclExporter::FclExporter(const std::string& indent) : Exporter(), _indent(indent) { }
- FclExporter::~FclExporter() {
- }
+ FclExporter::~FclExporter() { }
void FclExporter::setIndent(const std::string& indent) {
this->_indent = indent;
@@ -49,31 +38,32 @@ namespace fl {
std::string FclExporter::toString(const Engine* engine) const {
std::ostringstream fcl;
+ fcl << "//Code automatically generated with " << fuzzylite::library() << ".\n\n";
fcl << "FUNCTION_BLOCK " << engine->getName() << "\n\n";
fcl << "VAR_INPUT\n";
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
fcl << _indent << Op::validName(engine->getInputVariable(i)->getName()) << ": REAL;\n";
}
fcl << "END_VAR\n\n";
fcl << "VAR_OUTPUT\n";
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
fcl << _indent << Op::validName(engine->getOutputVariable(i)->getName()) << ": REAL;\n";
}
fcl << "END_VAR\n\n";
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
fcl << toString(inputVariable) << "\n";
}
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
fcl << toString(outputVariable) << "\n";
}
- for (int i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
RuleBlock* ruleblock = engine->getRuleBlock(i);
fcl << toString(ruleblock) << "\n";
}
@@ -85,15 +75,11 @@ namespace fl {
std::string FclExporter::toString(const InputVariable* inputVariable) const {
std::ostringstream fcl;
fcl << "FUZZIFY " << Op::validName(inputVariable->getName()) << "\n";
- if (not inputVariable->isEnabled()) {
- fcl << _indent << "ENABLED : " <<
- (inputVariable->isEnabled() ? "TRUE" : "FALSE") << ";\n";
- }
- fcl << _indent << "RANGE := (" << fl::Op::join(2, " .. ",
+ fcl << _indent << "RANGE := (" << Op::join(2, " .. ",
inputVariable->getMinimum(), inputVariable->getMaximum())
<< ");\n";
- for (int t = 0; t < inputVariable->numberOfTerms(); ++t) {
+ for (std::size_t t = 0; t < inputVariable->numberOfTerms(); ++t) {
Term* term = inputVariable->getTerm(t);
fcl << _indent << "TERM " << Op::validName(term->getName()) << " := " << toString(term)
<< ";\n";
@@ -105,15 +91,11 @@ namespace fl {
std::string FclExporter::toString(const OutputVariable* outputVariable) const {
std::ostringstream fcl;
fcl << "DEFUZZIFY " << Op::validName(outputVariable->getName()) << "\n";
- if (not outputVariable->isEnabled()) {
- fcl << _indent << "ENABLED : " <<
- (outputVariable->isEnabled() ? "TRUE" : "FALSE") << ";\n";
- }
- fcl << _indent << "RANGE := (" << fl::Op::join(2, " .. ",
+ fcl << _indent << "RANGE := (" << Op::join(2, " .. ",
outputVariable->getMinimum(), outputVariable->getMaximum())
<< ");\n";
- for (int t = 0; t < outputVariable->numberOfTerms(); ++t) {
+ for (std::size_t t = 0; t < outputVariable->numberOfTerms(); ++t) {
Term* term = outputVariable->getTerm(t);
fcl << _indent << "TERM " << Op::validName(term->getName()) << " := " << toString(term)
<< ";\n";
@@ -121,19 +103,15 @@ namespace fl {
if (outputVariable->getDefuzzifier()) {
fcl << _indent << "METHOD : " << toString(outputVariable->getDefuzzifier()) << ";\n";
}
- if (outputVariable->fuzzyOutput()->getAccumulation())
- fcl << _indent << "ACCU : " << toString(outputVariable->fuzzyOutput()->getAccumulation()) << ";\n";
+ if (outputVariable->fuzzyOutput()->getAggregation())
+ fcl << _indent << "ACCU : " << toString(outputVariable->fuzzyOutput()->getAggregation()) << ";\n";
- fcl << _indent << "DEFAULT := " << fl::Op::str(outputVariable->getDefaultValue());
- if (outputVariable->isLockedPreviousOutputValue()) {
+ fcl << _indent << "DEFAULT := " << Op::str(outputVariable->getDefaultValue());
+ if (outputVariable->isLockPreviousValue()) {
fcl << " | NC";
}
fcl << ";\n";
- if (outputVariable->isLockedOutputValueInRange()) {
- fcl << _indent << "LOCK : RANGE;\n";
- }
-
fcl << "END_DEFUZZIFY\n";
return fcl.str();
}
@@ -141,28 +119,24 @@ namespace fl {
std::string FclExporter::toString(const RuleBlock* ruleBlock) const {
std::ostringstream fcl;
fcl << "RULEBLOCK " << ruleBlock->getName() << "\n";
- if (not ruleBlock->isEnabled()) {
- fcl << _indent << "ENABLED : " <<
- (ruleBlock->isEnabled() ? "TRUE" : "FALSE") << ";\n";
- }
if (ruleBlock->getConjunction())
fcl << _indent << "AND : " << toString(ruleBlock->getConjunction()) << ";\n";
if (ruleBlock->getDisjunction())
fcl << _indent << "OR : " << toString(ruleBlock->getDisjunction()) << ";\n";
- if (ruleBlock->getActivation())
- fcl << _indent << "ACT : " << toString(ruleBlock->getActivation()) << ";\n";
+ if (ruleBlock->getImplication())
+ fcl << _indent << "ACT : " << toString(ruleBlock->getImplication()) << ";\n";
- for (int r = 0; r < ruleBlock->numberOfRules(); ++r) {
+ for (std::size_t r = 0; r < ruleBlock->numberOfRules(); ++r) {
fcl << _indent << "RULE " << (r + 1) << " : " <<
ruleBlock->getRule(r)->getText() << "\n";
}
fcl << "END_RULEBLOCK\n";
return fcl.str();
}
-
- std::string FclExporter::toString(const Norm* norm) const{
+
+ std::string FclExporter::toString(const Norm* norm) const {
if (not norm) return "NONE";
-
+
std::string name = norm->className();
//TNorms
if (name == Minimum().className()) return "MIN";
@@ -172,7 +146,7 @@ namespace fl {
if (name == EinsteinProduct().className()) return "EPROD";
if (name == HamacherProduct().className()) return "HPROD";
if (name == NilpotentMinimum().className()) return "NMIN";
-
+
//SNorms
if (name == Maximum().className()) return "MAX";
if (name == AlgebraicSum().className()) return "ASUM";
@@ -182,37 +156,8 @@ namespace fl {
if (name == EinsteinSum().className()) return "ESUM";
if (name == HamacherSum().className()) return "HSUM";
if (name == NilpotentMaximum().className()) return "NMAX";
-
- return norm->className();
- }
-
- //TODO: Delete in v6.0
- std::string FclExporter::toString(const TNorm* tnorm) const {
- if (not tnorm) return "NONE";
- std::string name = tnorm->className();
- if (name == Minimum().className()) return "MIN";
- if (name == AlgebraicProduct().className()) return "PROD";
- if (name == BoundedDifference().className()) return "BDIF";
- if (name == DrasticProduct().className()) return "DPROD";
- if (name == EinsteinProduct().className()) return "EPROD";
- if (name == HamacherProduct().className()) return "HPROD";
- if (name == NilpotentMinimum().className()) return "NMIN";
- return tnorm->className();
- }
- //TODO: Delete in v6.0
- std::string FclExporter::toString(const SNorm* snorm) const {
- if (not snorm) return "NONE";
- std::string name = snorm->className();
- if (name == Maximum().className()) return "MAX";
- if (name == AlgebraicSum().className()) return "ASUM";
- if (name == NormalizedSum().className()) return "NSUM";
- if (name == BoundedSum().className()) return "BSUM";
- if (name == DrasticSum().className()) return "DSUM";
- if (name == EinsteinSum().className()) return "ESUM";
- if (name == HamacherSum().className()) return "HSUM";
- if (name == NilpotentMaximum().className()) return "NMAX";
- return snorm->className();
+ return norm->className();
}
std::string FclExporter::toString(const Defuzzifier* defuzzifier) const {
@@ -232,15 +177,15 @@ namespace fl {
if (const Discrete * discrete = dynamic_cast<const Discrete*> (term)) {
std::ostringstream ss;
for (std::size_t i = 0; i < discrete->xy().size(); ++i) {
- ss << "(" << fl::Op::str(discrete->xy(i).first) << ", "
- << fl::Op::str(discrete->xy(i).second) << ")";
+ ss << "(" << Op::str(discrete->xy(i).first) << ", "
+ << Op::str(discrete->xy(i).second) << ")";
if (i + 1 < discrete->xy().size()) ss << " ";
}
return ss.str();
}
if (const Constant * constant = dynamic_cast<const Constant*> (term)) {
- return fl::Op::str(constant->getValue());
+ return Op::str(constant->getValue());
}
std::ostringstream ss;
@@ -252,5 +197,4 @@ namespace fl {
return new FclExporter(*this);
}
-
}
diff --git a/fuzzylite/src/imex/FclImporter.cpp b/fuzzylite/src/imex/FclImporter.cpp
index a56a9e1..06879cd 100644
--- a/fuzzylite/src/imex/FclImporter.cpp
+++ b/fuzzylite/src/imex/FclImporter.cpp
@@ -1,41 +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/FclImporter.h"
#include "fl/Headers.h"
-#include <iostream>
-#include <sstream>
-
namespace fl {
- FclImporter::FclImporter() : Importer() {
- }
+ FclImporter::FclImporter() : Importer() { }
- FclImporter::~FclImporter() {
- }
+ FclImporter::~FclImporter() { }
std::string FclImporter::name() const {
return "FclImporter";
@@ -57,24 +44,16 @@ namespace fl {
std::istringstream fclReader(fcl);
std::string line;
- int lineNumber = 0;
+ std::size_t lineNumber = 0;
while (std::getline(fclReader, 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();
- }
- line = Op::trim(line);
- if (line.empty() or line.at(0) == '%' or line.at(0) == '#'
- or (line.substr(0, 2) == "//")) {
+ line = Op::split(line, "//", false).front();
+ line = Op::split(line, "#", false).front();
+ line = Op::trim(Op::findReplace(line, ";", ""));
+ if (line.empty() or line.at(0) == '%') {
continue;
}
- line = fl::Op::findReplace(line, ";", "");
+
std::istringstream tokenizer(line);
std::string firstToken;
tokenizer >> firstToken;
@@ -102,7 +81,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] unknown block definition <" << firstToken
<< "> " << " in line " << lineNumber << ": " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
currentTag = tagFinder->first;
closingTag = tagFinder->second;
@@ -122,7 +101,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected <" << closingTag << "> before <"
<< firstToken << "> in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
} else {
block << line << "\n";
}
@@ -138,7 +117,7 @@ namespace fl {
} else {
ex << "expected <" << closingTag << ">, but not found";
}
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
return engine.release();
}
@@ -155,7 +134,7 @@ namespace fl {
} else {
std::ostringstream ex;
ex << "[syntax error] unexpected tag <" << tag << "> for block:\n" << block;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
}
@@ -169,9 +148,9 @@ namespace fl {
if (token.size() != 2) {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key : value) in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
- std::string name = fl::Op::validName(token.at(0));
+ std::string name = Op::validName(token.at(0));
if (tag == "VAR_INPUT")
engine->addInputVariable(new InputVariable(name));
else if (tag == "VAR_OUTPUT")
@@ -179,7 +158,7 @@ namespace fl {
else {
std::ostringstream ex;
ex << "[syntax error] unexpected tag <" << tag << "> in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
}
}
@@ -192,17 +171,17 @@ namespace fl {
std::string name;
std::size_t index = line.find_first_of(' ');
if (index != std::string::npos) {
- name = fl::Op::validName(line.substr(index + 1));
+ name = Op::validName(line.substr(index + 1));
} else {
std::ostringstream ex;
ex << "[syntax error] expected name of input variable in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
if (not engine->hasInputVariable(name)) {
std::ostringstream ex;
ex << "[syntax error] engine does not contain "
"input variable <" << name << "> from line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
InputVariable* inputVariable = engine->getInputVariable(name);
@@ -219,9 +198,9 @@ namespace fl {
inputVariable->setEnabled(parseEnabled(line));
} else if (firstToken == "TERM") {
inputVariable->addTerm(parseTerm(line, engine));
- } else throw fl::Exception("[syntax error] unexpected token "
+ } else throw Exception("[syntax error] unexpected token "
"<" + firstToken + ">" + line, FL_AT);
- } catch (fl::Exception& ex) {
+ } catch (Exception& ex) {
ex.append("At line: <" + line + ">");
throw;
}
@@ -237,23 +216,23 @@ namespace fl {
std::string name;
std::size_t index = line.find_first_of(' ');
if (index != std::string::npos) {
- name = fl::Op::validName(line.substr(index + 1));
+ name = Op::validName(line.substr(index + 1));
} else {
std::ostringstream ex;
ex << "[syntax error] expected an output variable name in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
if (not engine->hasOutputVariable(name)) {
std::ostringstream ex;
ex << "[syntax error] output variable <" << name
<< "> not registered in engine. "
<< "Line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
OutputVariable* outputVariable = engine->getOutputVariable(name);
while (std::getline(blockReader, line)) {
- line = fl::Op::trim(line);
+ line = Op::trim(line);
std::istringstream tokenizer(line);
std::string firstToken;
tokenizer >> firstToken;
@@ -262,27 +241,27 @@ namespace fl {
} else if (firstToken == "METHOD") {
outputVariable->setDefuzzifier(parseDefuzzifier(line));
} else if (firstToken == "ACCU") {
- outputVariable->fuzzyOutput()->setAccumulation(parseSNorm(line));
+ outputVariable->fuzzyOutput()->setAggregation(parseSNorm(line));
} else if (firstToken == "DEFAULT") {
std::pair<scalar, bool> defaultAndLock = parseDefaultValue(line);
outputVariable->setDefaultValue(defaultAndLock.first);
- outputVariable->setLockPreviousOutputValue(defaultAndLock.second or
- outputVariable->isLockedPreviousOutputValue());
+ outputVariable->setLockPreviousValue(defaultAndLock.second or
+ outputVariable->isLockPreviousValue());
} else if (firstToken == "RANGE") {
std::pair<scalar, scalar> minmax = parseRange(line);
outputVariable->setMinimum(minmax.first);
outputVariable->setMaximum(minmax.second);
} else if (firstToken == "LOCK") {
std::pair<bool, bool> output_range = parseLocks(line);
- outputVariable->setLockPreviousOutputValue(output_range.first);
- outputVariable->setLockOutputValueInRange(output_range.second);
+ outputVariable->setLockPreviousValue(output_range.first);
+ outputVariable->setLockValueInRange(output_range.second);
} else if (firstToken == "ENABLED") {
outputVariable->setEnabled(parseEnabled(line));
} else {
std::ostringstream ex;
ex << "[syntax error] unexpected token <" << firstToken <<
"> in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
}
@@ -295,8 +274,9 @@ namespace fl {
std::string name;
std::getline(blockReader, line);
std::size_t index = line.find_last_of(' ');
- if (index != std::string::npos) name = line.substr(index);
+ if (index != std::string::npos) name = line.substr(index + 1);
RuleBlock * ruleblock = new RuleBlock(name);
+ ruleblock->setActivation(new General);
engine->addRuleBlock(ruleblock);
while (std::getline(blockReader, line)) {
@@ -306,14 +286,14 @@ namespace fl {
} else if (firstToken == "OR") {
ruleblock->setDisjunction(parseSNorm(line));
} else if (firstToken == "ACT") {
- ruleblock->setActivation(parseTNorm(line));
+ ruleblock->setImplication(parseTNorm(line));
} else if (firstToken == "ENABLED") {
ruleblock->setEnabled(parseEnabled(line));
} else if (firstToken == "RULE") {
std::size_t ruleStart = line.find_first_of(':');
if (ruleStart == std::string::npos) ruleStart = 4; // "RULE".size()
std::string ruleText = line.substr(ruleStart + 1);
- ruleText = fl::Op::trim(ruleText);
+ ruleText = Op::trim(ruleText);
Rule* rule = new Rule(ruleText);
try {
rule->load(engine);
@@ -325,7 +305,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] keyword <" << firstToken
<< "> not recognized in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
}
}
@@ -336,7 +316,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key : value) in line: "
<< line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
std::string name = Op::trim(token.at(1));
std::string className = name;
@@ -358,7 +338,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key : value) in line: "
<< line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
std::string name = Op::trim(token.at(1));
std::string className = name;
@@ -412,7 +392,7 @@ namespace fl {
continue;
}
if (state == S_TERMCLASS) {
- if (fl::Op::isNumeric(token)) {
+ if (Op::isNumeric(token)) {
termClass = Constant().className();
parameters.push_back(token);
} else if (token == "(") {
@@ -429,16 +409,16 @@ namespace fl {
continue;
}
if (token == ";") break;
- parameters.push_back(fl::Op::trim(token));
+ parameters.push_back(Op::trim(token));
}
}
if (state <= S_TERMCLASS)
- throw fl::Exception("[syntax error] malformed term in line: " + line, FL_AT);
+ throw Exception("[syntax error] malformed term in line: " + line, FL_AT);
FL_unique_ptr<Term> term;
term.reset(FactoryManager::instance()->term()->constructObject(termClass));
- Term::updateReference(term.get(), engine);
- term->setName(fl::Op::validName(name));
+ term->updateReference(engine);
+ term->setName(Op::validName(name));
std::string separator;
if (not dynamic_cast<Function*> (term.get())) {
separator = " ";
@@ -453,10 +433,10 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key : value) in "
<< "line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
- std::string name = fl::Op::trim(token.at(1));
+ std::string name = Op::trim(token.at(1));
std::string className = name;
if (name == "NONE") className = "";
else if (name == "COG") className = Centroid().className();
@@ -476,7 +456,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key := value) in line: "
<< line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
std::vector<std::string> values = Op::split(token.at(1), "|");
@@ -485,24 +465,24 @@ namespace fl {
std::string nc;
if (values.size() == 2) nc = values.back();
- defaultValue = fl::Op::trim(defaultValue);
- nc = fl::Op::trim(nc);
+ defaultValue = Op::trim(defaultValue);
+ nc = Op::trim(nc);
scalar value;
try {
- value = fl::Op::toScalar(defaultValue);
+ value = Op::toScalar(defaultValue);
} catch (...) {
std::ostringstream ex;
ex << "[syntax error] expected numeric value, "
<< "but found <" << defaultValue << "> in line: "
<< line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
bool lockPreviousOutput = (nc == "NC");
if (not (lockPreviousOutput or nc.empty())) {
- throw fl::Exception("[syntax error] expected keyword <NC>, "
+ throw Exception("[syntax error] expected keyword <NC>, "
"but found <" + nc + "> in line: " + line, FL_AT);
}
@@ -515,7 +495,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key := value) in line: "
<< line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
std::string rangeToken = token.at(1);
@@ -532,7 +512,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type 'start .. end', "
<< "but found <" << range.str() << "> in line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
scalar minimum, maximum;
int index;
@@ -540,11 +520,11 @@ namespace fl {
minimum = Op::toScalar(token.at(index = 0));
maximum = Op::toScalar(token.at(index = 1));
} catch (std::exception& ex) {
- (void) ex;
+ FL_IUNUSED(ex);
std::ostringstream ss;
ss << "[syntax error] expected numeric value, but found <" << token.at(index) << "> in "
<< "line: " << line;
- throw fl::Exception(ss.str(), FL_AT);
+ throw Exception(ss.str(), FL_AT);
}
return std::pair<scalar, scalar>(minimum, maximum);
}
@@ -552,32 +532,32 @@ namespace fl {
std::pair<bool, bool> FclImporter::parseLocks(const std::string& line) const {
std::size_t index = line.find_first_of(":");
if (index == std::string::npos) {
- throw fl::Exception("[syntax error] expected property of type "
+ throw Exception("[syntax error] expected property of type "
"'key : value' in line: " + line, FL_AT);
}
bool output, range;
std::string value = line.substr(index + 1);
- std::vector<std::string> flags = fl::Op::split(value, "|");
+ std::vector<std::string> flags = Op::split(value, "|");
if (flags.size() == 1) {
- std::string flag = fl::Op::trim(flags.front());
+ std::string flag = Op::trim(flags.front());
output = (flag == "PREVIOUS");
range = (flag == "RANGE");
if (not (output or range)) {
- throw fl::Exception("[syntax error] expected locking flags "
+ throw Exception("[syntax error] expected locking flags "
"<PREVIOUS|RANGE>, but found <" + flag + "> in line: " + line, FL_AT);
}
} else if (flags.size() == 2) {
- std::string flagA = fl::Op::trim(flags.front());
- std::string flagB = fl::Op::trim(flags.back());
+ std::string flagA = Op::trim(flags.front());
+ std::string flagB = Op::trim(flags.back());
output = (flagA == "PREVIOUS" or flagB == "PREVIOUS");
range = (flagA == "RANGE" or flagB == "RANGE");
if (not (output and range)) {
- throw fl::Exception("[syntax error] expected locking flags "
+ throw Exception("[syntax error] expected locking flags "
"<PREVIOUS|RANGE>, but found "
"<" + flags.front() + "|" + flags.back() + "> in line: " + line, FL_AT);
}
} else {
- throw fl::Exception("[syntax error] expected locking flags "
+ throw Exception("[syntax error] expected locking flags "
"<PREVIOUS|RANGE>, but found "
"<" + value + "> in line: " + line, FL_AT);
}
@@ -590,13 +570,13 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] expected property of type (key : value) in "
<< "line: " << line;
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
- std::string boolean = fl::Op::trim(tokens.at(1));
+ std::string boolean = Op::trim(tokens.at(1));
if (boolean == "TRUE") return true;
if (boolean == "FALSE") return false;
- throw fl::Exception("[syntax error] expected boolean <TRUE|FALSE>, but found <" + line + ">", FL_AT);
+ throw Exception("[syntax error] expected boolean <TRUE|FALSE>, but found <" + line + ">", FL_AT);
}
FclImporter* FclImporter::clone() const {
diff --git a/fuzzylite/src/imex/FisExporter.cpp b/fuzzylite/src/imex/FisExporter.cpp
index 0934b33..2daac9a 100644
--- a/fuzzylite/src/imex/FisExporter.cpp
+++ b/fuzzylite/src/imex/FisExporter.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/FisExporter.h"
@@ -30,11 +22,9 @@
namespace fl {
- FisExporter::FisExporter() : Exporter() {
- }
+ FisExporter::FisExporter() : Exporter() { }
- FisExporter::~FisExporter() {
- }
+ FisExporter::~FisExporter() { }
std::string FisExporter::name() const {
return "FisExporter";
@@ -52,9 +42,10 @@ namespace fl {
return fis.str();
}
- //TODO: deal with multiple ruleblocks, merge them into one.
+
std::string FisExporter::exportSystem(const Engine* engine) const {
std::ostringstream fis;
+ fis << "#Code automatically generated with " << fuzzylite::library() << ".\n\n";
fis << "[System]\n";
fis << "Name='" << engine->getName() << "'\n";
std::string type;
@@ -66,57 +57,54 @@ namespace fl {
type = "tsukamoto";
} else if (engine->type() == Engine::InverseTsukamoto) {
type = "inverse tsukamoto";
- }else if (engine->type() == Engine::Hybrid){
+ } else if (engine->type() == Engine::Hybrid) {
type = "hybrid";
} else {
type = "unknown";
}
fis << "Type='" << type << "'\n";
- // fis << "Version=" << FL_VERSION << "\n";
+ fis << "Version=" << fuzzylite::version() << "\n";
fis << "NumInputs=" << engine->numberOfInputVariables() << "\n";
fis << "NumOutputs=" << engine->numberOfOutputVariables() << "\n";
-
- int numberOfRules = 0;
+
+ std::size_t numberOfRules = 0;
const TNorm* conjunction = fl::null;
const SNorm* disjunction = fl::null;
- const TNorm* activation = fl::null;
- for (int i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ const TNorm* implication = fl::null;
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
RuleBlock* rb = engine->getRuleBlock(i);
numberOfRules += rb->numberOfRules();
if (not conjunction) conjunction = rb->getConjunction();
if (not disjunction) disjunction = rb->getDisjunction();
- if (not activation) activation = rb->getActivation();
+ if (not implication) implication = rb->getImplication();
}
fis << "NumRules=" << numberOfRules << "\n";
- fis << "AndMethod='" << toString(conjunction) << "'\n";
- fis << "OrMethod='" << toString(disjunction) << "'\n";
- fis << "ImpMethod='" << toString(activation) << "'\n";
+ fis << "AndMethod='" << (conjunction ? toString(conjunction) : "min") << "'\n";
+ fis << "OrMethod='" << (disjunction ? toString(disjunction) : "max") << "'\n";
+ fis << "ImpMethod='" << (implication ? toString(implication) : "min") << "'\n";
- const SNorm* accumulation = fl::null;
+ const SNorm* aggregation = fl::null;
Defuzzifier* defuzzifier = fl::null;
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
- if (not accumulation) accumulation = outputVariable->fuzzyOutput()->getAccumulation();
+ if (not aggregation) aggregation = outputVariable->fuzzyOutput()->getAggregation();
if (not defuzzifier) defuzzifier = outputVariable->getDefuzzifier();
}
- fis << "AggMethod='" << toString(accumulation) << "'\n";
+ fis << "AggMethod='" << (aggregation ? toString(aggregation) : "max") << "'\n";
fis << "DefuzzMethod='" << toString(defuzzifier) << "'\n";
return fis.str();
}
std::string FisExporter::exportInputs(const Engine* engine) const {
std::ostringstream fis;
- for (int ixVar = 0; ixVar < engine->numberOfInputVariables(); ++ixVar) {
+ for (std::size_t ixVar = 0; ixVar < engine->numberOfInputVariables(); ++ixVar) {
InputVariable* var = engine->getInputVariable(ixVar);
fis << "[Input" << (ixVar + 1) << "]\n";
- if (not var->isEnabled()) {
- fis << "Enabled=" << var->isEnabled() << "\n";
- }
fis << "Name='" << Op::validName(var->getName()) << "'\n";
- fis << "Range=[" << fl::Op::join(2, " ", var->getMinimum(), var->getMaximum()) << "]\n";
+ fis << "Range=[" << Op::join(2, " ", var->getMinimum(), var->getMaximum()) << "]\n";
fis << "NumMFs=" << var->numberOfTerms() << "\n";
- for (int ixTerm = 0; ixTerm < var->numberOfTerms(); ++ixTerm) {
+ for (std::size_t ixTerm = 0; ixTerm < var->numberOfTerms(); ++ixTerm) {
fis << "MF" << (ixTerm + 1) << "='" << Op::validName(var->getTerm(ixTerm)->getName()) << "':"
<< toString(var->getTerm(ixTerm)) << "\n";
}
@@ -127,25 +115,13 @@ namespace fl {
std::string FisExporter::exportOutputs(const Engine* engine) const {
std::ostringstream fis;
- for (int ixVar = 0; ixVar < engine->numberOfOutputVariables(); ++ixVar) {
+ for (std::size_t ixVar = 0; ixVar < engine->numberOfOutputVariables(); ++ixVar) {
OutputVariable* var = engine->getOutputVariable(ixVar);
fis << "[Output" << (ixVar + 1) << "]\n";
- if (not var->isEnabled()) {
- fis << "Enabled=" << var->isEnabled() << "\n";
- }
fis << "Name='" << Op::validName(var->getName()) << "'\n";
- fis << "Range=[" << fl::Op::join(2, " ", var->getMinimum(), var->getMaximum()) << "]\n";
- if (not fl::Op::isNaN(var->getDefaultValue())) {
- fis << "Default=" << fl::Op::str(var->getDefaultValue()) << "\n";
- }
- if (var->isLockedPreviousOutputValue()) {
- fis << "LockPrevious=" << var->isLockedPreviousOutputValue() << "\n";
- }
- if (var->isLockedOutputValueInRange()) {
- fis << "LockRange=" << var->isLockedOutputValueInRange() << "\n";
- }
+ fis << "Range=[" << Op::join(2, " ", var->getMinimum(), var->getMaximum()) << "]\n";
fis << "NumMFs=" << var->numberOfTerms() << "\n";
- for (int ixTerm = 0; ixTerm < var->numberOfTerms(); ++ixTerm) {
+ for (std::size_t ixTerm = 0; ixTerm < var->numberOfTerms(); ++ixTerm) {
fis << "MF" << (ixTerm + 1) << "='" << Op::validName(var->getTerm(ixTerm)->getName()) << "':"
<< toString(var->getTerm(ixTerm)) << "\n";
}
@@ -157,10 +133,10 @@ namespace fl {
std::string FisExporter::exportRules(const Engine* engine) const {
std::ostringstream fis;
fis << "[Rules]\n";
- for (int ixRuleBlock = 0; ixRuleBlock < engine->numberOfRuleBlocks(); ++ixRuleBlock) {
+ for (std::size_t ixRuleBlock = 0; ixRuleBlock < engine->numberOfRuleBlocks(); ++ixRuleBlock) {
RuleBlock* rb = engine->getRuleBlock(ixRuleBlock);
if (engine->numberOfRuleBlocks() > 1) fis << "# RuleBlock " << rb->getName() << "\n";
- for (int ixRule = 0; ixRule < rb->numberOfRules(); ++ixRule) {
+ for (std::size_t ixRule = 0; ixRule < rb->numberOfRules(); ++ixRule) {
Rule* rule = rb->getRule(ixRule);
if (rule->isLoaded()) {
fis << exportRule(rule, engine) << "\n";
@@ -198,15 +174,15 @@ namespace fl {
}
}
if (not equalOperators) {
- throw fl::Exception("[exporter error] "
+ throw Exception("[exporter error] "
"fis files do not support rules with different connectors "
"(i.e. ['and', 'or']). All connectors within a rule must be the same", FL_AT);
}
std::ostringstream fis;
std::vector<Variable*> inputVariables, outputVariables;
- for (int i = 0; i < engine->numberOfInputVariables(); ++i)
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i)
inputVariables.push_back(engine->getInputVariable(i));
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i)
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i)
outputVariables.push_back(engine->getOutputVariable(i));
fis << translate(propositions, inputVariables) << ", ";
@@ -226,14 +202,14 @@ namespace fl {
std::ostringstream ss;
for (std::size_t ixVariable = 0; ixVariable < variables.size(); ++ixVariable) {
Variable* variable = variables.at(ixVariable);
- int termIndexPlusOne = 0;
+ std::size_t termIndexPlusOne = 0;
scalar plusHedge = 0;
int negated = 1;
for (std::size_t ixProposition = 0; ixProposition < propositions.size(); ++ixProposition) {
Proposition* proposition = propositions.at(ixProposition);
if (proposition->variable != variable) continue;
- for (int termIndex = 0; termIndex < variable->numberOfTerms(); ++termIndex) {
+ for (std::size_t termIndex = 0; termIndex < variable->numberOfTerms(); ++termIndex) {
if (variable->getTerm(termIndex) == proposition->term) {
termIndexPlusOne = termIndex + 1;
break;
@@ -259,8 +235,8 @@ namespace fl {
break;
}
if (negated < 0) ss << "-";
- if (not fl::Op::isNaN(plusHedge)) {
- ss << fl::Op::str(termIndexPlusOne + plusHedge);
+ if (not Op::isNaN(plusHedge)) {
+ ss << Op::str(termIndexPlusOne + plusHedge);
} else {
ss << termIndexPlusOne << ".?"; // Unreconized hedge combination
}
@@ -268,29 +244,6 @@ namespace fl {
}
return ss.str();
}
-
- std::string FisExporter::toString(const Norm * norm) const {
- if (not norm) return "";
- //TNorm
- if (norm->className() == Minimum().className()) return "min";
- if (norm->className() == AlgebraicProduct().className()) return "prod";
- if (norm->className() == BoundedDifference().className()) return "bounded_difference";
- if (norm->className() == DrasticProduct().className()) return "drastic_product";
- if (norm->className() == EinsteinProduct().className()) return "einstein_product";
- if (norm->className() == HamacherProduct().className()) return "hamacher_product";
- if (norm->className() == NilpotentMinimum().className()) return "nilpotent_minimum";
- //SNorm
- if (norm->className() == Maximum().className()) return "max";
- if (norm->className() == AlgebraicSum().className()) return "sum";
- if (norm->className() == BoundedSum().className()) return "bounded_sum";
- if (norm->className() == NormalizedSum().className()) return "normalized_sum";
- if (norm->className() == DrasticSum().className()) return "drastic_sum";
- if (norm->className() == EinsteinSum().className()) return "einstein_sum";
- if (norm->className() == HamacherSum().className()) return "hamacher_sum";
- if (norm->className() == NilpotentMaximum().className()) return "nilpotent_maximum";
-
- return norm->className();
- }
std::string FisExporter::toString(const TNorm * tnorm) const {
if (not tnorm) return "";
@@ -304,16 +257,17 @@ namespace fl {
return tnorm->className();
}
- std::string FisExporter::toString(const SNorm * snorm) const {
+ std::string FisExporter::toString(const SNorm* snorm) const {
if (not snorm) return "";
if (snorm->className() == Maximum().className()) return "max";
- if (snorm->className() == AlgebraicSum().className()) return "sum";
+ if (snorm->className() == AlgebraicSum().className()) return "probor";
if (snorm->className() == BoundedSum().className()) return "bounded_sum";
if (snorm->className() == NormalizedSum().className()) return "normalized_sum";
if (snorm->className() == DrasticSum().className()) return "drastic_sum";
if (snorm->className() == EinsteinSum().className()) return "einstein_sum";
if (snorm->className() == HamacherSum().className()) return "hamacher_sum";
if (snorm->className() == NilpotentMaximum().className()) return "nilpotent_maximum";
+ if (snorm->className() == UnboundedSum().className()) return "sum";
return snorm->className();
}
@@ -332,30 +286,36 @@ namespace fl {
std::string FisExporter::toString(const Term * term) const {
std::ostringstream ss;
if (const Bell * x = dynamic_cast<const Bell*> (term)) {
- ss << "'gbellmf',[" << fl::Op::join(3, " ",
+ ss << "'gbellmf',[" << Op::join(3, " ",
x->getWidth(), x->getSlope(), x->getCenter()) << "]";
return ss.str();
}
+ if (const Binary * x = dynamic_cast<const Binary*> (term)) {
+ ss << "'binarymf,[" << Op::join(2, " ",
+ x->getStart(), x->getDirection()) << "]";
+ return ss.str();
+ }
+
if (const Concave * x = dynamic_cast<const Concave*> (term)) {
- ss << "'concavemf',[" << fl::Op::join(2, " ",
+ ss << "'concavemf',[" << Op::join(2, " ",
x->getInflection(), x->getEnd()) << "]";
return ss.str();
}
if (const Constant * x = dynamic_cast<const Constant*> (term)) {
- ss << "'constant',[" << fl::Op::str(x->getValue()) << "]";
+ ss << "'constant',[" << Op::str(x->getValue()) << "]";
return ss.str();
}
if (const Cosine * x = dynamic_cast<const Cosine*> (term)) {
- ss << "'cosinemf',[" << fl::Op::join(2, " ",
+ ss << "'cosinemf',[" << Op::join(2, " ",
x->getCenter(), x->getWidth()) << "]";
return ss.str();
}
if (const Discrete * x = dynamic_cast<const Discrete*> (term)) {
- ss << "'discretemf',[" << fl::Op::join(Discrete::toVector(x->xy()), " ") << "]";
+ ss << "'discretemf',[" << Op::join(Discrete::toVector(x->xy()), " ") << "]";
return ss.str();
}
@@ -365,95 +325,95 @@ namespace fl {
}
if (const Gaussian * x = dynamic_cast<const Gaussian*> (term)) {
- ss << "'gaussmf',[" << fl::Op::join(2, " ",
+ ss << "'gaussmf',[" << Op::join(2, " ",
x->getStandardDeviation(), x->getMean()) << "]";
return ss.str();
}
if (const GaussianProduct * x = dynamic_cast<const GaussianProduct*> (term)) {
- ss << "'gauss2mf',[" << fl::Op::join(4, " ",
+ ss << "'gauss2mf',[" << Op::join(4, " ",
x->getStandardDeviationA(), x->getMeanA(),
x->getStandardDeviationB(), x->getMeanB()) << "]";
return ss.str();
}
if (const Linear * x = dynamic_cast<const Linear*> (term)) {
- ss << "'linear',[" << fl::Op::join<scalar>(x->coefficients(), " ") << "]";
+ ss << "'linear',[" << Op::join<scalar>(x->coefficients(), " ") << "]";
return ss.str();
}
if (const PiShape * x = dynamic_cast<const PiShape*> (term)) {
- ss << "'pimf',[" << fl::Op::join(4, " ",
+ ss << "'pimf',[" << Op::join(4, " ",
x->getBottomLeft(), x->getTopLeft(),
x->getTopRight(), x->getBottomRight()) << "]";
return ss.str();
}
if (const Ramp * x = dynamic_cast<const Ramp*> (term)) {
- ss << "'rampmf',[" << fl::Op::join(2, " ",
+ ss << "'rampmf',[" << Op::join(2, " ",
x->getStart(), x->getEnd()) << "]";
return ss.str();
}
if (const Rectangle * x = dynamic_cast<const Rectangle*> (term)) {
- ss << "'rectmf',[" << fl::Op::join(2, " ",
+ ss << "'rectmf',[" << Op::join(2, " ",
x->getStart(), x->getEnd()) << "]";
return ss.str();
}
if (const SigmoidDifference * x = dynamic_cast<const SigmoidDifference*> (term)) {
- ss << "'dsigmf',[" << fl::Op::join(4, " ",
+ ss << "'dsigmf',[" << Op::join(4, " ",
x->getRising(), x->getLeft(),
x->getFalling(), x->getRight()) << "]";
return ss.str();
}
if (const Sigmoid * x = dynamic_cast<const Sigmoid*> (term)) {
- ss << "'sigmf',[" << fl::Op::join(2, " ",
+ ss << "'sigmf',[" << Op::join(2, " ",
x->getSlope(), x->getInflection()) << "]";
return ss.str();
}
if (const SigmoidProduct * x = dynamic_cast<const SigmoidProduct*> (term)) {
- ss << "'psigmf',[" << fl::Op::join(4, " ",
+ ss << "'psigmf',[" << Op::join(4, " ",
x->getRising(), x->getLeft(),
x->getFalling(), x->getRight()) << "]";
return ss.str();
}
if (const SShape * x = dynamic_cast<const SShape*> (term)) {
- ss << "'smf',[" << fl::Op::join(2, " ",
+ ss << "'smf',[" << Op::join(2, " ",
x->getStart(), x->getEnd()) << "]";
return ss.str();
}
if (const Spike * x = dynamic_cast<const Spike*> (term)) {
- ss << "'spikemf',[" << fl::Op::join(2, " ",
+ ss << "'spikemf',[" << Op::join(2, " ",
x->getCenter(), x->getWidth()) << "]";
return ss.str();
}
if (const Trapezoid * x = dynamic_cast<const Trapezoid*> (term)) {
- ss << "'trapmf',[" << fl::Op::join(4, " ",
+ ss << "'trapmf',[" << Op::join(4, " ",
x->getVertexA(), x->getVertexB(), x->getVertexC(), x->getVertexD()) << "]";
return ss.str();
}
if (const Triangle * x = dynamic_cast<const Triangle*> (term)) {
- ss << "'trimf',[" << fl::Op::join(3, " ",
+ ss << "'trimf',[" << Op::join(3, " ",
x->getVertexA(), x->getVertexB(), x->getVertexC()) << "]";
return ss.str();
}
if (const ZShape * x = dynamic_cast<const ZShape*> (term)) {
- ss << "'zmf',[" << fl::Op::join(2, " ",
+ ss << "'zmf',[" << Op::join(2, " ",
x->getStart(), x->getEnd()) << "]";
return ss.str();
}
- ss << "[exporter error] term of class <" << term->className() << "> not supported";
- throw fl::Exception(ss.str(), FL_AT);
+ ss << "[exporter error] term of class <" << (term ? term->className() : "null") << "> not supported";
+ throw Exception(ss.str(), FL_AT);
}
FisExporter* FisExporter::clone() const {
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())) {
diff --git a/fuzzylite/src/imex/FldExporter.cpp b/fuzzylite/src/imex/FldExporter.cpp
index 9064250..e25af1b 100644
--- a/fuzzylite/src/imex/FldExporter.cpp
+++ b/fuzzylite/src/imex/FldExporter.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/FldExporter.h"
@@ -30,20 +22,15 @@
#include "fl/variable/InputVariable.h"
#include "fl/variable/OutputVariable.h"
-#include <cmath>
#include <fstream>
-#include <vector>
namespace fl {
FldExporter::FldExporter(const std::string& separator) : Exporter(),
_separator(separator), _exportHeaders(true),
- _exportInputValues(true), _exportOutputValues(true) {
-
- }
+ _exportInputValues(true), _exportOutputValues(true) { }
- FldExporter::~FldExporter() {
- }
+ FldExporter::~FldExporter() { }
std::string FldExporter::name() const {
return "FldExporter";
@@ -84,156 +71,235 @@ namespace fl {
std::string FldExporter::header(const Engine* engine) const {
std::vector<std::string> result;
if (_exportInputValues) {
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
- result.push_back("@InputVariable: " + inputVariable->getName() + ";");
+ result.push_back(inputVariable->getName());
}
}
if (_exportOutputValues) {
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
- result.push_back("@OutputVariable: " + outputVariable->getName() + ";");
+ result.push_back(outputVariable->getName());
}
}
- return "#@Engine: " + engine->getName() + ";\n#" + Op::join(result, _separator);
+ return Op::join(result, _separator);
}
std::string FldExporter::toString(const Engine* engine) const {
- return toString(const_cast<Engine*> (engine), 1024);
+ return toString(const_cast<Engine*> (engine), 1024, AllVariables);
}
- std::string FldExporter::toString(Engine* engine, int maximumNumberOfResults) const {
- std::ostringstream result;
- write(engine, result, maximumNumberOfResults);
- return result.str();
+ std::string FldExporter::toString(Engine* engine, int values, ScopeOfValues scope) const {
+ return toString(engine, values, scope, engine->inputVariables());
}
- void FldExporter::toFile(const std::string& path, Engine* engine, int maximumNumberOfResults) const {
- std::ofstream writer(path.c_str());
- if (not writer.is_open()) {
- throw fl::Exception("[file error] file <" + path + "> could not be created", FL_AT);
- }
- write(engine, writer, maximumNumberOfResults);
- writer.close();
+ std::string FldExporter::toString(Engine* engine, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
+ std::ostringstream result;
+ write(engine, result, values, scope, activeVariables);
+ return result.str();
}
- std::string FldExporter::toString(Engine* engine, const std::string& inputData) const {
+ std::string FldExporter::toString(Engine* engine, std::istream& reader) const {
std::ostringstream writer;
if (_exportHeaders) writer << header(engine) << "\n";
- std::istringstream reader(inputData);
std::string line;
+ int lineNumber = 0;
while (std::getline(reader, line)) {
+ ++lineNumber;
line = Op::trim(line);
- if (not line.empty() and line.at(0) == '#') continue; //comments are ignored, blank lines are retained
- std::vector<scalar> inputValues = parse(line);
- write(engine, writer, inputValues);
- writer.flush();
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+
+ write(engine, writer, inputValues, engine->inputVariables());
}
return writer.str();
}
- void FldExporter::toFile(const std::string& path, Engine* engine, const std::string& inputData) const {
+ void FldExporter::toFile(const std::string& path, Engine* engine, int values, ScopeOfValues scope) const {
+ toFile(path, engine, values, scope, engine->inputVariables());
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
std::ofstream writer(path.c_str());
if (not writer.is_open()) {
- throw fl::Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ }
+ write(engine, writer, values, scope, activeVariables);
+ writer.close();
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, std::istream& reader) const {
+ std::ofstream writer(path.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
}
if (_exportHeaders) writer << header(engine) << "\n";
- std::istringstream reader(inputData);
+
std::string line;
+ int lineNumber = 0;
while (std::getline(reader, line)) {
+ ++lineNumber;
line = Op::trim(line);
- if (not line.empty() and line.at(0) == '#') continue; //comments are ignored, blank lines are retained
- std::vector<scalar> inputValues = parse(line);
- write(engine, writer, inputValues);
- writer.flush();
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+
+ write(engine, writer, inputValues, engine->inputVariables());
}
writer.close();
}
- std::vector<scalar> FldExporter::parse(const std::string& x) const {
+ std::vector<scalar> FldExporter::parse(const std::string& values) const {
std::vector<scalar> inputValues;
- if (not (x.empty() or x.at(0) == '#')) {
- std::istringstream tokenizer(x);
- std::string token;
- while (tokenizer >> token)
- inputValues.push_back(fl::Op::toScalar(token));
+ if (not (values.empty() or values.at(0) == '#')) {
+ inputValues = Op::toScalars(values);
}
return inputValues;
}
- void FldExporter::write(Engine* engine, std::ostream& writer, int maximum) const {
+ void FldExporter::write(Engine* engine, std::ostream& writer, int values, ScopeOfValues scope) const {
+ write(engine, writer, values, scope, engine->inputVariables());
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
if (_exportHeaders) writer << header(engine) << "\n";
- int resolution = -1 + (int) std::max(1.0, std::pow(
- maximum, 1.0 / engine->numberOfInputVariables()));
+ if (activeVariables.size() != engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[exporter error] number of active variables "
+ "<" << activeVariables.size() << ">"
+ << "must match the number of input variables in the engine "
+ "<" << engine->inputVariables().size() << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ int resolution;
+ if (scope == AllVariables)
+ resolution = -1 + (int) std::max(1.0, std::pow(
+ values, 1.0 / engine->numberOfInputVariables()));
+ else //if (scope == EachVariable)
+ resolution = values - 1;
+
std::vector<int> sampleValues, minSampleValues, maxSampleValues;
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
sampleValues.push_back(0);
minSampleValues.push_back(0);
- maxSampleValues.push_back(resolution);
+ if (engine->inputVariables().at(i) == activeVariables.at(i))
+ maxSampleValues.push_back(resolution);
+ else maxSampleValues.push_back(0);
}
- engine->restart();
-
- bool overflow = false;
std::vector<scalar> inputValues(engine->numberOfInputVariables());
- while (not overflow) {
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ do {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
- inputValues.at(i) = inputVariable->getMinimum()
- + sampleValues.at(i) * inputVariable->range() / std::max(1, resolution);
+ if (inputVariable == activeVariables.at(i)) {
+ inputValues.at(i) = inputVariable->getMinimum()
+ + sampleValues.at(i) * inputVariable->range() / std::max(1, resolution);
+ } else {
+ inputValues.at(i) = inputVariable->getValue();
+ }
}
- write(engine, writer, inputValues);
- overflow = Op::increment(sampleValues, minSampleValues, maxSampleValues);
- }
+ write(engine, writer, inputValues, activeVariables);
+ } while (Op::increment(sampleValues, minSampleValues, maxSampleValues));
}
void FldExporter::write(Engine* engine, std::ostream& writer, std::istream& reader) const {
if (_exportHeaders) writer << header(engine) << "\n";
- engine->restart();
-
std::string line;
- int lineNumber = 0;
+ std::size_t lineNumber = 0;
while (std::getline(reader, line)) {
++lineNumber;
- std::vector<scalar> inputValues = parse(Op::trim(line));
+ line = Op::trim(line);
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
try {
- write(engine, writer, inputValues);
- } catch (fl::Exception& ex) {
+ write(engine, writer, inputValues, engine->inputVariables());
+ } catch (Exception& ex) {
ex.append(" writing line <" + Op::str(lineNumber) + ">");
throw;
}
}
}
- void FldExporter::write(Engine* engine, std::ostream& writer, const std::vector<scalar>& inputValues) const {
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ const std::vector<scalar>& inputValues) const {
+ write(engine, writer, inputValues, engine->inputVariables());
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ const std::vector<scalar>& inputValues,
+ const std::vector<InputVariable*>& activeVariables) const {
if (inputValues.empty()) {
writer << "\n";
return;
}
- if (int(inputValues.size()) < engine->numberOfInputVariables()) {
+ if (inputValues.size() < engine->numberOfInputVariables()) {
std::ostringstream ex;
ex << "[export error] engine has <" << engine->numberOfInputVariables() << "> "
"input variables, but input data provides <" << inputValues.size() << "> values";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (activeVariables.size() != engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[exporter error] number of active variables <" << activeVariables.size() << "> "
+ "must match the number of input variables in the engine <" << engine->inputVariables().size() << ">";
+ throw Exception(ex.str(), FL_AT);
}
- std::vector<std::string> values;
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ std::vector<scalar> values;
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
- scalar inputValue = inputVariable->isEnabled() ? inputValues.at(i) : fl::nan;
- inputVariable->setInputValue(inputValue);
- if (_exportInputValues) values.push_back(Op::str(inputValue));
+ scalar inputValue;
+ if (inputVariable == activeVariables.at(i)) {
+ inputValue = inputValues.at(i);
+ } else {
+ inputValue = inputVariable->getValue();
+ }
+ inputVariable->setValue(inputValue);
+ if (_exportInputValues) values.push_back(inputValue);
}
engine->process();
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
- outputVariable->defuzzify();
if (_exportOutputValues)
- values.push_back(Op::str(outputVariable->getOutputValue()));
+ values.push_back(outputVariable->getValue());
}
writer << Op::join(values, _separator) << "\n";
diff --git a/fuzzylite/src/imex/FllExporter.cpp b/fuzzylite/src/imex/FllExporter.cpp
index 0ffeb2f..6a86152 100644
--- a/fuzzylite/src/imex/FllExporter.cpp
+++ b/fuzzylite/src/imex/FllExporter.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/FllExporter.h"
@@ -29,11 +21,9 @@
namespace fl {
FllExporter::FllExporter(const std::string& indent, const std::string& separator)
- : Exporter(), _indent(indent), _separator(separator) {
- }
+ : Exporter(), _indent(indent), _separator(separator) { }
- FllExporter::~FllExporter() {
- }
+ FllExporter::~FllExporter() { }
std::string FllExporter::name() const {
return "FllExporter";
@@ -58,9 +48,17 @@ namespace fl {
std::string FllExporter::toString(const Engine* engine) const {
std::vector<std::string> result;
result.push_back("Engine: " + engine->getName());
- result.push_back(toString(engine->inputVariables()));
- result.push_back(toString(engine->outputVariables()));
- result.push_back(toString(engine->ruleBlocks()));
+ if (not engine->getDescription().empty())
+ result.push_back("description: " + engine->getDescription());
+ for (std::size_t i = 0 ; i < engine->numberOfInputVariables(); ++i){
+ result.push_back(toString(engine->getInputVariable(i)));
+ }
+ for (std::size_t i = 0 ; i < engine->numberOfOutputVariables(); ++i){
+ result.push_back(toString(engine->getOutputVariable(i)));
+ }
+ for (std::size_t i = 0 ; i < engine->numberOfRuleBlocks(); ++i){
+ result.push_back(toString(engine->getRuleBlock(i)));
+ }
return Op::join(result, _separator);
}
@@ -99,10 +97,15 @@ namespace fl {
std::string FllExporter::toString(const Variable* variable) const {
std::vector<std::string> result;
result.push_back("Variable: " + Op::validName(variable->getName()));
+ if (not variable->getDescription().empty()) {
+ result.push_back(_indent + "description: " + variable->getDescription());
+ }
result.push_back(_indent + "enabled: " + (variable->isEnabled() ? "true" : "false"));
result.push_back(_indent + "range: " + Op::join(2, " ",
variable->getMinimum(), variable->getMaximum()));
- for (int i = 0; i < variable->numberOfTerms(); ++i) {
+ result.push_back(_indent + "lock-range: " +
+ (variable->isLockValueInRange() ? "true" : "false"));
+ for (std::size_t i = 0; i < variable->numberOfTerms(); ++i) {
result.push_back(_indent + toString(variable->getTerm(i)));
}
return Op::join(result, _separator);
@@ -111,10 +114,15 @@ namespace fl {
std::string FllExporter::toString(const InputVariable* inputVariable) const {
std::vector<std::string> result;
result.push_back("InputVariable: " + Op::validName(inputVariable->getName()));
+ if (not inputVariable->getDescription().empty()) {
+ result.push_back(_indent + "description: " + inputVariable->getDescription());
+ }
result.push_back(_indent + "enabled: " + (inputVariable->isEnabled() ? "true" : "false"));
result.push_back(_indent + "range: " + Op::join(2, " ",
inputVariable->getMinimum(), inputVariable->getMaximum()));
- for (int i = 0; i < inputVariable->numberOfTerms(); ++i) {
+ result.push_back(_indent + "lock-range: " +
+ (inputVariable->isLockValueInRange() ? "true" : "false"));
+ for (std::size_t i = 0; i < inputVariable->numberOfTerms(); ++i) {
result.push_back(_indent + toString(inputVariable->getTerm(i)));
}
return Op::join(result, _separator);
@@ -123,19 +131,22 @@ namespace fl {
std::string FllExporter::toString(const OutputVariable* outputVariable) const {
std::vector<std::string> result;
result.push_back("OutputVariable: " + Op::validName(outputVariable->getName()));
+ if (not outputVariable->getDescription().empty()) {
+ result.push_back(_indent + "description: " + outputVariable->getDescription());
+ }
result.push_back(_indent + "enabled: " + (outputVariable->isEnabled() ? "true" : "false"));
result.push_back(_indent + "range: " + Op::join(2, " ",
outputVariable->getMinimum(), outputVariable->getMaximum()));
- result.push_back(_indent + "accumulation: " +
- toString(outputVariable->fuzzyOutput()->getAccumulation()));
+ result.push_back(_indent + "lock-range: " +
+ (outputVariable->isLockValueInRange() ? "true" : "false"));
+ result.push_back(_indent + "aggregation: " +
+ toString(outputVariable->fuzzyOutput()->getAggregation()));
result.push_back(_indent + "defuzzifier: " +
toString(outputVariable->getDefuzzifier()));
result.push_back(_indent + "default: " + Op::str(outputVariable->getDefaultValue()));
result.push_back(_indent + "lock-previous: " +
- (outputVariable->isLockedPreviousOutputValue() ? "true" : "false"));
- result.push_back(_indent + "lock-range: " +
- (outputVariable->isLockedOutputValueInRange() ? "true" : "false"));
- for (int i = 0; i < outputVariable->numberOfTerms(); ++i) {
+ (outputVariable->isLockPreviousValue() ? "true" : "false"));
+ for (std::size_t i = 0; i < outputVariable->numberOfTerms(); ++i) {
result.push_back(_indent + toString(outputVariable->getTerm(i)));
}
return Op::join(result, _separator);
@@ -144,12 +155,16 @@ namespace fl {
std::string FllExporter::toString(const RuleBlock* ruleBlock) const {
std::vector<std::string> result;
result.push_back("RuleBlock: " + ruleBlock->getName());
+ if (not ruleBlock->getDescription().empty()) {
+ result.push_back(_indent + "description: " + ruleBlock->getDescription());
+ }
result.push_back(_indent + "enabled: " +
(ruleBlock->isEnabled() ? "true" : "false"));
result.push_back(_indent + "conjunction: " + toString(ruleBlock->getConjunction()));
result.push_back(_indent + "disjunction: " + toString(ruleBlock->getDisjunction()));
+ result.push_back(_indent + "implication: " + toString(ruleBlock->getImplication()));
result.push_back(_indent + "activation: " + toString(ruleBlock->getActivation()));
- for (int i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
result.push_back(_indent + toString(ruleBlock->getRule(i)));
}
return Op::join(result, _separator);
@@ -169,11 +184,17 @@ namespace fl {
return "none";
}
+ std::string FllExporter::toString(const Activation* activation) const {
+ if (not activation) return "none";
+ if (activation->parameters().empty()) return activation->className();
+ return activation->className() + " " + activation->parameters();
+ }
+
std::string FllExporter::toString(const Defuzzifier* defuzzifier) const {
if (not defuzzifier) return "none";
if (const IntegralDefuzzifier * integralDefuzzifier =
dynamic_cast<const IntegralDefuzzifier*> (defuzzifier)) {
- return defuzzifier->className() + " " + Op::str<int>(integralDefuzzifier->getResolution());
+ return defuzzifier->className() + " " + Op::str(integralDefuzzifier->getResolution());
} else if (const WeightedDefuzzifier * weightedDefuzzifier =
dynamic_cast<const WeightedDefuzzifier*> (defuzzifier)) {
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);
}
-
}
diff --git a/fuzzylite/src/imex/Importer.cpp b/fuzzylite/src/imex/Importer.cpp
index faef71d..c0be7f5 100644
--- a/fuzzylite/src/imex/Importer.cpp
+++ b/fuzzylite/src/imex/Importer.cpp
@@ -1,46 +1,34 @@
/*
- 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/Importer.h"
#include "fl/Exception.h"
#include <fstream>
-#include <ostream>
namespace fl {
- Importer::Importer() {
- }
+ Importer::Importer() { }
- Importer::~Importer() {
-
- }
+ Importer::~Importer() { }
Engine* Importer::fromFile(const std::string& path) const {
std::ifstream reader(path.c_str());
if (not reader.is_open()) {
- throw fl::Exception("[file error] file <" + path + "> could not be opened", FL_AT);
+ throw Exception("[file error] file <" + path + "> could not be opened", FL_AT);
}
std::ostringstream textEngine;
std::string line;
diff --git a/fuzzylite/src/imex/JavaExporter.cpp b/fuzzylite/src/imex/JavaExporter.cpp
index a4948f8..6981dae 100644
--- a/fuzzylite/src/imex/JavaExporter.cpp
+++ b/fuzzylite/src/imex/JavaExporter.cpp
@@ -1,60 +1,59 @@
/*
- 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/JavaExporter.h"
#include "fl/Headers.h"
-#include <algorithm>
namespace fl {
- JavaExporter::JavaExporter() : Exporter() {
- }
+ JavaExporter::JavaExporter(bool usingVariableNames) : Exporter(),
+ _usingVariableNames(usingVariableNames) { }
- JavaExporter::~JavaExporter() {
-
- }
+ JavaExporter::~JavaExporter() { }
std::string JavaExporter::name() const {
return "JavaExporter";
}
+ void JavaExporter::setUsingVariableNames(bool usingVariableNames) {
+ this->_usingVariableNames = usingVariableNames;
+ }
+
+ bool JavaExporter::isUsingVariableNames() const {
+ return this->_usingVariableNames;
+ }
+
std::string JavaExporter::toString(const Engine* engine) const {
std::ostringstream ss;
+ ss << "//Code automatically generated with " << fuzzylite::library() << ".\n\n";
ss << "Engine engine = new Engine();\n";
ss << "engine.setName(\"" << engine->getName() << "\");\n";
+ ss << "engine.setDescription(\"" << engine->getDescription() << "\");\n";
ss << "\n";
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
ss << toString(engine->getInputVariable(i), engine) << "\n";
}
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
ss << toString(engine->getOutputVariable(i), engine) << "\n";
}
- for (int i = 0; i < engine->numberOfRuleBlocks(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfRuleBlocks(); ++i) {
ss << toString(engine->getRuleBlock(i), engine) << "\n";
}
@@ -63,21 +62,28 @@ namespace fl {
std::string JavaExporter::toString(const InputVariable* inputVariable, const Engine* engine) const {
std::ostringstream ss;
- std::string name = "inputVariable";
- if (engine->numberOfInputVariables() > 1) {
- int index = std::distance(engine->inputVariables().begin(),
- std::find(engine->inputVariables().begin(),
- engine->inputVariables().end(), inputVariable));
- name += Op::str<int>(index + 1);
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(inputVariable->getName());
+ } else {
+ name = "inputVariable";
+ if (engine->numberOfInputVariables() > 1) {
+ std::size_t index = std::distance(engine->inputVariables().begin(),
+ std::find(engine->inputVariables().begin(),
+ engine->inputVariables().end(), inputVariable));
+ name += Op::str(index + 1);
+ }
}
ss << "InputVariable " << name << " = new InputVariable();\n";
- ss << name << ".setEnabled(" << (inputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << ".setName(\"" << inputVariable->getName() << "\");\n";
+ ss << name << ".setDescription(\"" << inputVariable->getDescription() << "\");\n";
+ ss << name << ".setEnabled(" << (inputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << ".setRange("
<< toString(inputVariable->getMinimum()) << ", "
<< toString(inputVariable->getMaximum()) << ");\n";
-
- for (int i = 0; i < inputVariable->numberOfTerms(); ++i) {
+ ss << name << ".setLockValueInRange("
+ << (inputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ for (std::size_t i = 0; i < inputVariable->numberOfTerms(); ++i) {
ss << name << ".addTerm(" <<
toString(inputVariable->getTerm(i)) << ");\n";
}
@@ -87,30 +93,36 @@ namespace fl {
std::string JavaExporter::toString(const OutputVariable* outputVariable, const Engine* engine) const {
std::ostringstream ss;
- std::string name = "outputVariable";
- if (engine->numberOfOutputVariables() > 1) {
- int index = std::distance(engine->outputVariables().begin(),
- std::find(engine->outputVariables().begin(),
- engine->outputVariables().end(), outputVariable));
- name += Op::str<int>(index + 1);
+ std::string name;
+ if (isUsingVariableNames()) {
+ name = Op::validName(outputVariable->getName());
+ } else {
+ name = "outputVariable";
+ if (engine->numberOfOutputVariables() > 1) {
+ std::size_t index = std::distance(engine->outputVariables().begin(),
+ std::find(engine->outputVariables().begin(),
+ engine->outputVariables().end(), outputVariable));
+ name += Op::str(index + 1);
+ }
}
ss << "OutputVariable " << name << " = new OutputVariable();\n";
- ss << name << ".setEnabled(" << (outputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << ".setName(\"" << outputVariable->getName() << "\");\n";
+ ss << name << ".setDescription(\"" << outputVariable->getDescription() << "\");\n";
+ ss << name << ".setEnabled(" << (outputVariable->isEnabled() ? "true" : "false") << ");\n";
ss << name << ".setRange("
<< toString(outputVariable->getMinimum()) << ", "
<< toString(outputVariable->getMaximum()) << ");\n";
- ss << name << ".fuzzyOutput().setAccumulation(" <<
- toString(outputVariable->fuzzyOutput()->getAccumulation()) << ");\n";
+ ss << name << ".setLockValueInRange(" <<
+ (outputVariable->isLockValueInRange() ? "true" : "false") << ");\n";
+ ss << name << ".setAggregation(" <<
+ toString(outputVariable->fuzzyOutput()->getAggregation()) << ");\n";
ss << name << ".setDefuzzifier(" <<
toString(outputVariable->getDefuzzifier()) << ");\n";
ss << name << ".setDefaultValue(" <<
toString(outputVariable->getDefaultValue()) << ");\n";
- ss << name << ".setLockPreviousOutputValue(" <<
- (outputVariable->isLockedPreviousOutputValue() ? "true" : "false") << ");\n";
- ss << name << ".setLockOutputValueInRange(" <<
- (outputVariable->isLockedOutputValueInRange() ? "true" : "false") << ");\n";
- for (int i = 0; i < outputVariable->numberOfTerms(); ++i) {
+ ss << name << ".setLockPreviousValue(" <<
+ (outputVariable->isLockPreviousValue() ? "true" : "false") << ");\n";
+ for (std::size_t i = 0; i < outputVariable->numberOfTerms(); ++i) {
ss << name << ".addTerm(" <<
toString(outputVariable->getTerm(i)) << ");\n";
}
@@ -120,23 +132,33 @@ namespace fl {
std::string JavaExporter::toString(const RuleBlock* ruleBlock, const Engine* engine) const {
std::ostringstream ss;
- std::string name = "ruleBlock";
- if (engine->numberOfRuleBlocks() > 1) {
- int index = std::distance(engine->ruleBlocks().begin(),
- std::find(engine->ruleBlocks().begin(),
- engine->ruleBlocks().end(), ruleBlock));
- name += Op::str<int>(index + 1);
+ std::string name;
+
+ if (isUsingVariableNames() and not ruleBlock->getName().empty()) {
+ name = Op::validName(ruleBlock->getName());
+ } else {
+ name = "ruleBlock";
+ if (engine->numberOfRuleBlocks() > 1) {
+ std::size_t index = std::distance(engine->ruleBlocks().begin(),
+ std::find(engine->ruleBlocks().begin(),
+ engine->ruleBlocks().end(), ruleBlock));
+ name += Op::str(index + 1);
+ }
}
+
ss << "RuleBlock " << name << " = new RuleBlock();\n";
- ss << name << ".setEnabled(" << (ruleBlock->isEnabled() ? "true" : "false") << ");\n";
ss << name << ".setName(\"" << ruleBlock->getName() << "\");\n";
+ ss << name << ".setDescription(\"" << ruleBlock->getDescription() << "\");\n";
+ ss << name << ".setEnabled(" << (ruleBlock->isEnabled() ? "true" : "false") << ");\n";
ss << name << ".setConjunction("
<< toString(ruleBlock->getConjunction()) << ");\n";
ss << name << ".setDisjunction("
<< toString(ruleBlock->getDisjunction()) << ");\n";
+ ss << name << ".setImplication("
+ << toString(ruleBlock->getImplication()) << ");\n";
ss << name << ".setActivation("
<< toString(ruleBlock->getActivation()) << ");\n";
- for (int i = 0; i < ruleBlock->numberOfRules(); ++i) {
+ for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
Rule* rule = ruleBlock->getRule(i);
ss << name << ".addRule(Rule.parse(\"" << rule->getText() << "\", engine));\n";
}
@@ -183,7 +205,7 @@ namespace fl {
if (const IntegralDefuzzifier * integralDefuzzifier =
dynamic_cast<const IntegralDefuzzifier*> (defuzzifier)) {
return "new " + integralDefuzzifier->className() + "("
- + fl::Op::str(integralDefuzzifier->getResolution()) + ")";
+ + Op::str(integralDefuzzifier->getResolution()) + ")";
}
if (const WeightedDefuzzifier * weightedDefuzzifier =
dynamic_cast<const WeightedDefuzzifier*> (defuzzifier)) {
@@ -193,19 +215,22 @@ namespace fl {
return "new " + defuzzifier->className() + "()";
}
- std::string JavaExporter::toString(const Norm* norm) const{
- if (not norm) return "null";
- return "new " + norm->className() + "()";
- }
-
- std::string JavaExporter::toString(const TNorm* norm) const {
+ std::string JavaExporter::toString(const Norm* norm) const {
if (not norm) return "null";
return "new " + norm->className() + "()";
}
- std::string JavaExporter::toString(const SNorm* norm) const {
- if (not norm) return "null";
- return "new " + norm->className() + "()";
+ std::string JavaExporter::toString(const Activation* activation) const {
+ if (not activation) return "null";
+ std::string parameters = Op::trim(activation->parameters());
+ if (parameters.empty()) return "new " + activation->className() + "()";
+
+ std::vector<std::string> values = Op::split(parameters, " ");
+ for (std::size_t i = 0; i < values.size(); ++i) {
+ std::string parameter = values.at(i);
+ values.at(i) = (Op::isNumeric(parameter) ? parameter : ("\"" + parameter + "\""));
+ }
+ return "new " + activation->className() + "(" + Op::join(values, ", ") + ")";
}
std::string JavaExporter::toString(scalar value) const {
@@ -223,6 +248,4 @@ namespace fl {
return new JavaExporter(*this);
}
-
}
-
diff --git a/fuzzylite/src/imex/RScriptExporter.cpp b/fuzzylite/src/imex/RScriptExporter.cpp
new file mode 100644
index 0000000..5fe53c7
--- /dev/null
+++ b/fuzzylite/src/imex/RScriptExporter.cpp
@@ -0,0 +1,234 @@
+/*
+ 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 FuzzyLite License included with the software.
+
+ 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/RScriptExporter.h"
+
+#include "fl/Engine.h"
+#include "fl/imex/FllExporter.h"
+#include "fl/variable/InputVariable.h"
+#include "fl/variable/OutputVariable.h"
+
+#include <fstream>
+namespace fl {
+
+ RScriptExporter::RScriptExporter() : Exporter(),
+ _minimumColor("yellow"), _maximumColor("red"), _contourColor("black") { }
+
+ RScriptExporter::~RScriptExporter() { }
+
+ std::string RScriptExporter::name() const {
+ return "RScriptExporter";
+ }
+
+ void RScriptExporter::setMinimumColor(const std::string& minimumColor) {
+ this->_minimumColor = minimumColor;
+ }
+
+ std::string RScriptExporter::getMinimumColor() const {
+ return this->_minimumColor;
+ }
+
+ void RScriptExporter::setMaximumColor(const std::string& maximumColor) {
+ this->_maximumColor = maximumColor;
+ }
+
+ std::string RScriptExporter::getMaximumColor() const {
+ return _maximumColor;
+ }
+
+ void RScriptExporter::setContourColor(const std::string& contourColor) {
+ this->_contourColor = contourColor;
+ }
+
+ std::string RScriptExporter::getContourColor() const {
+ return this->_contourColor;
+ }
+
+ RScriptExporter* RScriptExporter::clone() const {
+ return new RScriptExporter(*this);
+ }
+
+ std::string RScriptExporter::toString(const Engine* engine) const {
+ if (engine->inputVariables().empty()) {
+ throw Exception("[exporter error] engine has no input variables to export the surface", FL_AT);
+ }
+ if (engine->outputVariables().empty()) {
+ throw Exception("[exporter error] engine has no output variables to export the surface", FL_AT);
+ }
+ InputVariable* a = engine->inputVariables().at(0);
+ InputVariable* b = engine->inputVariables().at(1 % engine->numberOfInputVariables());
+ return toString(const_cast<Engine*> (engine), a, b,
+ 1024, FldExporter::AllVariables, engine->outputVariables());
+ }
+
+ std::string RScriptExporter::toString(Engine* engine, InputVariable* a, InputVariable* b,
+ int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ostringstream writer;
+ writeScriptExportingDataFrame(engine, writer, a, b, values, scope, outputVariables);
+ return writer.str();
+ }
+
+ std::string RScriptExporter::toString(Engine* engine, InputVariable* a, InputVariable* b,
+ std::istream& reader, const std::vector<OutputVariable*>& outputVariables) const {
+ std::ostringstream writer;
+ writeScriptExportingDataFrame(engine, writer, a, b, reader, outputVariables);
+ return writer.str();
+ }
+
+ void RScriptExporter::toFile(const std::string& filePath, const Engine* engine) const {
+ if (engine->inputVariables().empty()) {
+ throw Exception("[exporter error] engine has no input variables to export the surface", FL_AT);
+ }
+ if (engine->outputVariables().empty()) {
+ throw Exception("[exporter error] engine has no output variables to export the surface", FL_AT);
+ }
+ InputVariable* a = engine->inputVariables().at(0);
+ InputVariable* b = engine->inputVariables().at(1 % engine->numberOfInputVariables());
+
+ toFile(filePath, const_cast<Engine*> (engine), a, b,
+ 1024, FldExporter::AllVariables, engine->outputVariables());
+ }
+
+ void RScriptExporter::toFile(const std::string& filePath, Engine* engine,
+ InputVariable* a, InputVariable* b, int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ofstream writer(filePath.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + filePath + "> could not be created", FL_AT);
+ }
+ writeScriptExportingDataFrame(engine, writer, a, b, values, scope, outputVariables);
+ writer.close();
+ }
+
+ void RScriptExporter::toFile(const std::string& filePath, Engine* engine,
+ InputVariable* a, InputVariable* b, std::istream& reader,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ofstream writer(filePath.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + filePath + "> could not be created", FL_AT);
+ }
+ writeScriptExportingDataFrame(engine, writer, a, b, reader, outputVariables);
+ writer.close();
+ }
+
+ void RScriptExporter::writeScriptImportingDataFrame(const Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, const std::string& dfPath,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ writeScriptHeader(writer, engine);
+
+ writer << "engine.fldFile = \"" << dfPath << "\"\n";
+ writer << "if (require(data.table)) {\n"
+ << " engine.df = data.table::fread(engine.fldFile, sep=\"auto\", header=\"auto\")\n"
+ << "} else {\n"
+ << " engine.df = read.table(engine.fldFile, header=TRUE)\n"
+ << "}\n";
+ writer << "\n";
+
+ writeScriptPlots(writer, a, b, outputVariables);
+ }
+
+ void RScriptExporter::writeScriptExportingDataFrame(Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, int values, FldExporter::ScopeOfValues scope,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ writeScriptHeader(writer, engine);
+
+ std::vector<InputVariable*> activeVariables = engine->inputVariables();
+ for (std::size_t i = 0; i < activeVariables.size(); ++i) {
+ if (activeVariables.at(i) != a and activeVariables.at(i) != b) {
+ activeVariables.at(i) = fl::null;
+ }
+ }
+ writer << "engine.fld = \"";
+ FldExporter().write(engine, writer, values, scope, activeVariables);
+ writer << "\"\n\n";
+ writer << "engine.df = read.delim(textConnection(engine.fld), header=TRUE, "
+ "sep=\" \", strip.white=TRUE)\n\n";
+
+ writeScriptPlots(writer, a, b, outputVariables);
+ }
+
+ void RScriptExporter::writeScriptExportingDataFrame(Engine* engine, std::ostream& writer,
+ InputVariable* a, InputVariable* b, std::istream& reader,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ writeScriptHeader(writer, engine);
+
+ writer << "engine.fld = \"";
+ FldExporter().write(engine, writer, reader);
+ writer << "\"\n\n";
+
+ writer << "engine.df = read.delim(textConnection(engine.fld), header=TRUE, "
+ "sep=\" \", strip.white=TRUE)\n\n";
+
+ writeScriptPlots(writer, a, b, outputVariables);
+ }
+
+ void RScriptExporter::writeScriptHeader(std::ostream& writer, const Engine* engine) const {
+ writer << "#Code automatically generated with " << fuzzylite::library() << ".\n\n"
+ << "library(ggplot2);\n"
+ << "\n";
+ writer << "engine.name = \"" << engine->getName() << "\"\n";
+ if (not engine->getDescription().empty())
+ writer << "engine.description = \"" << engine->getDescription() << "\"\n";
+ writer << "engine.fll = \"" << FllExporter().toString(engine) << "\"\n\n";
+ }
+
+ void RScriptExporter::writeScriptPlots(std::ostream& writer,
+ InputVariable* a, InputVariable* b,
+ const std::vector<OutputVariable*>& outputVariables) const {
+ std::ostringstream arrangeGrob;
+ arrangeGrob << "arrangeGrob(";
+ for (std::size_t i = 0; i < outputVariables.size(); ++i) {
+ OutputVariable* z = outputVariables.at(i);
+ if (a != b) {
+ writer << "engine.plot.i1i2_o" << (i + 1) << " = ggplot(engine.df, aes(" << a->getName() << ", " << b->getName() << ")) + \n"
+ << " geom_tile(aes(fill=" << z->getName() << ")) + \n"
+ << " scale_fill_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " stat_contour(aes(x=" << a->getName() << ", y=" << b->getName() << ", z=" << z->getName() << "), color=\"" << _contourColor << "\") + \n"
+ << " ggtitle(\"(" << a->getName() << ", " << b->getName() << ") = " << z->getName() << "\")\n\n";
+
+ writer << "engine.plot.i2i1_o" << (i + 1) << " = ggplot(engine.df, aes(" << b->getName() << ", " << a->getName() << ")) + \n"
+ << " geom_tile(aes(fill=" << z->getName() << ")) + \n"
+ << " scale_fill_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " stat_contour(aes(x=" << b->getName() << ", y=" << a->getName() << ", z=" << z->getName() << "), color=\"" << _contourColor << "\") + \n"
+ << " ggtitle(\"(" << b->getName() << ", " << a->getName() << ") = " << z->getName() << "\")\n\n";
+ arrangeGrob << "engine.plot.i1i2_o" << (i + 1) << ", " << "engine.plot.i2i1_o" << (i + 1) << ", ";
+ } else {
+ writer << "engine.plot.i1_o" << (i + 1) << " = ggplot(engine.df, aes(" << a->getName() << ", " << z->getName() << ")) + \n"
+ << " geom_line(aes(color=" << z->getName() << "), size=3, lineend=\"round\", linejoin=\"mitre\") + \n"
+ << " scale_color_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " ggtitle(\"" << a->getName() << " vs " << z->getName() << "\")\n\n";
+
+ writer << "engine.plot.o" << (i + 1) << "_i1 = ggplot(engine.df, aes(" << a->getName() << ", " << z->getName() << ")) + \n"
+ << " geom_line(aes(color=" << z->getName() << "), size=3, lineend=\"round\", linejoin=\"mitre\") + \n"
+ << " scale_color_gradient(low=\"" << _minimumColor << "\", high=\"" << _maximumColor << "\") + \n"
+ << " coord_flip() + \n"
+ << " ggtitle(\"" << z->getName() << " vs " << a->getName() << "\")\n\n";
+ arrangeGrob << "engine.plot.i1_o" << (i + 1) << ", " << "engine.plot.o" << (i + 1) << "_i1, ";
+ }
+
+ }
+ arrangeGrob << "ncol=2, top=engine.name)";
+ writer << "if (require(gridExtra)) {\n"
+ << " engine.plots = " << arrangeGrob.str() << "\n"
+ << " ggsave(paste0(engine.name, \".pdf\"), engine.plots)\n"
+ << " if (require(grid)) {\n"
+ << " grid.newpage()\n"
+ << " grid.draw(engine.plots)\n"
+ << " }\n"
+ << "}\n";
+ }
+}