dynrules
 All Classes Functions Variables
RuleSet.cpp
1 /*
2  * dynrules - Python dynamic rules engine
3  *
4  * Authors: Marcus von Appen
5  *
6  * This file is distributed under the Public Domain.
7  */
8 
9 #include <stdexcept>
10 #include "RuleSet.h"
11 
12 namespace dynrules
13 {
14 
16  _minweight(0),
17  _maxweight(0),
18  _weight(0),
19  _rules(0)
20 {
21 }
22 
23 RuleSet::RuleSet (double minweight, double maxweight) :
24  _minweight(0),
25  _maxweight(0),
26  _weight(0),
27  _rules(0)
28 {
29  if (minweight > maxweight)
30  throw std::invalid_argument ("maxweight must not be smaller than minweight");
31  this->_minweight = minweight;
32  this->_maxweight = maxweight;
33 }
34 
36 {
37 }
38 
39 double RuleSet::getMinWeight () const
40 {
41  return this->_minweight;
42 }
43 
44 void RuleSet::setMinWeight (double minweight)
45 {
46  if (minweight > this->_maxweight)
47  throw std::invalid_argument ("maxweight must not be smaller than minweight");
48  this->_minweight = minweight;
49 }
50 
51 double RuleSet::getMaxWeight () const
52 {
53  return this->_maxweight;
54 }
55 
56 void RuleSet::setMaxWeight (double maxweight)
57 {
58  if (maxweight < this->_minweight)
59  throw std::invalid_argument ("maxweight must not be smaller than minweight");
60  this->_maxweight = maxweight;
61 }
62 
63 double RuleSet::getWeight () const
64 {
65  return this->_weight;
66 }
67 
68 std::vector<Rule*> RuleSet::getRules () const
69 {
70  return this->_rules;
71 }
72 
73 void RuleSet::addRule (Rule* rule)
74 {
75  if (rule == 0)
76  throw std::invalid_argument ("rule must not be NULL");
77 
78  this->_rules.push_back (rule);
79  if (rule->getWeight() > this->_maxweight)
80  rule->setWeight (this->_maxweight);
81  else if (rule->getWeight () < this->_minweight)
82  rule->setWeight (this->_minweight);
83  this->_weight += rule->getWeight ();
84 }
85 
87 {
88  if (rule == 0)
89  return false;
90 
91  bool found = false;
92  std::vector<Rule*>::iterator iter;
93  for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++)
94  {
95  if ((*iter) == rule)
96  {
97  found = true;
98  break;
99  }
100  }
101  if (found)
102  {
103  this->_rules.erase (iter);
104  this->_weight -= (*iter)->getWeight ();
105  }
106  return found;
107 }
108 
110 {
111  std::vector<Rule*>::iterator iter;
112  for (iter = this->_rules.begin (); iter != this->_rules.end (); iter++)
113  if ((*iter)->getId () == id)
114  return *iter;
115  return 0;
116 }
117 
119 {
120  this->_rules.clear();
121  this->_weight = 0.f;
122 }
123 
124 void RuleSet::updateWeights (void *fitness)
125 {
126  /*
127  * Adapted from Pieter Spronck's algorithm as explained in
128  * Spronck et al: 2005, 'Adaptive Game AI with Dynamic Scripting'
129  */
130  Rule *rule;
131  std::vector<Rule*>::iterator it;
132  size_t count, usedcount = 0, nonactive;
133  double totweight = 0, adjustment, compensation, _remainder, weight;
134 
135  count = this->_rules.size ();
136  if (count == 0)
137  return;
138 
139  for (it = this->_rules.begin (); it != this->_rules.end (); it++)
140  {
141  rule = *it;
142  if (rule->getUsed ())
143  usedcount++;
144  }
145  if (usedcount == 0 || usedcount == count)
146  return;
147 
148  nonactive = count - usedcount;
149  adjustment = this->calculateAdjustment (fitness);
150  compensation = (static_cast<double>(-(static_cast<int>(usedcount)) *
151  adjustment)) / nonactive;
152  _remainder = 0;
153 
154  for (it = this->_rules.begin (); it != this->_rules.end (); it++)
155  {
156  rule = *it;
157 
158  weight = rule->getWeight () +
159  ((rule->getUsed ()) ? adjustment : compensation);
160 
161  if (weight < this->_minweight)
162  {
163  _remainder += (weight - this->_minweight);
164  rule->setWeight (this->_minweight);
165  }
166  else if (weight > this->_maxweight)
167  {
168  _remainder += (weight - this->_maxweight);
169  rule->setWeight (this->_maxweight);
170  }
171  else
172  rule->setWeight (weight);
173  totweight += rule->getWeight();
174  }
175 
176  this->_weight = totweight;
177  this->distributeRemainder (_remainder);
178 
179  totweight = 0;
180  for (it = this->_rules.begin (); it != this->_rules.end (); it++)
181  {
182  rule = *it;
183  rule->setUsed (false);
184  totweight += rule->getWeight ();
185  }
186  this->_weight = totweight;
187 }
188 
189 double RuleSet::calculateAdjustment (void *fitness)
190 {
191  return 0.f;
192 }
193 
194 void RuleSet::distributeRemainder (double remainder)
195 {
196 }
197 
198 } // namespace