summaryrefslogtreecommitdiff
path: root/fuzzylite/src/term/Discrete.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/term/Discrete.cpp')
-rw-r--r--fuzzylite/src/term/Discrete.cpp194
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;
}
-
}