diff options
Diffstat (limited to 'fuzzylite/src/term/Discrete.cpp')
-rw-r--r-- | fuzzylite/src/term/Discrete.cpp | 194 |
1 files changed, 107 insertions, 87 deletions
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; } - } |