summaryrefslogtreecommitdiff
path: root/fuzzylite/src/variable/OutputVariable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/variable/OutputVariable.cpp')
-rw-r--r--fuzzylite/src/variable/OutputVariable.cpp185
1 files changed, 108 insertions, 77 deletions
diff --git a/fuzzylite/src/variable/OutputVariable.cpp b/fuzzylite/src/variable/OutputVariable.cpp
index 6e1d906..0f85dc4 100644
--- a/fuzzylite/src/variable/OutputVariable.cpp
+++ b/fuzzylite/src/variable/OutputVariable.cpp
@@ -1,44 +1,31 @@
/*
- 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/variable/OutputVariable.h"
-#include "fl/defuzzifier/Defuzzifier.h"
#include "fl/imex/FllExporter.h"
-#include "fl/norm/SNorm.h"
-#include "fl/term/Accumulated.h"
-#include "fl/term/Activated.h"
namespace fl {
OutputVariable::OutputVariable(const std::string& name,
scalar minimum, scalar maximum)
: Variable(name, minimum, maximum),
- _fuzzyOutput(new Accumulated(name, minimum, maximum)), _outputValue(fl::nan),
- _previousOutputValue(fl::nan), _defaultValue(fl::nan),
- _lockOutputValueInRange(false), _lockPreviousOutputValue(false) {
- }
+ _fuzzyOutput(new Aggregated(name, minimum, maximum)),
+ _previousValue(fl::nan), _defaultValue(fl::nan),
+ _lockPreviousValue(false) { }
OutputVariable::OutputVariable(const OutputVariable& other) : Variable(other) {
copyFrom(other);
@@ -55,36 +42,33 @@ namespace fl {
return *this;
}
- OutputVariable::~OutputVariable() {
- }
+ OutputVariable::~OutputVariable() { }
void OutputVariable::copyFrom(const OutputVariable& other) {
_fuzzyOutput.reset(other._fuzzyOutput->clone());
if (other._defuzzifier.get()) _defuzzifier.reset(other._defuzzifier->clone());
- _outputValue = other._outputValue;
- _previousOutputValue = other._previousOutputValue;
+ _previousValue = other._previousValue;
_defaultValue = other._defaultValue;
- _lockOutputValueInRange = other._lockOutputValueInRange;
- _lockPreviousOutputValue = other._lockPreviousOutputValue;
+ _lockPreviousValue = other._lockPreviousValue;
}
void OutputVariable::setName(const std::string& name) {
Variable::setName(name);
- this->_fuzzyOutput->setName(name);
+ _fuzzyOutput->setName(name);
}
- Accumulated* OutputVariable::fuzzyOutput() const {
+ Aggregated* OutputVariable::fuzzyOutput() const {
return this->_fuzzyOutput.get();
}
void OutputVariable::setMinimum(scalar minimum) {
Variable::setMinimum(minimum);
- this->_fuzzyOutput->setMinimum(minimum);
+ _fuzzyOutput->setMinimum(minimum);
}
void OutputVariable::setMaximum(scalar maximum) {
Variable::setMaximum(maximum);
- this->_fuzzyOutput->setMaximum(maximum);
+ _fuzzyOutput->setMaximum(maximum);
}
void OutputVariable::setDefuzzifier(Defuzzifier* defuzzifier) {
@@ -95,20 +79,20 @@ namespace fl {
return this->_defuzzifier.get();
}
- void OutputVariable::setOutputValue(scalar outputValue) {
- this->_outputValue = outputValue;
+ void OutputVariable::setAggregation(SNorm* aggregation) {
+ this->_fuzzyOutput->setAggregation(aggregation);
}
- scalar OutputVariable::getOutputValue() const {
- return this->_outputValue;
+ SNorm* OutputVariable::getAggregation() const {
+ return this->_fuzzyOutput->getAggregation();
}
- void OutputVariable::setPreviousOutputValue(scalar previousOutputValue) {
- this->_previousOutputValue = previousOutputValue;
+ void OutputVariable::setPreviousValue(scalar previousOutputValue) {
+ this->_previousValue = previousOutputValue;
}
- scalar OutputVariable::getPreviousOutputValue() const {
- return this->_previousOutputValue;
+ scalar OutputVariable::getPreviousValue() const {
+ return this->_previousValue;
}
void OutputVariable::setDefaultValue(scalar defaultValue) {
@@ -119,77 +103,124 @@ namespace fl {
return this->_defaultValue;
}
- void OutputVariable::setLockOutputValueInRange(bool lockOutputValueInRange) {
- this->_lockOutputValueInRange = lockOutputValueInRange;
+ void OutputVariable::setLockPreviousValue(bool lockPreviousValue) {
+ this->_lockPreviousValue = lockPreviousValue;
}
- bool OutputVariable::isLockedOutputValueInRange() const {
- return this->_lockOutputValueInRange;
+ bool OutputVariable::isLockPreviousValue() const {
+ return this->_lockPreviousValue;
}
- void OutputVariable::setLockPreviousOutputValue(bool lockPreviousOutputValue) {
- this->_lockPreviousOutputValue = lockPreviousOutputValue;
+ Variable::Type OutputVariable::type() const {
+ return Variable::Output;
+ }
+
+ Complexity OutputVariable::complexity(const Activated& term) const {
+ Aggregated aggregated;
+ if (_fuzzyOutput->getAggregation()) {
+ aggregated.setAggregation(_fuzzyOutput->getAggregation()->clone());
+ }
+ aggregated.addTerm(term);
+ if (_defuzzifier.get()) {
+ return _defuzzifier->complexity(&aggregated);
+ }
+ return aggregated.complexityOfMembership();
+ }
+
+ Complexity OutputVariable::complexityOfDefuzzification() const {
+ Aggregated term;
+ for (std::size_t i = 0; i < _terms.size(); ++i) {
+ term.addTerm(_terms.at(i), fl::nan, fl::null);
+ }
+ if (_defuzzifier.get()) {
+ return _defuzzifier->complexity(&term);
+ }
+ return term.complexityOfMembership();
}
- bool OutputVariable::isLockedPreviousOutputValue() const {
- return this->_lockPreviousOutputValue;
+ Complexity OutputVariable::currentComplexity() const {
+ if (_defuzzifier.get())
+ return _defuzzifier->complexity(_fuzzyOutput.get());
+ return _fuzzyOutput->complexity();
}
void OutputVariable::defuzzify() {
- if (fl::Op::isFinite(this->_outputValue)) {
- this->_previousOutputValue = this->_outputValue;
+ if (not _enabled) return;
+
+ if (Op::isFinite(_value)) {
+ _previousValue = _value;
}
+ std::string exception;
scalar result = fl::nan;
- bool isValid = this->_enabled and not this->_fuzzyOutput->isEmpty();
+ bool isValid = not _fuzzyOutput->isEmpty();
if (isValid) {
- if (not _defuzzifier.get()) {
- throw fl::Exception("[defuzzifier error] "
- "defuzzifier needed to defuzzify output variable <" + _name + ">", FL_AT);
+ /* Checks whether the variable can be defuzzified without exceptions.
+ * If it cannot be defuzzified, be that due to a missing defuzzifier
+ * or aggregation operator, the expected behaviour is to leave the
+ * variable in a state that reflects an invalid defuzzification,
+ * that is, apply logic of default values and previous values.*/
+ isValid = false;
+ if (_defuzzifier.get()) {
+ try {
+ result = _defuzzifier->defuzzify(_fuzzyOutput.get(), _minimum, _maximum);
+ isValid = true;
+ } catch (std::exception& ex) {
+ exception = ex.what();
+ }
+ } else {
+ exception = "[defuzzifier error] "
+ "defuzzifier needed to defuzzify output variable <" + getName() + ">";
}
- result = this->_defuzzifier->defuzzify(this->_fuzzyOutput.get(), _minimum, _maximum);
- } else {
+ }
+
+ if (not isValid) {
//if a previous defuzzification was successfully performed and
//and the output value is supposed not to change when the output is empty
- if (_lockPreviousOutputValue and not Op::isNaN(_previousOutputValue)) {
- result = _previousOutputValue;
+ if (_lockPreviousValue and not Op::isNaN(_previousValue)) {
+ result = _previousValue;
} else {
result = _defaultValue;
}
}
- if (_lockOutputValueInRange) {
- result = fl::Op::bound(result, _minimum, _maximum);
- }
+ setValue(result);
- this->_outputValue = result;
+ if (not exception.empty()) {
+ throw Exception(exception, FL_AT);
+ }
}
std::string OutputVariable::fuzzyOutputValue() const {
std::ostringstream ss;
- for (std::size_t i = 0; i < _terms.size(); ++i) {
- scalar degree = _fuzzyOutput->activationDegree(_terms.at(i));
- if (i == 0) {
- ss << fl::Op::str(degree);
- } else {
- if (fl::Op::isNaN(degree) or fl::Op::isGE(degree, 0.0))
- ss << " + " << fl::Op::str(degree);
- else
- ss << " - " << fl::Op::str(std::fabs(degree));
- }
- ss << "/" << _terms.at(i)->getName();
+ if (not _terms.empty()) {
+ Term* first = _terms.front();
+ ss << Op::str(fuzzyOutput()->activationDegree(first))
+ << "/" << first->getName();
+ }
+ for (std::size_t i = 1; i < _terms.size(); ++i) {
+ scalar degree = fuzzyOutput()->activationDegree(_terms.at(i));
+ if (Op::isNaN(degree) or Op::isGE(degree, 0.0))
+ ss << " + " << Op::str(degree);
+ else
+ ss << " - " << Op::str(std::abs(degree));
+ ss << "/" << terms().at(i)->getName();
}
return ss.str();
}
void OutputVariable::clear() {
- _fuzzyOutput->clear();
- setPreviousOutputValue(fl::nan);
- setOutputValue(fl::nan);
+ fuzzyOutput()->clear();
+ setValue(fl::nan);
+ setPreviousValue(fl::nan);
}
std::string OutputVariable::toString() const {
return FllExporter().toString(this);
}
+ OutputVariable* OutputVariable::clone() const {
+ return new OutputVariable(*this);
+ }
+
}