Spinning Topp Logo BlackTopp Studios
inc
rollingaverage.h
Go to the documentation of this file.
1 // The DAGFrameScheduler is a Multi-Threaded lock free and wait free scheduling library.
2 // © Copyright 2010 - 2016 BlackTopp Studios Inc.
3 /* This file is part of The DAGFrameScheduler.
4 
5  The DAGFrameScheduler is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  The DAGFrameScheduler is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with The DAGFrameScheduler. If not, see <http://www.gnu.org/licenses/>.
17 */
18 /* The original authors have included a copy of the license specified above in the
19  'doc' folder. See 'gpl.txt'
20 */
21 /* We welcome the use of the DAGFrameScheduler to anyone, including companies who wish to
22  Build professional software and charge for their product.
23 
24  However there are some practical restrictions, so if your project involves
25  any of the following you should contact us and we will try to work something
26  out:
27  - DRM or Copy Protection of any kind(except Copyrights)
28  - Software Patents You Do Not Wish to Freely License
29  - Any Kind of Linking to Non-GPL licensed Works
30  - Are Currently In Violation of Another Copyright Holder's GPL License
31  - If You want to change our code and not add a few hundred MB of stuff to
32  your distribution
33 
34  These and other limitations could cause serious legal problems if you ignore
35  them, so it is best to simply contact us or the Free Software Foundation, if
36  you have any questions.
37 
38  Joseph Toppi - toppij@gmail.com
39  John Blackwood - makoenergy02@gmail.com
40 */
41 #ifndef _rollingaverage_h
42 #define _rollingaverage_h
43 
44 /// @file
45 /// @brief This stores the implementation and the declaration of the RollingAverage, BufferedRollingAverage, WeightedRollingAverage and the DefaultRollingAverage
46 
47 #include "datatypes.h"
48 
49 namespace Mezzanine
50 {
51  /// @brief The interface for rolling averages used in the Mezzanine, and threading library.
52  template <typename RecordType> class RollingAverage
53  {
54  public:
55  /// @brief Used for accessing the derived type when it may not be directly known.
56  typedef RecordType Type;
57 
58  /// @brief How many records does this use to calculate its wolling average.
59  /// @return A Whole containing the capacity.
60  virtual Whole RecordCapacity() const = 0;
61 
62  /// @brief Add another record.
63  /// @param Datum The record to be added. No gaurantee is provided that this record will be preserved, it could be use just once then discarded.
64  virtual void Insert(RecordType Datum) = 0;
65 
66  /// @brief What is the current rolling average.
67  /// @return The current rolling average.
68  /// @details The is no gaurantee on the time this runs in. It run in linear time relative to the amount of records or it could run in constant time
69  virtual RecordType GetAverage() const = 0;
70 
71  /// @brief Get a 0 indexed record of the past few insertions.
72  /// @param Index Which entry to access. This may have different effects with different rolling averages, such as being ignored or estimated.
73  /// @details This returns one insertion, with RecordCapacity()-1 being the newest, and 0 being the oldest.
74  /// @warning This is not guaranteed to accurate in all rolling averages.
75  /// @return A reference to something the resembles an inserted record.
76  virtual RecordType& operator[] (Whole Index) = 0;
77 
78  /// @brief Get a 0 indexed record of the past few insertions.
79  /// @details This returns one insertion, with RecordCapacity()-1 being the newest, and 0 being the oldest.
80  /// @param Index Which entry to access. This may have different effects with different rolling averages, such as being ignored or estimated.
81  /// @details This returns one insertion, with RecordCapacity()-1 being the newest, and 0 being the oldest.
82  /// @return A copy to something the resembles an inserted record.
83  virtual RecordType operator[] (Whole Index) const = 0;
84 
85  /// @brief Empty virtual Destructor.
86  virtual ~RollingAverage(){}
87  };//RollingAverage
88 
89  // Possible optimizations
90  // once the average is calculated store it until another insert is done, costs memory, saves cpu time
91  // cache the 1/count costs memory saves cpu time on float starved machines
92  //
93  // The Rolling Average is key to the way this algorithm works
94  // RecordType Needs to implement a constructor which accepts a single 0, +=, and / with size_t
95 
96  /// @brief A RollingAverage that stores a copy of each record. and does the math when queried
97  template <typename RecordType> class BufferedRollingAverage : public RollingAverage<RecordType>
98  {
99  protected:
100  /// @brief The collection of all the records that are being have been added going back as far as the capacity will allow.
101  /// @note All writes to this are performed through the iterator @ref Current
102  std::vector<RecordType> Records;
103 
104  /// @brief The iterator used to treat an std::vector as a circular buffer.
105  typename std::vector<RecordType>::iterator Current;
106 
107  /// @brief Move Current to the next place to be written
108  virtual void IncrementIterator()
109  {
110  if(Records.end() == ++Current)
111  { Current = Records.begin(); }
112  }
113 
114  public:
115  /// @brief Used for accessing the derived type when it may not be directly known.
116  typedef RecordType Type;
117 
118  /// @brief Constructor
119  /// @param RecordCount The capacity of the Rolling average. This defaults to 10.
121  {
122  Records.assign(RecordCount,RecordType(0));
123  Current = Records.begin();
124  }
125 
126  /// @brief Gets the capacity of this rolling average. How many records will this store.
127  virtual Whole RecordCapacity() const
128  { return Records.size(); }
129 
130  /// @brief Inserts a new record into the rolling average and if needed drops the oldest one out.
131  /// @param Datum The record to add.
132  virtual void Insert(RecordType Datum)
133  {
135  *Current = Datum;
136  }
137 
138  /// @brief Add up all the records and divide by the count. A simple arithmetic mean.
139  /// @return This returns the current average of all the records as a RecordType. If it is an Integer type floating parts are truncated.
140  virtual RecordType GetAverage() const
141  {
142  RecordType Results(0);
143  for(typename std::vector<RecordType>::const_iterator Iter = Records.begin(); Iter!=Records.end(); ++Iter)
144  {Results += *Iter;}
145  return Results/Records.size();
146  }
147 
148  /// @brief Copy constructor, performs deep copy.
149  /// @param Rhs The Rolling average to copy.
151  {
152  this->Current=this->Records.end() - (Rhs.Records.end()-Rhs.Current);
153  this->Records = std::vector<Type> (Rhs.Records);
154  }
155 
156  /// @brief Assignment operator, performs deep copy.
157  /// @param Rhs The Rolling average to copy.
158  /// @return A reference to this rolling average after assignment has occurred, to allow for operator chaining.
160  {
161  this->Current=this->Records.end() - (Rhs.Records.end()-Rhs.Current);
162  this->Records = std::vector<Type> (Rhs.Records);
163  }
164 
165  /// @brief Get an accurate record of insertions up to RecordCapacity()
166  /// @return A reference to an insertion.
167  /// @param Index Which insertion to retrieve? 0 being the oldest still tracked and RecordCapacity()-1 begin the newest
168  virtual RecordType& operator[] (Whole Index)
169  {
170  typename std::vector<RecordType>::iterator Iter = this->Current;
171 
172  for(Whole C = 0; C<=Index; C++)
173  {
174  if(Records.end() == ++Iter)
175  { Iter = Records.begin(); }
176  }
177 
178  return *Iter;
179  }
180 
181  /// @brief Get an accurate record of insertions up to RecordCapacity()
182  /// @return A copy of an inserted value.
183  /// @param Index Which insertion to retrieve? 0 being the oldest still tracked and RecordCapacity()-1 begin the newest
184  virtual RecordType operator[] (Whole Index) const
185  {
186  typename std::vector<RecordType>::const_iterator Iter = this->Current;
187 
188  for(Whole C = 0; C<=Index; C++)
189  {
190  if(Records.end() == ++Iter)
191  { Iter = Records.begin(); }
192  }
193 
194  return *Iter;
195  }
196 
197  /// @brief Deconstructor.
199  };//BufferedRollingAverage
200 
201  /// @brief A weighted average that does math with every insertion and stores nothing.
202  /// @details This is possibly an optimization over the BufferedRollingAverage. It has not yet been shown whether the amount of memory for
203  /// each task will significantly affect load times (From RAM to CPU cache) when starting a rolling average, or whether any
204  /// innaccuracies in sorting using this would outweigh that.
205  template <typename RecordType, typename MathType> class WeightedRollingAverage : public RollingAverage<RecordType>
206  {
207  protected:
208  /// @brief What the math says the current avergage is.
209  RecordType CurrentAverage;
210 
211  // @brief Replaces the capacity of normal rolling averages.
212  //Whole WeightCount;
213 
214  /// @brief Sometimes retrieving the value just inserted is too useful.
215  RecordType LastEntry;
216 
217  public:
218  /// @brief Used for accessing the derived type when it may not be directly known.
219  typedef RecordType Type;
220 
221  /// @brief Class Constructor.
222  /// @param Ignored This parameter is ignored.
224  :CurrentAverage(0),
225  //WeightCount(RecordCount),
226  LastEntry(1)
227  {}
228 
229  /// @brief Returns how many records this is emulating.
230  /// @return A Whole that stores the count of record emulation.
231  virtual Whole RecordCapacity() const
232  { return MEZZ_FRAMESTOTRACK; }
233 
234  /// @brief Update the currently stored Rolling average with a new data point/record.
235  /// @param Datum Update the Current Average according to the following formula CurrentAverage = CurrentAverage * ((RecordCount-1)/RecordCount) + Datum/RecordCount.
236  virtual void Insert(RecordType Datum)
237  {
238  LastEntry = Datum;
239  CurrentAverage = ( MathType(this->CurrentAverage) ? MathType(this->CurrentAverage) : MathType(1)) // A zero really screws with averages that tend to move away from zero
240  * ((MathType(MEZZ_FRAMESTOTRACK)-MathType(1))/MathType(MEZZ_FRAMESTOTRACK)) // Get weight of all the older members
241  + MathType(Datum)/MathType(MEZZ_FRAMESTOTRACK); // wGet the Weight of the Current Member
242  }
243 
244  /// @brief Get the current rolling average.
245  /// @return Get the Current Rolling average as a RecordType.
246  virtual RecordType GetAverage() const
247  { return CurrentAverage; }
248 
249  /// @brief Get the last insertion
250  /// @return The last insertion, always the last one, it is the only one stored.
251  virtual RecordType& operator[] (Whole)
252  { return LastEntry; }
253 
254  /// @brief Get the last insertion
255  /// @return The last insertion, always the last one, it is the only one stored.
256  virtual RecordType operator[] (Whole) const
257  { return LastEntry; }
258 
259  /// @brief Class Destructor.
261  };//WeightedRollingAverage
262 
263  /// @brief Use this to get the default rolling average for a given type.
264  /// @details use "DefaultRollingAverage<Whole>::Type" as Type to instantiate an instance of whatever type this is. This allows
265  /// newer code to benefit from testing that has been done.
266  template<class RecordType>
268  {
269  /// @brief The Default rolling average for all types is currently BufferedRollingAverage, this could change with future testing.
270  //typedef BufferedRollingAverage<RecordType> Type;
272  };//DefaultRollingAverage
273 
274 #ifdef SWIG
275  %template(RollingAverageWhole) RollingAverage<Whole>;
276  %template(WeightedRollingAverageWhole) WeightedRollingAverage<Whole,Whole>;
277  %template(BufferedRollingAverageWhole) BufferedRollingAverage<Whole>;
278 
279  %template(RollingAverageReal) RollingAverage<Real>;
280  %template(WeightedRollingAverageReal) WeightedRollingAverage<Real,Real>;
281  %template(BufferedRollingAverageReal) BufferedRollingAverage<Real>;
282 
283  %template(RollingAverageInteger) RollingAverage<Integer>;
284  %template(WeightedRollingAverageInteger) WeightedRollingAverage<Integer,Integer>;
285  %template(BufferedRollingAverageInteger) BufferedRollingAverage<Integer>;
286 #endif
287 
288 }//Mezzanine
289 #endif
290 
WeightedRollingAverage< RecordType, RecordType > Type
The Default rolling average for all types is currently BufferedRollingAverage, this could change with...
Use this to get the default rolling average for a given type.
virtual RecordType GetAverage() const =0
What is the current rolling average.
A weighted average that does math with every insertion and stores nothing.
virtual Whole RecordCapacity() const
Gets the capacity of this rolling average. How many records will this store.
virtual RecordType GetAverage() const
Add up all the records and divide by the count. A simple arithmetic mean.
WeightedRollingAverage(const Whole &Ignored=MEZZ_FRAMESTOTRACK)
Class Constructor.
BufferedRollingAverage(const Whole &RecordCount=MEZZ_FRAMESTOTRACK)
Constructor.
virtual Whole RecordCapacity() const =0
How many records does this use to calculate its wolling average.
All the definitions for datatypes as well as some basic conversion functions are defined here...
virtual RecordType & operator[](Whole Index)
Get an accurate record of insertions up to RecordCapacity()
#define MEZZ_FRAMESTOTRACK
Used to control how long frames track length and other similar values. This is controlled by the CMak...
std::vector< RecordType > Records
The collection of all the records that are being have been added going back as far as the capacity wi...
RecordType Type
Used for accessing the derived type when it may not be directly known.
virtual void IncrementIterator()
Move Current to the next place to be written.
virtual ~BufferedRollingAverage()
Deconstructor.
BufferedRollingAverage(const BufferedRollingAverage &Rhs)
Copy constructor, performs deep copy.
virtual RecordType & operator[](Whole)
Get the last insertion.
virtual ~WeightedRollingAverage()
Class Destructor.
RecordType LastEntry
Sometimes retrieving the value just inserted is too useful.
virtual void Insert(RecordType Datum)=0
Add another record.
The interface for rolling averages used in the Mezzanine, and threading library.
virtual RecordType GetAverage() const
Get the current rolling average.
RecordType CurrentAverage
What the math says the current avergage is.
virtual ~RollingAverage()
Empty virtual Destructor.
A RollingAverage that stores a copy of each record. and does the math when queried.
virtual void Insert(RecordType Datum)
Update the currently stored Rolling average with a new data point/record.
std::vector< RecordType >::iterator Current
The iterator used to treat an std::vector as a circular buffer.
The bulk of the engine components go in this namspace.
Definition: actor.cpp:56
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
Definition: datatypes.h:151
virtual RecordType & operator[](Whole Index)=0
Get a 0 indexed record of the past few insertions.
RecordType Type
Used for accessing the derived type when it may not be directly known.
RecordType Type
Used for accessing the derived type when it may not be directly known.
virtual void Insert(RecordType Datum)
Inserts a new record into the rolling average and if needed drops the oldest one out.
virtual Whole RecordCapacity() const
Returns how many records this is emulating.
BufferedRollingAverage & operator=(const BufferedRollingAverage &Rhs)
Assignment operator, performs deep copy.