summaryrefslogtreecommitdiff
path: root/fuzzylite/src/term
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/term')
-rw-r--r--fuzzylite/src/term/Accumulated.cpp211
-rw-r--r--fuzzylite/src/term/Activated.cpp100
-rw-r--r--fuzzylite/src/term/Bell.cpp99
-rw-r--r--fuzzylite/src/term/Concave.cpp107
-rw-r--r--fuzzylite/src/term/Constant.cpp70
-rw-r--r--fuzzylite/src/term/Cosine.cpp96
-rw-r--r--fuzzylite/src/term/Discrete.cpp210
-rw-r--r--fuzzylite/src/term/Function.cpp600
-rw-r--r--fuzzylite/src/term/Gaussian.cpp92
-rw-r--r--fuzzylite/src/term/GaussianProduct.cpp120
-rw-r--r--fuzzylite/src/term/Linear.cpp135
-rw-r--r--fuzzylite/src/term/PiShape.cpp133
-rw-r--r--fuzzylite/src/term/Ramp.cpp110
-rw-r--r--fuzzylite/src/term/Rectangle.cpp93
-rw-r--r--fuzzylite/src/term/SShape.cpp102
-rw-r--r--fuzzylite/src/term/Sigmoid.cpp98
-rw-r--r--fuzzylite/src/term/SigmoidDifference.cpp114
-rw-r--r--fuzzylite/src/term/SigmoidProduct.cpp112
-rw-r--r--fuzzylite/src/term/Spike.cpp90
-rw-r--r--fuzzylite/src/term/Term.cpp74
-rw-r--r--fuzzylite/src/term/Trapezoid.cpp130
-rw-r--r--fuzzylite/src/term/Triangle.cpp115
-rw-r--r--fuzzylite/src/term/ZShape.cpp102
23 files changed, 3113 insertions, 0 deletions
diff --git a/fuzzylite/src/term/Accumulated.cpp b/fuzzylite/src/term/Accumulated.cpp
new file mode 100644
index 0000000..979af9f
--- /dev/null
+++ b/fuzzylite/src/term/Accumulated.cpp
@@ -0,0 +1,211 @@
+/*
+ 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
new file mode 100644
index 0000000..9a27b4b
--- /dev/null
+++ b/fuzzylite/src/term/Activated.cpp
@@ -0,0 +1,100 @@
+/*
+ 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/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() {
+ }
+
+ std::string Activated::className() const {
+ return "Activated";
+ }
+
+ 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);
+ }
+
+ std::string Activated::parameters() const {
+ FllExporter exporter;
+ std::ostringstream ss;
+ ss << Op::str(_degree) << " " << exporter.toString(_activation) << " "
+ << exporter.toString(_term);
+ return ss.str();
+ }
+
+ void Activated::configure(const std::string& parameters) {
+ (void) parameters;
+ }
+
+ std::string Activated::toString() const {
+ FllExporter exporter;
+ std::ostringstream ss;
+ ss << exporter.toString(_activation) << "("
+ << Op::str(_degree) << ","
+ << _term->getName() << ")";
+ return ss.str();
+ }
+
+ void Activated::setTerm(const Term* term) {
+ this->_term = term;
+ }
+
+ const Term* Activated::getTerm() const {
+ return this->_term;
+ }
+
+ void Activated::setDegree(scalar degree) {
+ this->_degree = degree;
+ }
+
+ scalar Activated::getDegree() const {
+ return this->_degree;
+ }
+
+ void Activated::setActivation(const TNorm* activation) {
+ this->_activation = activation;
+ }
+
+ const TNorm* Activated::getActivation() const {
+ return this->_activation;
+ }
+
+ Activated* Activated::clone() const {
+ return new Activated(*this);
+ }
+
+}
diff --git a/fuzzylite/src/term/Bell.cpp b/fuzzylite/src/term/Bell.cpp
new file mode 100644
index 0000000..fc0b215
--- /dev/null
+++ b/fuzzylite/src/term/Bell.cpp
@@ -0,0 +1,99 @@
+/*
+ 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/Bell.h"
+
+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) {
+ }
+
+ Bell::~Bell() {
+ }
+
+ std::string Bell::className() const {
+ return "Bell";
+ }
+
+ 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)));
+ }
+
+ std::string Bell::parameters() const {
+ return Op::join(3, " ", _center, _width, _slope) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Bell::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 3;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setCenter(Op::toScalar(values.at(0)));
+ setWidth(Op::toScalar(values.at(1)));
+ setSlope(Op::toScalar(values.at(2)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Bell::setWidth(scalar a) {
+ this->_width = a;
+ }
+
+ scalar Bell::getWidth() const {
+ return this->_width;
+ }
+
+ void Bell::setSlope(scalar b) {
+ this->_slope = b;
+ }
+
+ scalar Bell::getSlope() const {
+ return this->_slope;
+ }
+
+ void Bell::setCenter(scalar c) {
+ this->_center = c;
+ }
+
+ scalar Bell::getCenter() const {
+ return this->_center;
+ }
+
+ Bell* Bell::clone() const {
+ return new Bell(*this);
+ }
+
+ Term* Bell::constructor() {
+ return new Bell;
+ }
+
+}
diff --git a/fuzzylite/src/term/Concave.cpp b/fuzzylite/src/term/Concave.cpp
new file mode 100644
index 0000000..37679ae
--- /dev/null
+++ b/fuzzylite/src/term/Concave.cpp
@@ -0,0 +1,107 @@
+/*
+ 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/Concave.h"
+
+namespace fl {
+
+ Concave::Concave(const std::string& name, scalar inflection, scalar end, scalar height)
+ : Term(name, height), _inflection(inflection), _end(end) {
+
+ }
+
+ Concave::~Concave() {
+
+ }
+
+ std::string Concave::className() const {
+ return "Concave";
+ }
+
+ 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);
+ }
+ } else { //Concave decreasing
+ if (fl::Op::isGt(x, _end)) {
+ return _height * (_inflection - _end) / (_inflection - 2 * _end + x);
+ }
+ }
+ return _height * 1.0;
+ }
+
+ std::string Concave::parameters() const {
+ return Op::join(2, " ", _inflection, _end) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+
+ }
+
+ void Concave::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setInflection(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+
+ }
+
+ void Concave::setInflection(scalar start) {
+ this->_inflection = start;
+ }
+
+ scalar Concave::getInflection() const {
+ return this->_inflection;
+ }
+
+ void Concave::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar Concave::getEnd() const {
+ return this->_end;
+ }
+
+ Concave* Concave::clone() const {
+ return new Concave(*this);
+ }
+
+ Term* Concave::constructor() {
+ return new Concave;
+ }
+
+
+
+
+
+}
diff --git a/fuzzylite/src/term/Constant.cpp b/fuzzylite/src/term/Constant.cpp
new file mode 100644
index 0000000..d52f8ec
--- /dev/null
+++ b/fuzzylite/src/term/Constant.cpp
@@ -0,0 +1,70 @@
+/*
+ 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/Constant.h"
+
+namespace fl {
+
+ Constant::Constant(const std::string& name, scalar value)
+ : Term(name), _value(value) {
+ }
+
+ Constant::~Constant() {
+ }
+
+ std::string Constant::className() const {
+ return "Constant";
+ }
+
+ scalar Constant::membership(scalar x) const {
+ (void) x;
+ return this->_value;
+ }
+
+ std::string Constant::parameters() const {
+ return Op::str(_value);
+ }
+
+ void Constant::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ setValue(Op::toScalar(parameters));
+ }
+
+ void Constant::setValue(scalar value) {
+ this->_value = value;
+ }
+
+ scalar Constant::getValue() const {
+ return this->_value;
+ }
+
+ Constant* Constant::clone() const {
+ return new Constant(*this);
+ }
+
+ Term* Constant::constructor() {
+ return new Constant;
+ }
+
+}
diff --git a/fuzzylite/src/term/Cosine.cpp b/fuzzylite/src/term/Cosine.cpp
new file mode 100644
index 0000000..a1402ad
--- /dev/null
+++ b/fuzzylite/src/term/Cosine.cpp
@@ -0,0 +1,96 @@
+/*
+ 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/Cosine.h"
+
+namespace fl {
+
+ Cosine::Cosine(const std::string& name, scalar center, scalar width, scalar height)
+ : Term(name, height), _center(center), _width(width) {
+
+ }
+
+ Cosine::~Cosine() {
+
+ }
+
+ std::string Cosine::className() const {
+ return "Cosine";
+ }
+
+ std::string Cosine::parameters() const {
+ return Op::join(2, " ", _center, _width) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Cosine::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setCenter(Op::toScalar(values.at(0)));
+ setWidth(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+
+ }
+
+ 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;
+ const scalar pi = 4.0 * std::atan(1.0);
+ return _height * (0.5 * (1.0 + std::cos(2.0 / _width * pi * (x - _center))));
+ }
+
+ void Cosine::setCenter(scalar center) {
+ this->_center = center;
+ }
+
+ scalar Cosine::getCenter() const {
+ return this->_center;
+ }
+
+ void Cosine::setWidth(scalar width) {
+ this->_width = width;
+ }
+
+ scalar Cosine::getWidth() const {
+ return this->_width;
+ }
+
+ Cosine* Cosine::clone() const {
+ return new Cosine(*this);
+ }
+
+ Term* Cosine::constructor() {
+ return new Cosine;
+ }
+}
diff --git a/fuzzylite/src/term/Discrete.cpp b/fuzzylite/src/term/Discrete.cpp
new file mode 100644
index 0000000..212ada2
--- /dev/null
+++ b/fuzzylite/src/term/Discrete.cpp
@@ -0,0 +1,210 @@
+/*
+ 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/Discrete.h"
+
+#include <cstdarg>
+
+namespace fl {
+
+ Discrete::Discrete(const std::string& name, const std::vector<Pair>& xy, scalar height)
+ : Term(name, height), _xy(xy) {
+ }
+
+ Discrete::~Discrete() {
+ }
+
+ std::string Discrete::className() const {
+ return "Discrete";
+ }
+
+ scalar Discrete::membership(scalar _x_) const {
+ if (fl::Op::isNaN(_x_)) return fl::nan;
+ if (_xy.empty())
+ throw fl::Exception("[discrete error] term is empty", FL_AT);
+
+ /* ______________________
+ * / \
+ * / \
+ * ____________/ \____________
+ * x[0] x[n-1]
+ */
+
+
+ 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;
+
+ 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 (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);
+ }
+
+ 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);
+ if (i + 1 < _xy.size()) ss << " ";
+ }
+ if (not Op::isEq(_height, 1.0)) ss << " " << Op::str(_height);
+ return ss.str();
+ }
+
+ void Discrete::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> strValues = Op::split(parameters, " ");
+ std::vector<scalar> values(strValues.size());
+ for (std::size_t i = 0; i < strValues.size(); ++i) {
+ values.at(i) = Op::toScalar(strValues.at(i));
+ }
+ if (values.size() % 2 == 0) {
+ setHeight(1.0);
+ } else {
+ setHeight(values.back());
+ values.pop_back();
+ }
+ 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;
+ }
+
+ const std::vector<Discrete::Pair>& Discrete::xy() const {
+ return this->_xy;
+ }
+
+ std::vector<Discrete::Pair>& Discrete::xy() {
+ return this->_xy;
+ }
+
+ const Discrete::Pair& Discrete::xy(int index) const {
+ return this->_xy.at(index);
+ }
+
+ Discrete::Pair& Discrete::xy(int index) {
+ return this->_xy.at(index);
+ }
+
+ 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);
+ }
+
+ std::vector<Pair> result((xy.size() + 1) / 2);
+ for (std::size_t i = 0; i + 1 < xy.size(); i += 2) {
+ result.at(i / 2).first = xy.at(i);
+ result.at(i / 2).second = xy.at(i + 1);
+ }
+ return result;
+ }
+
+ std::vector<Discrete::Pair> Discrete::toPairs(const std::vector<scalar>& xy,
+ scalar missingValue) FL_INOEXCEPT {
+ std::vector<Pair> result((xy.size() + 1) / 2);
+ for (std::size_t i = 0; i + 1 < xy.size(); i += 2) {
+ result.at(i / 2).first = xy.at(i);
+ result.at(i / 2).second = xy.at(i + 1);
+ }
+ if (xy.size() % 2 != 0) {
+ result.back().first = xy.back();
+ result.back().second = missingValue;
+ }
+ return result;
+ }
+
+ std::vector<scalar> Discrete::toVector(const std::vector<Pair>& xy) {
+ std::vector<scalar> result(xy.size() * 2);
+ for (std::size_t i = 0; i < xy.size(); ++i) {
+ result.at(2 * i) = xy.at(i).first;
+ result.at(2 * i + 1) = xy.at(i).second;
+ }
+ 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::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;
+ if (i + 1 < xy.size()) os << outerSeparator;
+ }
+ return os.str();
+ }
+
+ Discrete* Discrete::clone() const {
+ return new Discrete(*this);
+ }
+
+ Term* Discrete::constructor() {
+ return new Discrete;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/Function.cpp b/fuzzylite/src/term/Function.cpp
new file mode 100644
index 0000000..c0f54b8
--- /dev/null
+++ b/fuzzylite/src/term/Function.cpp
@@ -0,0 +1,600 @@
+/*
+ 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/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 {
+
+ /**
+ * Parsing elements
+ */
+
+
+ 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) {
+
+ }
+
+ 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) {
+ }
+
+ 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) {
+ }
+
+ Function::Element::~Element() {
+
+ }
+
+ bool Function::Element::isOperator() const {
+ return type == OPERATOR;
+ }
+
+ bool Function::Element::isFunction() const {
+ return type == FUNCTION;
+ }
+
+ Function::Element* Function::Element::clone() const {
+ return new Element(*this);
+ }
+
+ std::string Function::Element::toString() const {
+ std::ostringstream ss;
+
+ if (type == OPERATOR) {
+ ss << "Operator (name=" << name << ", "
+ << "description=" << description << ", "
+ << "precedence=" << precedence << ", "
+ << "arity=" << arity << ", "
+ << "associativity=" << associativity << ", ";
+ if (arity == 1) ss << "pointer=" << unary;
+ else if (arity == 2) ss << "pointer=" << binary;
+ else ss << "pointer=error";
+ ss << ")";
+ } else if (type == FUNCTION) {
+ ss << "Function (name=" << name << ", "
+ << "description=" << description << ", "
+ << "arity=" << arity << ", "
+ << "associativity=" << associativity << ", ";
+ if (arity == 1) ss << "pointer=" << unary;
+ else if (arity == 2) ss << "pointer=" << binary;
+ else ss << "pointer=error";
+ ss << ")";
+ }
+ return ss.str();
+ }
+
+ /******************************
+ * Tree Node Elements
+ ******************************/
+
+ Function::Node::Node(Element* element, Node* left, Node* right)
+ : 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) {
+ }
+
+ Function::Node::Node(scalar 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) {
+ copyFrom(other);
+ }
+
+ Function::Node& Function::Node::operator=(const Node& other) {
+ if (this != &other) {
+ element.reset(fl::null);
+ left.reset(fl::null);
+ right.reset(fl::null);
+
+ copyFrom(other);
+ }
+ return *this;
+ }
+
+ void Function::Node::copyFrom(const Node& other) {
+ if (other.element.get()) element.reset(other.element->clone());
+ if (other.left.get()) left.reset(other.left->clone());
+ if (other.right.get()) right.reset(other.right->clone());
+ variable = other.variable;
+ value = other.value;
+ }
+
+ Function::Node::~Node() {
+ }
+
+ scalar Function::Node::evaluate(const std::map<std::string, scalar>* variables) const {
+ scalar result = fl::nan;
+ if (element.get()) {
+ if (element->unary) {
+ result = element->unary(left->evaluate(variables));
+ } else if (element->binary) {
+ result = element->binary(right->evaluate(variables), left->evaluate(variables));
+ } else {
+ std::ostringstream ex;
+ ex << "[function error] arity <" << element->arity << "> of "
+ << (element->isOperator() ? "operator" : "function") <<
+ " <" << element->name << "> is fl::null";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+
+ } else if (not variable.empty()) {
+ if (not variables) {
+ throw fl::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] "
+ "unknown variable <" + variable + ">", FL_AT);
+ } else {
+ result = value;
+ }
+ return result;
+ }
+
+ Function::Node* Function::Node::clone() const {
+ return new Node(*this);
+ }
+
+ std::string Function::Node::toString() const {
+ std::ostringstream ss;
+ if (element.get()) ss << element->name;
+ else if (not variable.empty()) ss << variable;
+ else ss << fl::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 node->variable.empty()) {
+ return node->variable;
+ }
+
+ std::ostringstream ss;
+ ss << node->toString();
+ if (node->left.get())
+ ss << " " << this->toPrefix(node->left.get());
+ if (node->right.get())
+ ss << " " << this->toPrefix(node->right.get());
+ return ss.str();
+ }
+
+ 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 node->variable.empty()) {
+ return node->variable;
+ }
+
+ std::ostringstream ss;
+ if (node->left.get())
+ ss << this->toInfix(node->left.get()) << " ";
+ ss << node->toString();
+ if (node->right.get())
+ ss << " " << this->toInfix(node->right.get());
+ return ss.str();
+ }
+
+ 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 node->variable.empty()) {
+ return node->variable;
+ }
+
+ std::ostringstream ss;
+ if (node->left.get())
+ ss << this->toPostfix(node->left.get()) << " ";
+ if (node->right.get())
+ ss << this->toPostfix(node->right.get()) << " ";
+ ss << node->toString();
+ return ss.str();
+ }
+
+ /**********************************
+ * Function class.
+ **********************************/
+ Function::Function(const std::string& name,
+ const std::string& formula, const 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) {
+ if (other._root.get()) _root.reset(other._root->clone());
+ variables = other.variables;
+ }
+
+ Function& Function::operator=(const Function& other) {
+ if (this != &other) {
+ _root.reset(fl::null);
+
+ Term::operator=(other);
+ _formula = other._formula;
+ _engine = other._engine;
+ if (other._root.get()) _root.reset(other._root->clone());
+ variables = other.variables;
+ }
+ return *this;
+ }
+
+ Function::~Function() {
+ }
+
+ std::string Function::className() const {
+ return "Function";
+ }
+
+ scalar Function::membership(scalar x) const {
+ if (not this->_root.get()) {
+ throw fl::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();
+ }
+ for (int i = 0; i < this->_engine->numberOfOutputVariables(); ++i) {
+ OutputVariable* output = this->_engine->getOutputVariable(i);
+ this->variables[output->getName()] = output->getOutputValue();
+ }
+ }
+ this->variables["x"] = x;
+ return this->evaluate(&this->variables);
+ }
+
+ 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 (localVariables)
+ return this->_root->evaluate(localVariables);
+ return this->_root->evaluate(&this->variables);
+ }
+
+ std::string Function::parameters() const {
+ return _formula;
+ }
+
+ void Function::configure(const std::string& parameters) {
+ load(parameters);
+ }
+
+ Function* Function::create(const std::string& name,
+ const std::string& infix, const Engine* engine) {
+ FL_unique_ptr<Function> result(new Function(name));
+ result->load(infix, engine);
+ return result.release();
+ }
+
+ bool Function::isLoaded() const {
+ return this->_root.get() != fl::null;
+ }
+
+ void Function::unload() {
+ this->_root.reset(fl::null);
+ this->variables.clear();
+ }
+
+ void Function::load() {
+ load(this->_formula);
+ }
+
+ void Function::load(const std::string& formula) {
+ load(formula, this->_engine);
+ }
+
+ void Function::load(const std::string& formula,
+ const Engine* engine) {
+ unload();
+ this->_formula = formula;
+ this->_engine = engine;
+ this->_root.reset(parse(formula));
+ membership(0.0); //make sure function evaluates without throwing exception.
+ }
+
+ void Function::setFormula(const std::string& formula) {
+ this->_formula = formula;
+ }
+
+ std::string Function::getFormula() const {
+ return this->_formula;
+ }
+
+ void Function::setEngine(const Engine* engine) {
+ this->_engine = engine;
+ }
+
+ const Engine* Function::getEngine() const {
+ return this->_engine;
+ }
+
+ Function::Node* Function::root() const {
+ return this->_root.get();
+ }
+
+ Function* Function::clone() const {
+ return new Function(*this);
+ }
+
+ Term* Function::constructor() {
+ return new Function;
+ }
+
+ 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();
+ 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())) {
+ 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) + " ");
+ }
+ return result;
+ }
+
+ /****************************************
+ * The Glorious Parser
+ * Shunting-yard algorithm
+ * TODO: Maybe change it for http://en.wikipedia.org/wiki/Operator-precedence_parser
+ ***************************************/
+
+ std::string Function::toPostfix(const std::string& formula) const {
+ std::string spacedFormula = space(formula);
+
+ std::queue<std::string> queue;
+ std::stack<std::string> stack;
+
+ std::stringstream tokenizer(spacedFormula);
+ std::string token;
+ FunctionFactory* factory = fl::FactoryManager::instance()->function();
+ while (tokenizer >> token) {
+ Element* element = factory->getObject(token);
+ bool isOperand = not element and token != "(" and token != ")" and token != ",";
+
+ if (isOperand) {
+ queue.push(token);
+
+ } else if (element and element->isFunction()) {
+ stack.push(token);
+
+ } else if (token == ",") {
+ while (not stack.empty() and stack.top() != "(") {
+ queue.push(stack.top());
+ stack.pop();
+ }
+ if (stack.empty() or stack.top() != "(") {
+ std::ostringstream ex;
+ ex << "[parsing error] mismatching parentheses in: " << formula;
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+
+ } else if (element and element->isOperator()) {
+ Element* op1 = element;
+ for (;;) {
+ Element* op2 = fl::null;
+ if (not stack.empty()) op2 = factory->getObject(stack.top());
+ if (not op2) break;
+
+ if ((op1->associativity < 0 and op1->precedence == op2->precedence)
+ or op1->precedence < op2->precedence) {
+ queue.push(stack.top());
+ stack.pop();
+ } else
+ break;
+ }
+ stack.push(token);
+
+ } else if (token == "(") {
+ stack.push(token);
+
+ } else if (token == ")") {
+ while (not stack.empty() and stack.top() != "(") {
+ queue.push(stack.top());
+ stack.pop();
+ }
+ if (stack.empty() or stack.top() != "(") {
+ std::ostringstream ex;
+ ex << "[parsing error] mismatching parentheses in: " << formula;
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ stack.pop(); //get rid of "("
+
+ Element* top = fl::null;
+ if (not stack.empty()) top = factory->getObject(stack.top());
+ if (top and top->isFunction()) {
+ queue.push(stack.top());
+ stack.pop();
+ }
+ } else {
+ std::ostringstream ex;
+ ex << "[parsing error] unexpected error with token <" << token << ">";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ }
+
+ while (not stack.empty()) {
+ if (stack.top() == "(" or stack.top() == ")") {
+ std::ostringstream ex;
+ ex << "[parsing error] mismatching parentheses in: " << formula;
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ queue.push(stack.top());
+ stack.pop();
+ }
+
+ std::stringstream ssPostfix;
+ while (not queue.empty()) {
+ ssPostfix << queue.front();
+ 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);
+ std::string postfix = toPostfix(formula);
+
+ std::stack<Node*> stack;
+
+ std::istringstream tokenizer(postfix);
+ std::string token;
+ FunctionFactory* factory = fl::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()) {
+ 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);
+ }
+
+ Node* node = new Node(element->clone());
+ node->left.reset(stack.top());
+ stack.pop();
+ if (element->arity == 2) {
+ node->right.reset(stack.top());
+ stack.pop();
+ }
+ stack.push(node);
+
+ } else if (isOperand) {
+ Node* node;
+ try {
+ scalar value = fl::Op::toScalar(token);
+ node = new Node(value);
+ } catch (std::exception& ex) {
+ (void) ex;
+ node = new Node(token);
+ }
+ stack.push(node);
+ }
+ }
+
+ if (stack.size() != 1)
+ throw fl::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
new file mode 100644
index 0000000..5b709f9
--- /dev/null
+++ b/fuzzylite/src/term/Gaussian.cpp
@@ -0,0 +1,92 @@
+/*
+ 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/Gaussian.h"
+
+namespace fl {
+
+ Gaussian::Gaussian(const std::string& name,
+ scalar mean, scalar standardDeviation, scalar height)
+ : Term(name, height), _mean(mean), _standardDeviation(standardDeviation) {
+ }
+
+ Gaussian::~Gaussian() {
+ }
+
+ std::string Gaussian::className() const {
+ return "Gaussian";
+ }
+
+ 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));
+ }
+
+ std::string Gaussian::parameters() const {
+ return Op::join(2, " ", _mean, _standardDeviation) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Gaussian::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setMean(Op::toScalar(values.at(0)));
+ setStandardDeviation(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Gaussian::setMean(scalar c) {
+ this->_mean = c;
+ }
+
+ scalar Gaussian::getMean() const {
+ return this->_mean;
+ }
+
+ void Gaussian::setStandardDeviation(scalar sigma) {
+ this->_standardDeviation = sigma;
+ }
+
+ scalar Gaussian::getStandardDeviation() const {
+ return this->_standardDeviation;
+ }
+
+ Gaussian* Gaussian::clone() const {
+ return new Gaussian(*this);
+ }
+
+ Term* Gaussian::constructor() {
+ return new Gaussian;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/GaussianProduct.cpp b/fuzzylite/src/term/GaussianProduct.cpp
new file mode 100644
index 0000000..b9652e1
--- /dev/null
+++ b/fuzzylite/src/term/GaussianProduct.cpp
@@ -0,0 +1,120 @@
+/*
+ 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/GaussianProduct.h"
+
+namespace fl {
+
+ GaussianProduct::GaussianProduct(const std::string& name,
+ scalar meanA, scalar standardDeviationA, scalar meanB, scalar standardDeviationB,
+ scalar height)
+ : Term(name, height), _meanA(meanA), _standardDeviationA(standardDeviationA),
+ _meanB(meanB), _standardDeviationB(standardDeviationB) {
+ }
+
+ GaussianProduct::~GaussianProduct() {
+ }
+
+ std::string GaussianProduct::className() const {
+ return "GaussianProduct";
+ }
+
+ 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;
+ }
+
+ std::string GaussianProduct::parameters() const {
+ return Op::join(4, " ", _meanA, _standardDeviationA, _meanB, _standardDeviationB) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void GaussianProduct::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setMeanA(Op::toScalar(values.at(0)));
+ setStandardDeviationA(Op::toScalar(values.at(1)));
+ setMeanB(Op::toScalar(values.at(2)));
+ setStandardDeviationB(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void GaussianProduct::setMeanA(scalar meanA) {
+ this->_meanA = meanA;
+ }
+
+ scalar GaussianProduct::getMeanA() const {
+ return this->_meanA;
+ }
+
+ void GaussianProduct::setStandardDeviationA(scalar sigmaA) {
+ this->_standardDeviationA = sigmaA;
+ }
+
+ scalar GaussianProduct::getStandardDeviationA() const {
+ return this->_standardDeviationA;
+ }
+
+ void GaussianProduct::setMeanB(scalar meanB) {
+ this->_meanB = meanB;
+ }
+
+ scalar GaussianProduct::getMeanB() const {
+ return this->_meanB;
+ }
+
+ void GaussianProduct::setStandardDeviationB(scalar sigmaB) {
+ this->_standardDeviationB = sigmaB;
+ }
+
+ scalar GaussianProduct::getStandardDeviationB() const {
+ return this->_standardDeviationB;
+ }
+
+ GaussianProduct* GaussianProduct::clone() const {
+ return new GaussianProduct(*this);
+ }
+
+ Term* GaussianProduct::constructor() {
+ return new GaussianProduct;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/Linear.cpp b/fuzzylite/src/term/Linear.cpp
new file mode 100644
index 0000000..4111a00
--- /dev/null
+++ b/fuzzylite/src/term/Linear.cpp
@@ -0,0 +1,135 @@
+/*
+ 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/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) {
+ }
+
+ Linear::~Linear() {
+ }
+
+ std::string Linear::className() const {
+ return "Linear";
+ }
+
+ scalar Linear::membership(scalar x) const {
+ (void) x;
+ if (not _engine) throw fl::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();
+ }
+ if (_coefficients.size() > _engine->inputVariables().size()) {
+ result += _coefficients.back();
+ }
+ return result;
+ }
+
+ void Linear::set(const std::vector<scalar>& coeffs, const Engine* engine) {
+ setCoefficients(coeffs);
+ setEngine(engine);
+ }
+
+ void Linear::setCoefficients(const std::vector<scalar>& coeffs) {
+ this->_coefficients = coeffs;
+ }
+
+ const std::vector<scalar>& Linear::coefficients() const {
+ return this->_coefficients;
+ }
+
+ std::vector<scalar>& Linear::coefficients() {
+ return this->_coefficients;
+ }
+
+ void Linear::setEngine(const Engine* engine) {
+ this->_engine = engine;
+ }
+
+ const Engine* Linear::getEngine() const {
+ return this->_engine;
+ }
+
+ std::string Linear::parameters() const {
+ return Op::join(this->_coefficients, " ");
+ }
+
+ void Linear::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> strValues = Op::split(parameters, " ");
+ std::vector<scalar> values;
+ for (std::size_t i = 0; i < strValues.size(); ++i) {
+ values.push_back(Op::toScalar(strValues.at(i)));
+ }
+ this->_coefficients = values;
+ }
+
+ Linear* Linear::clone() const {
+ return new Linear(*this);
+ }
+
+ Term* Linear::constructor() {
+ return new Linear;
+ }
+
+ 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);
+ }
+
+ 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
new file mode 100644
index 0000000..ba3e99f
--- /dev/null
+++ b/fuzzylite/src/term/PiShape.cpp
@@ -0,0 +1,133 @@
+/*
+ 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/PiShape.h"
+
+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) {
+ }
+
+ 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));
+
+ 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));
+
+ return _height * 0.0;
+ }
+
+ std::string PiShape::parameters() const {
+ return Op::join(4, " ", _bottomLeft, _topLeft, _topRight, _bottomRight) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void PiShape::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setBottomLeft(Op::toScalar(values.at(0)));
+ setTopLeft(Op::toScalar(values.at(1)));
+ setTopRight(Op::toScalar(values.at(2)));
+ setBottomRight(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void PiShape::setBottomLeft(scalar a) {
+ this->_bottomLeft = a;
+ }
+
+ scalar PiShape::getBottomLeft() const {
+ return this->_bottomLeft;
+ }
+
+ void PiShape::setTopLeft(scalar b) {
+ this->_topLeft = b;
+ }
+
+ scalar PiShape::getTopLeft() const {
+ return this->_topLeft;
+ }
+
+ void PiShape::setTopRight(scalar d) {
+ this->_topRight = d;
+ }
+
+ scalar PiShape::getTopRight() const {
+ return this->_topRight;
+ }
+
+ void PiShape::setBottomRight(scalar c) {
+ this->_bottomRight = c;
+ }
+
+ scalar PiShape::getBottomRight() const {
+ return this->_bottomRight;
+ }
+
+ PiShape* PiShape::clone() const {
+ return new PiShape(*this);
+ }
+
+ Term* PiShape::constructor() {
+ return new PiShape;
+ }
+
+}
diff --git a/fuzzylite/src/term/Ramp.cpp b/fuzzylite/src/term/Ramp.cpp
new file mode 100644
index 0000000..f224045
--- /dev/null
+++ b/fuzzylite/src/term/Ramp.cpp
@@ -0,0 +1,110 @@
+/*
+ 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/Ramp.h"
+
+namespace fl {
+
+ Ramp::Ramp(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) {
+ }
+
+ Ramp::~Ramp() {
+ }
+
+ std::string Ramp::className() const {
+ return "Ramp";
+ }
+
+ scalar Ramp::membership(scalar x) const {
+ if (fl::Op::isNaN(x)) return fl::nan;
+
+ if (Op::isEq(_start, _end)) return _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);
+ } 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);
+ }
+ }
+
+ std::string Ramp::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Ramp::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Ramp::setStart(scalar start) {
+ this->_start = start;
+ }
+
+ scalar Ramp::getStart() const {
+ return this->_start;
+ }
+
+ void Ramp::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar Ramp::getEnd() const {
+ return this->_end;
+ }
+
+ 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 (fl::Op::isGt(range, 0.0)) return POSITIVE;
+
+ return NEGATIVE;
+ }
+
+ Ramp* Ramp::clone() const {
+ return new Ramp(*this);
+ }
+
+ Term* Ramp::constructor() {
+ return new Ramp;
+ }
+
+}
diff --git a/fuzzylite/src/term/Rectangle.cpp b/fuzzylite/src/term/Rectangle.cpp
new file mode 100644
index 0000000..363b15d
--- /dev/null
+++ b/fuzzylite/src/term/Rectangle.cpp
@@ -0,0 +1,93 @@
+/*
+ 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/Rectangle.h"
+
+namespace fl {
+
+ Rectangle::Rectangle(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) {
+ }
+
+ Rectangle::~Rectangle() {
+ }
+
+ std::string Rectangle::className() const {
+ return "Rectangle";
+ }
+
+ 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;
+ }
+
+ std::string Rectangle::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Rectangle::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Rectangle::setStart(scalar minimum) {
+ this->_start = minimum;
+ }
+
+ scalar Rectangle::getStart() const {
+ return this->_start;
+ }
+
+ void Rectangle::setEnd(scalar maximum) {
+ this->_end = maximum;
+ }
+
+ scalar Rectangle::getEnd() const {
+ return this->_end;
+ }
+
+ Rectangle* Rectangle::clone() const {
+ return new Rectangle(*this);
+ }
+
+ Term* Rectangle::constructor() {
+ return new Rectangle;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/SShape.cpp b/fuzzylite/src/term/SShape.cpp
new file mode 100644
index 0000000..cd02be1
--- /dev/null
+++ b/fuzzylite/src/term/SShape.cpp
@@ -0,0 +1,102 @@
+/*
+ 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/SShape.h"
+
+namespace fl {
+
+ SShape::SShape(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) {
+ }
+
+ SShape::~SShape() {
+ }
+
+ std::string SShape::className() const {
+ return "SShape";
+ }
+
+ 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::isLE(x, _start)) return _height * 0.0;
+
+ if (Op::isLE(x, average))
+ return _height * (2.0 * std::pow((x - _start) / difference, 2));
+
+ if (Op::isLt(x, _end))
+ return _height * (1.0 - 2.0 * std::pow((x - _end) / difference, 2));
+
+ return _height * 1.0;
+ }
+
+ std::string SShape::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void SShape::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void SShape::setStart(scalar start) {
+ this->_start = start;
+ }
+
+ scalar SShape::getStart() const {
+ return this->_start;
+ }
+
+ void SShape::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar SShape::getEnd() const {
+ return this->_end;
+ }
+
+ SShape* SShape::clone() const {
+ return new SShape(*this);
+ }
+
+ Term* SShape::constructor() {
+ return new SShape;
+ }
+
+}
diff --git a/fuzzylite/src/term/Sigmoid.cpp b/fuzzylite/src/term/Sigmoid.cpp
new file mode 100644
index 0000000..77d7f82
--- /dev/null
+++ b/fuzzylite/src/term/Sigmoid.cpp
@@ -0,0 +1,98 @@
+/*
+ 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/Sigmoid.h"
+
+namespace fl {
+
+ Sigmoid::Sigmoid(const std::string& name, scalar inflection, scalar slope, scalar height)
+ : Term(name, height), _inflection(inflection), _slope(slope) {
+ }
+
+ Sigmoid::~Sigmoid() {
+ }
+
+ std::string Sigmoid::className() const {
+ return "Sigmoid";
+ }
+
+ 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)));
+ }
+
+ std::string Sigmoid::parameters() const {
+ return Op::join(2, " ", _inflection, _slope) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Sigmoid::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setInflection(Op::toScalar(values.at(0)));
+ setSlope(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Sigmoid::setSlope(scalar a) {
+ this->_slope = a;
+ }
+
+ scalar Sigmoid::getSlope() const {
+ return this->_slope;
+ }
+
+ void Sigmoid::setInflection(scalar c) {
+ this->_inflection = c;
+ }
+
+ scalar Sigmoid::getInflection() const {
+ return this->_inflection;
+ }
+
+ Sigmoid::Direction Sigmoid::direction() const {
+ if (not fl::Op::isFinite(_slope) or fl::Op::isEq(_slope, 0.0)) return ZERO;
+
+ if (fl::Op::isGt(_slope, 0.0)) return POSITIVE;
+
+ return NEGATIVE;
+ }
+
+ Sigmoid* Sigmoid::clone() const {
+ return new Sigmoid(*this);
+ }
+
+ Term* Sigmoid::constructor() {
+ return new Sigmoid;
+ }
+
+}
diff --git a/fuzzylite/src/term/SigmoidDifference.cpp b/fuzzylite/src/term/SigmoidDifference.cpp
new file mode 100644
index 0000000..55a586c
--- /dev/null
+++ b/fuzzylite/src/term/SigmoidDifference.cpp
@@ -0,0 +1,114 @@
+/*
+ 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/SigmoidDifference.h"
+
+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) {
+ }
+
+ SigmoidDifference::~SigmoidDifference() {
+ }
+
+ std::string SigmoidDifference::className() const {
+ return "SigmoidDifference";
+ }
+
+ scalar SigmoidDifference::membership(scalar x) const {
+ if (fl::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);
+ }
+
+ std::string SigmoidDifference::parameters() const {
+ return Op::join(4, " ", _left, _rising, _falling, _right) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void SigmoidDifference::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setLeft(Op::toScalar(values.at(0)));
+ setRising(Op::toScalar(values.at(1)));
+ setFalling(Op::toScalar(values.at(2)));
+ setRight(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void SigmoidDifference::setLeft(scalar leftInflection) {
+ this->_left = leftInflection;
+ }
+
+ scalar SigmoidDifference::getLeft() const {
+ return this->_left;
+ }
+
+ void SigmoidDifference::setRising(scalar risingSlope) {
+ this->_rising = risingSlope;
+ }
+
+ scalar SigmoidDifference::getRising() const {
+ return this->_rising;
+ }
+
+ void SigmoidDifference::setFalling(scalar fallingSlope) {
+ this->_falling = fallingSlope;
+ }
+
+ scalar SigmoidDifference::getFalling() const {
+ return this->_falling;
+ }
+
+ void SigmoidDifference::setRight(scalar rightInflection) {
+ this->_right = rightInflection;
+ }
+
+ scalar SigmoidDifference::getRight() const {
+ return this->_right;
+ }
+
+ SigmoidDifference* SigmoidDifference::clone() const {
+ return new SigmoidDifference(*this);
+ }
+
+ Term* SigmoidDifference::constructor() {
+ return new SigmoidDifference;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/SigmoidProduct.cpp b/fuzzylite/src/term/SigmoidProduct.cpp
new file mode 100644
index 0000000..9e43ac9
--- /dev/null
+++ b/fuzzylite/src/term/SigmoidProduct.cpp
@@ -0,0 +1,112 @@
+/*
+ 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/SigmoidProduct.h"
+
+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) {
+ }
+
+ SigmoidProduct::~SigmoidProduct() {
+ }
+
+ std::string SigmoidProduct::className() const {
+ return "SigmoidProduct";
+ }
+
+ 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;
+ }
+
+ std::string SigmoidProduct::parameters() const {
+ return Op::join(4, " ", _left, _rising, _falling, _right) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void SigmoidProduct::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setLeft(Op::toScalar(values.at(0)));
+ setRising(Op::toScalar(values.at(1)));
+ setFalling(Op::toScalar(values.at(2)));
+ setRight(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+
+ }
+
+ void SigmoidProduct::setRising(scalar risingSlope) {
+ this->_rising = risingSlope;
+ }
+
+ scalar SigmoidProduct::getRising() const {
+ return this->_rising;
+ }
+
+ void SigmoidProduct::setLeft(scalar leftInflection) {
+ this->_left = leftInflection;
+ }
+
+ scalar SigmoidProduct::getLeft() const {
+ return this->_left;
+ }
+
+ void SigmoidProduct::setRight(scalar rightInflection) {
+ this->_right = rightInflection;
+ }
+
+ scalar SigmoidProduct::getRight() const {
+ return this->_right;
+ }
+
+ void SigmoidProduct::setFalling(scalar fallingSlope) {
+ this->_falling = fallingSlope;
+ }
+
+ scalar SigmoidProduct::getFalling() const {
+ return this->_falling;
+ }
+
+ SigmoidProduct* SigmoidProduct::clone() const {
+ return new SigmoidProduct(*this);
+ }
+
+ Term* SigmoidProduct::constructor() {
+ return new SigmoidProduct;
+ }
+
+}
diff --git a/fuzzylite/src/term/Spike.cpp b/fuzzylite/src/term/Spike.cpp
new file mode 100644
index 0000000..f4b73bf
--- /dev/null
+++ b/fuzzylite/src/term/Spike.cpp
@@ -0,0 +1,90 @@
+/*
+ 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/Spike.h"
+
+namespace fl {
+
+ Spike::Spike(const std::string& name, scalar center, scalar width, scalar height)
+ : Term(name, height), _center(center), _width(width) {
+ }
+
+ Spike::~Spike() {
+
+ }
+
+ std::string Spike::className() const {
+ return "Spike";
+ }
+
+ 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)));
+ }
+
+ std::string Spike::parameters() const {
+ return Op::join(2, " ", _center, _width) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void Spike::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setCenter(Op::toScalar(values.at(0)));
+ setWidth(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Spike::setCenter(scalar center) {
+ this->_center = center;
+ }
+
+ scalar Spike::getCenter() const {
+ return this->_center;
+ }
+
+ void Spike::setWidth(scalar width) {
+ this->_width = width;
+ }
+
+ scalar Spike::getWidth() const {
+ return this->_width;
+ }
+
+ Spike* Spike::clone() const {
+ return new Spike(*this);
+ }
+
+ Term* Spike::constructor() {
+ return new Spike;
+ }
+}
diff --git a/fuzzylite/src/term/Term.cpp b/fuzzylite/src/term/Term.cpp
new file mode 100644
index 0000000..143a98f
--- /dev/null
+++ b/fuzzylite/src/term/Term.cpp
@@ -0,0 +1,74 @@
+/*
+ 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/Term.h"
+
+#include "fl/imex/FllExporter.h"
+#include "fl/term/Linear.h"
+#include "fl/term/Function.h"
+
+namespace fl {
+
+ Term::Term(const std::string& name, scalar height) : _name(name), _height(height) {
+
+ }
+
+ Term::~Term() {
+
+ }
+
+ void Term::setName(const std::string& name) {
+ this->_name = name;
+ }
+
+ std::string Term::getName() const {
+ return this->_name;
+ }
+
+ void Term::setHeight(scalar height) {
+ this->_height = height;
+ }
+
+ scalar Term::getHeight() const {
+ return this->_height;
+ }
+
+ std::string Term::toString() const {
+ 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
+ }
+ }
+ }
+
+}
diff --git a/fuzzylite/src/term/Trapezoid.cpp b/fuzzylite/src/term/Trapezoid.cpp
new file mode 100644
index 0000000..60abcc4
--- /dev/null
+++ b/fuzzylite/src/term/Trapezoid.cpp
@@ -0,0 +1,130 @@
+/*
+ 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/Trapezoid.h"
+
+namespace fl {
+
+ Trapezoid::Trapezoid(const std::string& name,
+ 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;
+ this->_vertexC = _vertexA + range * 4.0 / 5.0;
+ }
+ }
+
+ Trapezoid::~Trapezoid() {
+ }
+
+ std::string Trapezoid::className() const {
+ return "Trapezoid";
+ }
+
+ scalar Trapezoid::membership(scalar x) const {
+ if (fl::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));
+
+ if (Op::isLE(x, _vertexC))
+ return _height * 1.0;
+
+ if (Op::isLt(x, _vertexD))
+ return _height * (_vertexD - x) / (_vertexD - _vertexC);
+
+ return _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) : "");
+ }
+
+ void Trapezoid::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 4;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setVertexA(Op::toScalar(values.at(0)));
+ setVertexB(Op::toScalar(values.at(1)));
+ setVertexC(Op::toScalar(values.at(2)));
+ setVertexD(Op::toScalar(values.at(3)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Trapezoid::setVertexA(scalar a) {
+ this->_vertexA = a;
+ }
+
+ scalar Trapezoid::getVertexA() const {
+ return this->_vertexA;
+ }
+
+ void Trapezoid::setVertexB(scalar b) {
+ this->_vertexB = b;
+ }
+
+ scalar Trapezoid::getVertexB() const {
+ return this->_vertexB;
+ }
+
+ void Trapezoid::setVertexC(scalar c) {
+ this->_vertexC = c;
+ }
+
+ scalar Trapezoid::getVertexC() const {
+ return this->_vertexC;
+ }
+
+ void Trapezoid::setVertexD(scalar d) {
+ this->_vertexD = d;
+ }
+
+ scalar Trapezoid::getVertexD() const {
+ return this->_vertexD;
+ }
+
+ Trapezoid* Trapezoid::clone() const {
+ return new Trapezoid(*this);
+ }
+
+ Term* Trapezoid::constructor() {
+ return new Trapezoid;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/Triangle.cpp b/fuzzylite/src/term/Triangle.cpp
new file mode 100644
index 0000000..2fce1a6
--- /dev/null
+++ b/fuzzylite/src/term/Triangle.cpp
@@ -0,0 +1,115 @@
+/*
+ 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/Triangle.h"
+
+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;
+ }
+ }
+
+ Triangle::~Triangle() {
+ }
+
+ std::string Triangle::className() const {
+ return "Triangle";
+ }
+
+ scalar Triangle::membership(scalar x) const {
+ if (fl::Op::isNaN(x)) return fl::nan;
+
+ if (Op::isLt(x, _vertexA) or Op::isGt(x, _vertexC))
+ return _height * 0.0;
+
+ if (Op::isEq(x, _vertexB))
+ return _height * 1.0;
+
+ if (Op::isLt(x, _vertexB))
+ return _height * (x - _vertexA) / (_vertexB - _vertexA);
+
+ return _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) : "");
+ }
+
+ void Triangle::configure(const std::string& parameters) {
+ if (parameters.empty()) return;
+ std::vector<std::string> values = Op::split(parameters, " ");
+ std::size_t required = 3;
+ if (values.size() < required) {
+ std::ostringstream ex;
+ ex << "[configuration error] term <" << className() << ">"
+ << " requires <" << required << "> parameters";
+ throw fl::Exception(ex.str(), FL_AT);
+ }
+ setVertexA(Op::toScalar(values.at(0)));
+ setVertexB(Op::toScalar(values.at(1)));
+ setVertexC(Op::toScalar(values.at(2)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void Triangle::setVertexA(scalar a) {
+ this->_vertexA = a;
+ }
+
+ scalar Triangle::getVertexA() const {
+ return this->_vertexA;
+ }
+
+ void Triangle::setVertexB(scalar b) {
+ this->_vertexB = b;
+ }
+
+ scalar Triangle::getVertexB() const {
+ return this->_vertexB;
+ }
+
+ void Triangle::setVertexC(scalar c) {
+ this->_vertexC = c;
+ }
+
+ scalar Triangle::getVertexC() const {
+ return this->_vertexC;
+ }
+
+ Triangle* Triangle::clone() const {
+ return new Triangle(*this);
+ }
+
+ Term* Triangle::constructor() {
+ return new Triangle;
+ }
+
+
+}
diff --git a/fuzzylite/src/term/ZShape.cpp b/fuzzylite/src/term/ZShape.cpp
new file mode 100644
index 0000000..86668b6
--- /dev/null
+++ b/fuzzylite/src/term/ZShape.cpp
@@ -0,0 +1,102 @@
+/*
+ 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/ZShape.h"
+
+namespace fl {
+
+ ZShape::ZShape(const std::string& name, scalar start, scalar end, scalar height)
+ : Term(name, height), _start(start), _end(end) {
+ }
+
+ ZShape::~ZShape() {
+ }
+
+ std::string ZShape::className() const {
+ return "ZShape";
+ }
+
+ 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::isLE(x, _start)) return _height * 1.0;
+
+ if (Op::isLE(x, average))
+ return _height * (1.0 - 2.0 * std::pow((x - _start) / difference, 2));
+
+ if (Op::isLt(x, _end))
+ return _height * (2.0 * std::pow((x - _end) / difference, 2));
+
+ return _height * 0.0;
+ }
+
+ std::string ZShape::parameters() const {
+ return Op::join(2, " ", _start, _end) +
+ (not Op::isEq(_height, 1.0) ? " " + Op::str(_height) : "");
+ }
+
+ void ZShape::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 fl::Exception(ex.str(), FL_AT);
+ }
+ setStart(Op::toScalar(values.at(0)));
+ setEnd(Op::toScalar(values.at(1)));
+ if (values.size() > required)
+ setHeight(Op::toScalar(values.at(required)));
+ }
+
+ void ZShape::setStart(scalar start) {
+ this->_start = start;
+ }
+
+ scalar ZShape::getStart() const {
+ return this->_start;
+ }
+
+ void ZShape::setEnd(scalar end) {
+ this->_end = end;
+ }
+
+ scalar ZShape::getEnd() const {
+ return this->_end;
+ }
+
+ ZShape* ZShape::clone() const {
+ return new ZShape(*this);
+ }
+
+ Term* ZShape::constructor() {
+ return new ZShape;
+ }
+
+}