summaryrefslogtreecommitdiff
path: root/fuzzylite/src/rule/Antecedent.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/rule/Antecedent.cpp')
-rw-r--r--fuzzylite/src/rule/Antecedent.cpp293
1 files changed, 186 insertions, 107 deletions
diff --git a/fuzzylite/src/rule/Antecedent.cpp b/fuzzylite/src/rule/Antecedent.cpp
index aa18a68..5f0b0be 100644
--- a/fuzzylite/src/rule/Antecedent.cpp
+++ b/fuzzylite/src/rule/Antecedent.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/rule/Antecedent.h"
@@ -28,29 +20,21 @@
#include "fl/factory/HedgeFactory.h"
#include "fl/factory/FactoryManager.h"
#include "fl/hedge/Any.h"
-#include "fl/hedge/Hedge.h"
-#include "fl/norm/SNorm.h"
-#include "fl/norm/TNorm.h"
#include "fl/rule/Expression.h"
#include "fl/rule/Rule.h"
-#include "fl/term/Accumulated.h"
-#include "fl/term/Function.h"
-#include "fl/term/Term.h"
+#include "fl/term/Aggregated.h"
#include "fl/variable/InputVariable.h"
#include "fl/variable/OutputVariable.h"
-#include <algorithm>
#include <stack>
-
namespace fl {
Antecedent::Antecedent()
- : _text(""), _expression(fl::null) {
- }
+ : _text(""), _expression(fl::null) { }
Antecedent::~Antecedent() {
- unload();
+ _expression.reset(fl::null);
}
void Antecedent::setText(const std::string& text) {
@@ -62,24 +46,29 @@ namespace fl {
}
Expression* Antecedent::getExpression() const {
- return this->_expression;
+ return this->_expression.get();
+ }
+
+ void Antecedent::setExpression(Expression* expression) {
+ this->_expression.reset(expression);
}
bool Antecedent::isLoaded() const {
- return this->_expression != fl::null;
+ return _expression.get() != fl::null;
}
scalar Antecedent::activationDegree(const TNorm* conjunction, const SNorm* disjunction) const {
- return this->activationDegree(conjunction, disjunction, this->_expression);
+ return this->activationDegree(conjunction, disjunction, _expression.get());
}
scalar Antecedent::activationDegree(const TNorm* conjunction, const SNorm* disjunction,
const Expression* node) const {
if (not isLoaded()) {
- throw fl::Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ throw Exception("[antecedent error] antecedent <" + getText() + "> is not loaded", FL_AT);
}
- const Proposition* proposition = dynamic_cast<const Proposition*> (node);
- if (proposition) {
+ const Expression::Type expression = node->type();
+ if (expression == Expression::Proposition) {
+ const Proposition* proposition = static_cast<const Proposition*> (node);
if (not proposition->variable->isEnabled()) {
return 0.0;
}
@@ -96,62 +85,147 @@ namespace fl {
}
}
scalar result = fl::nan;
- if (InputVariable * inputVariable = dynamic_cast<InputVariable*> (proposition->variable)) {
- result = proposition->term->membership(inputVariable->getInputValue());
- } else if (OutputVariable * outputVariable = dynamic_cast<OutputVariable*> (proposition->variable)) {
- result = outputVariable->fuzzyOutput()->activationDegree(proposition->term);
+ Variable::Type variableType = proposition->variable->type();
+ if (variableType == Variable::Input) {
+ result = proposition->term->membership(proposition->variable->getValue());
+ } else if (variableType == Variable::Output) {
+ result = static_cast<OutputVariable*> (proposition->variable)
+ ->fuzzyOutput()->activationDegree(proposition->term);
}
- for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
- rit != proposition->hedges.rend(); ++rit) {
- result = (*rit)->hedge(result);
+
+ if (not proposition->hedges.empty()) {
+ for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ rit != proposition->hedges.rend(); ++rit) {
+ result = (*rit)->hedge(result);
+ }
}
return result;
}
//if node is an operator
- const Operator* fuzzyOperator = dynamic_cast<const Operator*> (node);
- if (not (fuzzyOperator->left and fuzzyOperator->right)) {
+ if (expression == Expression::Operator) {
+ const Operator* fuzzyOperator = static_cast<const Operator*> (node);
+ if (not (fuzzyOperator->left and fuzzyOperator->right)) {
+ std::ostringstream ex;
+ ex << "[syntax error] left and right operands must exist";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (fuzzyOperator->name == Rule::andKeyword()) {
+ if (not conjunction) throw Exception("[conjunction error] "
+ "the following rule requires a conjunction operator:\n" + _text, FL_AT);
+ return conjunction->compute(
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->left),
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->right));
+ }
+
+ if (fuzzyOperator->name == Rule::orKeyword()) {
+ if (not disjunction) throw Exception("[disjunction error] "
+ "the following rule requires a disjunction operator:\n" + _text, FL_AT);
+ return disjunction->compute(
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->left),
+ this->activationDegree(conjunction, disjunction, fuzzyOperator->right));
+ }
std::ostringstream ex;
- ex << "[syntax error] left and right operands must exist";
- throw fl::Exception(ex.str(), FL_AT);
+ ex << "[syntax error] operator <" << fuzzyOperator->name << "> not recognized";
+ throw Exception(ex.str(), FL_AT);
+
+ } else {
+ std::ostringstream ss;
+ ss << "[antecedent error] expected a Proposition or Operator, but found <";
+ if (node) ss << node->toString();
+ ss << ">";
+ throw Exception(ss.str(), FL_AT);
}
- if (fuzzyOperator->name == Rule::andKeyword()) {
- if (not conjunction) throw fl::Exception("[conjunction error] "
- "the following rule requires a conjunction operator:\n" + _text, FL_AT);
- return conjunction->compute(
- this->activationDegree(conjunction, disjunction, fuzzyOperator->left),
- this->activationDegree(conjunction, disjunction, fuzzyOperator->right));
+ }
+
+
+ Complexity Antecedent::complexity(const TNorm* conjunction, const SNorm* disjunction) const {
+ return complexity(conjunction, disjunction, _expression.get());
+ }
+
+ Complexity Antecedent::complexity(const TNorm* conjunction, const SNorm* disjunction,
+ const Expression* node) const {
+ if (not isLoaded()) {
+ return Complexity();
}
- if (fuzzyOperator->name == Rule::orKeyword()) {
- if (not disjunction) throw fl::Exception("[disjunction error] "
- "the following rule requires a disjunction operator:\n" + _text, FL_AT);
- return disjunction->compute(
- this->activationDegree(conjunction, disjunction, fuzzyOperator->left),
- this->activationDegree(conjunction, disjunction, fuzzyOperator->right));
+ Complexity result;
+ const Expression::Type expression = node->type();
+ if (expression == Expression::Proposition) {
+ const Proposition* proposition = static_cast<const Proposition*> (node);
+ if (not proposition->variable->isEnabled()) {
+ return result;
+ }
+
+ if (not proposition->hedges.empty()) {
+ //if last hedge is "Any", apply hedges in reverse order and return degree
+ std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ if (dynamic_cast<Any*> (*rit)) {
+ result += (*rit)->complexity();
+ while (++rit != proposition->hedges.rend()) {
+ result = (*rit)->complexity();
+ }
+ return result;
+ }
+ }
+ Variable::Type variableType = proposition->variable->type();
+ if (variableType == Variable::Input) {
+ result += proposition->term->complexity();
+ } else if (variableType == Variable::Output) {
+ OutputVariable* outputVariable = static_cast<OutputVariable*> (proposition->variable);
+ result += outputVariable->fuzzyOutput()->complexityOfActivationDegree();
+ }
+
+ if (not proposition->hedges.empty()) {
+ for (std::vector<Hedge*>::const_reverse_iterator rit = proposition->hedges.rbegin();
+ rit != proposition->hedges.rend(); ++rit) {
+ result += (*rit)->complexity();
+ }
+ }
+ return result;
}
- std::ostringstream ex;
- ex << "[syntax error] operator <" << fuzzyOperator->name << "> not recognized";
- throw fl::Exception(ex.str(), FL_AT);
+ //if node is an operator
+ if (expression == Expression::Operator) {
+ const Operator* fuzzyOperator = static_cast<const Operator*> (node);
+ if (not (fuzzyOperator->left and fuzzyOperator->right)) {
+ std::ostringstream ex;
+ ex << "[syntax error] left and right operands must exist";
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (fuzzyOperator->name == Rule::andKeyword()) {
+ if (conjunction) {
+ result += conjunction->complexity();
+ }
+ result += complexity(conjunction, disjunction, fuzzyOperator->left)
+ + complexity(conjunction, disjunction, fuzzyOperator->right);
+ return result;
+ }
+ if (fuzzyOperator->name == Rule::orKeyword()) {
+ if (disjunction) {
+ result += disjunction->complexity();
+ }
+ result += complexity(conjunction, disjunction, fuzzyOperator->left)
+ + complexity(conjunction, disjunction, fuzzyOperator->right);
+ return result;
+ }
+ }
+ return Complexity();
}
void Antecedent::unload() {
- if (_expression) {
- delete _expression;
- _expression = fl::null;
- }
+ _expression.reset(fl::null);
}
- void Antecedent::load(fl::Rule* rule, const Engine* engine) {
- load(_text, rule, engine);
+ void Antecedent::load(const Engine* engine) {
+ load(getText(), engine);
}
- void Antecedent::load(const std::string& antecedent, fl::Rule* rule, const Engine* engine) {
+ void Antecedent::load(const std::string& antecedent, const Engine* engine) {
FL_DBG("Antecedent: " << antecedent);
unload();
- this->_text = antecedent;
- if (fl::Op::trim(antecedent).empty()) {
- throw fl::Exception("[syntax error] antecedent is empty", FL_AT);
+ setText(antecedent);
+ if (Op::trim(antecedent).empty()) {
+ throw Exception("[syntax error] antecedent is empty", FL_AT);
}
/*
Builds an proposition tree from the antecedent of a fuzzy rule.
@@ -179,8 +253,10 @@ namespace fl {
while (tokenizer >> token) {
if (state bitand S_VARIABLE) {
Variable* variable = fl::null;
- if (engine->hasInputVariable(token)) variable = engine->getInputVariable(token);
- else if (engine->hasOutputVariable(token)) variable = engine->getOutputVariable(token);
+ if (engine->hasInputVariable(token))
+ variable = engine->getInputVariable(token);
+ else if (engine->hasOutputVariable(token))
+ variable = engine->getOutputVariable(token);
if (variable) {
proposition = new Proposition;
proposition->variable = variable;
@@ -201,15 +277,9 @@ namespace fl {
}
if (state bitand S_HEDGE) {
- Hedge* hedge = rule->getHedge(token);
- if (not hedge) {
- HedgeFactory* factory = FactoryManager::instance()->hedge();
- if (factory->hasConstructor(token)) {
- hedge = factory->constructObject(token);
- rule->addHedge(hedge);
- }
- }
- if (hedge) {
+ HedgeFactory* factory = FactoryManager::instance()->hedge();
+ if (factory->hasConstructor(token)) {
+ Hedge* hedge = factory->constructObject(token);
proposition->hedges.push_back(hedge);
if (dynamic_cast<Any*> (hedge)) {
state = S_VARIABLE bitor S_AND_OR;
@@ -236,7 +306,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] logical operator <" << token << "> expects two operands,"
<< "but found <" << expressionStack.size() << "> in antecedent";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
Operator* fuzzyOperator = new Operator;
fuzzyOperator->name = token;
@@ -258,33 +328,33 @@ namespace fl {
if ((state bitand S_VARIABLE) or (state bitand S_AND_OR)) {
std::ostringstream ex;
ex << "[syntax error] antecedent expected variable or logical operator, but found <" << token << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
if (state bitand S_IS) {
std::ostringstream ex;
ex << "[syntax error] antecedent expected keyword <" << Rule::isKeyword() << ">, but found <" << token << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
if ((state bitand S_HEDGE) or (state bitand S_TERM)) {
std::ostringstream ex;
ex << "[syntax error] antecedent expected hedge or term, but found <" << token << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
std::ostringstream ex;
ex << "[syntax error] unexpected token <" << token << "> in antecedent";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
if (not ((state bitand S_VARIABLE) or (state bitand S_AND_OR))) { //only acceptable final state
if (state bitand S_IS) {
std::ostringstream ex;
ex << "[syntax error] antecedent expected keyword <" << Rule::isKeyword() << "> after <" << token << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
if ((state bitand S_HEDGE) or (state bitand S_TERM)) {
std::ostringstream ex;
ex << "[syntax error] antecedent expected hedge or term after <" << token << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
}
@@ -299,7 +369,7 @@ namespace fl {
std::ostringstream ex;
ex << "[syntax error] unable to parse the following expressions in antecedent <"
<< Op::join(errors, " ") << ">";
- throw fl::Exception(ex.str(), FL_AT);
+ throw Exception(ex.str(), FL_AT);
}
} catch (...) {
for (std::size_t i = 0; i < expressionStack.size(); ++i) {
@@ -308,59 +378,68 @@ namespace fl {
}
throw;
}
- this->_expression = expressionStack.top();
+ setExpression(expressionStack.top());
}
std::string Antecedent::toString() const {
- return toInfix(this->_expression);
+ return toInfix(getExpression());
}
std::string Antecedent::toPrefix(const Expression* node) const {
if (not isLoaded()) {
- throw fl::Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ throw Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
}
- if (not node) node = this->_expression;
+ if (not node) node = getExpression();
if (dynamic_cast<const Proposition*> (node)) {
return node->toString();
}
- const Operator* fuzzyOperator = dynamic_cast<const Operator*> (node);
std::stringstream ss;
- ss << fuzzyOperator->toString() << " "
- << toPrefix(fuzzyOperator->left) << " "
- << toPrefix(fuzzyOperator->right) << " ";
+ if (const Operator * fuzzyOperator = dynamic_cast<const Operator*> (node)) {
+ ss << fuzzyOperator->toString() << " "
+ << toPrefix(fuzzyOperator->left) << " "
+ << toPrefix(fuzzyOperator->right) << " ";
+ } else {
+ ss << "[antecedent error] unknown class of Expression <" << (node ? node->toString() : "null") << ">";
+ }
return ss.str();
}
std::string Antecedent::toInfix(const Expression* node) const {
if (not isLoaded()) {
- throw fl::Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ throw Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
}
- if (not node) node = this->_expression;
+ if (not node) node = getExpression();
if (dynamic_cast<const Proposition*> (node)) {
return node->toString();
}
- const Operator* fuzzyOperator = dynamic_cast<const Operator*> (node);
std::stringstream ss;
- ss << toInfix(fuzzyOperator->left) << " "
- << fuzzyOperator->toString() << " "
- << toInfix(fuzzyOperator->right) << " ";
+ if (const Operator * fuzzyOperator = dynamic_cast<const Operator*> (node)) {
+ ss << toInfix(fuzzyOperator->left) << " "
+ << fuzzyOperator->toString() << " "
+ << toInfix(fuzzyOperator->right) << " ";
+ } else {
+ ss << "[antecedent error] unknown class of Expression <" << (node ? node->toString() : "null") << ">";
+ }
return ss.str();
}
std::string Antecedent::toPostfix(const Expression* node) const {
if (not isLoaded()) {
- throw fl::Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
+ throw Exception("[antecedent error] antecedent <" + _text + "> is not loaded", FL_AT);
}
- if (not node) node = this->_expression;
+ if (not node) node = getExpression();
if (dynamic_cast<const Proposition*> (node)) {
return node->toString();
}
- const Operator* fuzzyOperator = dynamic_cast<const Operator*> (node);
std::stringstream ss;
- ss << toPostfix(fuzzyOperator->left) << " "
- << toPostfix(fuzzyOperator->right) << " "
- << fuzzyOperator->toString() << " ";
+ if (const Operator * fuzzyOperator = dynamic_cast<const Operator*> (node)) {
+ ss << toPostfix(fuzzyOperator->left) << " "
+ << toPostfix(fuzzyOperator->right) << " "
+ << fuzzyOperator->toString() << " ";
+ } else {
+ ss << "[antecedent error] unknown class of Expression <" << (node ? node->toString() : "null") << ">";
+ }
return ss.str();
}