Page MenuHomePhorge

History.hpp
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

History.hpp

/*******************************************************************************
*
* File: History.hpp
*
* Contents: Definition of History Module.
*
* Copyright 2017
*
* Author: David Juhasz (david.juhasz@tuwien.ac.at)
*
******************************************************************************/
#ifndef ROSA_AGENT_HISTORY_HPP
#define ROSA_AGENT_HISTORY_HPP
#include "rosa/agent/Module.h"
#include "rosa/config/config.h"
#include "rosa/support/debug.hpp"
#include "rosa/support/type_helper.hpp"
#include <array>
namespace rosa {
namespace agent {
// Retention policies defining what a History instance should do when the
// number of recorded entries reached its capacity.
enum class HistoryPolicy {
SRWF, // Stop Recording When Full -- no new entry is recorded when full
FIFO // First In First Out -- overwrite the earliest entry with a new one
};
// NOTE: Not thread-safe implementation, which should not be a problem as a
// Module instance is an internal component of an Agent, which is the basic
// unit of concurrency.
template <typename T, size_t N, HistoryPolicy P>
class History : public Module, private std::array<T, N + 1> {
// Bring into scope inherited functions that are used.
// INV: max_size() == N + 1 && N == max_size() - 1
using std::array<T, N + 1>::max_size;
using std::array<T, N + 1>::operator[];
// The indices of the first data element and the first empty slot in the
// circular buffer.
size_t Data, Space;
public:
// Ctor. Initializes indices.
History(void) noexcept : Data(0), Space(0) {}
// Dtor.
~History(void) = default;
// Tells the policy applied to the History.
static constexpr HistoryPolicy policyOfHistory(void) noexcept { return P; }
// Tells how many entries may be recorded by the History.
// NOTE: The number of entries that are actually recorded may be smaller.
static constexpr size_t lengthOfHistory(void) noexcept { return N; }
// Tells how many entries are currently recorded by the History.
// POST: 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
inline size_t numberOfEntries(void) const noexcept {
return Data <= Space ? Space - Data : max_size() - Data + Space;
}
// Tells if the History has not recorded any entries yet.
inline bool empty(void) const noexcept {
return numberOfEntries() == 0;
}
// Gives a constant lvalue reference to the I-th latest entry stored in the
// History.
// PRE: 0 <= I && I <= numberOfEntries()
const T &entry(const size_t I = 0) const noexcept {
ASSERT(0 <= I && I < numberOfEntries()); // Boundary check.
// Position counted back from the last recorded entry.
typename std::make_signed<const size_t>::type Pos = Space - (1 + I);
// Actual index wrapped around to the end of the buffer if negative.
return (*this)[Pos >= 0 ? Pos : max_size() + Pos];
}
private:
// Tells if the circular buffer is full.
inline bool full(void) const noexcept { return numberOfEntries() == N; }
// Pushes a new entry into the circular buffer, removing the earliest entry
// if the buffer is full.
void pushBack(const T& V) noexcept {
// Store value to the first empty slot and step Space index.
(*this)[Space] = V;
Space = (Space + 1) % max_size();
if (Data == Space) {
// Buffer was full, step Data index.
Data = (Data + 1) % max_size();
}
}
public:
// Adds a new entry to the History and tells if the operation was successful.
// NOTE: Success of the operation depends on the actual policy.
bool addEntry(const T &V) noexcept {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::SRWF:
if (full()) {
return false;
}
// NOTE: Fall through to FIFO which unconditionally pushes the new entry.
case HistoryPolicy::FIFO:
// FIFO and SRWF not full.
pushBack(V);
return true;
}
}
// Tells the trend set by the entries recorded by the History. The number of
// steps to go back in the History is given as argument.
// NOTE: The number of steps that can be made is limited by the number of
// entries recorded by the History.
// NOTE: The function is made a template only to be able to use enable_if.
// STATIC PRE: std::is_arithmetic<T>::value && std::is_signed<T>::value
// PRE: 0 <= D && D < N
template <typename X = T>
typename std::enable_if<
std::is_arithmetic<X>::value && std::is_signed<X>::value, X>::type
trend(const size_t D = N - 1) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < N); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No entries for computing trend.
return {}; // Zero element of T
} else {
// Here at least two entries.
// S is the number of steps that can be done.
const size_t S = std::min(numberOfEntries() - 1, D);
size_t I = S;
// Compute trend with linear regression.
size_t SumIndices = 0;
T SumEntries = {};
T SumSquareEntries = {};
T SumProduct = {};
while (I > 0) {
// NOTE: Indexing for the regression starts in the past.
const size_t Index = S - I;
const T Entry = entry(--I);
SumIndices += Index;
SumEntries += Entry;
SumSquareEntries += Entry * Entry;
SumProduct += Entry * Index;
}
return (SumProduct * S - SumEntries * SumIndices) /
(SumSquareEntries * S - SumEntries * SumEntries);
}
}
// Tells the average absolute difference between consequtive entries recorded
// by the History. The number of steps to go back in the History is given as
// argument.
// NOTE: The number of steps that can be made is limited by the number of
// entries recorded by the History.
// NOTE: The function is made a template only to be able to use enable_if.
// STATIC PRE: std::is_arithmetic<T>::value
// PRE: 0 <= D && D < N
template <typename X = T>
typename std::enable_if<std::is_arithmetic<X>::value, unsigned_t<X>>::type
averageAbsDiff(const size_t D = N - 1) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < N); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No difference to average.
return {}; // Zero element of T
} else {
// Here at least two entries.
// S is the number of steps that can be done.
const size_t S = std::min(numberOfEntries() - 1, D);
// Sum up differences as non-negative values only, hence using an
// unsigned variable for that.
unsigned_t<T> Diffs = {}; // Init to zero.
// Count down entry indices and sum up all the absolute differences.
size_t I = S;
T Last = entry(I);
while (I > 0) {
T Next = entry(--I);
Diffs += Last < Next ? Next - Last : Last - Next;
Last = Next;
}
// Return the average of the summed differences.
return Diffs / S;
}
}
};
// Convenience operator to add new entries to a History instance.
// NOTE: The result of the member function addEntry is ignored by the operator.
template <typename T, size_t N, HistoryPolicy P>
History<T, N, P> &operator<<(History<T, N, P> &H, const T &V) noexcept {
H.addEntry(V);
return H;
}
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_HISTORY_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sat, May 30, 11:41 PM (16 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
328043
Default Alt Text
History.hpp (7 KB)

Event Timeline