1 /*
2  fuzzylite (R), a fuzzy logic control library in C++.
3  Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
4  Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
5 
6  This file is part of fuzzylite.
7 
8  fuzzylite is free software: you can redistribute it and/or modify it under
9  the terms of the FuzzyLite License included with the software.
10 
11  You should have received a copy of the FuzzyLite License along with
12  fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
13 
14  fuzzylite is a registered trademark of FuzzyLite Limited.
15  */
16 
17 #include "fl/variable/Variable.h"
18 
19 #include "fl/imex/FllExporter.h"
20 #include "fl/norm/Norm.h"
21 #include "fl/term/Constant.h"
22 #include "fl/term/Linear.h"
23 
24 #include <queue>
25 
26 namespace fl {
27 
Variable(const std::string & name,scalar minimum,scalar maximum)28     Variable::Variable(const std::string& name, scalar minimum, scalar maximum)
29     : _name(name), _description(""),
30     _value(fl::nan), _minimum(minimum), _maximum(maximum),
31     _enabled(true), _lockValueInRange(false) { }
32 
Variable(const Variable & other)33     Variable::Variable(const Variable& other) {
34         copyFrom(other);
35     }
36 
operator =(const Variable & other)37     Variable& Variable::operator=(const Variable& other) {
38         if (this != &other) {
39             for (std::size_t i = 0; i < _terms.size(); ++i) {
40                 delete _terms.at(i);
41             }
42             _terms.clear();
43             copyFrom(other);
44         }
45         return *this;
46     }
47 
copyFrom(const Variable & other)48     void Variable::copyFrom(const Variable& other) {
49         _name = other._name;
50         _description = other._description;
51         _value = other._value;
52         _minimum = other._minimum;
53         _maximum = other._maximum;
54         _enabled = other._enabled;
55         _lockValueInRange = other._lockValueInRange;
56         for (std::size_t i = 0; i < other._terms.size(); ++i) {
57             _terms.push_back(other._terms.at(i)->clone());
58         }
59     }
60 
~Variable()61     Variable::~Variable() {
62         for (std::size_t i = 0; i < _terms.size(); ++i) {
63             delete _terms.at(i);
64         }
65     }
66 
setName(const std::string & name)67     void Variable::setName(const std::string& name) {
68         this->_name = name;
69     }
70 
getName() const71     std::string Variable::getName() const {
72         return this->_name;
73     }
74 
setDescription(const std::string & description)75     void Variable::setDescription(const std::string& description) {
76         this->_description = description;
77     }
78 
getDescription() const79     std::string Variable::getDescription() const {
80         return this->_description;
81     }
82 
setValue(scalar value)83     void Variable::setValue(scalar value) {
84         this->_value = _lockValueInRange
85                 ? Op::bound(value, _minimum, _maximum)
86                 : value;
87     }
88 
getValue() const89     scalar Variable::getValue() const {
90         return this->_value;
91     }
92 
setRange(scalar minimum,scalar maximum)93     void Variable::setRange(scalar minimum, scalar maximum) {
94         setMinimum(minimum);
95         setMaximum(maximum);
96     }
97 
range() const98     scalar Variable::range() const {
99         return getMaximum() - getMinimum();
100     }
101 
setMinimum(scalar minimum)102     void Variable::setMinimum(scalar minimum) {
103         this->_minimum = minimum;
104     }
105 
getMinimum() const106     scalar Variable::getMinimum() const {
107         return this->_minimum;
108     }
109 
setMaximum(scalar maximum)110     void Variable::setMaximum(scalar maximum) {
111         this->_maximum = maximum;
112     }
113 
getMaximum() const114     scalar Variable::getMaximum() const {
115         return this->_maximum;
116     }
117 
setEnabled(bool enabled)118     void Variable::setEnabled(bool enabled) {
119         this->_enabled = enabled;
120     }
121 
isEnabled() const122     bool Variable::isEnabled() const {
123         return this->_enabled;
124     }
125 
setLockValueInRange(bool lockValueInRange)126     void Variable::setLockValueInRange(bool lockValueInRange) {
127         this->_lockValueInRange = lockValueInRange;
128     }
129 
isLockValueInRange() const130     bool Variable::isLockValueInRange() const {
131         return this->_lockValueInRange;
132     }
133 
type() const134     Variable::Type Variable::type() const {
135         return None;
136     }
137 
complexity() const138     Complexity Variable::complexity() const {
139         Complexity result;
140         if (isEnabled()) {
141             for (std::size_t i = 0; i < _terms.size(); ++i) {
142                 result += _terms.at(i)->complexity();
143             }
144         }
145         return result;
146     }
147 
fuzzify(scalar x) const148     std::string Variable::fuzzify(scalar x) const {
149         std::ostringstream ss;
150         for (std::size_t i = 0; i < terms().size(); ++i) {
151             Term* term = _terms.at(i);
152             scalar fx = fl::nan;
153             try {
154                 fx = term->membership(x);
155             } catch (...) {
156                 //ignore
157             }
158             if (i == 0) {
159                 ss << Op::str(fx);
160             } else {
161                 if (Op::isNaN(fx) or Op::isGE(fx, 0.0))
162                     ss << " + " << Op::str(fx);
163                 else
164                     ss << " - " << Op::str(std::abs(fx));
165             }
166             ss << "/" << term->getName();
167         }
168         return ss.str();
169     }
170 
highestMembership(scalar x,scalar * yhighest) const171     Term* Variable::highestMembership(scalar x, scalar* yhighest) const {
172         Term* result = fl::null;
173         scalar ymax = 0.0;
174         for (std::size_t i = 0; i < _terms.size(); ++i) {
175             scalar y = fl::nan;
176             Term* term = _terms.at(i);
177             try {
178                 y = term->membership(x);
179             } catch (...) {
180                 //ignore
181             }
182             if (Op::isGt(y, ymax)) {
183                 ymax = y;
184                 result = term;
185             }
186         }
187         if (yhighest) *yhighest = ymax;
188         return result;
189     }
190 
toString() const191     std::string Variable::toString() const {
192         return FllExporter().toString(this);
193     }
194 
195     /**
196      * Operations for datatype _terms
197      */
198 
199     typedef std::pair<Term*, scalar> TermCentroid;
200 
201     struct Ascending {
202 
operator ()fl::Ascending203         bool operator()(const TermCentroid& a, const TermCentroid& b) const {
204             return a.second > b.second;
205         }
206     };
207 
sort()208     void Variable::sort() {
209         std::priority_queue <TermCentroid, std::vector<TermCentroid>, Ascending> termCentroids;
210         Centroid defuzzifier;
211         FL_DBG("Sorting...");
212         for (std::size_t i = 0; i < _terms.size(); ++i) {
213             Term* term = _terms.at(i);
214             scalar centroid = fl::inf;
215             try {
216                 if (dynamic_cast<const Constant*> (term) or dynamic_cast<const Linear*> (term)) {
217                     centroid = term->membership(0);
218                 } else {
219                     centroid = defuzzifier.defuzzify(term, getMinimum(), getMaximum());
220                 }
221             } catch (...) { //ignore error possibly due to Function not loaded
222                 centroid = fl::inf;
223             }
224             termCentroids.push(TermCentroid(term, centroid));
225             FL_DBG(term->toString() << " -> " << centroid)
226         }
227 
228         std::vector<Term*> sortedTerms;
229         while (termCentroids.size() > 0) {
230             sortedTerms.push_back(termCentroids.top().first);
231             FL_DBG(termCentroids.top().first->toString() << " -> " << termCentroids.top().second);
232             termCentroids.pop();
233         }
234         setTerms(sortedTerms);
235     }
236 
addTerm(Term * term)237     void Variable::addTerm(Term* term) {
238         _terms.push_back(term);
239     }
240 
insertTerm(Term * term,std::size_t index)241     void Variable::insertTerm(Term* term, std::size_t index) {
242         _terms.insert(_terms.begin() + index, term);
243     }
244 
getTerm(std::size_t index) const245     Term* Variable::getTerm(std::size_t index) const {
246         return _terms.at(index);
247     }
248 
getTerm(const std::string & name) const249     Term* Variable::getTerm(const std::string& name) const {
250         for (std::size_t i = 0; i < terms().size(); ++i) {
251             if (_terms.at(i)->getName() == name) {
252                 return terms().at(i);
253             }
254         }
255         throw Exception("[variable error] term <" + name + "> "
256                 "not found in variable <" + getName() + ">", FL_AT);
257     }
258 
hasTerm(const std::string & name) const259     bool Variable::hasTerm(const std::string& name) const {
260         for (std::size_t i = 0; i < _terms.size(); ++i) {
261             if (_terms.at(i)->getName() == name) {
262                 return true;
263             }
264         }
265         return false;
266     }
267 
removeTerm(std::size_t index)268     Term* Variable::removeTerm(std::size_t index) {
269         Term* result = _terms.at(index);
270         _terms.erase(_terms.begin() + index);
271         return result;
272     }
273 
numberOfTerms() const274     std::size_t Variable::numberOfTerms() const {
275         return _terms.size();
276     }
277 
terms() const278     const std::vector<Term*>& Variable::terms() const {
279         return this->_terms;
280     }
281 
setTerms(const std::vector<Term * > & terms)282     void Variable::setTerms(const std::vector<Term*>& terms) {
283         this->_terms = terms;
284     }
285 
terms()286     std::vector<Term*>& Variable::terms() {
287         return this->_terms;
288     }
289 
clone() const290     Variable* Variable::clone() const {
291         return new Variable(*this);
292     }
293 
294 }
295 
296