diff options
Diffstat (limited to 'fuzzylite/src/Engine.cpp')
-rw-r--r-- | fuzzylite/src/Engine.cpp | 698 |
1 files changed, 698 insertions, 0 deletions
diff --git a/fuzzylite/src/Engine.cpp b/fuzzylite/src/Engine.cpp new file mode 100644 index 0000000..f1e23c0 --- /dev/null +++ b/fuzzylite/src/Engine.cpp @@ -0,0 +1,698 @@ +/* + 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/Engine.h" + +#include "fl/defuzzifier/WeightedAverage.h" +#include "fl/defuzzifier/WeightedSum.h" +#include "fl/factory/DefuzzifierFactory.h" +#include "fl/factory/FactoryManager.h" +#include "fl/factory/SNormFactory.h" +#include "fl/factory/TNormFactory.h" +#include "fl/hedge/Hedge.h" +#include "fl/imex/FllExporter.h" +#include "fl/norm/t/AlgebraicProduct.h" +#include "fl/rule/Consequent.h" +#include "fl/rule/Expression.h" +#include "fl/rule/Rule.h" +#include "fl/rule/RuleBlock.h" +#include "fl/term/Accumulated.h" +#include "fl/term/Constant.h" +#include "fl/term/Linear.h" +#include "fl/term/Function.h" +#include "fl/term/Ramp.h" +#include "fl/term/Sigmoid.h" +#include "fl/term/SShape.h" +#include "fl/term/ZShape.h" +#include "fl/variable/InputVariable.h" +#include "fl/variable/OutputVariable.h" + + +namespace fl { + + Engine::Engine(const std::string& name) : _name(name) { + } + + Engine::Engine(const Engine& other) : _name("") { + copyFrom(other); + } + + Engine& Engine::operator=(const Engine& other) { + if (this != &other) { + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) + delete _ruleblocks.at(i); + _ruleblocks.clear(); + for (std::size_t i = 0; i < _outputVariables.size(); ++i) + delete _outputVariables.at(i); + _outputVariables.clear(); + for (std::size_t i = 0; i < _inputVariables.size(); ++i) + delete _inputVariables.at(i); + _inputVariables.clear(); + + copyFrom(other); + } + return *this; + } + + void Engine::copyFrom(const Engine& other) { + _name = other._name; + for (std::size_t i = 0; i < other._inputVariables.size(); ++i) + _inputVariables.push_back(new InputVariable(*other._inputVariables.at(i))); + for (std::size_t i = 0; i < other._outputVariables.size(); ++i) + _outputVariables.push_back(new OutputVariable(*other._outputVariables.at(i))); + + updateReferences(); + + for (std::size_t i = 0; i < other._ruleblocks.size(); ++i) { + RuleBlock* ruleBlock = new RuleBlock(*other._ruleblocks.at(i)); + try { + ruleBlock->loadRules(this); + } catch (...) { + } + _ruleblocks.push_back(ruleBlock); + } + } + + void Engine::updateReferences() const { + std::vector<Variable*> myVariables = variables(); + for (std::size_t i = 0; i < myVariables.size(); ++i) { + Variable* variable = myVariables.at(i); + for (int t = 0; t < variable->numberOfTerms(); ++t) { + Term::updateReference(variable->getTerm(t), this); + } + } + } + + Engine::~Engine() { + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) delete _ruleblocks.at(i); + for (std::size_t i = 0; i < _outputVariables.size(); ++i) delete _outputVariables.at(i); + for (std::size_t i = 0; i < _inputVariables.size(); ++i) delete _inputVariables.at(i); + } + + void Engine::configure(const std::string& conjunctionT, const std::string& disjunctionS, + const std::string& activationT, const std::string& accumulationS, + const std::string& defuzzifierName, int resolution) { + TNormFactory* tnormFactory = FactoryManager::instance()->tnorm(); + SNormFactory* snormFactory = FactoryManager::instance()->snorm(); + DefuzzifierFactory* defuzzFactory = FactoryManager::instance()->defuzzifier(); + TNorm* conjunction = tnormFactory->constructObject(conjunctionT); + SNorm* disjunction = snormFactory->constructObject(disjunctionS); + TNorm* activation = tnormFactory->constructObject(activationT); + SNorm* accumulation = snormFactory->constructObject(accumulationS); + Defuzzifier* defuzzifier = defuzzFactory->constructObject(defuzzifierName); + IntegralDefuzzifier* integralDefuzzifier = dynamic_cast<IntegralDefuzzifier*> (defuzzifier); + if (integralDefuzzifier) integralDefuzzifier->setResolution(resolution); + + configure(conjunction, disjunction, activation, accumulation, defuzzifier); + } + + void Engine::configure(TNorm* conjunction, SNorm* disjunction, + TNorm* activation, SNorm* accumulation, Defuzzifier* defuzzifier) { + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) { + _ruleblocks.at(i)->setConjunction(conjunction ? conjunction->clone() : fl::null); + _ruleblocks.at(i)->setDisjunction(disjunction ? disjunction->clone() : fl::null); + _ruleblocks.at(i)->setActivation(activation ? activation->clone() : fl::null); + } + + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + _outputVariables.at(i)->setDefuzzifier(defuzzifier ? defuzzifier->clone() : fl::null); + _outputVariables.at(i)->fuzzyOutput()->setAccumulation( + accumulation ? accumulation->clone() : fl::null); + } + if (defuzzifier) delete defuzzifier; + if (accumulation) delete accumulation; + if (activation) delete activation; + if (disjunction) delete disjunction; + if (conjunction) delete conjunction; + } + + bool Engine::isReady(std::string* status) const { + std::ostringstream ss; + if (_inputVariables.empty()) { + ss << "- Engine <" << _name << "> has no input variables\n"; + } + for (std::size_t i = 0; i < _inputVariables.size(); ++i) { + InputVariable* inputVariable = _inputVariables.at(i); + if (not inputVariable) { + ss << "- Engine <" << _name << "> has a fl::null input variable at index <" << i << ">\n"; + } else if (inputVariable->terms().empty()) { + //ignore because sometimes inputs can be empty: takagi-sugeno/matlab/slcpp1.fis + // ss << "- Input variable <" << _inputVariables.at(i)->getName() << ">" + // << " has no terms\n"; + } + } + + if (_outputVariables.empty()) { + ss << "- Engine <" << _name << "> has no output variables\n"; + } + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + if (not outputVariable) { + ss << "- Engine <" << _name << "> has a fl::null output variable at index <" << i << ">\n"; + } else { + if (outputVariable->terms().empty()) { + ss << "- Output variable <" << outputVariable->getName() << ">" + << " has no terms\n"; + } + Defuzzifier* defuzzifier = outputVariable->getDefuzzifier(); + if (not defuzzifier) { + ss << "- Output variable <" << outputVariable->getName() << ">" + << " has no defuzzifier\n"; + } + SNorm* accumulation = outputVariable->fuzzyOutput()->getAccumulation(); + if (not accumulation and dynamic_cast<IntegralDefuzzifier*> (defuzzifier)) { + ss << "- Output variable <" << outputVariable->getName() << ">" + << " has no accumulation operator\n"; + } + } + } + + if (_ruleblocks.empty()) { + ss << "- Engine <" << _name << "> has no rule blocks\n"; + } + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) { + RuleBlock* ruleblock = _ruleblocks.at(i); + if (not ruleblock) { + ss << "- Engine <" << _name << "> has a fl::null rule block at index <" << i << ">\n"; + } else { + if (ruleblock->rules().empty()) { + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no rules\n"; + } + int requiresConjunction = 0; + int requiresDisjunction = 0; + int requiresActivation = 0; + for (int r = 0; r < ruleblock->numberOfRules(); ++r) { + Rule* rule = ruleblock->getRule(r); + if (not rule) { + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() + << "> has a fl::null rule at index <" << r << ">\n"; + } else { + std::size_t thenIndex = rule->getText().find(" " + Rule::thenKeyword() + " "); + std::size_t andIndex = rule->getText().find(" " + Rule::andKeyword() + " "); + std::size_t orIndex = rule->getText().find(" " + Rule::orKeyword() + " "); + if (andIndex != std::string::npos and andIndex < thenIndex) { + ++requiresConjunction; + } + if (orIndex != std::string::npos and orIndex < thenIndex) { + ++requiresDisjunction; + } + if (rule->isLoaded()) { + Consequent* consequent = rule->getConsequent(); + for (std::size_t c = 0; c < consequent->conclusions().size(); ++c) { + Proposition* proposition = consequent->conclusions().at(c); + const OutputVariable* outputVariable = + dynamic_cast<const OutputVariable*> (proposition->variable); + if (outputVariable and dynamic_cast<IntegralDefuzzifier*> (outputVariable->getDefuzzifier())) { + ++requiresActivation; + break; + } + } + } + } + } + const TNorm* conjunction = ruleblock->getConjunction(); + if (requiresConjunction > 0 and not conjunction) { + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no conjunction operator\n"; + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has " + << requiresConjunction << " rules that require conjunction operator\n"; + } + const SNorm* disjunction = ruleblock->getDisjunction(); + if (requiresDisjunction > 0 and not disjunction) { + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no disjunction operator\n"; + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has " + << requiresDisjunction << " rules that require disjunction operator\n"; + } + const TNorm* activation = ruleblock->getActivation(); + if (requiresActivation > 0 and not activation) { + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has no activation operator\n"; + ss << "- Rule block " << (i + 1) << " <" << ruleblock->getName() << "> has " + << requiresActivation << " rules that require activation operator\n"; + } + } + } + if (status) *status = ss.str(); + return ss.str().empty(); + } + + void Engine::restart() { + for (std::size_t i = 0; i < _inputVariables.size(); ++i) { + _inputVariables.at(i)->setInputValue(fl::nan); + } + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + _outputVariables.at(i)->clear(); + } + } + + void Engine::process() { + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + _outputVariables.at(i)->fuzzyOutput()->clear(); + } + + FL_DEBUG_BEGIN; + FL_DBG("==============="); + FL_DBG("CURRENT INPUTS:"); + for (std::size_t i = 0; i < _inputVariables.size(); ++i) { + InputVariable* inputVariable = _inputVariables.at(i); + scalar inputValue = inputVariable->getInputValue(); + if (inputVariable->isEnabled()) { + FL_DBG(inputVariable->getName() << ".input = " << Op::str(inputValue)); + FL_DBG(inputVariable->getName() << ".fuzzy = " << inputVariable->fuzzify(inputValue)); + } else { + FL_DBG(inputVariable->getName() << ".enabled = false"); + } + } + FL_DEBUG_END; + + + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) { + RuleBlock* ruleBlock = _ruleblocks.at(i); + if (ruleBlock->isEnabled()) { + ruleBlock->activate(); + } + } + + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + _outputVariables.at(i)->defuzzify(); + } + + FL_DEBUG_BEGIN; + FL_DBG("==============="); + FL_DBG("CURRENT OUTPUTS:"); + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + if (outputVariable->isEnabled()) { + FL_DBG(outputVariable->getName() << ".default = " + << outputVariable->getDefaultValue()); + + FL_DBG(outputVariable->getName() << ".lockValueInRange = " + << outputVariable->isLockedOutputValueInRange()); + + FL_DBG(outputVariable->getName() << ".lockPreviousValue= " + << outputVariable->isLockedPreviousOutputValue()); + + scalar output = outputVariable->getOutputValue(); + FL_DBG(outputVariable->getName() << ".output = " << output); + FL_DBG(outputVariable->getName() << ".fuzzy = " << + outputVariable->fuzzify(output)); + FL_DBG(outputVariable->fuzzyOutput()->toString()); + } else { + FL_DBG(outputVariable->getName() << ".enabled = false"); + } + } + FL_DBG("=============="); + FL_DEBUG_END; + } + + void Engine::setName(const std::string& name) { + this->_name = name; + } + + std::string Engine::getName() const { + return this->_name; + } + + std::string Engine::toString() const { + return FllExporter().toString(this); + } + + Engine::Type Engine::type(std::string* name, std::string* reason) const { + if (_outputVariables.empty()) { + if (name) *name = "Unknown"; + if (reason) *reason = "- Engine has no output variables"; + return Engine::Unknown; + } + + //Mamdani + bool mamdani = true; + for (std::size_t i = 0; mamdani and i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + //Defuzzifier must be integral + mamdani = mamdani and dynamic_cast<IntegralDefuzzifier*> (outputVariable->getDefuzzifier()); + } + //Larsen + bool larsen = mamdani and not _ruleblocks.empty(); + //Larsen is Mamdani with AlgebraicProduct as Activation + if (mamdani) { + for (std::size_t i = 0; larsen and i < _ruleblocks.size(); ++i) { + RuleBlock* ruleBlock = _ruleblocks.at(i); + larsen = larsen and dynamic_cast<const AlgebraicProduct*> (ruleBlock->getActivation()); + } + } + if (larsen) { + if (name) *name = "Larsen"; + if (reason) *reason = "- Output variables have integral defuzzifiers\n" + "- Rule blocks activate using the algebraic product T-Norm"; + return Engine::Larsen; + } + if (mamdani) { + if (name) *name = "Mamdani"; + if (reason) *reason = "-Output variables have integral defuzzifiers"; + return Engine::Mamdani; + } + //Else, keep checking + + //TakagiSugeno + bool takagiSugeno = true; + for (std::size_t i = 0; takagiSugeno and i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + //Defuzzifier is Weighted + WeightedDefuzzifier* weightedDefuzzifier = + dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier()); + + takagiSugeno = takagiSugeno and weightedDefuzzifier and + (weightedDefuzzifier->getType() == WeightedDefuzzifier::Automatic or + weightedDefuzzifier->getType() == WeightedDefuzzifier::TakagiSugeno); + + if (takagiSugeno) { + //Takagi-Sugeno has only Constant, Linear or Function terms + for (int t = 0; takagiSugeno and t < outputVariable->numberOfTerms(); ++t) { + Term* term = outputVariable->getTerm(t); + takagiSugeno = takagiSugeno and + weightedDefuzzifier->inferType(term) == WeightedDefuzzifier::TakagiSugeno; + } + } + } + if (takagiSugeno) { + if (name) *name = "Takagi-Sugeno"; + if (reason) *reason = "- Output variables have weighted defuzzifiers\n" + "- Output variables have constant, linear or function terms"; + return Engine::TakagiSugeno; + } + + //Tsukamoto + bool tsukamoto = true; + for (std::size_t i = 0; tsukamoto and i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + //Defuzzifier is Weighted + WeightedDefuzzifier* weightedDefuzzifier = + dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier()); + + tsukamoto = tsukamoto and weightedDefuzzifier and + (weightedDefuzzifier->getType() == WeightedDefuzzifier::Automatic or + weightedDefuzzifier->getType() == WeightedDefuzzifier::Tsukamoto); + if (tsukamoto) { + //Tsukamoto has only monotonic terms: Concave, Ramp, Sigmoid, SShape, or ZShape + for (int t = 0; tsukamoto and t < outputVariable->numberOfTerms(); ++t) { + Term* term = outputVariable->getTerm(t); + tsukamoto = tsukamoto and weightedDefuzzifier->isMonotonic(term); + } + } + } + if (tsukamoto) { + if (name) *name = "Tsukamoto"; + if (reason) *reason = "- Output variables have weighted defuzzifiers\n" + "- Output variables only have monotonic terms"; + return Engine::Tsukamoto; + } + + //Inverse Tsukamoto + bool inverseTsukamoto = true; + for (std::size_t i = 0; inverseTsukamoto and i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + //Defuzzifier cannot be integral + WeightedDefuzzifier* weightedDefuzzifier = + dynamic_cast<WeightedDefuzzifier*> (outputVariable->getDefuzzifier()); + inverseTsukamoto = inverseTsukamoto and weightedDefuzzifier; + } + if (inverseTsukamoto) { + if (name) *name = "Inverse Tsukamoto"; + if (reason) *reason = "- Output variables have weighted defuzzifiers\n" + "- Output variables do not only have constant, linear or function terms\n" + "- Output variables do not only have monotonic terms"; + return Engine::InverseTsukamoto; + } + + bool hybrid = true; + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + OutputVariable* outputVariable = _outputVariables.at(i); + //Output variables have non-fl::null defuzzifiers + hybrid = hybrid and outputVariable->getDefuzzifier(); + } + if (hybrid) { + if (name) *name = "Hybrid"; + if (reason) *reason = "- Output variables have different defuzzifiers"; + return Engine::Hybrid; + } + + if (name) *name = "Unknown"; + if (reason) *reason = "- There are output variables without a defuzzifier"; + return Engine::Unknown; + } + + Engine* Engine::clone() const { + return new Engine(*this); + } + + std::vector<Variable*> Engine::variables() const { + std::vector<Variable*> result; + result.reserve(_inputVariables.size() + _outputVariables.size()); + result.insert(result.end(), _inputVariables.begin(), _inputVariables.end()); + result.insert(result.end(), _outputVariables.begin(), _outputVariables.end()); + return result; + } + + /** + * Operations for InputVariables + */ + void Engine::setInputValue(const std::string& name, scalar value) { + InputVariable* inputVariable = getInputVariable(name); + inputVariable->setInputValue(value); + } + + void Engine::addInputVariable(InputVariable* inputVariable) { + this->_inputVariables.push_back(inputVariable); + } + + InputVariable* Engine::setInputVariable(InputVariable* inputVariable, int index) { + InputVariable* result = this->_inputVariables.at(index); + this->_inputVariables.at(index) = inputVariable; + return result; + } + + void Engine::insertInputVariable(InputVariable* inputVariable, int index) { + this->_inputVariables.insert(this->_inputVariables.begin() + index, + inputVariable); + } + + InputVariable* Engine::getInputVariable(int index) const { + return this->_inputVariables.at(index); + } + + InputVariable* Engine::getInputVariable(const std::string& name) const { + for (std::size_t i = 0; i < _inputVariables.size(); ++i) { + if (_inputVariables.at(i)->getName() == name) + return _inputVariables.at(i); + } + throw fl::Exception("[engine error] input variable <" + name + "> not found", FL_AT); + } + + bool Engine::hasInputVariable(const std::string& name) const { + for (std::size_t i = 0; i < _inputVariables.size(); ++i) { + if (_inputVariables.at(i)->getName() == name) + return true; + } + return false; + } + + InputVariable* Engine::removeInputVariable(int index) { + InputVariable* result = this->_inputVariables.at(index); + this->_inputVariables.erase(this->_inputVariables.begin() + index); + return result; + } + + InputVariable* Engine::removeInputVariable(const std::string& name) { + for (std::size_t i = 0; i < _inputVariables.size(); ++i) { + if (_inputVariables.at(i)->getName() == name) { + InputVariable* result = this->_inputVariables.at(i); + this->_inputVariables.erase(this->_inputVariables.begin() + i); + return result; + } + } + throw fl::Exception("[engine error] input variable <" + name + "> not found", FL_AT); + } + + int Engine::numberOfInputVariables() const { + return this->_inputVariables.size(); + } + + const std::vector<InputVariable*>& Engine::inputVariables() const { + return this->_inputVariables; + } + + void Engine::setInputVariables(const std::vector<InputVariable*>& inputVariables) { + this->_inputVariables = inputVariables; + } + + std::vector<InputVariable*>& Engine::inputVariables() { + return this->_inputVariables; + } + + /** + * Operations for OutputVariables + */ + scalar Engine::getOutputValue(const std::string& name) { + OutputVariable* outputVariable = getOutputVariable(name); + return outputVariable->getOutputValue(); + } + + void Engine::addOutputVariable(OutputVariable* outputVariable) { + this->_outputVariables.push_back(outputVariable); + } + + OutputVariable* Engine::setOutputVariable(OutputVariable* outputVariable, int index) { + OutputVariable* result = this->_outputVariables.at(index); + this->_outputVariables.at(index) = outputVariable; + return result; + } + + void Engine::insertOutputVariable(OutputVariable* outputVariable, int index) { + this->_outputVariables.insert(this->_outputVariables.begin() + index, + outputVariable); + } + + OutputVariable* Engine::getOutputVariable(int index) const { + return this->_outputVariables.at(index); + } + + OutputVariable* Engine::getOutputVariable(const std::string& name) const { + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + if (_outputVariables.at(i)->getName() == name) + return _outputVariables.at(i); + } + throw fl::Exception("[engine error] output variable <" + name + "> not found", FL_AT); + } + + bool Engine::hasOutputVariable(const std::string& name) const { + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + if (_outputVariables.at(i)->getName() == name) + return true; + } + return false; + } + + OutputVariable* Engine::removeOutputVariable(int index) { + OutputVariable* result = this->_outputVariables.at(index); + this->_outputVariables.erase(this->_outputVariables.begin() + index); + return result; + } + + OutputVariable* Engine::removeOutputVariable(const std::string& name) { + for (std::size_t i = 0; i < _outputVariables.size(); ++i) { + if (_outputVariables.at(i)->getName() == name) { + OutputVariable* result = this->_outputVariables.at(i); + this->_outputVariables.erase(this->_outputVariables.begin() + i); + return result; + } + } + throw fl::Exception("[engine error] output variable <" + name + "> not found", FL_AT); + } + + int Engine::numberOfOutputVariables() const { + return this->_outputVariables.size(); + } + + const std::vector<OutputVariable*>& Engine::outputVariables() const { + return this->_outputVariables; + } + + void Engine::setOutputVariables(const std::vector<OutputVariable*>& outputVariables) { + this->_outputVariables = outputVariables; + } + + std::vector<OutputVariable*>& Engine::outputVariables() { + return this->_outputVariables; + } + + /** + * Operations for iterable datatype _ruleblocks + */ + void Engine::addRuleBlock(RuleBlock* ruleblock) { + this->_ruleblocks.push_back(ruleblock); + } + + RuleBlock* Engine::setRuleBlock(RuleBlock* ruleBlock, int index) { + RuleBlock* result = this->_ruleblocks.at(index); + this->_ruleblocks.at(index) = ruleBlock; + return result; + } + + void Engine::insertRuleBlock(RuleBlock* ruleblock, int index) { + this->_ruleblocks.insert(this->_ruleblocks.begin() + index, ruleblock); + } + + RuleBlock* Engine::getRuleBlock(int index) const { + return this->_ruleblocks.at(index); + } + + RuleBlock* Engine::getRuleBlock(const std::string& name) const { + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) { + if (_ruleblocks.at(i)->getName() == name) + return _ruleblocks.at(i); + } + throw fl::Exception("[engine error] rule block <" + name + "> not found", FL_AT); + } + + bool Engine::hasRuleBlock(const std::string& name) const { + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) { + if (_ruleblocks.at(i)->getName() == name) + return true; + } + return false; + } + + RuleBlock* Engine::removeRuleBlock(int index) { + RuleBlock* result = this->_ruleblocks.at(index); + this->_ruleblocks.erase(this->_ruleblocks.begin() + index); + return result; + } + + RuleBlock* Engine::removeRuleBlock(const std::string& name) { + for (std::size_t i = 0; i < _ruleblocks.size(); ++i) { + if (_ruleblocks.at(i)->getName() == name) { + RuleBlock* result = this->_ruleblocks.at(i); + this->_ruleblocks.erase(this->_ruleblocks.begin() + i); + return result; + } + } + throw fl::Exception("[engine error] rule block <" + name + "> not found", FL_AT); + } + + int Engine::numberOfRuleBlocks() const { + return this->_ruleblocks.size(); + } + + const std::vector<RuleBlock*>& Engine::ruleBlocks() const { + return this->_ruleblocks; + } + + void Engine::setRuleBlocks(const std::vector<RuleBlock*>& ruleBlocks) { + this->_ruleblocks = ruleBlocks; + } + + std::vector<RuleBlock*>& Engine::ruleBlocks() { + return this->_ruleblocks; + } + + +} |