dynrules

RuleSet.cpp

00001 /*
00002  * dynrules - Python dynamic rules engine
00003  *
00004  * Authors: Marcus von Appen
00005  *
00006  * This file is distributed under the Public Domain.
00007  */
00008 
00009 #include <stdexcept>
00010 #include "RuleSet.h"
00011 
00012 namespace dynrules
00013 {
00014 
00015 RuleSet::RuleSet () :
00016     _minweight(0),
00017     _maxweight(0),
00018     _weight(0),
00019     _rules(0)
00020 {
00021 }
00022 
00023 RuleSet::RuleSet (double minweight, double maxweight) :
00024     _minweight(0),
00025     _maxweight(0),
00026     _weight(0),
00027     _rules(0)
00028 {
00029     if (minweight > maxweight)
00030         throw std::invalid_argument ("maxweight must not be smaller than minweight");
00031     this->_minweight = minweight;
00032     this->_maxweight = maxweight;
00033 }
00034 
00035 RuleSet::~RuleSet ()
00036 {
00037 }
00038 
00039 double RuleSet::getMinWeight () const
00040 {
00041     return this->_minweight;
00042 }
00043 
00044 void RuleSet::setMinWeight (double minweight)
00045 {
00046     if (minweight > this->_maxweight)
00047         throw std::invalid_argument ("maxweight must not be smaller than minweight");
00048     this->_minweight = minweight;
00049 }
00050 
00051 double RuleSet::getMaxWeight () const
00052 {
00053     return this->_maxweight;
00054 }
00055 
00056 void RuleSet::setMaxWeight (double maxweight)
00057 {
00058     if (maxweight < this->_minweight)
00059         throw std::invalid_argument ("maxweight must not be smaller than minweight");
00060     this->_maxweight = maxweight;
00061 }
00062 
00063 double RuleSet::getWeight () const
00064 {
00065     return this->_weight;
00066 }
00067 
00068 std::vector<Rule*> RuleSet::getRules () const
00069 {
00070     return this->_rules;
00071 }
00072 
00073 void RuleSet::addRule (Rule* rule)
00074 {
00075     if (rule == 0)
00076         throw std::invalid_argument ("rule must not be NULL");
00077 
00078     this->_rules.push_back (rule);
00079     if (rule->getWeight() > this->_maxweight)
00080         rule->setWeight (this->_maxweight);
00081     else if (rule->getWeight () < this->_minweight)
00082         rule->setWeight (this->_minweight);
00083     this->_weight += rule->getWeight ();
00084 }
00085 
00086 bool RuleSet::removeRule (Rule* rule)
00087 {
00088     if (rule == 0)
00089         return false;
00090 
00091     bool found = false;
00092     std::vector<Rule*>::iterator iter;
00093     for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++)
00094     {
00095         if ((*iter) == rule)
00096         {
00097             found = true;
00098             break;
00099         }
00100     }
00101     if (found)
00102     {
00103         this->_rules.erase (iter);
00104         this->_weight -= (*iter)->getWeight ();
00105     }
00106     return found;
00107 }
00108 
00109 Rule *RuleSet::find (int id)
00110 {
00111     std::vector<Rule*>::iterator iter;
00112     for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++)
00113         if ((*iter)->getId () == id)
00114             return *iter;
00115     return 0;
00116 }
00117 
00118 void RuleSet::clear ()
00119 {
00120     this->_rules.clear();
00121     this->_weight = 0.f;
00122 }
00123 
00124 void RuleSet::updateWeights (void *fitness)
00125 {
00126     /*
00127      * Adapted from Pieter Spronck's algorithm as explained in
00128      * Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'
00129      */
00130     Rule *rule;
00131     std::vector<Rule*>::iterator it;
00132     size_t count, usedcount = 0, nonactive;
00133     double totweight = 0, adjustment, compensation, _remainder, weight;
00134 
00135     count = this->_rules.size ();
00136     if (count == 0)
00137         return;
00138 
00139     for (it = this->_rules.begin (); it != this->_rules.end (); it++)
00140     {
00141         rule = *it;
00142         if (rule->getUsed ())
00143             usedcount++;
00144     }
00145     if (usedcount == 0 || usedcount == count)
00146         return;
00147 
00148     nonactive = count - usedcount;
00149     adjustment = this->calculateAdjustment (fitness);
00150     compensation = (static_cast<double>(-(static_cast<int>(usedcount)) *
00151             adjustment)) / nonactive;
00152     _remainder = 0;
00153 
00154     for (it = this->_rules.begin (); it != this->_rules.end (); it++)
00155     {
00156         rule = *it;
00157 
00158         weight = rule->getWeight () +
00159             ((rule->getUsed ()) ? adjustment : compensation);
00160 
00161         if (weight < this->_minweight)
00162         {
00163             _remainder += (weight - this->_minweight);
00164             rule->setWeight (this->_minweight);
00165         }
00166         else if (weight > this->_maxweight)
00167         {
00168             _remainder += (weight - this->_maxweight);
00169             rule->setWeight (this->_maxweight);
00170         }
00171         else
00172             rule->setWeight (weight);
00173         totweight += rule->getWeight();
00174     }
00175 
00176     this->_weight = totweight;
00177     this->distributeRemainder (_remainder);
00178 
00179     totweight = 0;
00180     for (it = this->_rules.begin (); it != this->_rules.end (); it++)
00181     {
00182         rule = *it;
00183         rule->setUsed (false);
00184         totweight += rule->getWeight ();
00185     }
00186     this->_weight = totweight;
00187 }
00188 
00189 double RuleSet::calculateAdjustment (void *fitness)
00190 {
00191     return 0.f;
00192 }
00193 
00194 void RuleSet::distributeRemainder (double remainder)
00195 {
00196 }
00197 
00198 } // namespace
 All Classes Functions Variables