diff options
Diffstat (limited to 'fuzzylite/src/term')
25 files changed, 1157 insertions, 1048 deletions
diff --git a/fuzzylite/src/term/Accumulated.cpp b/fuzzylite/src/term/Accumulated.cpp deleted file mode 100644 index 979af9f..0000000 --- a/fuzzylite/src/term/Accumulated.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - Author: Juan Rada-Vilela, Ph.D. - Copyright (C) 2010-2014 FuzzyLite Limited - All rights reserved - - 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. - - 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. - - */ - -#include "fl/term/Accumulated.h" - -#include "fl/imex/FllExporter.h" -#include "fl/norm/SNorm.h" -#include "fl/norm/s/Maximum.h" -#include "fl/term/Activated.h" - - -namespace fl { - - Accumulated::Accumulated(const std::string& name, scalar minimum, scalar maximum, - SNorm* accumulation) - : Term(name), _minimum(minimum), _maximum(maximum), _accumulation(accumulation) { - } - - Accumulated::Accumulated(const Accumulated& other) : Term(other) { - copyFrom(other); - } - - Accumulated& Accumulated::operator=(const Accumulated& other) { - if (this != &other) { - clear(); - _accumulation.reset(fl::null); - - Term::operator=(other); - copyFrom(other); - } - return *this; - } - - Accumulated::~Accumulated() { - clear(); - } - - void Accumulated::copyFrom(const Accumulated& source) { - _minimum = source._minimum; - _maximum = source._maximum; - - if (source._accumulation.get()) - _accumulation.reset(source._accumulation->clone()); - - for (std::size_t i = 0; i < source._terms.size(); ++i) { - _terms.push_back(source._terms.at(i)->clone()); - } - } - - std::string Accumulated::className() const { - return "Accumulated"; - } - - scalar Accumulated::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - if (not (_terms.empty() or _accumulation.get())) { //Exception for IntegralDefuzzifiers - throw fl::Exception("[accumulation error] " - "accumulation operator needed to accumulate " + toString(), FL_AT); - } - scalar mu = 0.0; - for (std::size_t i = 0; i < _terms.size(); ++i) { - mu = _accumulation->compute(mu, _terms.at(i)->membership(x)); - } - return mu; - } - - scalar Accumulated::activationDegree(const Term* forTerm) const { - scalar result = 0.0; - for (std::size_t i = 0; i < _terms.size(); ++i) { - Activated* activatedTerm = _terms.at(i); - if (activatedTerm->getTerm() == forTerm) { - if (_accumulation.get()) result = _accumulation->compute(result, activatedTerm->getDegree()); - else result += activatedTerm->getDegree(); //Default for WeightDefuzzifier - } - } - return result; - } - - std::string Accumulated::parameters() const { - FllExporter exporter; - std::ostringstream ss; - ss << exporter.toString(_accumulation.get()); - ss << " " << Op::str(_minimum) << " " << Op::str(_maximum) << " "; - for (std::size_t i = 0; i < _terms.size(); ++i) { - ss << " " << exporter.toString(_terms.at(i)); - } - return ss.str(); - } - - void Accumulated::configure(const std::string& parameters) { - (void) parameters; - } - - Accumulated* Accumulated::clone() const { - return new Accumulated(*this); - } - - std::string Accumulated::toString() const { - std::vector<std::string> accumulate; - for (std::size_t i = 0; i < _terms.size(); ++i) { - accumulate.push_back(_terms.at(i)->toString()); - } - FllExporter exporter; - std::ostringstream ss; - ss << _name << ": " << className() << " " - << exporter.toString(_accumulation.get()) << "[" - << fl::Op::join(accumulate, ",") << "]"; - return ss.str(); - } - - void Accumulated::setMinimum(scalar minimum) { - this->_minimum = minimum; - } - - scalar Accumulated::getMinimum() const { - return this->_minimum; - } - - void Accumulated::setMaximum(scalar maximum) { - this->_maximum = maximum; - } - - scalar Accumulated::getMaximum() const { - return this->_maximum; - } - - void Accumulated::setRange(scalar minimum, scalar maximum) { - setMinimum(minimum); - setMaximum(maximum); - } - - scalar Accumulated::range() const { - return this->_maximum - this->_minimum; - } - - void Accumulated::setAccumulation(SNorm* accumulation) { - this->_accumulation.reset(accumulation); - } - - SNorm* Accumulated::getAccumulation() const { - return this->_accumulation.get(); - } - - /** - * Operations for std::vector _terms - */ - - - void Accumulated::addTerm(const Term* term, scalar degree, const TNorm* activation) { - this->_terms.push_back(new Activated(term, degree, activation)); - } - - void Accumulated::addTerm(Activated* term) { - this->_terms.push_back(term); - } - - Activated* Accumulated::removeTerm(int index) { - Activated* term = this->_terms.at(index); - this->_terms.erase(this->_terms.begin() + index); - return term; - } - - void Accumulated::clear() { - for (std::size_t i = 0; i < _terms.size(); ++i) { - delete _terms.at(i); - } - _terms.clear(); - } - - Activated* Accumulated::getTerm(int index) const { - return this->_terms.at(index); - } - - const std::vector<Activated*>& Accumulated::terms() const { - return this->_terms; - } - - std::vector<Activated*>& Accumulated::terms() { - return this->_terms; - } - - int Accumulated::numberOfTerms() const { - return _terms.size(); - } - - bool Accumulated::isEmpty() const { - return _terms.empty(); - } - -} diff --git a/fuzzylite/src/term/Activated.cpp b/fuzzylite/src/term/Activated.cpp index 9a27b4b..80eda6c 100644 --- a/fuzzylite/src/term/Activated.cpp +++ b/fuzzylite/src/term/Activated.cpp @@ -1,71 +1,81 @@ /* - 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/term/Activated.h" #include "fl/imex/FllExporter.h" -#include "fl/norm/TNorm.h" namespace fl { - Activated::Activated(const Term* term, scalar degree, const TNorm* activation) - : Term(""), _term(term), _degree(degree), _activation(activation) { - if (term) this->_name = term->getName(); + Activated::Activated(const Term* term, scalar degree, const TNorm* implication) + : Term(""), _term(term), _degree(degree), _implication(implication) { + if (term) setName(term->getName()); } - Activated::~Activated() { - } + Activated::~Activated() { } std::string Activated::className() const { return "Activated"; } + Complexity Activated::complexity() const { + Complexity result; + result.comparison(3); + if (_implication) { + result += _implication->complexity(); + } + if (_term) { + result += _term->complexity(); + } + return result; + } + scalar Activated::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - if (not _activation) throw fl::Exception("[activation error] " - "activation operator needed to activate " + _term->toString(), FL_AT); - return _activation->compute(this->_term->membership(x), _degree); + if (Op::isNaN(x)) return fl::nan; + if (not _term) + throw Exception("[activation error] no term available to activate", FL_AT); + if (not _implication) + throw Exception("[implication error] implication operator needed " + "to activate " + getTerm()->toString(), FL_AT); + return _implication->compute(_term->membership(x), _degree); } std::string Activated::parameters() const { FllExporter exporter; std::ostringstream ss; - ss << Op::str(_degree) << " " << exporter.toString(_activation) << " " - << exporter.toString(_term); + ss << Op::str(getDegree()) << " " << exporter.toString(getImplication()) << " " + << exporter.toString(getTerm()); return ss.str(); } void Activated::configure(const std::string& parameters) { - (void) parameters; + FL_IUNUSED(parameters); } std::string Activated::toString() const { FllExporter exporter; std::ostringstream ss; - ss << exporter.toString(_activation) << "(" - << Op::str(_degree) << "," - << _term->getName() << ")"; + if (getImplication()) { + ss << exporter.toString(getImplication()) << "(" + << Op::str(getDegree()) << "," + << getTerm()->getName() << ")"; + } else { + ss << "(" << Op::str(getDegree()) << "*" //"\u2297: (*)" + << getTerm()->getName() << ")"; + } return ss.str(); } @@ -85,12 +95,12 @@ namespace fl { return this->_degree; } - void Activated::setActivation(const TNorm* activation) { - this->_activation = activation; + void Activated::setImplication(const TNorm* implication) { + this->_implication = implication; } - const TNorm* Activated::getActivation() const { - return this->_activation; + const TNorm* Activated::getImplication() const { + return this->_implication; } Activated* Activated::clone() const { diff --git a/fuzzylite/src/term/Aggregated.cpp b/fuzzylite/src/term/Aggregated.cpp new file mode 100644 index 0000000..d1e2c89 --- /dev/null +++ b/fuzzylite/src/term/Aggregated.cpp @@ -0,0 +1,247 @@ +/* + 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/term/Aggregated.h" + +#include "fl/imex/FllExporter.h" +#include "fl/norm/s/Maximum.h" + +namespace fl { + + Aggregated::Aggregated(const std::string& name, scalar minimum, scalar maximum, + SNorm* aggregation) + : Term(name), _minimum(minimum), _maximum(maximum), _aggregation(aggregation) { } + + Aggregated::Aggregated(const Aggregated& other) : Term(other) { + copyFrom(other); + } + + Aggregated& Aggregated::operator=(const Aggregated& other) { + if (this != &other) { + clear(); + _aggregation.reset(fl::null); + + Term::operator=(other); + copyFrom(other); + } + return *this; + } + + Aggregated::~Aggregated() { } + + void Aggregated::copyFrom(const Aggregated& source) { + _minimum = source._minimum; + _maximum = source._maximum; + + if (source._aggregation.get()) + _aggregation.reset(source._aggregation->clone()); + + for (std::size_t i = 0; i < source._terms.size(); ++i) { + _terms.push_back(source._terms.at(i)); + } + } + + std::string Aggregated::className() const { + return "Aggregated"; + } + + Complexity Aggregated::complexity() const { + return complexityOfMembership(); + } + + Complexity Aggregated::complexityOfMembership() const { + Complexity result; + result.comparison(3); + if (_aggregation.get()) { + result += _aggregation->complexity().multiply(scalar(_terms.size())); + } + for (std::size_t i = 0; i < _terms.size(); ++i) { + result += _terms.at(i).complexity(); + } + return result; + } + + scalar Aggregated::membership(scalar x) const { + if (Op::isNaN(x)) return fl::nan; + if (not (_terms.empty() or _aggregation.get())) { //Exception for IntegralDefuzzifiers + throw Exception("[aggregation error] " + "aggregation operator needed to aggregate variable " + "<" + getName() + ">", FL_AT); + } + scalar mu = 0.0; + for (std::size_t i = 0; i < _terms.size(); ++i) { + mu = _aggregation->compute(mu, _terms.at(i).membership(x)); + } + return mu; + } + + Complexity Aggregated::complexityOfActivationDegree() const { + Complexity result; + result.comparison(2); + if (_aggregation.get()) { + result += _aggregation->complexity(); + } else result.arithmetic(1); + result.multiply(scalar(_terms.size())); + return result; + } + + scalar Aggregated::activationDegree(const Term* forTerm) const { + scalar result = 0.0; + for (std::size_t i = 0; i < _terms.size(); ++i) { + const Activated& activatedTerm = _terms.at(i); + if (activatedTerm.getTerm() == forTerm) { + if (_aggregation.get()) + result = _aggregation->compute(result, activatedTerm.getDegree()); + else + result += activatedTerm.getDegree(); //Default for WeightDefuzzifier + } + } + return result; + } + + const Activated* Aggregated::highestActivatedTerm() const { + const Activated* maximumTerm = fl::null; + scalar maximumActivation = -fl::inf; + for (std::size_t i = 0; i < _terms.size(); ++i) { + const Activated& activated = _terms.at(i); + if (Op::isGt(activated.getDegree(), maximumActivation)) { + maximumActivation = activated.getDegree(); + maximumTerm = &activated; + } + } + return maximumTerm; + } + + std::string Aggregated::parameters() const { + FllExporter exporter; + std::ostringstream ss; + ss << exporter.toString(getAggregation()); + ss << " " << Op::str(getMinimum()) << " " << Op::str(getMaximum()) << " "; + for (std::size_t i = 0; i < terms().size(); ++i) { + ss << " " << exporter.toString(&terms().at(i)); + } + return ss.str(); + } + + void Aggregated::configure(const std::string& parameters) { + FL_IUNUSED(parameters); + } + + Aggregated* Aggregated::clone() const { + return new Aggregated(*this); + } + + std::string Aggregated::toString() const { + std::vector<std::string> aggregate; + for (std::size_t i = 0; i < terms().size(); ++i) { + aggregate.push_back(terms().at(i).toString()); + } + FllExporter exporter; + std::ostringstream ss; + if (getAggregation()) { + ss << getName() << ": " << className() << " " + << exporter.toString(getAggregation()) << "[" + << Op::join(aggregate, ",") << "]"; + } else { + ss << getName() << ": " << className() << " " << "[" + << Op::join(aggregate, "+") << "]"; //\u2295: (+) + } + return ss.str(); + } + + void Aggregated::setMinimum(scalar minimum) { + this->_minimum = minimum; + } + + scalar Aggregated::getMinimum() const { + return this->_minimum; + } + + void Aggregated::setMaximum(scalar maximum) { + this->_maximum = maximum; + } + + scalar Aggregated::getMaximum() const { + return this->_maximum; + } + + void Aggregated::setRange(scalar minimum, scalar maximum) { + setMinimum(minimum); + setMaximum(maximum); + } + + scalar Aggregated::range() const { + return getMaximum() - getMinimum(); + } + + void Aggregated::setAggregation(SNorm* aggregation) { + this->_aggregation.reset(aggregation); + } + + SNorm* Aggregated::getAggregation() const { + return this->_aggregation.get(); + } + + /** + * Operations for std::vector _terms + */ + + + void Aggregated::addTerm(const Term* term, scalar degree, const TNorm* implication) { + _terms.push_back(Activated(term, degree, implication)); + FL_DBG("Aggregating " << _terms.back().toString()); + } + + void Aggregated::addTerm(const Activated& term) { + _terms.push_back(term); + FL_DBG("Aggregating " << _terms.back().toString()); + } + + const Activated& Aggregated::removeTerm(std::size_t index) { + const Activated& term = _terms.at(index); + _terms.erase(_terms.begin() + index); + return term; + } + + void Aggregated::clear() { + _terms.clear(); + } + + const Activated& Aggregated::getTerm(std::size_t index) const { + return _terms.at(index); + } + + void Aggregated::setTerms(const std::vector<Activated>& terms) { + this->_terms = terms; + } + + const std::vector<Activated>& Aggregated::terms() const { + return this->_terms; + } + + std::vector<Activated>& Aggregated::terms() { + return this->_terms; + } + + std::size_t Aggregated::numberOfTerms() const { + return _terms.size(); + } + + bool Aggregated::isEmpty() const { + return _terms.empty(); + } + +} diff --git a/fuzzylite/src/term/Bell.cpp b/fuzzylite/src/term/Bell.cpp index fc0b215..bd63753 100644 --- a/fuzzylite/src/term/Bell.cpp +++ b/fuzzylite/src/term/Bell.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/term/Bell.h" @@ -27,24 +19,26 @@ namespace fl { Bell::Bell(const std::string& name, scalar center, scalar width, scalar slope, scalar height) - : Term(name, height), _center(center), _width(width), _slope(slope) { - } + : Term(name, height), _center(center), _width(width), _slope(slope) { } - Bell::~Bell() { - } + Bell::~Bell() { } std::string Bell::className() const { return "Bell"; } + Complexity Bell::complexity() const { + return Complexity().comparison(1).arithmetic(6).function(2); + } + scalar Bell::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - return _height * (1.0 / (1.0 + std::pow(std::abs((x - _center) / _width), 2 * _slope))); + if (Op::isNaN(x)) return fl::nan; + return Term::_height * (1.0 / (1.0 + std::pow(std::abs((x - _center) / _width), 2.0 * _slope))); } std::string Bell::parameters() const { return Op::join(3, " ", _center, _width, _slope) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Bell::configure(const std::string& parameters) { @@ -55,7 +49,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setCenter(Op::toScalar(values.at(0))); setWidth(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/Binary.cpp b/fuzzylite/src/term/Binary.cpp new file mode 100644 index 0000000..368530b --- /dev/null +++ b/fuzzylite/src/term/Binary.cpp @@ -0,0 +1,96 @@ +/* + 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/term/Binary.h" + +namespace fl { + + Binary::Binary(const std::string& name, scalar start, scalar direction, scalar height) + : Term(name, height), _start(start), _direction(direction) { } + + Binary::~Binary() { } + + std::string Binary::className() const { + return "Binary"; + } + + Complexity Binary::complexity() const { + return Complexity().comparison(5).arithmetic(1); + } + + scalar Binary::membership(scalar x) const { + if (Op::isNaN(x)) return fl::nan; + if (_direction > _start and Op::isGE(x, _start)) { + return Term::_height * 1.0; + } + if (_direction < _start and Op::isLE(x, _start)) { + return Term::_height * 1.0; + } + return Term::_height * 0.0; + } + + std::string Binary::parameters() const { + return Op::join(2, " ", _start, _direction) + + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); + } + + void Binary::configure(const std::string& parameters) { + if (parameters.empty()) return; + std::vector<std::string> values = Op::split(parameters, " "); + std::size_t required = 2; + if (values.size() < required) { + std::ostringstream ex; + ex << "[configuration error] term <" << className() << ">" + << " requires <" << required << "> parameters"; + throw Exception(ex.str(), FL_AT); + } + setStart(Op::toScalar(values.at(0))); + setDirection(Op::toScalar(values.at(1))); + if (values.size() > required) + setHeight(Op::toScalar(values.at(required))); + } + + void Binary::setStart(scalar minimum) { + this->_start = minimum; + } + + scalar Binary::getStart() const { + return this->_start; + } + + void Binary::setDirection(scalar direction) { + this->_direction = direction; + } + + scalar Binary::getDirection() const { + return this->_direction; + } + + Binary::Direction Binary::direction() const { + if (this->_direction > _start) return Positive; + if (this->_direction < _start) return Negative; + return Undefined; + } + + Binary* Binary::clone() const { + return new Binary(*this); + } + + Term* Binary::constructor() { + return new Binary; + } + +} diff --git a/fuzzylite/src/term/Concave.cpp b/fuzzylite/src/term/Concave.cpp index 37679ae..c585edc 100644 --- a/fuzzylite/src/term/Concave.cpp +++ b/fuzzylite/src/term/Concave.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/term/Concave.h" @@ -27,35 +19,47 @@ namespace fl { Concave::Concave(const std::string& name, scalar inflection, scalar end, scalar height) - : Term(name, height), _inflection(inflection), _end(end) { - - } + : Term(name, height), _inflection(inflection), _end(end) { } - Concave::~Concave() { - - } + Concave::~Concave() { } std::string Concave::className() const { return "Concave"; } + Complexity Concave::complexity() const { + return Complexity().comparison(1 + 3).arithmetic(1 + 5); + } + scalar Concave::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - if (fl::Op::isLE(_inflection, _end)) { //Concave increasing - if (fl::Op::isLt(x, _end)) { - return _height * (_end - _inflection) / (2 * _end - _inflection - x); + if (Op::isNaN(x)) return fl::nan; + if (Op::isLE(_inflection, _end)) { //Concave increasing + if (Op::isLt(x, _end)) { + return Term::_height * (_end - _inflection) / (2.0 * _end - _inflection - x); } } else { //Concave decreasing - if (fl::Op::isGt(x, _end)) { - return _height * (_inflection - _end) / (_inflection - 2 * _end + x); + if (Op::isGt(x, _end)) { + return Term::_height * (_inflection - _end) / (_inflection - 2.0 * _end + x); } } - return _height * 1.0; + return Term::_height * 1.0; + } + + scalar Concave::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const { + FL_IUNUSED(minimum); + FL_IUNUSED(maximum); + scalar i = _inflection; + scalar e = _end; + return (i - e) / membership(activationDegree) + 2 * e - i; + } + + bool Concave::isMonotonic() const { + return true; } std::string Concave::parameters() const { return Op::join(2, " ", _inflection, _end) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } @@ -67,7 +71,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setInflection(Op::toScalar(values.at(0))); setEnd(Op::toScalar(values.at(1))); @@ -100,8 +104,4 @@ namespace fl { return new Concave; } - - - - } diff --git a/fuzzylite/src/term/Constant.cpp b/fuzzylite/src/term/Constant.cpp index d52f8ec..7c0422e 100644 --- a/fuzzylite/src/term/Constant.cpp +++ b/fuzzylite/src/term/Constant.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/term/Constant.h" @@ -27,18 +19,20 @@ namespace fl { Constant::Constant(const std::string& name, scalar value) - : Term(name), _value(value) { - } + : Term(name), _value(value) { } - Constant::~Constant() { - } + Constant::~Constant() { } std::string Constant::className() const { return "Constant"; } + Complexity Constant::complexity() const { + return Complexity(); + } + scalar Constant::membership(scalar x) const { - (void) x; + FL_IUNUSED(x); return this->_value; } diff --git a/fuzzylite/src/term/Cosine.cpp b/fuzzylite/src/term/Cosine.cpp index a1402ad..78162ea 100644 --- a/fuzzylite/src/term/Cosine.cpp +++ b/fuzzylite/src/term/Cosine.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/term/Cosine.h" @@ -27,13 +19,9 @@ namespace fl { Cosine::Cosine(const std::string& name, scalar center, scalar width, scalar height) - : Term(name, height), _center(center), _width(width) { + : Term(name, height), _center(center), _width(width) { } - } - - Cosine::~Cosine() { - - } + Cosine::~Cosine() { } std::string Cosine::className() const { return "Cosine"; @@ -41,7 +29,7 @@ namespace fl { std::string Cosine::parameters() const { return Op::join(2, " ", _center, _width) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Cosine::configure(const std::string& parameters) { @@ -52,7 +40,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setCenter(Op::toScalar(values.at(0))); setWidth(Op::toScalar(values.at(1))); @@ -61,13 +49,17 @@ namespace fl { } + Complexity Cosine::complexity() const { + return Complexity().comparison(3).arithmetic(4 + 1 + 7).function(2); + } + scalar Cosine::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - if (fl::Op::isLt(x, _center - _width / 2.0) - or fl::Op::isGt(x, _center + _width / 2.0)) - return _height * 0.0; + if (Op::isNaN(x)) return fl::nan; + if (Op::isLt(x, _center - 0.5 * _width) + or Op::isGt(x, _center + 0.5 * _width)) + return Term::_height * 0.0; const scalar pi = 4.0 * std::atan(1.0); - return _height * (0.5 * (1.0 + std::cos(2.0 / _width * pi * (x - _center)))); + return Term::_height * (0.5 * (1.0 + std::cos(2.0 / _width * pi * (x - _center)))); } void Cosine::setCenter(scalar center) { @@ -93,4 +85,5 @@ namespace fl { Term* Cosine::constructor() { return new Cosine; } + } diff --git a/fuzzylite/src/term/Discrete.cpp b/fuzzylite/src/term/Discrete.cpp index 212ada2..9951867 100644 --- a/fuzzylite/src/term/Discrete.cpp +++ b/fuzzylite/src/term/Discrete.cpp @@ -1,88 +1,89 @@ /* - 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/term/Discrete.h" -#include <cstdarg> - namespace fl { Discrete::Discrete(const std::string& name, const std::vector<Pair>& xy, scalar height) - : Term(name, height), _xy(xy) { - } + : Term(name, height), _xy(xy) { } - Discrete::~Discrete() { - } + Discrete::~Discrete() { } std::string Discrete::className() const { return "Discrete"; } - scalar Discrete::membership(scalar _x_) const { - if (fl::Op::isNaN(_x_)) return fl::nan; + bool compare(const Discrete::Pair& a, const Discrete::Pair& b) { + return a.first < b.first; + } + + void Discrete::sort(std::vector<Pair>& pairs) { + std::sort(pairs.begin(), pairs.end(), compare); + } + + void Discrete::sort() { + std::sort(_xy.begin(), _xy.end(), compare); + } + + Complexity Discrete::complexity() const { + return Complexity().comparison(1 + 4).arithmetic(1 + 1 + 1).function(1) + .function(2 * std::log(scalar(_xy.size()))); + } + + scalar Discrete::membership(scalar x) const { + if (Op::isNaN(x)) return fl::nan; if (_xy.empty()) - throw fl::Exception("[discrete error] term is empty", FL_AT); + throw Exception("[discrete error] term is empty", FL_AT); /* ______________________ - * / \ - * / \ - * ____________/ \____________ - * x[0] x[n-1] + / \ + / \ + ____________/ \____________ + x[0] x[n-1] */ + if (Op::isLE(x, _xy.front().first)) + return Term::_height * _xy.front().second; + if (Op::isGE(x, _xy.back().first)) + return Term::_height * _xy.back().second; - if (fl::Op::isLE(_x_, _xy.front().first)) return _height * _xy.front().second; - if (fl::Op::isGE(_x_, _xy.back().first)) return _height * _xy.back().second; - - int lower = -1, upper = -1; + const Pair value(x, fl::nan); + typedef std::vector<Discrete::Pair>::const_iterator Bound; + //std::lower_bound finds the first number greater than or equal to x + Bound lowerBound(std::lower_bound(_xy.begin(), _xy.end(), value, compare)); - for (std::size_t i = 0; i < _xy.size(); ++i) { - if (Op::isEq(_xy.at(i).first, _x_)) return _height * _xy.at(i).second; - //approximate on the left - if (Op::isLt(_xy.at(i).first, _x_)) { - lower = i; - } - //get the immediate next one on the right - if (Op::isGt(_xy.at(i).first, _x_)) { - upper = i; - break; - } + //if the lower bound is equal to x + if (Op::isEq(x, lowerBound->first)) { + return Term::_height * lowerBound->second; } - if (upper < 0) upper = _xy.size() - 1; - if (lower < 0) lower = 0; - - return _height * Op::scale(_x_, _xy.at(lower).first, _xy.at(upper).first, - _xy.at(lower).second, _xy.at(upper).second); + //find the upper bound starting from a copy of lowerBound + const Bound upperBound(std::upper_bound(_xy.begin(), _xy.end(), value, compare)); + --lowerBound; //One arithmetic + return Term::_height * Op::scale(x, lowerBound->first, upperBound->first, + lowerBound->second, upperBound->second); } std::string Discrete::parameters() const { std::ostringstream ss; for (std::size_t i = 0; i < _xy.size(); ++i) { - ss << fl::Op::str(_xy.at(i).first) << " " << fl::Op::str(_xy.at(i).second); + ss << Op::str(_xy.at(i).first) << " " << Op::str(_xy.at(i).second); if (i + 1 < _xy.size()) ss << " "; } - if (not Op::isEq(_height, 1.0)) ss << " " << Op::str(_height); + if (not Op::isEq(getHeight(), 1.0)) ss << " " << Op::str(getHeight()); return ss.str(); } @@ -102,36 +103,8 @@ namespace fl { this->_xy = toPairs(values); } - template <typename T> - Discrete* Discrete::create(const std::string& name, int argc, - T x1, T y1, ...) { // throw (fl::Exception) { - std::vector<scalar> xy(argc); - xy.at(0) = x1; - xy.at(1) = y1; - va_list args; - va_start(args, y1); - for (int i = 2; i < argc; ++i) { - xy.at(i) = (scalar) va_arg(args, T); - } - va_end(args); - - FL_unique_ptr<Discrete> result(new Discrete(name)); - if (xy.size() % 2 != 0) { - result->setHeight(xy.back()); - xy.pop_back(); - } - result->setXY(toPairs(xy)); - return result.release(); - } - - template FL_API Discrete* Discrete::create(const std::string& name, int argc, - double x1, double y1, ...); // throw (fl::Exception); - //double, not scalar because variadic promotes floats to double - template FL_API Discrete* Discrete::create(const std::string& name, int argc, - int x1, int y1, ...); // throw (fl::Exception); - - void Discrete::setXY(const std::vector<Pair>& pairs) { - this->_xy = pairs; + void Discrete::setXY(const std::vector<Pair>& xy) { + this->_xy = xy; } const std::vector<Discrete::Pair>& Discrete::xy() const { @@ -142,19 +115,51 @@ namespace fl { return this->_xy; } - const Discrete::Pair& Discrete::xy(int index) const { + const Discrete::Pair& Discrete::xy(std::size_t index) const { return this->_xy.at(index); } - Discrete::Pair& Discrete::xy(int index) { + Discrete::Pair& Discrete::xy(std::size_t index) { return this->_xy.at(index); } + std::vector<scalar> Discrete::x() const { + std::vector<scalar> result(_xy.size()); + for (std::size_t i = 0; i < result.size(); ++i) { + result.at(i) = _xy.at(i).first; + } + return result; + } + + std::vector<scalar> Discrete::y() const { + std::vector<scalar> result(_xy.size()); + for (std::size_t i = 0; i < result.size(); ++i) { + result.at(i) = _xy.at(i).second; + } + return result; + } + + scalar Discrete::x(std::size_t index) const { + return _xy.at(index).first; + } + + scalar& Discrete::x(std::size_t index) { + return _xy.at(index).first; + } + + scalar Discrete::y(std::size_t index) const { + return _xy.at(index).second; + } + + scalar& Discrete::y(std::size_t index) { + return _xy.at(index).second; + } + std::vector<Discrete::Pair> Discrete::toPairs(const std::vector<scalar>& xy) { if (xy.size() % 2 != 0) { std::ostringstream os; os << "[discrete error] missing value in set of pairs (|xy|=" << xy.size() << ")"; - throw fl::Exception(os.str(), FL_AT); + throw Exception(os.str(), FL_AT); } std::vector<Pair> result((xy.size() + 1) / 2); @@ -188,16 +193,32 @@ namespace fl { return result; } - std::string Discrete::formatXY(const std::vector<Pair>& xy, const std::string& prefix, const std::string& innerSeparator, const std::string& postfix, const std::string& outerSeparator) { + std::string Discrete::formatXY(const std::vector<Pair>& xy, const std::string& prefix, + const std::string& innerSeparator, const std::string& suffix, const std::string& outerSeparator) { std::ostringstream os; for (std::size_t i = 0; i < xy.size(); ++i) { - os << prefix << fl::Op::str(xy.at(i).first) << innerSeparator - << fl::Op::str(xy.at(i).second) << postfix; + os << prefix << Op::str(xy.at(i).first) << innerSeparator + << Op::str(xy.at(i).second) << suffix; if (i + 1 < xy.size()) os << outerSeparator; } return os.str(); } + Discrete* Discrete::discretize(const Term* term, scalar start, scalar end, int resolution, + bool boundedMembershipFunction) { + FL_unique_ptr<Discrete> result(new Discrete(term->getName())); + scalar dx = (end - start) / resolution; + scalar x, y; + for (int i = 0; i <= resolution; ++i) { + x = start + i * dx; + y = term->membership(x); + if (boundedMembershipFunction) + y = Op::bound(y, scalar(0.0), scalar(1.0)); + result->xy().push_back(Discrete::Pair(x, y)); + } + return result.release(); + } + Discrete* Discrete::clone() const { return new Discrete(*this); } @@ -206,5 +227,4 @@ namespace fl { return new Discrete; } - } diff --git a/fuzzylite/src/term/Function.cpp b/fuzzylite/src/term/Function.cpp index c0f54b8..42f4aaa 100644 --- a/fuzzylite/src/term/Function.cpp +++ b/fuzzylite/src/term/Function.cpp @@ -1,43 +1,30 @@ /* - 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/term/Function.h" #include "fl/Engine.h" #include "fl/factory/FactoryManager.h" -#include "fl/factory/FunctionFactory.h" #include "fl/rule/Rule.h" #include "fl/variable/InputVariable.h" #include "fl/variable/OutputVariable.h" -#include <cctype> -#include <functional> #include <queue> -#include <signal.h> #include <stack> - namespace fl { /** @@ -47,32 +34,26 @@ namespace fl { Function::Element::Element(const std::string& name, const std::string& description, Type type) : name(name), description(description), type(type), unary(fl::null), binary(fl::null), arity(0), - precedence(0), associativity(-1) { - - } + precedence(0), associativity(-1) { } Function::Element::Element(const std::string& name, const std::string& description, Type type, Unary unary, int precedence, int associativity) : name(name), description(description), type(type), unary(unary), binary(fl::null), arity(1), - precedence(precedence), associativity(associativity) { - } + precedence(precedence), associativity(associativity) { } Function::Element::Element(const std::string& name, const std::string& description, Type type, Binary binary, int precedence, int associativity) : name(name), description(description), type(type), unary(fl::null), binary(binary), arity(2), - precedence(precedence), associativity(associativity) { - } + precedence(precedence), associativity(associativity) { } - Function::Element::~Element() { - - } + Function::Element::~Element() { } bool Function::Element::isOperator() const { - return type == OPERATOR; + return type == Operator; } bool Function::Element::isFunction() const { - return type == FUNCTION; + return type == Function; } Function::Element* Function::Element::clone() const { @@ -82,7 +63,7 @@ namespace fl { std::string Function::Element::toString() const { std::ostringstream ss; - if (type == OPERATOR) { + if (type == Operator) { ss << "Operator (name=" << name << ", " << "description=" << description << ", " << "precedence=" << precedence << ", " @@ -92,7 +73,7 @@ namespace fl { else if (arity == 2) ss << "pointer=" << binary; else ss << "pointer=error"; ss << ")"; - } else if (type == FUNCTION) { + } else if (type == Function) { ss << "Function (name=" << name << ", " << "description=" << description << ", " << "arity=" << arity << ", " @@ -110,16 +91,13 @@ namespace fl { ******************************/ Function::Node::Node(Element* element, Node* left, Node* right) - : element(element), left(left), right(right), variable(""), value(fl::nan) { - } + : element(element), left(left), right(right), variable(""), value(fl::nan) { } Function::Node::Node(const std::string& variable) - : element(fl::null), left(fl::null), right(fl::null), variable(variable), value(fl::nan) { - } + : element(fl::null), left(fl::null), right(fl::null), variable(variable), value(fl::nan) { } Function::Node::Node(scalar value) - : element(fl::null), left(fl::null), right(fl::null), variable(""), value(value) { - } + : element(fl::null), left(fl::null), right(fl::null), variable(""), value(value) { } Function::Node::Node(const Node& other) : element(fl::null), left(fl::null), right(fl::null), variable(""), value(fl::nan) { @@ -145,8 +123,7 @@ namespace fl { value = other.value; } - Function::Node::~Node() { - } + Function::Node::~Node() { } scalar Function::Node::evaluate(const std::map<std::string, scalar>* variables) const { scalar result = fl::nan; @@ -160,17 +137,17 @@ namespace fl { ex << "[function error] arity <" << element->arity << "> of " << (element->isOperator() ? "operator" : "function") << " <" << element->name << "> is fl::null"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } } else if (not variable.empty()) { if (not variables) { - throw fl::Exception("[function error] " + throw Exception("[function error] " "expected a map of variables, but none was provided", FL_AT); } std::map<std::string, scalar>::const_iterator it = variables->find(variable); if (it != variables->end()) result = it->second; - else throw fl::Exception("[function error] " + else throw Exception("[function error] " "unknown variable <" + variable + ">", FL_AT); } else { result = value; @@ -178,6 +155,36 @@ namespace fl { return result; } + std::size_t Function::Node::treeSize(const Node* root) const { + if (not root) root = this; + std::size_t result = 0; + if (root->left.get()) { + result += treeSize(root->left.get()); + } + if (root->right.get()) { + result += treeSize(root->right.get()); + } + if (root->element.get()) { + result += 1; + } + return result; + } + + std::size_t Function::Node::treeSize(Element::Type type, const Node* root) const { + if (not root) root = this; + std::size_t result = 0; + if (root->left.get()) { + result += treeSize(type, root->left.get()); + } + if (root->right.get()) { + result += treeSize(type, root->right.get()); + } + if (root->element.get() and root->element->type == type) { + result += 1; + } + return result; + } + Function::Node* Function::Node::clone() const { return new Node(*this); } @@ -186,14 +193,14 @@ namespace fl { std::ostringstream ss; if (element.get()) ss << element->name; else if (not variable.empty()) ss << variable; - else ss << fl::Op::str(value); + else ss << Op::str(value); return ss.str(); } std::string Function::Node::toPrefix(const Node* node) const { if (not node) node = this; - if (not fl::Op::isNaN(node->value)) { //is terminal - return fl::Op::str(node->value); + if (not Op::isNaN(node->value)) { //is terminal + return Op::str(node->value); } if (not node->variable.empty()) { return node->variable; @@ -210,8 +217,8 @@ namespace fl { std::string Function::Node::toInfix(const Node* node) const { if (not node) node = this; - if (not fl::Op::isNaN(node->value)) { //is proposition - return fl::Op::str(node->value); + if (not Op::isNaN(node->value)) { //is proposition + return Op::str(node->value); } if (not node->variable.empty()) { return node->variable; @@ -228,8 +235,8 @@ namespace fl { std::string Function::Node::toPostfix(const Node* node) const { if (not node) node = this; - if (not fl::Op::isNaN(node->value)) { //is proposition - return fl::Op::str(node->value); + if (not Op::isNaN(node->value)) { //is proposition + return Op::str(node->value); } if (not node->variable.empty()) { return node->variable; @@ -249,8 +256,7 @@ namespace fl { **********************************/ Function::Function(const std::string& name, const std::string& formula, const Engine* engine) - : Term(name), _root(fl::null), _formula(formula), _engine(engine) { - } + : Term(name), _root(fl::null), _formula(formula), _engine(engine) { } Function::Function(const Function& other) : Term(other), _root(fl::null), _formula(other._formula), _engine(other._engine) { @@ -271,25 +277,41 @@ namespace fl { return *this; } - Function::~Function() { - } + Function::~Function() { } std::string Function::className() const { return "Function"; } + Complexity Function::complexity() const { + Complexity result; + result.comparison(2 + 2); //membership(scalar) + membership(std::map) + if (_engine) { //insert variables in map + const std::size_t engineVariables = _engine->variables().size(); + result.function(engineVariables * std::log(scalar(variables.size() + engineVariables))); + result.function(1 * std::log(scalar(variables.size() + engineVariables))); + } + if (_root.get()) { + //Node::evaluate multiplies by tree size + const scalar treeSize = scalar(_root->treeSize()); + result.comparison(3 * treeSize); //if element, unary, binary + result.function(treeSize * std::log(treeSize)); //only operands in tree + } + return result; + } + scalar Function::membership(scalar x) const { - if (not this->_root.get()) { - throw fl::Exception("[function error] function <" + _formula + "> not loaded.", FL_AT); + if (not _root.get()) { + throw Exception("[function error] function <" + _formula + "> not loaded.", FL_AT); } - if (this->_engine) { - for (int i = 0; i < this->_engine->numberOfInputVariables(); ++i) { - InputVariable* input = this->_engine->getInputVariable(i); - this->variables[input->getName()] = input->getInputValue(); + if (_engine) { + for (std::size_t i = 0; i < _engine->numberOfInputVariables(); ++i) { + InputVariable* input = _engine->getInputVariable(i); + this->variables[input->getName()] = input->getValue(); } - for (int i = 0; i < this->_engine->numberOfOutputVariables(); ++i) { - OutputVariable* output = this->_engine->getOutputVariable(i); - this->variables[output->getName()] = output->getOutputValue(); + for (std::size_t i = 0; i < _engine->numberOfOutputVariables(); ++i) { + OutputVariable* output = _engine->getOutputVariable(i); + this->variables[output->getName()] = output->getValue(); } } this->variables["x"] = x; @@ -297,15 +319,15 @@ namespace fl { } scalar Function::evaluate(const std::map<std::string, scalar>* localVariables) const { - if (not this->_root.get()) - throw fl::Exception("[function error] evaluation failed because the function is not loaded", FL_AT); + if (not _root.get()) + throw Exception("[function error] evaluation failed because the function is not loaded", FL_AT); if (localVariables) - return this->_root->evaluate(localVariables); - return this->_root->evaluate(&this->variables); + return _root->evaluate(localVariables); + return _root->evaluate(&this->variables); } std::string Function::parameters() const { - return _formula; + return getFormula(); } void Function::configure(const std::string& parameters) { @@ -329,18 +351,17 @@ namespace fl { } void Function::load() { - load(this->_formula); + load(getFormula()); } void Function::load(const std::string& formula) { - load(formula, this->_engine); + load(formula, getEngine()); } void Function::load(const std::string& formula, const Engine* engine) { - unload(); - this->_formula = formula; - this->_engine = engine; + setFormula(formula); + setEngine(engine); this->_root.reset(parse(formula)); membership(0.0); //make sure function evaluates without throwing exception. } @@ -373,23 +394,32 @@ namespace fl { return new Function; } + void Function::updateReference(const Engine* engine) { + setEngine(engine); + try { + load(); + } catch (...) { + //ignore + } + } + std::string Function::space(const std::string& formula) const { std::vector<std::string> chars; chars.push_back("("); chars.push_back(")"); chars.push_back(","); - std::vector<std::string> operators = fl::FactoryManager::instance()->function()->availableOperators(); + std::vector<std::string> operators = FactoryManager::instance()->function()->availableOperators(); for (std::size_t i = 0; i < operators.size(); ++i) { - if (not (operators.at(i) == fl::Rule::andKeyword() or - operators.at(i) == fl::Rule::orKeyword())) { + if (not (operators.at(i) == Rule::andKeyword() or + operators.at(i) == Rule::orKeyword())) { chars.push_back(operators.at(i)); } } std::string result = formula; for (std::size_t i = 0; i < chars.size(); ++i) { - result = fl::Op::findReplace(result, chars.at(i), " " + chars.at(i) + " "); + result = Op::findReplace(result, chars.at(i), " " + chars.at(i) + " "); } return result; } @@ -397,7 +427,7 @@ namespace fl { /**************************************** * The Glorious Parser * Shunting-yard algorithm - * TODO: Maybe change it for http://en.wikipedia.org/wiki/Operator-precedence_parser + * @todo: maybe change it for http://en.wikipedia.org/wiki/Operator-precedence_parser ***************************************/ std::string Function::toPostfix(const std::string& formula) const { @@ -408,7 +438,7 @@ namespace fl { std::stringstream tokenizer(spacedFormula); std::string token; - FunctionFactory* factory = fl::FactoryManager::instance()->function(); + FunctionFactory* factory = FactoryManager::instance()->function(); while (tokenizer >> token) { Element* element = factory->getObject(token); bool isOperand = not element and token != "(" and token != ")" and token != ","; @@ -427,7 +457,7 @@ namespace fl { if (stack.empty() or stack.top() != "(") { std::ostringstream ex; ex << "[parsing error] mismatching parentheses in: " << formula; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } } else if (element and element->isOperator()) { @@ -457,7 +487,7 @@ namespace fl { if (stack.empty() or stack.top() != "(") { std::ostringstream ex; ex << "[parsing error] mismatching parentheses in: " << formula; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } stack.pop(); //get rid of "(" @@ -470,7 +500,7 @@ namespace fl { } else { std::ostringstream ex; ex << "[parsing error] unexpected error with token <" << token << ">"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } } @@ -478,7 +508,7 @@ namespace fl { if (stack.top() == "(" or stack.top() == ")") { std::ostringstream ex; ex << "[parsing error] mismatching parentheses in: " << formula; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } queue.push(stack.top()); stack.pop(); @@ -490,43 +520,31 @@ namespace fl { queue.pop(); if (not queue.empty()) ssPostfix << " "; } - // FL_DBG("postfix=" << ssPostfix.str()); return ssPostfix.str(); } - // bool FunctionFactory::isOperand(const std::string& name) const { - // //An operand is not a parenthesis... - // if (name == "(" or name == ")" or name == ",") return false; - // //nor an operator... - // if (isOperator(name)) return false; - // //nor a function... - // if (isFunction(name)) return false; - // //...it is everything else :) - // return true; - // } - Function::Node* Function::parse(const std::string& formula) { if (formula.empty()) - throw fl::Exception("[function error] formula is empty", FL_AT); + throw Exception("[function error] formula is empty", FL_AT); std::string postfix = toPostfix(formula); std::stack<Node*> stack; std::istringstream tokenizer(postfix); std::string token; - FunctionFactory* factory = fl::FactoryManager::instance()->function(); + FunctionFactory* factory = FactoryManager::instance()->function(); while (tokenizer >> token) { Element* element = factory->getObject(token); bool isOperand = not element and token != "(" and token != ")" and token != ","; if (element) { - if (element->arity > (int) stack.size()) { + if (element->arity > static_cast<int> (stack.size())) { std::ostringstream ss; ss << "[function error] " << (element->isOperator() ? "operator" : "function") << " <" << element->name << "> has arity <" << element->arity << ">, " "but found <" << stack.size() << "> element" << (stack.size() == 1 ? "" : "s"); - throw fl::Exception(ss.str(), FL_AT); + throw Exception(ss.str(), FL_AT); } Node* node = new Node(element->clone()); @@ -541,10 +559,10 @@ namespace fl { } else if (isOperand) { Node* node; try { - scalar value = fl::Op::toScalar(token); + scalar value = Op::toScalar(token); node = new Node(value); } catch (std::exception& ex) { - (void) ex; + FL_IUNUSED(ex); node = new Node(token); } stack.push(node); @@ -552,49 +570,9 @@ namespace fl { } if (stack.size() != 1) - throw fl::Exception("[function error] ill-formed formula <" + formula + ">", FL_AT); + throw Exception("[function error] ill-formed formula <" + formula + ">", FL_AT); return stack.top(); } - void Function::main() { - Function f; - std::string text = "3+4*2/(1-5)^2^3"; - FL_LOG(f.toPostfix(text)); - FL_LOG("P: " << f.parse(text)->toInfix()); - FL_LOG(">" << f.parse(text)->evaluate()); - //3 4 2 * 1 5 - 2 3 ^ ^ / + - - f.variables["y"] = 1.0; - text = "sin(y*x)^2/x"; - FL_LOG("pre: " << f.parse(text)->toPrefix()); - FL_LOG("in: " << f.parse(text)->toInfix()); - FL_LOG("pos: " << f.parse(text)->toPostfix()); - f.load(text); - FL_LOG("Result: " << f.membership(1)); - //y x * sin 2 ^ x / - - - text = "(Temperature is High and Oxygen is Low) or " - "(Temperature is Low and (Oxygen is Low or Oxygen is High))"; - FL_LOG(f.toPostfix(text)); - - f.variables["pi"] = 3.14; - text = "-5 *4/sin(-pi/2)"; - FL_LOG(f.toPostfix(text)); - try { - FL_LOG(f.parse(text)->evaluate()); - } catch (std::exception& e) { - FL_LOG(e.what()); - } - f.variables["pi"] = 3.14; - text = "~5 *4/sin(~pi/2)"; - FL_LOG(f.toPostfix(text)); - try { - FL_LOG(f.parse(text)->evaluate(&f.variables)); - } catch (std::exception& e) { - FL_LOG(e.what()); - } - } - } diff --git a/fuzzylite/src/term/Gaussian.cpp b/fuzzylite/src/term/Gaussian.cpp index 5b709f9..8413b59 100644 --- a/fuzzylite/src/term/Gaussian.cpp +++ b/fuzzylite/src/term/Gaussian.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/term/Gaussian.h" @@ -28,24 +20,26 @@ namespace fl { Gaussian::Gaussian(const std::string& name, scalar mean, scalar standardDeviation, scalar height) - : Term(name, height), _mean(mean), _standardDeviation(standardDeviation) { - } + : Term(name, height), _mean(mean), _standardDeviation(standardDeviation) { } - Gaussian::~Gaussian() { - } + Gaussian::~Gaussian() { } std::string Gaussian::className() const { return "Gaussian"; } + Complexity Gaussian::complexity() const { + return Complexity().comparison(1).arithmetic(7).function(1); + } + scalar Gaussian::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - return _height * std::exp((-(x - _mean) * (x - _mean)) / (2 * _standardDeviation * _standardDeviation)); + if (Op::isNaN(x)) return fl::nan; + return Term::_height * std::exp((-(x - _mean) * (x - _mean)) / (2.0 * _standardDeviation * _standardDeviation)); } std::string Gaussian::parameters() const { return Op::join(2, " ", _mean, _standardDeviation) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Gaussian::configure(const std::string& parameters) { @@ -56,7 +50,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setMean(Op::toScalar(values.at(0))); setStandardDeviation(Op::toScalar(values.at(1))); @@ -64,16 +58,16 @@ namespace fl { setHeight(Op::toScalar(values.at(required))); } - void Gaussian::setMean(scalar c) { - this->_mean = c; + void Gaussian::setMean(scalar mean) { + this->_mean = mean; } scalar Gaussian::getMean() const { return this->_mean; } - void Gaussian::setStandardDeviation(scalar sigma) { - this->_standardDeviation = sigma; + void Gaussian::setStandardDeviation(scalar standardDeviation) { + this->_standardDeviation = standardDeviation; } scalar Gaussian::getStandardDeviation() const { diff --git a/fuzzylite/src/term/GaussianProduct.cpp b/fuzzylite/src/term/GaussianProduct.cpp index b9652e1..791790c 100644 --- a/fuzzylite/src/term/GaussianProduct.cpp +++ b/fuzzylite/src/term/GaussianProduct.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/term/GaussianProduct.h" @@ -30,32 +22,37 @@ namespace fl { scalar meanA, scalar standardDeviationA, scalar meanB, scalar standardDeviationB, scalar height) : Term(name, height), _meanA(meanA), _standardDeviationA(standardDeviationA), - _meanB(meanB), _standardDeviationB(standardDeviationB) { - } + _meanB(meanB), _standardDeviationB(standardDeviationB) { } - GaussianProduct::~GaussianProduct() { - } + GaussianProduct::~GaussianProduct() { } std::string GaussianProduct::className() const { return "GaussianProduct"; } + Complexity GaussianProduct::complexity() const { + return Complexity().comparison(1 + 2).arithmetic(9 + 9 + 2).function(2); + } + scalar GaussianProduct::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - bool xLEa = fl::Op::isLE(x, _meanA); - scalar a = (1 - xLEa) + xLEa * std::exp( - (-(x - _meanA) * (x - _meanA)) / (2 * _standardDeviationA * _standardDeviationA) - ); - bool xGEb = fl::Op::isGE(x, _meanB); - scalar b = (1 - xGEb) + xGEb * std::exp( - (-(x - _meanB) * (x - _meanB)) / (2 * _standardDeviationB * _standardDeviationB) - ); - return _height * a * b; + if (Op::isNaN(x)) return fl::nan; + + scalar a = 1.0, b = 1.0; + if (Op::isLt(x, _meanA)) { + a = std::exp((-(x - _meanA) * (x - _meanA)) / + (2.0 * _standardDeviationA * _standardDeviationA)); + } + if (Op::isGt(x, _meanB)) { + b = std::exp((-(x - _meanB) * (x - _meanB)) / + (2.0 * _standardDeviationB * _standardDeviationB)); + } + + return Term::_height * a * b; } std::string GaussianProduct::parameters() const { return Op::join(4, " ", _meanA, _standardDeviationA, _meanB, _standardDeviationB) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void GaussianProduct::configure(const std::string& parameters) { @@ -66,7 +63,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setMeanA(Op::toScalar(values.at(0))); setStandardDeviationA(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/Linear.cpp b/fuzzylite/src/term/Linear.cpp index 4111a00..e6efb43 100644 --- a/fuzzylite/src/term/Linear.cpp +++ b/fuzzylite/src/term/Linear.cpp @@ -1,72 +1,72 @@ /* - 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/term/Linear.h" -#include "fl/Engine.h" #include "fl/variable/InputVariable.h" -#include <cstdarg> - namespace fl { Linear::Linear(const std::string& name, const std::vector<scalar>& coefficients, const Engine* engine) - : Term(name), _coefficients(coefficients), _engine(engine) { - } + : Term(name), _coefficients(coefficients), _engine(engine) { } - Linear::~Linear() { - } + Linear::~Linear() { } std::string Linear::className() const { return "Linear"; } + Complexity Linear::complexity() const { + Complexity result; + result.comparison(1 + 1); + if (_engine) { + result.arithmetic(scalar(_engine->variables().size())); + result.comparison(scalar(_engine->variables().size())); //if (i < coefficients) + } + return result; + } + scalar Linear::membership(scalar x) const { - (void) x; - if (not _engine) throw fl::Exception("[linear error] term <" + getName() + "> " + FL_IUNUSED(x); + if (not _engine) + throw Exception("[linear error] term <" + getName() + "> " "is missing a reference to the engine", FL_AT); scalar result = 0.0; - for (std::size_t i = 0; i < _engine->inputVariables().size(); ++i) { - if (i < _coefficients.size()) - result += _coefficients.at(i) * _engine->inputVariables().at(i)->getInputValue(); + const std::size_t numberOfInputVariables = _engine->inputVariables().size(); + const std::size_t numberOfCoefficients = _coefficients.size(); + for (std::size_t i = 0; i < numberOfInputVariables; ++i) { + if (i < numberOfCoefficients) + result += _coefficients.at(i) * _engine->inputVariables().at(i)->getValue(); } - if (_coefficients.size() > _engine->inputVariables().size()) { + if (numberOfCoefficients > numberOfInputVariables) { result += _coefficients.back(); } return result; } - void Linear::set(const std::vector<scalar>& coeffs, const Engine* engine) { - setCoefficients(coeffs); + void Linear::set(const std::vector<scalar>& coefficients, const Engine* engine) { + setCoefficients(coefficients); setEngine(engine); } - void Linear::setCoefficients(const std::vector<scalar>& coeffs) { - this->_coefficients = coeffs; + void Linear::setCoefficients(const std::vector<scalar>& coefficients) { + this->_coefficients = coefficients; } const std::vector<scalar>& Linear::coefficients() const { @@ -90,6 +90,7 @@ namespace fl { } void Linear::configure(const std::string& parameters) { + this->_coefficients.clear(); if (parameters.empty()) return; std::vector<std::string> strValues = Op::split(parameters, " "); std::vector<scalar> values; @@ -103,33 +104,12 @@ namespace fl { return new Linear(*this); } - Term* Linear::constructor() { - return new Linear; + void Linear::updateReference(const Engine* engine) { + setEngine(engine); } - template <typename T> - Linear* Linear::create(const std::string& name, - const Engine* engine, T firstCoefficient, ...) {// throw (fl::Exception) { - if (not engine) throw fl::Exception("[linear error] cannot create term <" + name + "> " - "without a reference to the engine", FL_AT); - std::vector<scalar> coefficients; - coefficients.push_back(firstCoefficient); - - va_list args; - va_start(args, firstCoefficient); - for (std::size_t i = 0; i < engine->inputVariables().size(); ++i) { - coefficients.push_back((scalar) va_arg(args, T)); - } - va_end(args); - - return new Linear(name, coefficients, engine); + Term* Linear::constructor() { + return new Linear; } - template FL_API Linear* Linear::create(const std::string& name, - const Engine* engine, - double firstCoefficient, ...); - - template FL_API Linear* Linear::create(const std::string& name, - const Engine* engine, - int firstCoefficient, ...); } diff --git a/fuzzylite/src/term/PiShape.cpp b/fuzzylite/src/term/PiShape.cpp index ba3e99f..6c91f54 100644 --- a/fuzzylite/src/term/PiShape.cpp +++ b/fuzzylite/src/term/PiShape.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/term/PiShape.h" @@ -29,47 +21,45 @@ namespace fl { PiShape::PiShape(const std::string& name, scalar bottomLeft, scalar topLeft, scalar topRight, scalar bottomRight, scalar height) : Term(name, height), _bottomLeft(bottomLeft), _topLeft(topLeft), - _topRight(topRight), _bottomRight(bottomRight) { - } + _topRight(topRight), _bottomRight(bottomRight) { } - PiShape::~PiShape() { - } + PiShape::~PiShape() { } std::string PiShape::className() const { return "PiShape"; } - scalar PiShape::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - //from Octave smf.m - scalar a_b_ave = (_bottomLeft + _topLeft) / 2.0; - scalar b_minus_a = _topLeft - _bottomLeft; - scalar c_d_ave = (_topRight + _bottomRight) / 2.0; - scalar d_minus_c = _bottomRight - _topRight; - - if (Op::isLE(x, _bottomLeft)) return _height * 0.0; - - if (Op::isLE(x, a_b_ave)) - return _height * (2.0 * std::pow((x - _bottomLeft) / b_minus_a, 2)); - - if (Op::isLt(x, _topLeft)) - return _height * (1.0 - 2.0 * std::pow((x - _topLeft) / b_minus_a, 2)); + Complexity PiShape::complexity() const { + return Complexity().comparison(1 + 6).arithmetic(1 + 5 + 5).function(1 + 1); + } + scalar PiShape::membership(scalar x) const { + if (Op::isNaN(x)) return fl::nan; + + scalar sshape; + if (Op::isLE(x, _bottomLeft)) + sshape = 0.0; + else if (Op::isLE(x, 0.5 * (_bottomLeft + _topLeft))) + sshape = 2.0 * std::pow((x - _bottomLeft) / (_topLeft - _bottomLeft), 2); + else if (Op::isLt(x, _topLeft)) + sshape = 1.0 - 2.0 * std::pow((x - _topLeft) / (_topLeft - _bottomLeft), 2); + else sshape = 1.0; + + scalar zshape; if (Op::isLE(x, _topRight)) - return _height * 1.0; - - if (Op::isLE(x, c_d_ave)) - return _height * (1.0 - 2.0 * std::pow((x - _topRight) / d_minus_c, 2)); - - if (Op::isLt(x, _bottomRight)) - return _height * (2.0 * std::pow((x - _bottomRight) / d_minus_c, 2)); + zshape = 1.0; + else if (Op::isLE(x, 0.5 * (_topRight + _bottomRight))) + zshape = 1.0 - 2.0 * std::pow((x - _topRight) / (_bottomRight - _topRight), 2); + else if (Op::isLt(x, _bottomRight)) + zshape = 2.0 * std::pow((x - _bottomRight) / (_bottomRight - _topRight), 2); + else zshape = 0.0; - return _height * 0.0; + return Term::_height * sshape * zshape; } std::string PiShape::parameters() const { return Op::join(4, " ", _bottomLeft, _topLeft, _topRight, _bottomRight) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void PiShape::configure(const std::string& parameters) { @@ -80,7 +70,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setBottomLeft(Op::toScalar(values.at(0))); setTopLeft(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/Ramp.cpp b/fuzzylite/src/term/Ramp.cpp index f224045..d29233d 100644 --- a/fuzzylite/src/term/Ramp.cpp +++ b/fuzzylite/src/term/Ramp.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/term/Ramp.h" @@ -27,35 +19,52 @@ namespace fl { Ramp::Ramp(const std::string& name, scalar start, scalar end, scalar height) - : Term(name, height), _start(start), _end(end) { - } + : Term(name, height), _start(start), _end(end) { } - Ramp::~Ramp() { - } + Ramp::~Ramp() { } std::string Ramp::className() const { return "Ramp"; } + Complexity Ramp::complexity() const { + return Complexity().comparison(1 + 4).arithmetic(1 + 3); + } + scalar Ramp::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; + if (Op::isNaN(x)) return fl::nan; - if (Op::isEq(_start, _end)) return _height * 0.0; + if (Op::isEq(_start, _end)) + return Term::_height * 0.0; if (Op::isLt(_start, _end)) { - if (Op::isLE(x, _start)) return _height * 0.0; - if (Op::isGE(x, _end)) return _height * 1.0; - return _height * (x - _start) / (_end - _start); + if (Op::isLE(x, _start)) + return Term::_height * 0.0; + if (Op::isGE(x, _end)) + return Term::_height * 1.0; + return Term::_height * (x - _start) / (_end - _start); } else { - if (Op::isGE(x, _start)) return _height * 0.0; - if (Op::isLE(x, _end)) return _height * 1.0; - return _height * (_start - x) / (_start - _end); + if (Op::isGE(x, _start)) + return Term::_height * 0.0; + if (Op::isLE(x, _end)) + return Term::_height * 1.0; + return Term::_height * (_start - x) / (_start - _end); } } + scalar Ramp::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const { + FL_IUNUSED(minimum); + FL_IUNUSED(maximum); + return Op::scale(activationDegree, 0, 1, _start, _end); + } + + bool Ramp::isMonotonic() const { + return true; + } + std::string Ramp::parameters() const { return Op::join(2, " ", _start, _end) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Ramp::configure(const std::string& parameters) { @@ -66,7 +75,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setStart(Op::toScalar(values.at(0))); setEnd(Op::toScalar(values.at(1))); @@ -92,11 +101,11 @@ namespace fl { Ramp::Direction Ramp::direction() const { scalar range = this->_end - this->_start; - if (not fl::Op::isFinite(range) or fl::Op::isEq(range, 0.0)) return ZERO; + if (not Op::isFinite(range) or Op::isEq(range, 0.0)) return Zero; - if (fl::Op::isGt(range, 0.0)) return POSITIVE; + if (Op::isGt(range, 0.0)) return Positive; - return NEGATIVE; + return Negative; } Ramp* Ramp::clone() const { diff --git a/fuzzylite/src/term/Rectangle.cpp b/fuzzylite/src/term/Rectangle.cpp index 363b15d..4f975d0 100644 --- a/fuzzylite/src/term/Rectangle.cpp +++ b/fuzzylite/src/term/Rectangle.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/term/Rectangle.h" @@ -27,26 +19,28 @@ namespace fl { Rectangle::Rectangle(const std::string& name, scalar start, scalar end, scalar height) - : Term(name, height), _start(start), _end(end) { - } + : Term(name, height), _start(start), _end(end) { } - Rectangle::~Rectangle() { - } + Rectangle::~Rectangle() { } std::string Rectangle::className() const { return "Rectangle"; } + Complexity Rectangle::complexity() const { + return Complexity().comparison(1 + 2).arithmetic(1); + } + scalar Rectangle::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - if (fl::Op::isLt(x, _start) or fl::Op::isGt(x, _end)) - return _height * 0.0; - return _height * 1.0; + if (Op::isNaN(x)) return fl::nan; + if (Op::isGE(x, _start) and Op::isLE(x, _end)) + return Term::_height * 1.0; + return Term::_height * 0.0; } std::string Rectangle::parameters() const { return Op::join(2, " ", _start, _end) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Rectangle::configure(const std::string& parameters) { @@ -57,7 +51,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setStart(Op::toScalar(values.at(0))); setEnd(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/SShape.cpp b/fuzzylite/src/term/SShape.cpp index cd02be1..65dfd2b 100644 --- a/fuzzylite/src/term/SShape.cpp +++ b/fuzzylite/src/term/SShape.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/term/SShape.h" @@ -27,36 +19,58 @@ namespace fl { SShape::SShape(const std::string& name, scalar start, scalar end, scalar height) - : Term(name, height), _start(start), _end(end) { - } + : Term(name, height), _start(start), _end(end) { } - SShape::~SShape() { - } + SShape::~SShape() { } std::string SShape::className() const { return "SShape"; } + Complexity SShape::complexity() const { + return Complexity().comparison(1 + 3).arithmetic(1 + 3 + 4).function(1); + } + scalar SShape::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - //from Octave smf.m - scalar average = (_start + _end) / 2.0; - scalar difference = _end - _start; + if (Op::isNaN(x)) return fl::nan; - if (Op::isLE(x, _start)) return _height * 0.0; + if (Op::isLE(x, _start)) + return Term::_height * 0.0; - if (Op::isLE(x, average)) - return _height * (2.0 * std::pow((x - _start) / difference, 2)); + if (Op::isLE(x, 0.5 * (_start + _end))) + return Term::_height * (2.0 * std::pow((x - _start) / (_end - _start), 2)); if (Op::isLt(x, _end)) - return _height * (1.0 - 2.0 * std::pow((x - _end) / difference, 2)); + return Term::_height * (1.0 - 2.0 * std::pow((x - _end) / (_end - _start), 2)); + + return Term::_height * 1.0; + } + + scalar SShape::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const { + FL_IUNUSED(minimum); + FL_IUNUSED(maximum); + + scalar w = activationDegree; + scalar z = fl::nan; + + scalar difference = _end - _start; + scalar a = _start + std::sqrt(0.5 * w * difference * difference); + scalar b = _end + std::sqrt(-0.5 * (w - 1.0) * difference * difference); + if (std::abs(w - membership(a)) < std::abs(w - membership(b))) { + z = a; + } else { + z = b; + } + return z; + } - return _height * 1.0; + bool SShape::isMonotonic() const { + return true; } std::string SShape::parameters() const { return Op::join(2, " ", _start, _end) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void SShape::configure(const std::string& parameters) { @@ -67,7 +81,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setStart(Op::toScalar(values.at(0))); setEnd(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/Sigmoid.cpp b/fuzzylite/src/term/Sigmoid.cpp index 77d7f82..fcf165e 100644 --- a/fuzzylite/src/term/Sigmoid.cpp +++ b/fuzzylite/src/term/Sigmoid.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/term/Sigmoid.h" @@ -27,24 +19,58 @@ namespace fl { Sigmoid::Sigmoid(const std::string& name, scalar inflection, scalar slope, scalar height) - : Term(name, height), _inflection(inflection), _slope(slope) { - } + : Term(name, height), _inflection(inflection), _slope(slope) { } - Sigmoid::~Sigmoid() { - } + Sigmoid::~Sigmoid() { } std::string Sigmoid::className() const { return "Sigmoid"; } + Complexity Sigmoid::complexity() const { + return Complexity().comparison(1).arithmetic(1 + 4).function(1); + } + scalar Sigmoid::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - return _height * 1.0 / (1.0 + std::exp(-_slope * (x - _inflection))); + if (Op::isNaN(x)) return fl::nan; + return Term::_height * 1.0 / (1.0 + std::exp(-_slope * (x - _inflection))); + } + + scalar Sigmoid::tsukamoto(scalar activationDegree, + scalar minimum, scalar maximum) const { + + scalar w = activationDegree; + scalar z = fl::nan; + + if (Op::isEq(w, 1.0)) { + if (Op::isGE(_slope, 0.0)) { + z = maximum; + } else { + z = minimum; + } + + } else if (Op::isEq(w, 0.0)) { + if (Op::isGE(_slope, 0.0)) { + z = minimum; + } else { + z = maximum; + } + } else { + scalar a = _slope; + scalar b = _inflection; + z = b + (std::log(1.0 / w - 1.0) / -a); + } + + return z; + } + + bool Sigmoid::isMonotonic() const { + return true; } std::string Sigmoid::parameters() const { return Op::join(2, " ", _inflection, _slope) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Sigmoid::configure(const std::string& parameters) { @@ -55,7 +81,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setInflection(Op::toScalar(values.at(0))); setSlope(Op::toScalar(values.at(1))); @@ -80,11 +106,11 @@ namespace fl { } Sigmoid::Direction Sigmoid::direction() const { - if (not fl::Op::isFinite(_slope) or fl::Op::isEq(_slope, 0.0)) return ZERO; + if (not Op::isFinite(_slope) or Op::isEq(_slope, 0.0)) return Zero; - if (fl::Op::isGt(_slope, 0.0)) return POSITIVE; + if (Op::isGt(_slope, 0.0)) return Positive; - return NEGATIVE; + return Negative; } Sigmoid* Sigmoid::clone() const { diff --git a/fuzzylite/src/term/SigmoidDifference.cpp b/fuzzylite/src/term/SigmoidDifference.cpp index 55a586c..8f7ee80 100644 --- a/fuzzylite/src/term/SigmoidDifference.cpp +++ b/fuzzylite/src/term/SigmoidDifference.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/term/SigmoidDifference.h" @@ -29,27 +21,29 @@ namespace fl { SigmoidDifference::SigmoidDifference(const std::string& name, scalar left, scalar rising, scalar falling, scalar right, scalar height) - : Term(name, height), _left(left), _rising(rising), _falling(falling), _right(right) { - } + : Term(name, height), _left(left), _rising(rising), _falling(falling), _right(right) { } - SigmoidDifference::~SigmoidDifference() { - } + SigmoidDifference::~SigmoidDifference() { } std::string SigmoidDifference::className() const { return "SigmoidDifference"; } + Complexity SigmoidDifference::complexity() const { + return Complexity().comparison(1).arithmetic(2 + 4 + 4).function(2 + 1); + } + scalar SigmoidDifference::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; + if (Op::isNaN(x)) return fl::nan; - scalar a = 1.0 / (1 + std::exp(-_rising * (x - _left))); - scalar b = 1.0 / (1 + std::exp(-_falling * (x - _right))); - return _height * std::abs(a - b); + const scalar a = 1.0 / (1.0 + std::exp(-_rising * (x - _left))); + const scalar b = 1.0 / (1.0 + std::exp(-_falling * (x - _right))); + return Term::_height * std::abs(a - b); } std::string SigmoidDifference::parameters() const { return Op::join(4, " ", _left, _rising, _falling, _right) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void SigmoidDifference::configure(const std::string& parameters) { @@ -60,7 +54,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setLeft(Op::toScalar(values.at(0))); setRising(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/SigmoidProduct.cpp b/fuzzylite/src/term/SigmoidProduct.cpp index 9e43ac9..5f35750 100644 --- a/fuzzylite/src/term/SigmoidProduct.cpp +++ b/fuzzylite/src/term/SigmoidProduct.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/term/SigmoidProduct.h" @@ -29,25 +21,28 @@ namespace fl { SigmoidProduct::SigmoidProduct(const std::string& name, scalar left, scalar rising, scalar falling, scalar right, scalar height) - : Term(name, height), _left(left), _rising(rising), _falling(falling), _right(right) { - } + : Term(name, height), _left(left), _rising(rising), _falling(falling), _right(right) { } - SigmoidProduct::~SigmoidProduct() { - } + SigmoidProduct::~SigmoidProduct() { } std::string SigmoidProduct::className() const { return "SigmoidProduct"; } + Complexity SigmoidProduct::complexity() const { + return Complexity().comparison(1).arithmetic(2 + 4 + 4).function(2); + } + scalar SigmoidProduct::membership(scalar x) const { - scalar a = 1.0 / (1 + std::exp(-_rising * (x - _left))); - scalar b = 1.0 / (1 + std::exp(-_falling * (x - _right))); - return _height * a * b; + if (Op::isNaN(x)) return fl::nan; + const scalar a = 1.0 + std::exp(-_rising * (x - _left)); + const scalar b = 1.0 + std::exp(-_falling * (x - _right)); + return Term::_height * 1.0 / (a * b); } std::string SigmoidProduct::parameters() const { return Op::join(4, " ", _left, _rising, _falling, _right) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void SigmoidProduct::configure(const std::string& parameters) { @@ -58,7 +53,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setLeft(Op::toScalar(values.at(0))); setRising(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/Spike.cpp b/fuzzylite/src/term/Spike.cpp index f4b73bf..a19810d 100644 --- a/fuzzylite/src/term/Spike.cpp +++ b/fuzzylite/src/term/Spike.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/term/Spike.h" @@ -27,25 +19,26 @@ namespace fl { Spike::Spike(const std::string& name, scalar center, scalar width, scalar height) - : Term(name, height), _center(center), _width(width) { - } - - Spike::~Spike() { + : Term(name, height), _center(center), _width(width) { } - } + Spike::~Spike() { } std::string Spike::className() const { return "Spike"; } + Complexity Spike::complexity() const { + return Complexity().comparison(1).arithmetic(1 + 3).function(2); + } + scalar Spike::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - return _height * std::exp(-std::fabs(10.0 / _width * (x - _center))); + if (Op::isNaN(x)) return fl::nan; + return Term::_height * std::exp(-std::abs(10.0 / _width * (x - _center))); } std::string Spike::parameters() const { return Op::join(2, " ", _center, _width) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Spike::configure(const std::string& parameters) { @@ -56,7 +49,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setCenter(Op::toScalar(values.at(0))); setWidth(Op::toScalar(values.at(1))); @@ -87,4 +80,5 @@ namespace fl { Term* Spike::constructor() { return new Spike; } + } diff --git a/fuzzylite/src/term/Term.cpp b/fuzzylite/src/term/Term.cpp index 143a98f..bf7520d 100644 --- a/fuzzylite/src/term/Term.cpp +++ b/fuzzylite/src/term/Term.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/term/Term.h" @@ -30,13 +22,9 @@ namespace fl { - Term::Term(const std::string& name, scalar height) : _name(name), _height(height) { - - } - - Term::~Term() { + Term::Term(const std::string& name, scalar height) : _name(name), _height(height) { } - } + Term::~Term() { } void Term::setName(const std::string& name) { this->_name = name; @@ -58,17 +46,20 @@ namespace fl { return FllExporter().toString(this); } - void Term::updateReference(Term* term, const Engine* engine) { - if (Linear * linear = dynamic_cast<Linear*> (term)) { - linear->setEngine(engine); - } else if (Function * function = dynamic_cast<Function*> (term)) { - function->setEngine(engine); - try { - function->load(); - } catch (...) { - //ignore - } - } + void Term::updateReference(const Engine* engine) { + FL_IUNUSED(engine); + //do nothing } + scalar Term::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const { + FL_IUNUSED(minimum); + FL_IUNUSED(maximum); + return membership(activationDegree); + } + + bool Term::isMonotonic() const { + return false; + } + + } diff --git a/fuzzylite/src/term/Trapezoid.cpp b/fuzzylite/src/term/Trapezoid.cpp index 60abcc4..4773dbb 100644 --- a/fuzzylite/src/term/Trapezoid.cpp +++ b/fuzzylite/src/term/Trapezoid.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/term/Trapezoid.h" @@ -30,7 +22,6 @@ namespace fl { scalar vertexA, scalar vertexB, scalar vertexC, scalar vertexD, scalar height) : Term(name, height), _vertexA(vertexA), _vertexB(vertexB), _vertexC(vertexC), _vertexD(vertexD) { if (Op::isNaN(vertexC) and Op::isNaN(vertexD)) { - //TODO: Modify FLL to allow passing two parameters only. this->_vertexD = _vertexB; scalar range = _vertexD - _vertexA; this->_vertexB = _vertexA + range * 1.0 / 5.0; @@ -38,34 +29,41 @@ namespace fl { } } - Trapezoid::~Trapezoid() { - } + Trapezoid::~Trapezoid() { } std::string Trapezoid::className() const { return "Trapezoid"; } + Complexity Trapezoid::complexity() const { + return Complexity().comparison(1 + 6).arithmetic(1 + 3).function(1); + } + scalar Trapezoid::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; + if (Op::isNaN(x)) return fl::nan; if (Op::isLt(x, _vertexA) or Op::isGt(x, _vertexD)) - return _height * 0.0; - - if (Op::isLt(x, _vertexB)) - return _height * Op::min(scalar(1.0), (x - _vertexA) / (_vertexB - _vertexA)); + return Term::_height * 0.0; + if (Op::isLt(x, _vertexB)) { + if (_vertexA == -fl::inf) return Term::_height * 1.0; + return Term::_height * Op::min(scalar(1.0), (x - _vertexA) / (_vertexB - _vertexA)); + } if (Op::isLE(x, _vertexC)) - return _height * 1.0; + return Term::_height * 1.0; - if (Op::isLt(x, _vertexD)) - return _height * (_vertexD - x) / (_vertexD - _vertexC); + if (Op::isLt(x, _vertexD)) { + if (_vertexD == fl::inf) return Term::_height * 1.0; + return Term::_height * (_vertexD - x) / (_vertexD - _vertexC); + } - return _height * 0.0; + if (_vertexD == fl::inf) return Term::_height * 1.0; + return Term::_height * 0.0; } std::string Trapezoid::parameters() const { return Op::join(4, " ", _vertexA, _vertexB, _vertexC, _vertexD)+ - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Trapezoid::configure(const std::string& parameters) { @@ -76,7 +74,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setVertexA(Op::toScalar(values.at(0))); setVertexB(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/Triangle.cpp b/fuzzylite/src/term/Triangle.cpp index 2fce1a6..9d1835c 100644 --- a/fuzzylite/src/term/Triangle.cpp +++ b/fuzzylite/src/term/Triangle.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/term/Triangle.h" @@ -28,38 +20,44 @@ namespace fl { Triangle::Triangle(const std::string& name, scalar vertexA, scalar vertexB, scalar vertexC, scalar height) : Term(name, height), _vertexA(vertexA), _vertexB(vertexB), _vertexC(vertexC) { - if (fl::Op::isNaN(vertexC)) { - //TODO: Modify FLL to allow passing two parameters only. - this->_vertexC = vertexB; - this->_vertexB = (vertexA + vertexB) / 2.0; + if (Op::isNaN(vertexC)) { + this->_vertexC = _vertexB; + this->_vertexB = 0.5 * (_vertexA + _vertexB); } } - Triangle::~Triangle() { - } + Triangle::~Triangle() { } std::string Triangle::className() const { return "Triangle"; } + Complexity Triangle::complexity() const { + return Complexity().comparison(1 + 5).arithmetic(4); + } + scalar Triangle::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; + if (Op::isNaN(x)) return fl::nan; if (Op::isLt(x, _vertexA) or Op::isGt(x, _vertexC)) - return _height * 0.0; + return Term::_height * 0.0; if (Op::isEq(x, _vertexB)) - return _height * 1.0; - - if (Op::isLt(x, _vertexB)) - return _height * (x - _vertexA) / (_vertexB - _vertexA); + return Term::_height * 1.0; - return _height * (_vertexC - x) / (_vertexC - _vertexB); + if (Op::isLt(x, _vertexB)) { + if (_vertexA == -fl::inf) + return Term::_height * 1.0; + return Term::_height * (x - _vertexA) / (_vertexB - _vertexA); + } + if (_vertexC == fl::inf) + return Term::_height * 1.0; + return Term::_height * (_vertexC - x) / (_vertexC - _vertexB); } std::string Triangle::parameters() const { return Op::join(3, " ", _vertexA, _vertexB, _vertexC) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void Triangle::configure(const std::string& parameters) { @@ -70,7 +68,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setVertexA(Op::toScalar(values.at(0))); setVertexB(Op::toScalar(values.at(1))); diff --git a/fuzzylite/src/term/ZShape.cpp b/fuzzylite/src/term/ZShape.cpp index 86668b6..9054b20 100644 --- a/fuzzylite/src/term/ZShape.cpp +++ b/fuzzylite/src/term/ZShape.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/term/ZShape.h" @@ -27,36 +19,58 @@ namespace fl { ZShape::ZShape(const std::string& name, scalar start, scalar end, scalar height) - : Term(name, height), _start(start), _end(end) { - } + : Term(name, height), _start(start), _end(end) { } - ZShape::~ZShape() { - } + ZShape::~ZShape() { } std::string ZShape::className() const { return "ZShape"; } + Complexity ZShape::complexity() const { + return Complexity().comparison(1 + 3).arithmetic(3 + 4).function(1); + } + scalar ZShape::membership(scalar x) const { - if (fl::Op::isNaN(x)) return fl::nan; - //from Octave zmf.m - scalar average = (_start + _end) / 2; - scalar difference = _end - _start; + if (Op::isNaN(x)) return fl::nan; - if (Op::isLE(x, _start)) return _height * 1.0; + if (Op::isLE(x, _start)) + return Term::_height * 1.0; - if (Op::isLE(x, average)) - return _height * (1.0 - 2.0 * std::pow((x - _start) / difference, 2)); + if (Op::isLE(x, 0.5 * (_start + _end))) + return Term::_height * (1.0 - 2.0 * std::pow((x - _start) / (_end - _start), 2)); if (Op::isLt(x, _end)) - return _height * (2.0 * std::pow((x - _end) / difference, 2)); + return Term::_height * (2.0 * std::pow((x - _end) / (_end - _start), 2)); + + return Term::_height * 0.0; + } + + scalar ZShape::tsukamoto(scalar activationDegree, scalar minimum, scalar maximum) const { + FL_IUNUSED(minimum); + FL_IUNUSED(maximum); + + scalar w = activationDegree; + scalar z = fl::nan; + + scalar difference = _end - _start; + scalar a = _start + std::sqrt(-0.5 * (w - 1.0) * difference * difference); + scalar b = _end + std::sqrt(0.5 * w * difference * difference); + if (std::abs(w - membership(a)) < std::abs(w - membership(b))) { + z = a; + } else { + z = b; + } + return z; + } - return _height * 0.0; + bool ZShape::isMonotonic() const { + return true; } std::string ZShape::parameters() const { return Op::join(2, " ", _start, _end) + - (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : ""); + (not Op::isEq(getHeight(), 1.0) ? " " + Op::str(getHeight()) : ""); } void ZShape::configure(const std::string& parameters) { @@ -67,7 +81,7 @@ namespace fl { std::ostringstream ex; ex << "[configuration error] term <" << className() << ">" << " requires <" << required << "> parameters"; - throw fl::Exception(ex.str(), FL_AT); + throw Exception(ex.str(), FL_AT); } setStart(Op::toScalar(values.at(0))); setEnd(Op::toScalar(values.at(1))); |