// 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 <cstdio>
#include <cassert>
#include <cmath>
#include <typeinfo>
#include <string.h>
// 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.<br>
* 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.<br>
* 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.<br>
* 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.<br>
* 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.<br>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.<br>
* Přidá fuzzy množinu a defuzzifikační funkci.
* @param t Fuzzy set.<br>Fuzzy množina.
* @param def Defuzzification function.<br>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.<br>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.<br> Defuzzifikuje se.
* @return It returns sharp value.<br>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.<br>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.<br>
* Vyhodnotí FuzzyBlock (proměnnou whera) a po defuzzifikaci vrátí ostrou hodnotu.
* @return Sharp value after defuzzification.<br>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.<br>
* Objekty této třídy jsou obvykle vytvářeny uvnitř příkazu if.
*/
FuzzyExpr::FuzzyExpr(FONode * node) : value(node) { }
/**
* It creates object tree.<br>Vytvoří strom objektů.
*/
FuzzyExpr::operator bool()
{
/*
FuzzyRuleValue=value;
RuleWeight=1.0;
*/
Rules::Factory()->addCondition(dynamic_cast<FOperation *>(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.<br>
* 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.<br>
* 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.<br>
* 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.<br>
* 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<FuzzyVariable*>::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.<br>
* 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<FuzzyVariable*>::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
syntax highlighted by Code2HTML, v. 0.9.1