// cz - příliš žluťoučký kůň úpěl ďábelské ódy ///////////////////////////////////////////////////////////////////////////// // fuzzyrul.cc // // SIMLIB version: 2.16.3 // Date: 2001-04-04 // Copyright (c) 1999-2001 Dr. Ing. Petr Peringer, David Martinek // // This library is licensed under GNU Library GPL. See the file COPYING. // // Warning: this is EXPERIMENTAL code, interfaces can be changed // // Fuzzy subsystem for SIMLIB // version 0.6 --- We apr 4 10:33:52 CEST 2001 // ///////////////////////////////////////////////////////////////////////////// // Implementation of fuzzy rules. ///////////////////////////////////////////////////////////////////////////// #include "simlib.h" #include "fuzzy.h" #include "internal.h" #include #include #include #include #include // global result of if(condition) rule // should be in static of class FuzzyInferenceRules //static double FuzzyRuleValue=1.0f; //static double RuleWeight=1.0; ///////////////////////////////////////////////////////////////////////////// // Static class Rules FuzzyGeneralRules * Rules::rules = NULL; FuzzyRuleFactory * Rules::factory = NULL; bool Rules::addedInput = false; bool Rules::addedOutput = false; bool Rules::addRule = false; /** It initializes data members. */ void Rules::init() { if (Rules::rules != NULL) delete rules; if (Rules::factory != NULL) delete factory; Rules::rules = NULL; Rules::factory = NULL; Rules::addedInput = false; Rules::addedOutput = false; Rules::addRule = false; } /** * It adds next input into the list. This is needed because of error checking.
* Přidá další vstup do seznamu. Tato metoda je potřeba kvůli ošetření chyb. */ void Rules::addFuzzyInput(FuzzyInput * input) { if (Rules::rules == NULL) { Rules::rules = new FuzzyGeneralRules(); } Rules::rules->addFuzzyInput(input); Rules::addedInput = true; } /** * It adds next output into the list. This is needed because of error checking.
* Přidá další výstup do seznamu. Tato metoda je potřeba kvůli ošetření chyb. */ void Rules::addFuzzyOutput(FuzzyOutput * output) { if (Rules::rules == NULL) { Rules::rules = new FuzzyGeneralRules(); } Rules::rules->addFuzzyOutput(output); Rules::addedOutput = true; } /** * It returns complete definition of inference rules. See at class FuzzyExpr to see how to * create inference rules.
* Vrací kompletní definici inferenčních pravidel. Podívejte se na třídu FuzzyExpr jak se * vytváří inferenční pravidla. */ FuzzyGeneralRules * Rules::getRules() { if (!(Rules::addedOutput && Rules::addedInput)) { SIMLIB_error("In fuzzy regulator must be defined inputs and outputs!"); } FuzzyGeneralRules * result = Rules::rules; Rules::rules = NULL; Rules::init(); return result; } /** * It produces error if there is not enough inputs and outputs or it returns FuzzyRuleFactory.
* Způsobí chybu, jestliže není definováno dostatečné množství vstupů a výstupů nebo vrátí * FuzzyRuleFactory. */ FuzzyRuleFactory * Rules::Factory() { if (!(Rules::addedOutput && Rules::addedInput)) { SIMLIB_error("In fuzzy regulator must be defined inputs and outputs!"); } if (Rules::factory == NULL) { Rules::factory = Rules::rules->createRuleFactory(); } return Rules::factory; } /** * It adds new rule into rules.
Přidá nové pravidlo do rules. */ void Rules::addNewRule() { Rules::rules->add(Rules::factory->createRule()); } ///////////////////////////////////////////////////////////////////////////// // FuzzyOutput --- continuous output (aggregation, defuzzification) // /** * It adds fuzzy set and defuzzification function.
* Přidá fuzzy množinu a defuzzifikační funkci. * @param t Fuzzy set.
Fuzzy množina. * @param def Defuzzification function.
Defuzzifikační funkce. */ FuzzyOutput::FuzzyOutput(const FuzzySet &t, double (*def)(const FuzzyVariable&)) : FuzzyVariable(t), defuzzify(def) { TRACE(printf("FuzzyOutput::FuzzyOutput()\n")); // default: zero all } /** * It assignes fuzzy value by word value.
Přiřadí fuzzy hodnotu pomocí slovní hodnoty. */ // op = in fuzzy rule const char *FuzzyOutput::operator = (const char *val) { /* int i = search(val); (*this)[i] = max((*this)[i], RuleWeight*FuzzyRuleValue); */ // Rules::Factory()->addConsequent(Rules::Factory()->createNode(this, strdup(val))); Rules::Factory()->addConsequent(Rules::Factory()->createNode(this, val)); Rules::addRule = true; return val; // allow a=b=c="xx" } /** * It defuzzifies itself.
Defuzzifikuje se. * @return It returns sharp value.
Vrátí osrou hodnotu. */ double FuzzyOutput::Defuzzify() { // Print(); if(defuzzify==0) SIMLIB_error("no defuuzification method set"); value = defuzzify(*this); //::Print("Defuzzify=%g\n",value); return value; } /** It adds defuzzification function.
Přidá defuzzifikační funkci. */ void FuzzyOutput::SetDefuzzifyMethod(double (*f)(const FuzzyVariable&)) { if(f==0) SIMLIB_error("no defuzification method"); defuzzify = f; } /** * Evaluates FuzzyBlock (variable where) and after defuzzification returns sharp value.
* Vyhodnotí FuzzyBlock (proměnnou whera) a po defuzzifikaci vrátí ostrou hodnotu. * @return Sharp value after defuzzification.
Ostrá hodnota po defuzzifikaci. */ double FuzzyOutput::Value() { if (Where() == 0) SIMLIB_error("Fuzzy set should be used inside FuzzyBlock only"); Where()->Evaluate(); // evaluate fuzzy block return value; // return value; } FuzzyOutput::~FuzzyOutput() { TRACE(printf("~FuzzyOutput()\n")); } ///////////////////////////////////////////////////////////////////////////// // FuzzyExpr --- fuzzy expression value class // TODO: check if allowed -- global state set in class FuzzyInfer /** * Objects of this class are usualy created inside if command.
* Objekty této třídy jsou obvykle vytvářeny uvnitř příkazu if. */ FuzzyExpr::FuzzyExpr(FONode * node) : value(node) { } /** * It creates object tree.
Vytvoří strom objektů. */ FuzzyExpr::operator bool() { /* FuzzyRuleValue=value; RuleWeight=1.0; */ Rules::Factory()->addCondition(dynamic_cast(Value())); return true; // always go to then section } ///////////////////////////////////////////////////////////////////////////// // Fuzzy operators // // AND /** * if ((FuzzyExpr) && (FuzzyExpr)) */ FuzzyExpr operator && (FuzzyExpr o1, FuzzyExpr o2) { // return FuzzyExpr(min(o1.Value(), o2.Value())); return FuzzyExpr(Rules::Factory()->createNode(o1.Value(), o2.Value(), FuzzyInferenceRules::opAND)); } // OR /** * if ((FuzzyExpr) || (FuzzyExpr)) */ FuzzyExpr operator || (FuzzyExpr o1, FuzzyExpr o2) { // return FuzzyExpr(max(o1.Value(), o2.Value())); return FuzzyExpr(Rules::Factory()->createNode(o1.Value(), o2.Value(), FuzzyInferenceRules::opOR)); } // NOT /** * if (!(FuzzyExpr)) */ FuzzyExpr operator ! (FuzzyExpr o1) { // return FuzzyExpr(1-o1.Value()); return FuzzyExpr(Rules::Factory()->createNode(o1.Value(), FuzzyInferenceRules::opNOT)); } // is /** * if ((input == "wordvalue")...) */ FuzzyExpr operator == (FuzzyInput &in, const char *s) { if (Rules::addRule) { Rules::addRule = false; Rules::addNewRule(); } // return FuzzyExpr(Rules::Factory()->createNode(&in, strdup(s))); return FuzzyExpr(Rules::Factory()->createNode(&in, s)); } // TODO: kontrola neprazdne then-casti // rule: // if (a=="small" && b=="big") out="big" // alternativni syntaxe: (e1) -> (e2) // (e1), (e2) // (e1); (e2) // e = |||||||||||||||||||||| // out("big").add( e ) // 2lists: // expression += e // result += out ///////////////////////////////////////////////////////////////////////////// // FuzzyBlock --- base class for inference blocks // FuzzyBlock *activeFuzzyBlock = 0; // 0 == global /** * If inference rules are specified by FuzzyExpr way then you must call * EndConstructor method on the end of constructor.
* Jestliže jsou inferenční pravidla specifikována pomocí FuzzyExpr, pak musíte * zavolat metodu EndConstructor na konci konstruktoru. */ FuzzyBlock::FuzzyBlock() { where = activeFuzzyBlock; // hierarhical position activeFuzzyBlock = this; lastTime = -1.0; } /** * If inference rules are specified by FuzzyExpr way then you must call this * method on the end of constructor.
* Jestliže jsou inferenční pravidla specifikována pomocí FuzzyExpr, pak musíte * zavolat tuto metodu na konci konstruktoru. */ void FuzzyBlock::EndConstructor() { activeFuzzyBlock = where; } /** * It registers fuzzy variable inside this object. If inference rules are NOT specified * by FuzzyExpr way then you must call this method inside the constructor for all FuzzyInput * and FuzzyOutput variables.
* Registruje fuzzy proměnnou v tomto objektu. Jestliže NEjsou inferenční pravidla * specifikována pomocí FuzzyExpr, pak musíte zavolat tuto metodu v konstruktoru pro všechny * proměnné typu FuzzyInput a FuzzyOutput. */ void FuzzyBlock::Register(FuzzyVariable *fs) { vlist.push_back(fs); } /** * It evaluates whole block. It calls method Behavior.
* Vyhodnotí celý blok. Volá metodu Behavior. */ void FuzzyBlock::Evaluate() { // TODO: OPTIMIZATION: check if evaluated // #### warning: returns-in-time, algebraic loops, discontinuities ###!!! if(lastTime==Time) return; // was already evaluated at this time lastTime = Time; // for_each dlist::iterator i; for(i=vlist.begin(); i!=vlist.end(); i++) (*i)->Init(); // fuzzify input, init output Behavior(); // execute rules, aggregate output // for_each for(i=vlist.begin(); i!=vlist.end(); i++) (*i)->Done(); // defuzzify outputs } ///////////////////////////////////////////////////////////// // 2001-02-26 - David Martinek added class FuzzySampledBlock // - sampled fuzzy block with inference rules /** * It evaluates fuzzy inference rules but only in sampled time steps.
* Vyhodnotí fuzzy inferenční pravidla, ale jenom ve vzorkovaných časových okamžicích. */ void FuzzySampledBlock::Evaluate() { if ((Time - lastTime >= sampler->getTimeStep()) || (Time == 0)) { lastTime = Time; dlist::iterator i; for (i = vlist.begin(); i != vlist.end(); i++) (*i)->Init(); // fuzzify input, init output Behavior(); for (i = vlist.begin(); i != vlist.end(); i++) (*i)->Done(); // defuzzify outputs } } // end