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/Engine.h" 18 19 #include "fl/activation/General.h" 20 #include "fl/defuzzifier/WeightedAverage.h" 21 #include "fl/defuzzifier/WeightedSum.h" 22 #include "fl/factory/DefuzzifierFactory.h" 23 #include "fl/factory/FactoryManager.h" 24 #include "fl/imex/FllExporter.h" 25 #include "fl/norm/t/AlgebraicProduct.h" 26 #include "fl/rule/Consequent.h" 27 #include "fl/rule/Expression.h" 28 #include "fl/rule/Rule.h" 29 #include "fl/rule/RuleBlock.h" 30 #include "fl/term/Aggregated.h" 31 #include "fl/term/Constant.h" 32 #include "fl/term/Linear.h" 33 #include "fl/term/Ramp.h" 34 #include "fl/term/Sigmoid.h" 35 #include "fl/term/SShape.h" 36 #include "fl/term/ZShape.h" 37 #include "fl/variable/InputVariable.h" 38 #include "fl/variable/OutputVariable.h" 39 40 namespace fl { 41 Engine(const std::string & name)42 Engine::Engine(const std::string& name) : _name(name) { } 43 Engine(const Engine & other)44 Engine::Engine(const Engine& other) : _name(""), _description("") { 45 copyFrom(other); 46 } 47 operator =(const Engine & other)48 Engine& Engine::operator=(const Engine& other) { 49 if (this != &other) { 50 for (std::size_t i = 0; i < _ruleBlocks.size(); ++i) 51 delete _ruleBlocks.at(i); 52 _ruleBlocks.clear(); 53 for (std::size_t i = 0; i < _outputVariables.size(); ++i) 54 delete _outputVariables.at(i); 55 _outputVariables.clear(); 56 for (std::size_t i = 0; i < _inputVariables.size(); ++i) 57 delete _inputVariables.at(i); 58 _inputVariables.clear(); 59 60 copyFrom(other); 61 } 62 return *this; 63 } 64 copyFrom(const Engine & other)65 void Engine::copyFrom(const Engine& other) { 66 _name = other._name; 67 _description = other._description; 68 for (std::size_t i = 0; i < other._inputVariables.size(); ++i) 69 _inputVariables.push_back(new InputVariable(*other._inputVariables.at(i))); 70 for (std::size_t i = 0; i < other._outputVariables.size(); ++i) 71 _outputVariables.push_back(new OutputVariable(*other._outputVariables.at(i))); 72 73 updateReferences(); 74 75 for (std::size_t i = 0; i < other._ruleBlocks.size(); ++i) { 76 RuleBlock* ruleBlock = new RuleBlock(*other._ruleBlocks.at(i)); 77 try { 78 ruleBlock->loadRules(this); 79 } catch (...) { 80 //ignore 81 } 82 _ruleBlocks.push_back(ruleBlock); 83 } 84 } 85 updateReferences() const86 void Engine::updateReferences() const { 87 std::vector<Variable*> myVariables = variables(); 88 for (std::size_t i = 0; i < myVariables.size(); ++i) { 89 Variable* variable = myVariables.at(i); 90 for (std::size_t t = 0; t < variable->numberOfTerms(); ++t) { 91 variable->getTerm(t)->updateReference(this); 92 } 93 } 94 } 95 ~Engine()96 Engine::~Engine() { 97 for (std::size_t i = 0; i < _ruleBlocks.size(); ++i) 98 delete _ruleBlocks.at(i); 99 for (std::size_t i = 0; i < _outputVariables.size(); ++i) 100 delete _outputVariables.at(i); 101 for (std::size_t i = 0; i < _inputVariables.size(); ++i) 102 delete _inputVariables.at(i); 103 } 104 configure(const std::string & conjunction,const std::string & disjunction,const std::string & implication,const std::string & aggregation,const std::string & defuzzifier,const std::string & activation)105 void Engine::configure(const std::string& conjunction, const std::string& disjunction, 106 const std::string& implication, const std::string& aggregation, 107 const std::string& defuzzifier, const std::string& activation) { 108 TNormFactory* tnormFactory = FactoryManager::instance()->tnorm(); 109 SNormFactory* snormFactory = FactoryManager::instance()->snorm(); 110 DefuzzifierFactory* defuzzFactory = FactoryManager::instance()->defuzzifier(); 111 ActivationFactory* activationFactory = FactoryManager::instance()->activation(); 112 113 TNorm* conjunctionObject = tnormFactory->constructObject(conjunction); 114 SNorm* disjunctionObject = snormFactory->constructObject(disjunction); 115 TNorm* implicationObject = tnormFactory->constructObject(implication); 116 SNorm* aggregationObject = snormFactory->constructObject(aggregation); 117 Defuzzifier* defuzzifierObject = defuzzFactory->constructObject(defuzzifier); 118 Activation* activationObject = activationFactory->constructObject(activation); 119 120 configure(conjunctionObject, disjunctionObject, 121 implicationObject, aggregationObject, defuzzifierObject, 122 activationObject); 123 } 124 configure(TNorm * conjunction,SNorm * disjunction,TNorm * implication,SNorm * aggregation,Defuzzifier * defuzzifier,Activation * activation)125 void Engine::configure(TNorm* conjunction, SNorm* disjunction, 126 TNorm* implication, SNorm* aggregation, Defuzzifier* defuzzifier, 127 Activation* activation) { 128 for (std::size_t i = 0; i < numberOfRuleBlocks(); ++i) { 129 RuleBlock* ruleBlock = ruleBlocks().at(i); 130 ruleBlock->setConjunction(conjunction ? conjunction->clone() : fl::null); 131 ruleBlock->setDisjunction(disjunction ? disjunction->clone() : fl::null); 132 ruleBlock->setImplication(implication ? implication->clone() : fl::null); 133 ruleBlock->setActivation(activation ? activation->clone() : new General); 134 } 135 136 for (std::size_t i = 0; i < numberOfOutputVariables(); ++i) { 137 OutputVariable* outputVariable = getOutputVariable(i); 138 outputVariable->setDefuzzifier(defuzzifier ? defuzzifier->clone() : fl::null); 139 outputVariable->setAggregation(aggregation ? aggregation->clone() : fl::null); 140 } 141 if (defuzzifier) delete defuzzifier; 142 if (aggregation) delete aggregation; 143 if (implication) delete implication; 144 if (disjunction) delete disjunction; 145 if (conjunction) delete conjunction; 146 if (activation) delete activation; 147 } 148 isReady(std::string * status) const149 bool Engine::isReady(std::string* status) const { 150 std::ostringstream ss; 151 if (inputVariables().empty()) { 152 ss << "- Engine <" << getName() << "> has no input variables\n"; 153 } 154 for (std::size_t i = 0; i < inputVariables().size(); ++i) { 155 InputVariable* inputVariable = inputVariables().at(i); 156 if (not inputVariable) { 157 ss << "- Engine <" << getName() << "> has a fl::null input variable at index <" << i << ">\n"; 158 } 159 /*else if (inputVariable->terms().empty()) { 160 ignore because sometimes inputs can be empty: takagi-sugeno/matlab/slcpp1.fis 161 ss << "- Input variable <" << _inputVariables.at(i)->getName() << ">" 162 << " has no terms\n"; 163 }*/ 164 } 165 166 if (outputVariables().empty()) { 167 ss << "- Engine <" << _name << "> has no output variables\n"; 168 } 169 for (std::size_t i = 0; i < outputVariables().size(); ++i) { 170 OutputVariable* outputVariable = outputVariables().at(i); 171 if (not outputVariable) { 172 ss << "- Engine <" << getName() << "> has a fl::null output variable at index <" << i << ">\n"; 173 } else { 174 if (outputVariable->terms().empty()) { 175 ss << "- Output variable <" << outputVariable->getName() << ">" 176 << " has no terms\n"; 177 } 178 Defuzzifier* defuzzifier = outputVariable->getDefuzzifier(); 179 if (not defuzzifier) { 180 ss << "- Output variable <" << outputVariable->getName() << ">" 181 << " has no defuzzifier\n"; 182 } 183 SNorm* aggregation = outputVariable->fuzzyOutput()->getAggregation(); 184 if (not aggregation and dynamic_cast<IntegralDefuzzifier*> (defuzzifier)) { 185 ss << "- Output variable <" << outputVariable->getName() << ">" 186 << " has no aggregation operator\n"; 187 } 188 } 189 } 190 191 if (ruleBlocks().empty()) { 192 ss << "- Engine <" << getName() << "> has no rule blocks\n"; 193 } 194 for (std::size_t i = 0; i < ruleBlocks().size(); ++i) { 195 RuleBlock* ruleblock = ruleBlocks().at(i); 196 if (not ruleblock) { 197 ss << "- Engine <" << getName() << "> has a fl::null rule block at index <" << i << ">\n"; 198 } else { 199 if (ruleblock->rules().empty()) { 200 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no rules\n"; 201 } 202 int requiresConjunction = 0; 203 int requiresDisjunction = 0; 204 int requiresImplication = 0; 205 for (std::size_t r = 0; r < ruleblock->numberOfRules(); ++r) { 206 Rule* rule = ruleblock->getRule(r); 207 if (not rule) { 208 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() 209 << "> has a fl::null rule at index <" << r << ">\n"; 210 } else { 211 std::size_t thenIndex = rule->getText().find(" " + Rule::thenKeyword() + " "); 212 std::size_t andIndex = rule->getText().find(" " + Rule::andKeyword() + " "); 213 std::size_t orIndex = rule->getText().find(" " + Rule::orKeyword() + " "); 214 if (andIndex != std::string::npos and andIndex < thenIndex) { 215 ++requiresConjunction; 216 } 217 if (orIndex != std::string::npos and orIndex < thenIndex) { 218 ++requiresDisjunction; 219 } 220 if (rule->isLoaded()) { 221 Consequent* consequent = rule->getConsequent(); 222 for (std::size_t c = 0; c < consequent->conclusions().size(); ++c) { 223 Proposition* proposition = consequent->conclusions().at(c); 224 const OutputVariable* outputVariable = 225 dynamic_cast<const OutputVariable*> (proposition->variable); 226 if (outputVariable and dynamic_cast<IntegralDefuzzifier*> (outputVariable->getDefuzzifier())) { 227 ++requiresImplication; 228 break; 229 } 230 } 231 } 232 } 233 } 234 const TNorm* conjunction = ruleblock->getConjunction(); 235 if (requiresConjunction > 0 and not conjunction) { 236 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no conjunction operator\n"; 237 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has " 238 << requiresConjunction << " rules that require conjunction operator\n"; 239 } 240 const SNorm* disjunction = ruleblock->getDisjunction(); 241 if (requiresDisjunction > 0 and not disjunction) { 242 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no disjunction operator\n"; 243 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has " 244 << requiresDisjunction << " rules that require disjunction operator\n"; 245 } 246 const TNorm* implication = ruleblock->getImplication(); 247 if (requiresImplication > 0 and not implication) { 248 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no implication operator\n"; 249 ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has " 250 << requiresImplication << " rules that require implication operator\n"; 251 } 252 } 253 } 254 if (status) *status = ss.str(); 255 return ss.str().empty(); 256 } 257 restart()258 void Engine::restart() { 259 for (std::size_t i = 0; i < inputVariables().size(); ++i) { 260 inputVariables().at(i)->setValue(fl::nan); 261 } 262 for (std::size_t i = 0; i < outputVariables().size(); ++i) { 263 outputVariables().at(i)->clear(); 264 } 265 } 266 complexity() const267 Complexity Engine::complexity() const { 268 Complexity result; 269 for (std::size_t i = 0; i < _ruleBlocks.size(); ++i) { 270 const RuleBlock* ruleBlock = _ruleBlocks.at(i); 271 if (ruleBlock->isEnabled()) { 272 result += ruleBlock->complexity(); 273 } 274 } 275 return result; 276 } 277 process()278 void Engine::process() { 279 for (std::size_t i = 0; i < _outputVariables.size(); ++i) { 280 _outputVariables.at(i)->fuzzyOutput()->clear(); 281 } 282 283 FL_DEBUG_BEGIN; 284 FL_DBG("==============="); 285 FL_DBG("CURRENT INPUTS:"); 286 for (std::size_t i = 0; i < _inputVariables.size(); ++i) { 287 InputVariable* inputVariable = _inputVariables.at(i); 288 scalar inputValue = inputVariable->getValue(); 289 if (inputVariable->isEnabled()) { 290 FL_DBG(inputVariable->getName() << ".input = " << Op::str(inputValue)); 291 FL_DBG(inputVariable->getName() << ".fuzzy = " << inputVariable->fuzzify(inputValue)); 292 } else { 293 FL_DBG(inputVariable->getName() << ".enabled = false"); 294 } 295 } 296 FL_DEBUG_END; 297 298 299 for (std::size_t i = 0; i < _ruleBlocks.size(); ++i) { 300 RuleBlock* ruleBlock = _ruleBlocks.at(i); 301 if (ruleBlock->isEnabled()) { 302 FL_DBG("==============="); 303 FL_DBG("RULE BLOCK: " << ruleBlock->getName()); 304 ruleBlock->activate(); 305 } 306 } 307 308 for (std::size_t i = 0; i < _outputVariables.size(); ++i) { 309 _outputVariables.at(i)->defuzzify(); 310 } 311 312 FL_DEBUG_BEGIN; 313 FL_DBG("==============="); 314 FL_DBG("CURRENT OUTPUTS:"); 315 for (std::size_t i = 0; i < _outputVariables.size(); ++i) { 316 OutputVariable* outputVariable = _outputVariables.at(i); 317 if (outputVariable->isEnabled()) { 318 FL_DBG(outputVariable->getName() << ".default = " 319 << outputVariable->getDefaultValue()); 320 321 FL_DBG(outputVariable->getName() << ".lockValueInRange = " 322 << outputVariable->isLockValueInRange()); 323 324 FL_DBG(outputVariable->getName() << ".lockPreviousValue= " 325 << outputVariable->isLockPreviousValue()); 326 327 scalar output = outputVariable->getValue(); 328 FL_DBG(outputVariable->getName() << ".output = " << output); 329 FL_DBG(outputVariable->getName() << ".fuzzy = " << 330 outputVariable->fuzzify(output)); 331 FL_DBG(outputVariable->fuzzyOutput()->toString()); 332 } else { 333 FL_DBG(outputVariable->getName() << ".enabled = false"); 334 } 335 } 336 FL_DBG("=============="); 337 FL_DEBUG_END; 338 } 339 setName(const std::string & name)340 void Engine::setName(const std::string& name) { 341 this->_name = name; 342 } 343 getName() const344 std::string Engine::getName() const { 345 return this->_name; 346 } 347 setDescription(const std::string & description)348 void Engine::setDescription(const std::string& description) { 349 this->_description = description; 350 } 351 getDescription() const352 std::string Engine::getDescription() const { 353 return this->_description; 354 } 355 toString() const356 std::string Engine::toString() const { 357 return FllExporter().toString(this); 358 } 359 type(std::string * name,std::string * reason) const360 Engine::Type Engine::type(std::string* name, std::string* reason) const { 361 if (outputVariables().empty()) { 362 if (name) *name = "Unknown"; 363 if (reason) *reason = "- Engine has no output variables"; 364 return Engine::Unknown; 365 } 366 367 //Mamdani 368 bool mamdani = true; 369 for (std::size_t i = 0; mamdani and i < outputVariables().size(); ++i) { 370 OutputVariable* outputVariable = outputVariables().at(i); 371 //Defuzzifier must be integral 372 mamdani = mamdani and dynamic_cast<IntegralDefuzzifier*> (outputVariable->getDefuzzifier()); 373 } 374 //Larsen 375 bool larsen = mamdani and not ruleBlocks().empty(); 376 //Larsen is Mamdani with AlgebraicProduct as Implication 377 if (mamdani) { 378 for (std::size_t i = 0; larsen and i < ruleBlocks().size(); ++i) { 379 RuleBlock* ruleBlock = ruleBlocks().at(i); 380 larsen = larsen and dynamic_cast<const AlgebraicProduct*> (ruleBlock->getImplication()); 381 } 382 } 383 if (larsen) { 384 if (name) *name = "Larsen"; 385 if (reason) *reason = "- Output variables have integral defuzzifiers\n" 386 "- Implication in rule blocks is the algebraic product T-Norm"; 387 return Engine::Larsen; 388 } 389 if (mamdani) { 390 if (name) *name = "Mamdani"; 391 if (reason) *reason = "-Output variables have integral defuzzifiers"; 392 return Engine::Mamdani; 393 } 394 //Else, keep checking 395 396 //TakagiSugeno 397 bool takagiSugeno = true; 398 for (std::size_t i = 0; takagiSugeno and i < outputVariables().size(); ++i) { 399 OutputVariable* outputVariable = outputVariables().at(i); 400 //Defuzzifier is Weighted 401 WeightedDefuzzifier* weightedDefuzzifier = 402 dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier()); 403 404 takagiSugeno = takagiSugeno and weightedDefuzzifier and 405 (weightedDefuzzifier->getType() == WeightedDefuzzifier::Automatic or 406 weightedDefuzzifier->getType() == WeightedDefuzzifier::TakagiSugeno); 407 408 if (takagiSugeno) { 409 //Takagi-Sugeno has only Constant, Linear or Function terms 410 for (std::size_t t = 0; takagiSugeno and t < outputVariable->numberOfTerms(); ++t) { 411 Term* term = outputVariable->getTerm(t); 412 takagiSugeno = takagiSugeno and 413 weightedDefuzzifier->inferType(term) == WeightedDefuzzifier::TakagiSugeno; 414 } 415 } 416 } 417 if (takagiSugeno) { 418 if (name) *name = "Takagi-Sugeno"; 419 if (reason) *reason = "- Output variables have weighted defuzzifiers\n" 420 "- Output variables have constant, linear or function terms"; 421 return Engine::TakagiSugeno; 422 } 423 424 //Tsukamoto 425 bool tsukamoto = true; 426 for (std::size_t i = 0; tsukamoto and i < outputVariables().size(); ++i) { 427 OutputVariable* outputVariable = outputVariables().at(i); 428 //Defuzzifier is Weighted 429 WeightedDefuzzifier* weightedDefuzzifier = 430 dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier()); 431 432 tsukamoto = tsukamoto and weightedDefuzzifier and 433 (weightedDefuzzifier->getType() == WeightedDefuzzifier::Automatic or 434 weightedDefuzzifier->getType() == WeightedDefuzzifier::Tsukamoto); 435 if (tsukamoto) { 436 //Tsukamoto has only monotonic terms: Concave, Ramp, Sigmoid, SShape, or ZShape 437 for (std::size_t t = 0; tsukamoto and t < outputVariable->numberOfTerms(); ++t) { 438 Term* term = outputVariable->getTerm(t); 439 tsukamoto = tsukamoto and term->isMonotonic(); 440 } 441 } 442 } 443 if (tsukamoto) { 444 if (name) *name = "Tsukamoto"; 445 if (reason) *reason = "- Output variables have weighted defuzzifiers\n" 446 "- Output variables only have monotonic terms"; 447 return Engine::Tsukamoto; 448 } 449 450 //Inverse Tsukamoto 451 bool inverseTsukamoto = true; 452 for (std::size_t i = 0; inverseTsukamoto and i < outputVariables().size(); ++i) { 453 OutputVariable* outputVariable = outputVariables().at(i); 454 //Defuzzifier cannot be integral 455 WeightedDefuzzifier* weightedDefuzzifier = 456 dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier()); 457 inverseTsukamoto = inverseTsukamoto and weightedDefuzzifier; 458 } 459 if (inverseTsukamoto) { 460 if (name) *name = "Inverse Tsukamoto"; 461 if (reason) *reason = "- Output variables have weighted defuzzifiers\n" 462 "- Output variables do not only have constant, linear or function terms\n" 463 "- Output variables do not only have monotonic terms"; 464 return Engine::InverseTsukamoto; 465 } 466 467 bool hybrid = true; 468 for (std::size_t i = 0; i < outputVariables().size(); ++i) { 469 OutputVariable* outputVariable = outputVariables().at(i); 470 //Output variables have non-fl::null defuzzifiers 471 hybrid = hybrid and outputVariable->getDefuzzifier(); 472 } 473 if (hybrid) { 474 if (name) *name = "Hybrid"; 475 if (reason) *reason = "- Output variables have different types of defuzzifiers"; 476 return Engine::Hybrid; 477 } 478 479 if (name) *name = "Unknown"; 480 if (reason) *reason = "- One or more output variables do not have a defuzzifier"; 481 return Engine::Unknown; 482 } 483 clone() const484 Engine* Engine::clone() const { 485 return new Engine(*this); 486 } 487 variables() const488 std::vector<Variable*> Engine::variables() const { 489 std::vector<Variable*> result; 490 result.reserve(inputVariables().size() + outputVariables().size()); 491 result.insert(result.end(), inputVariables().begin(), inputVariables().end()); 492 result.insert(result.end(), outputVariables().begin(), outputVariables().end()); 493 return result; 494 } 495 496 /** 497 * Operations for InputVariables 498 */ setInputValue(const std::string & name,scalar value)499 void Engine::setInputValue(const std::string& name, scalar value) { 500 InputVariable* inputVariable = getInputVariable(name); 501 inputVariable->setValue(value); 502 } 503 addInputVariable(InputVariable * inputVariable)504 void Engine::addInputVariable(InputVariable* inputVariable) { 505 inputVariables().push_back(inputVariable); 506 } 507 setInputVariable(InputVariable * inputVariable,std::size_t index)508 InputVariable* Engine::setInputVariable(InputVariable* inputVariable, std::size_t index) { 509 InputVariable* result = inputVariables().at(index); 510 inputVariables().at(index) = inputVariable; 511 return result; 512 } 513 insertInputVariable(InputVariable * inputVariable,std::size_t index)514 void Engine::insertInputVariable(InputVariable* inputVariable, std::size_t index) { 515 inputVariables().insert(inputVariables().begin() + index, inputVariable); 516 } 517 getInputVariable(std::size_t index) const518 InputVariable* Engine::getInputVariable(std::size_t index) const { 519 return inputVariables().at(index); 520 } 521 getInputVariable(const std::string & name) const522 InputVariable* Engine::getInputVariable(const std::string& name) const { 523 for (std::size_t i = 0; i < inputVariables().size(); ++i) { 524 if (inputVariables().at(i)->getName() == name) 525 return inputVariables().at(i); 526 } 527 throw Exception("[engine error] input variable <" + name + "> not found", FL_AT); 528 } 529 hasInputVariable(const std::string & name) const530 bool Engine::hasInputVariable(const std::string& name) const { 531 for (std::size_t i = 0; i < inputVariables().size(); ++i) { 532 if (inputVariables().at(i)->getName() == name) 533 return true; 534 } 535 return false; 536 } 537 removeInputVariable(std::size_t index)538 InputVariable* Engine::removeInputVariable(std::size_t index) { 539 InputVariable* result = inputVariables().at(index); 540 inputVariables().erase(inputVariables().begin() + index); 541 return result; 542 } 543 removeInputVariable(const std::string & name)544 InputVariable* Engine::removeInputVariable(const std::string& name) { 545 for (std::size_t i = 0; i < inputVariables().size(); ++i) { 546 if (inputVariables().at(i)->getName() == name) { 547 InputVariable* result = inputVariables().at(i); 548 inputVariables().erase(inputVariables().begin() + i); 549 return result; 550 } 551 } 552 throw Exception("[engine error] input variable <" + name + "> not found", FL_AT); 553 } 554 numberOfInputVariables() const555 std::size_t Engine::numberOfInputVariables() const { 556 return inputVariables().size(); 557 } 558 inputVariables() const559 const std::vector<InputVariable*>& Engine::inputVariables() const { 560 return this->_inputVariables; 561 } 562 setInputVariables(const std::vector<InputVariable * > & inputVariables)563 void Engine::setInputVariables(const std::vector<InputVariable*>& inputVariables) { 564 this->_inputVariables = inputVariables; 565 } 566 inputVariables()567 std::vector<InputVariable*>& Engine::inputVariables() { 568 return this->_inputVariables; 569 } 570 571 /** 572 * Operations for OutputVariables 573 */ getOutputValue(const std::string & name)574 scalar Engine::getOutputValue(const std::string& name) { 575 OutputVariable* outputVariable = getOutputVariable(name); 576 return outputVariable->getValue(); 577 } 578 addOutputVariable(OutputVariable * outputVariable)579 void Engine::addOutputVariable(OutputVariable* outputVariable) { 580 outputVariables().push_back(outputVariable); 581 } 582 setOutputVariable(OutputVariable * outputVariable,std::size_t index)583 OutputVariable* Engine::setOutputVariable(OutputVariable* outputVariable, std::size_t index) { 584 OutputVariable* result = outputVariables().at(index); 585 outputVariables().at(index) = outputVariable; 586 return result; 587 } 588 insertOutputVariable(OutputVariable * outputVariable,std::size_t index)589 void Engine::insertOutputVariable(OutputVariable* outputVariable, std::size_t index) { 590 outputVariables().insert(outputVariables().begin() + index, outputVariable); 591 } 592 getOutputVariable(std::size_t index) const593 OutputVariable* Engine::getOutputVariable(std::size_t index) const { 594 return outputVariables().at(index); 595 } 596 getOutputVariable(const std::string & name) const597 OutputVariable* Engine::getOutputVariable(const std::string& name) const { 598 for (std::size_t i = 0; i < outputVariables().size(); ++i) { 599 if (outputVariables().at(i)->getName() == name) 600 return outputVariables().at(i); 601 } 602 throw Exception("[engine error] output variable <" + name + "> not found", FL_AT); 603 } 604 hasOutputVariable(const std::string & name) const605 bool Engine::hasOutputVariable(const std::string& name) const { 606 for (std::size_t i = 0; i < outputVariables().size(); ++i) { 607 if (outputVariables().at(i)->getName() == name) 608 return true; 609 } 610 return false; 611 } 612 removeOutputVariable(std::size_t index)613 OutputVariable* Engine::removeOutputVariable(std::size_t index) { 614 OutputVariable* result = outputVariables().at(index); 615 outputVariables().erase(outputVariables().begin() + index); 616 return result; 617 } 618 removeOutputVariable(const std::string & name)619 OutputVariable* Engine::removeOutputVariable(const std::string& name) { 620 for (std::size_t i = 0; i < outputVariables().size(); ++i) { 621 if (outputVariables().at(i)->getName() == name) { 622 OutputVariable* result = outputVariables().at(i); 623 outputVariables().erase(outputVariables().begin() + i); 624 return result; 625 } 626 } 627 throw Exception("[engine error] output variable <" + name + "> not found", FL_AT); 628 } 629 numberOfOutputVariables() const630 std::size_t Engine::numberOfOutputVariables() const { 631 return outputVariables().size(); 632 } 633 outputVariables() const634 const std::vector<OutputVariable*>& Engine::outputVariables() const { 635 return this->_outputVariables; 636 } 637 setOutputVariables(const std::vector<OutputVariable * > & outputVariables)638 void Engine::setOutputVariables(const std::vector<OutputVariable*>& outputVariables) { 639 this->_outputVariables = outputVariables; 640 } 641 outputVariables()642 std::vector<OutputVariable*>& Engine::outputVariables() { 643 return this->_outputVariables; 644 } 645 646 /** 647 * Operations for iterable datatype _ruleblocks 648 */ addRuleBlock(RuleBlock * ruleblock)649 void Engine::addRuleBlock(RuleBlock* ruleblock) { 650 ruleBlocks().push_back(ruleblock); 651 } 652 setRuleBlock(RuleBlock * ruleBlock,std::size_t index)653 RuleBlock* Engine::setRuleBlock(RuleBlock* ruleBlock, std::size_t index) { 654 RuleBlock* result = ruleBlocks().at(index); 655 ruleBlocks().at(index) = ruleBlock; 656 return result; 657 } 658 insertRuleBlock(RuleBlock * ruleblock,std::size_t index)659 void Engine::insertRuleBlock(RuleBlock* ruleblock, std::size_t index) { 660 ruleBlocks().insert(ruleBlocks().begin() + index, ruleblock); 661 } 662 getRuleBlock(std::size_t index) const663 RuleBlock* Engine::getRuleBlock(std::size_t index) const { 664 return ruleBlocks().at(index); 665 } 666 getRuleBlock(const std::string & name) const667 RuleBlock* Engine::getRuleBlock(const std::string& name) const { 668 for (std::size_t i = 0; i < ruleBlocks().size(); ++i) { 669 if (ruleBlocks().at(i)->getName() == name) 670 return ruleBlocks().at(i); 671 } 672 throw Exception("[engine error] rule block <" + name + "> not found", FL_AT); 673 } 674 hasRuleBlock(const std::string & name) const675 bool Engine::hasRuleBlock(const std::string& name) const { 676 for (std::size_t i = 0; i < ruleBlocks().size(); ++i) { 677 if (ruleBlocks().at(i)->getName() == name) 678 return true; 679 } 680 return false; 681 } 682 removeRuleBlock(std::size_t index)683 RuleBlock* Engine::removeRuleBlock(std::size_t index) { 684 RuleBlock* result = ruleBlocks().at(index); 685 ruleBlocks().erase(ruleBlocks().begin() + index); 686 return result; 687 } 688 removeRuleBlock(const std::string & name)689 RuleBlock* Engine::removeRuleBlock(const std::string& name) { 690 for (std::size_t i = 0; i < ruleBlocks().size(); ++i) { 691 if (ruleBlocks().at(i)->getName() == name) { 692 RuleBlock* result = ruleBlocks().at(i); 693 ruleBlocks().erase(ruleBlocks().begin() + i); 694 return result; 695 } 696 } 697 throw Exception("[engine error] rule block <" + name + "> not found", FL_AT); 698 } 699 numberOfRuleBlocks() const700 std::size_t Engine::numberOfRuleBlocks() const { 701 return ruleBlocks().size(); 702 } 703 ruleBlocks() const704 const std::vector<RuleBlock*>& Engine::ruleBlocks() const { 705 return this->_ruleBlocks; 706 } 707 setRuleBlocks(const std::vector<RuleBlock * > & ruleBlocks)708 void Engine::setRuleBlocks(const std::vector<RuleBlock*>& ruleBlocks) { 709 this->_ruleBlocks = ruleBlocks; 710 } 711 ruleBlocks()712 std::vector<RuleBlock*>& Engine::ruleBlocks() { 713 return this->_ruleBlocks; 714 } 715 716 } 717