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