Page MenuHomePhorge

No OneTemporary

Size
39 KB
Referenced Files
None
Subscribers
None
diff --git a/include/rosa/agent/FunctionAbstractions.hpp b/include/rosa/agent/FunctionAbstractions.hpp
index 6467f50..a7442c6 100644
--- a/include/rosa/agent/FunctionAbstractions.hpp
+++ b/include/rosa/agent/FunctionAbstractions.hpp
@@ -1,360 +1,360 @@
//===-- rosa/agent/FunctionAbstractions.hpp ---------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/FunctionAbstractions.hpp
///
/// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *FunctionAbstractions* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP
#define ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP
#include "rosa/agent/Abstraction.hpp"
#include "rosa/agent/Functionality.h"
#include "rosa/support/debug.hpp"
#include <algorithm>
#include <cmath>
#include <memory>
#include <vector>
namespace rosa {
namespace agent {
//@benedikt: check if your partialfunctions can take infinity as
// argument
/// Implements \c rosa::agent::Abstraction as a linear function,
/// y = Coefficient * X + Intercept.
///
/// \note This implementation is supposed to be used to represent a linear
/// function from an arithmetic domain to an arithmetic range. This is enforced
/// statically.
///
/// \tparam D type of the functions domain
/// \tparam R type of the functions range
template <typename D, typename R>
class LinearFunction : public Abstraction<D, R> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<D>::value),
"LinearFunction not arithmetic T");
STATIC_ASSERT((std::is_arithmetic<R>::value),
"LinearFunction not to arithmetic");
protected:
/// The Intercept of the linear function
const D Intercept;
/// The Coefficient of the linear function
const D Coefficient;
public:
/// Creates an instance.
///
/// \param Intercept the intercept of the linear function
/// \param Coefficient the coefficient of the linear function
LinearFunction(D Intercept, D Coefficient) noexcept
: Abstraction<D, R>(Intercept), Intercept(Intercept),
Coefficient(Coefficient) {}
/// Creates an instance given the two points on a linear function.
///
/// \param x1 The x-value of the first point
/// \param y1 The x-value of the first point
/// \param x2 The y-value of the second point
/// \param y2 The y-value of the second point
LinearFunction(D x1, R y1, D x2, R y2) noexcept
: LinearFunction<D, R>(y1 - x1 * (y1 - y2) / (x1 - x2),
(y1 - y2) / (x1 - x2)) {}
/// Creates an instance given the two points on a linear function.
///
/// \param p1 The coordinates of the first point
/// \param p2 The coordinates of the second point
LinearFunction(std::pair<D, R> p1, std::pair<D, R> p2) noexcept
: LinearFunction<D, R>(p1.first, p1.second, p2.first, p2.second) {}
/// Destroys \p this object.
~LinearFunction(void) = default;
/// Checks wether the Abstraction evaluates to default at the given position
/// As LinearFunctions can be evaluated everythwere, this is always false
///
/// \param V the value at which to check if the function falls back to it's
/// default value.
///
/// \return false
bool isDefaultAt(const D &V) const noexcept override {
(void)V;
return false;
}
/// Getter for member variable Intercept
///
/// \return Intercept
D getIntercept() const { return Intercept; }
/// Setter for member variable Intercept
///
/// \param Intercept the new Intercept
void setIntercept(const D &Intercept) { this->Intercept = Intercept; }
/// Getter for member variable Coefficient
///
/// \return Coefficient
D getCoefficient() const { return Coefficient; }
/// Setter for member variable Coefficient
///
/// \param Coefficient the new Intercept
void setCoefficient(const D &Coefficient) { this->Coefficient = Coefficient; }
/// Set Intercept and Coefficient from two points on the linear function
///
/// \param x1 The x-value of the first point
/// \param y1 The x-value of the first point
/// \param x2 The y-value of the second point
/// \param y2 The y-value of the second point
void setFromPoints(D x1, R y1, D x2, R y2) {
Coefficient = (y1 - y2) / (x1 - x2);
Intercept = y1 - Coefficient * x1;
}
/// Set Intercept and Coefficient from two points on the linear function
///
/// \param p1 The coordinates of the first point
/// \param p2 The coordinates of the second point
inline void setFromPoints(std::pair<D, R> p1, std::pair<D, R> p2) {
setFromPoints(p1.first, p1.second, p2.first, p2.second);
}
/// Evaluates the linear function
///
/// \param X the value at which to evaluate the function
///
/// \return Coefficient*X + Intercept
virtual R operator()(const D &X) const noexcept override {
return Intercept + X * Coefficient;
}
};
/// Implements \c rosa::agent::Abstraction as a sine function,
/// y = Amplitude * sin(Frequency * X + Phase) + Average.
///
/// \note This implementation is supposed to be used to represent a sine
/// function from an arithmetic domain to an arithmetic range. This is enforced
/// statically.
///
/// \tparam D type of the functions domain
/// \tparam R type of the functions range
template <typename D, typename R>
class SineFunction : public Abstraction<D, R> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<D>::value),
"SineFunction not arithmetic T");
STATIC_ASSERT((std::is_arithmetic<R>::value),
"SineFunction not to arithmetic");
protected:
/// The frequency of the sine wave
const D Frequency;
/// The Ampiltude of the sine wave
const D Amplitude;
/// The Phase-shift of the sine wave
const D Phase;
/// The y-shift of the sine wave
const D Average;
public:
/// Creates an instance.
///
/// \param Frequency the frequency of the sine wave
/// \param Amplitude the amplitude of the sine wave
/// \param Phase the phase of the sine wave
/// \param Average the average of the sine wave
SineFunction(D Frequency, D Amplitude, D Phase, D Average) noexcept
: Abstraction<D, R>(Average), Frequency(Frequency), Amplitude(Amplitude),
Phase(Phase), Average(Average) {}
/// Destroys \p this object.
~SineFunction(void) = default;
/// Checks wether the Abstraction evaluates to default at the given position
/// As SineFunctions can be evaluated everythwere, this is always false
///
/// \param V the value at which to check if the function falls back to it's
/// default value.
///
/// \return false
bool isDefaultAt(const D &V) const noexcept override {
(void)V;
return false;
}
/// Evaluates the sine function
///
/// \param X the value at which to evaluate the function
/// \return the value of the sine-function at X
virtual R operator()(const D &X) const noexcept override {
return Amplitude * sin(Frequency * X + Phase) + Average;
}
};
enum StepDirection { StepUp, StepDown };
/// Implements \c rosa::agent::PartialFunction as a step function from 0 to 1
/// with a ramp in between
///
/// \tparam D type of the functions domain
/// \tparam R type of the functions range
template <typename D, typename R>
class StepFunction : public Abstraction<D, R> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<D>::value), "abstracting not arithmetic");
STATIC_ASSERT((std::is_arithmetic<R>::value),
"abstracting not to arithmetic");
private:
D Coefficient;
D RightLimit;
StepDirection Direction;
public:
/// Creates an instance by Initializing the underlying \c Abstraction.
///
/// \param Coefficient Coefficient of the ramp
/// \param Direction wether to step up or down
///
/// \pre Coefficient > 0
StepFunction(D Coefficient, StepDirection Direction = StepUp)
: Abstraction<D, R>(0), Coefficient(Coefficient),
RightLimit(1.0f / Coefficient), Direction(Direction) {
ASSERT(Coefficient > 0);
}
/// Destroys \p this object.
~StepFunction(void) = default;
/// Setter for Coefficient
///
/// \param Coefficient the new Coefficient
void setCoefficient(const D &Coefficient) {
ASSERT(Coefficient > 0);
this->Coefficient = Coefficient;
this->RightLimit = 1 / Coefficient;
}
/// Setter for RightLimit
///
- /// \param RightLimit_ the new RightLimit
+ /// \param _RightLimit the new RightLimit
void setRightLimit(const D &_RightLimit) {
ASSERT(_RightLimit > 0);
this->RightLimit = _RightLimit;
this->Coefficient = 1 / _RightLimit;
}
/// Checks wether the Abstraction evaluates to default at the given position
///
/// \param V the value at which to check if the function falls back to it's
/// default value.
///
/// \return false if the is negative, true otherwise
bool isDefaultAt(const D &V) const noexcept override { return V > 0; }
/// Executes the Abstraction
///
/// \param V value to abstract
///
/// \return the abstracted value
R operator()(const D &V) const noexcept override {
R ret = 0;
if (V <= 0)
ret = 0;
else if (V >= RightLimit)
ret = 1;
else
ret = V * Coefficient;
return Direction == StepDirection::StepUp ? ret : 1 - ret;
}
};
/// Implements \c rosa::agent::Abstraction as a partial function from a domain
/// to a range.
///
/// \note This implementation is supposed to be used to represent a partial
/// function from an arithmetic domain to an arithmetic range. This is enforced
/// statically.
///
/// A partial function is defined as a list of abstractions, where each
/// abstraction is associated a range in which it is defined. These ranges must
/// be mutually exclusive.
///
/// \tparam D type of the functions domain
/// \tparam R type of the functions range
template <typename D, typename R>
class PartialFunction : public Abstraction<D, R> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<D>::value), "abstracting not arithmetic");
STATIC_ASSERT((std::is_arithmetic<R>::value),
"abstracting not to arithmetic");
private:
/// A \c rosa::agent::RangeAbstraction RA is used to represent the association
/// from ranges to Abstractions.
/// This returns the Abstraction that is defined for any given value, or
/// a default Abstraction if no Abstraction is defined for that value.
RangeAbstraction<D, std::shared_ptr<Abstraction<D, R>>> RA;
public:
/// Creates an instance by Initializing the underlying \c Abstraction.
///
/// \param Map the mapping to do abstraction according to
/// \param Default abstraction to abstract to by default
///
/// \pre Each key defines a valid range such that `first <= second` and
/// there are no overlapping ranges defined by the keys.
PartialFunction(
const std::map<std::pair<D, D>, std::shared_ptr<Abstraction<D, R>>> &Map,
const R Default)
: Abstraction<D, R>(Default),
RA(Map,
std::shared_ptr<Abstraction<D, R>>(new Abstraction<D, R>(Default))) {
}
/// Destroys \p this object.
~PartialFunction(void) = default;
/// Checks wether the Abstraction evaluates to default at the given position
///
/// \param V the value at which to check if the function falls back to it's
/// default value.
///
/// \return false if the value falls into a defined range and the Abstraction
/// defined for that range does not fall back to it's default value.
bool isDefaultAt(const D &V) const noexcept override {
return RA.isDefaultAt(V) ? true : RA(V)->isDefaultAt(V);
}
/// Searches for an Abstraction for the given value and executes it for that
/// value, if such an Abstraction is found. The default Abstraction is
/// evaluated otherwise.
///
/// \param V value to abstract
///
/// \return the abstracted value based on the set mapping
R operator()(const D &V) const noexcept override {
return RA(V)->operator()(V);
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP
diff --git a/include/rosa/agent/History.hpp b/include/rosa/agent/History.hpp
index 803aa96..139d3f8 100644
--- a/include/rosa/agent/History.hpp
+++ b/include/rosa/agent/History.hpp
@@ -1,582 +1,582 @@
//===-- rosa/agent/History.hpp ----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/History.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Definition of *history* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_HISTORY_HPP
#define ROSA_AGENT_HISTORY_HPP
#include "rosa/agent/Functionality.h"
#include "rosa/config/config.h"
#include "rosa/support/debug.hpp"
#include "rosa/support/type_helper.hpp"
#include <algorithm>
#include <array>
#include <limits>
#include <vector>
namespace rosa {
namespace agent {
// @benedikt: todo: assert in history, which checks if push_back worked
/// Retention policies defining what a \c rosa::agent::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
LIFO ///< Last In First Out -- overwrite the latest entry with a new one
};
template <typename T, HistoryPolicy P> class History : public Functionality {
public:
History(void) noexcept {}
/// Destroys \p this object.
virtual ~History(void) = default;
/// Tells the retention policy applied to \p this object.
///
/// \return \c rosa::agent::History::P
static constexpr HistoryPolicy policy(void) noexcept { return P; }
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return The max number of entries that may be recorded
virtual size_t maxLength(void) const noexcept = 0;
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
/// \endcode
virtual size_t numberOfEntries(void) const noexcept = 0;
/// Tells if \p this object has not recorded anything yet.
///
/// \return if \p this object has no entries recorded
bool empty(void) const noexcept { return numberOfEntries() == 0; }
/// Tells if the history reached it's maximum length
///
/// \return if the history reached it's maximum length.
bool full(void) const noexcept { return numberOfEntries() == maxLength(); }
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
virtual const T &entry(const size_t I = 0) const noexcept = 0;
/// Removes all entries recorded in \p this object.
virtual void clear() noexcept = 0;
private:
/// Pushes a new entry into the history.
///
/// \note The earliest entry gets overwritten if the history is full.
///
/// \param V value to push into the history
virtual void pushBack(const T &V) noexcept = 0;
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
virtual void replaceFront(const T &V) noexcept = 0;
public:
/// Adds a new entry to \p this object and tells if the operation was
/// successful.
///
/// \note Success of the operation depends on the actual policy.
///
/// \param V value to store
///
/// \return if \p V was successfully stored
bool addEntry(const T &V) noexcept {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::LIFO:
if (full()) {
replaceFront(V);
return true;
}
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 \p this object.
///
/// The number of steps to go back when calculating the trend is defined as
/// argument to the function.
///
/// \note The number of steps that can be made is limited by the number of
/// entries recorded by \p this object.
///
/// \note The function is made a template only to be able to use
/// \c std::enable_if.
///
/// \tparam X always use the default!
///
/// \param D number of steps to go back in *history*
///
/// \return trend set by analyzed entries
///
/// \pre Statically, \p this object stores signed arithmetic values:\code
/// std::is_arithmetic<T>::value && std::is_signed<T>::value
/// \endcode Dynamically, \p D is a valid number of steps to take:\code
/// 0 <= D && D < lengthOfHistory()
/// \endcode
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) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < maxLength()); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No entries for computing trend.
return {}; // Zero element of \p T
} else {
// Here at least two entries.
// \c 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 consecutive entries recorded
/// by \p this object
/// The number of steps to go back when calculating the average is defined as
/// argument to the function.
///
/// \note The number of steps that can be made is limited by the number of
/// entries recorded by \p this object.
///
/// \note The function is made a template only to be able to use
/// \c std::enable_if.
///
/// \tparam X always use the default!
///
/// \param D number of steps to go back in *history*
///
/// \pre Statically, \p this object stores arithmetic values:\code
/// std::is_arithmetic<T>::value
/// \endcode Dynamically, \p D is a valid number of steps to take:\code
/// 0 <= D && D < lengthOfHistory()
/// \endcode
template <typename X = T>
typename std::enable_if<std::is_arithmetic<X>::value, size_t>::type
averageAbsDiff(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < maxLength()); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No difference to average.
return {}; // Zero element of \p T
} else {
// Here at least two entries.
// \c 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.
size_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;
}
}
/// Tells the average of all entries recorded by \p this object
///
/// \tparam R type of the result
template <typename R> R average() const noexcept {
R Average = 0;
for (size_t I = 0; I < numberOfEntries(); I++) {
Average += entry(I);
}
Average /= numberOfEntries();
return Average;
}
};
/// Implements *history* by recording and storing values.
/// The length of the underlying std::array is static and must be set at
/// compile-time
///
/// \note Not thread-safe implementation, which should not be a problem as any
/// instance of \c rosa::agent::Functionality is an internal component of a
/// \c rosa::Agent, which is the basic unit of concurrency.
///
/// \tparam T type of values to store
/// \tparam N number of values to store at most
/// \tparam P retention policy to follow when capacity is reached
///
/// \invariant The size of the underlying \c std::array is `N + 1`:\code
/// max_size() == N + 1 && N == max_size() - 1
/// \endcode
template <typename T, size_t N, HistoryPolicy P>
class StaticLengthHistory : public History<T, P>, private std::array<T, N + 1> {
// Bring into scope inherited functions that are used.
using std::array<T, N + 1>::max_size;
using std::array<T, N + 1>::operator[];
/// The index of the first data element in the circular buffer.
size_t Data;
/// The index of the first empty slot in the circular buffer.
size_t Space;
public:
using History<T, P>::policy;
using History<T, P>::empty;
using History<T, P>::full;
using History<T, P>::addEntry;
using History<T, P>::trend;
using History<T, P>::averageAbsDiff;
/// Creates an instances by initializing the indices for the circular buffer.
StaticLengthHistory(void) noexcept : Data(0), Space(0) {}
/// Destroys \p this object.
~StaticLengthHistory(void) override = default;
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return \c rosa::agent::History::N
size_t maxLength(void) const noexcept override { return N; }
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
/// \endcode
size_t numberOfEntries(void) const noexcept override {
return Data <= Space ? Space - Data : max_size() - Data + Space;
}
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
const T &entry(const size_t I = 0) const noexcept override {
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];
}
/// Removes all entries recorded in \p this object.
void clear() noexcept override {
Data = 0;
Space = 0;
}
private:
/// Pushes a new entry into the circular buffer.
///
/// \note The earliest entry gets overwritten if the buffer is full.
///
/// \param V value to push into the buffer
void pushBack(const T &V) noexcept override {
// 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();
}
}
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
void replaceFront(const T &V) noexcept override {
(*this)[(Space - 1) % max_size()] = V;
}
};
/// Adds a new entry to a \c rosa::agent::History instance.
///
/// \note The result of \c rosa::agent::History::addEntry is ignored.
///
/// \tparam T type of values stored in \p H
/// \tparam N number of values \p H is able to store
/// \tparam P retention policy followed by \p H when capacity is reached
///
/// \param H to add a new entry to
/// \param V value to add to \p H
///
/// \return \p H after adding \p V to it
template <typename T, size_t N, HistoryPolicy P>
StaticLengthHistory<T, N, P> &operator<<(StaticLengthHistory<T, N, P> &H,
const T &V) noexcept {
H.addEntry(V);
return H;
}
/// Implements *DynamicLengthHistory* by recording and storing values.
///
/// \note Not thread-safe implementation, which should not be a problem as any
/// instance of \c rosa::agent::Functionality is an internal component of a
/// \c rosa::Agent, which is the basic unit of concurrency.
///
/// \tparam T type of values to store
/// \tparam P retention policy to follow when capacity is reached
template <typename T, HistoryPolicy P>
class DynamicLengthHistory : public History<T, P>, private std::vector<T> {
private:
// Bring into scope inherited functions that are used.
using std::vector<T>::size;
using std::vector<T>::resize;
using std::vector<T>::push_back;
using std::vector<T>::pop_back;
using std::vector<T>::max_size;
/// The current length of the DynamicLengthHistory.
size_t Length;
public:
// Bring into scope inherited functions that are used.
using std::vector<T>::erase;
using std::vector<T>::begin;
using std::vector<T>::end;
using std::vector<T>::rbegin;
using std::vector<T>::rend;
using std::vector<T>::operator[];
// Bring into scope inherited functions that are used.
using History<T, P>::policy;
using History<T, P>::empty;
using History<T, P>::full;
using History<T, P>::addEntry;
using History<T, P>::trend;
using History<T, P>::averageAbsDiff;
/// Creates an instances by setting an initial length
DynamicLengthHistory(size_t Length) noexcept : Length(Length) {
this->resize(Length);
}
/// Destroys \p this object.
~DynamicLengthHistory(void) override = default;
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return \c rosa::agent::DynamicLengthHistory::N
size_t maxLength(void) const noexcept override { return Length; }
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <=
/// lengthOfHistory() \endcode
size_t numberOfEntries(void) const noexcept override { return size(); }
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
const T &entry(const size_t I = 0) const noexcept override {
ASSERT(0 <= I && I < numberOfEntries()); // Boundary check.
return this->operator[](size() - I - 1);
}
/// Removes all entries recorded in \p this object.
void clear() noexcept override { erase(begin(), end()); }
/// Sort all entries in ascending order.
void sortAscending(void) noexcept { std::sort(begin(), end()); }
/// Sort all entries in descending order.
void sortDescending(void) noexcept { std::sort(rbegin(), rend()); }
/// Delets one element of the history.
///
- /// \param the element which shall be deleted.
+ /// \param V the element which shall be deleted.
void deleteEntry(T &V) {
auto it = std::find(begin(), end(), V);
if (it != end()) {
erase(it);
}
}
/// Gives back the lowest entry of the history.
///
/// \return the lowest entry. In case of an empty history, the maximum value
/// of the chosen data type is returned.
T lowestEntry() {
auto it = std::min_element(begin(), end());
if (it == end()) {
return std::numeric_limits<T>::max();
} else {
return *it;
}
}
/// Gives back the highest entry of the history.
///
/// \return the highest entry. In case of an empty history, the minimum value
/// of the chosen data type is returned.
T highestEntry() {
auto it = std::max_element(begin(), end());
if (it == end()) {
return std::numeric_limits<T>::min();
} else {
return *it;
}
}
private:
/// Pushes a new entry into the circular buffer.
///
/// \note The earliest entry gets overwritten if the buffer is full.
///
/// \param V value to push into the buffer
void pushBack(const T &V) noexcept override {
if (full()) {
erase(begin());
}
push_back(V);
}
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
void replaceFront(const T &V) noexcept override {
(void)pop_back();
push_back(V);
}
public:
/// Resizes the History length. If the new length is smaller than the number
/// of currently stored values, values are deleted according to the
/// HistoryPolicy.
///
/// @param NewLength The new Length of the History.
void setLength(size_t NewLength) noexcept {
Length = NewLength;
if (NewLength < numberOfEntries()) {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::LIFO:
case HistoryPolicy::SRWF:
// Delete last numberOfEntries() - NewLength items from the back
erase(begin() + NewLength, end());
break;
case HistoryPolicy::FIFO:
// Delete last numberOfEntries() - NewLength items from the front
erase(begin(), begin() + (numberOfEntries() - NewLength));
break;
}
}
this->resize(Length);
}
};
/// Adds a new entry to a \c rosa::agent::DynamicLengthHistory instance.
///
/// \note The result of \c rosa::agent::DynamicLengthHistory::addEntry is
/// ignored.
///
/// \tparam T type of values stored in \p H
/// \tparam P retention policy followed by \p H when capacity is reached
///
/// \param H to add a new entry to
/// \param V value to add to \p H
///
/// \return \p H after adding \p V to it
template <typename T, HistoryPolicy P>
DynamicLengthHistory<T, P> &operator<<(DynamicLengthHistory<T, P> &H,
const T &V) noexcept {
H.addEntry(V);
return H;
}
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_HISTORY_HPP
diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp
index a356c93..30e11fb 100644
--- a/include/rosa/support/math.hpp
+++ b/include/rosa/support/math.hpp
@@ -1,201 +1,153 @@
//===-- rosa/support/math.hpp -----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/math.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Math helpers.
///
//===----------------------------------------------------------------------===//
// !!!!!! Please check lines 60 - 180 forward !!!!!!!!!!!!!!
#ifndef ROSA_SUPPORT_MATH_HPP
#define ROSA_SUPPORT_MATH_HPP
#include "debug.hpp"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdarg>
#include <cstdlib>
#include <limits>
#include <type_traits>
namespace rosa {
/// Computes log base 2 of a number.
///
/// \param N the number to compute log base 2 for
///
/// \return log base 2 of \p N
constexpr size_t log2(const size_t N) {
return ((N < 2) ? 1 : 1 + log2(N / 2));
}
/// Tells the next representable floating point value.
///
/// \tparam T type to operate on
///
/// \note The second type argument enforces \p T being a floating point type,
/// always use the default value!
///
/// \param V value to which find the next representable one
///
/// \return the next representable value of type \p T after value \p V
///
/// \pre Type \p T must be a floating point type, which is enforced by
/// `std::enable_if` in the second type argument.
template <typename T,
typename = std::enable_if_t<std::is_floating_point<T>::value>>
T nextRepresentableFloatingPoint(const T V) {
return std::nextafter(V, std::numeric_limits<T>::infinity());
}
-#if false //can't compile original
-// copied from the internet and adapted
-//
-(https://stackoverflow.com/questions/1657883/variable-number-of-arguments-in-c)
+
/// Conjuncts two or more values with each other.
///
-/// \param two or more values of the same datatype
+/// \param Data an array of the data
///
/// \return the conjunction of the values given as parameter.
-template <typename CONFDATATYPE>
-CONFDATATYPE fuzzyAND(int n_args, ...) noexcept {
- // TODO: check datatype, if there are at least two arguments, and if they are
- // between 0 and 1
- // David suggests: nstead of a variadic argument, you could pass the values as
- // an std::array (with a template argument for the length). When you pass the
- // values as a container, you can simply use std::max_element and
- // std::min_element to have a one-liner implementation of the these fuzzy
- // functions.
- va_list ap;
- va_start(ap, n_args);
- CONFDATATYPE min = va_arg(ap, CONFDATATYPE);
- for (int i = 2; i <= n_args; i++) {
- CONFDATATYPE a = va_arg(ap, CONFDATATYPE);
- min = std::min(a, min);
- }
- va_end(ap);
- return min;
-}
-#else
-
template <typename CONFDATATYPE, std::size_t size>
-CONFDATATYPE fuzzyAND(std::array<CONFDATATYPE, size> Data) noexcept {
+CONFDATATYPE fuzzyAND(const std::array<CONFDATATYPE, size> & Data) noexcept {
STATIC_ASSERT(std::is_arithmetic<CONFDATATYPE>::value,
"Type of FuzzyAnd is not arithmetic");
STATIC_ASSERT(size > 1, "Number of Arguments is to little");
for (auto tmp : Data)
ASSERT(tmp <= 1 && tmp >= 0);
return *std::min_element(Data.begin(), Data.end());
}
-#if false // safer
+/// Conjuncts two or more values with each other. It's a wrapper for \c fuzzyAND() [array]
+///
+/// \param Data first data to get the type explicitly
+///
+/// \param Datan a package of data
+///
+/// \note the types of Datan must be the same type as Data
+///
+/// \return the conjunction of the values given as parameter.
template <typename CONFDATATYPE, typename... _CONFDATATYPE>
std::enable_if_t<
std::conjunction_v<std::is_same<CONFDATATYPE, _CONFDATATYPE>...>,
CONFDATATYPE>
-fuzzyAND(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept {
+fuzzyAND(CONFDATATYPE & Data, _CONFDATATYPE&... Datan) noexcept {
return fuzzyAND(
std::array<CONFDATATYPE, sizeof...(Datan) + 1>{Data, Datan...});
}
-#else
-template <typename CONFDATATYPE, typename... _CONFDATATYPE>
-CONFDATATYPE fuzzyAND(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept {
- return fuzzyAND(
- std::array<CONFDATATYPE, sizeof...(Datan) + 1>{Data, Datan...});
-}
-#endif
-#endif
-#if false //can't compile original
+
/// Disjuncts two or more values with each other.
-///
-///
-///
+///
+/// \param Data an array with the data.
+///
/// \return the disjunction of the values given as parameter.
-// copied from the internet
-// (https://stackoverflow.com/questions/1657883/variable-number-of-arguments-in-c)
-template <typename CONFDATATYPE>
-CONFDATATYPE fuzzyOR(int n_args, ...) noexcept {
- // TODO: check datatype and if they are between 0 and 1
- // David suggests: nstead of a variadic argument, you could pass the values as
- // an std::array (with a template argument for the length). When you pass the
- // values as a container, you can simply use std::max_element and
- // std::min_element to have a one-liner implementation of the these fuzzy
- // functions.
- va_list ap;
- va_start(ap, n_args);
- CONFDATATYPE max = va_arg(ap, CONFDATATYPE);
- for (int i = 2; i <= n_args; i++) {
- CONFDATATYPE a = va_arg(ap, CONFDATATYPE);
- max = std::max(a, max);
- }
- va_end(ap);
- return max;
-}
-#else
-
-
template <typename CONFDATATYPE, std::size_t size>
-CONFDATATYPE fuzzyOR(std::array<CONFDATATYPE, size> Data) noexcept {
+CONFDATATYPE fuzzyOR(const std::array<CONFDATATYPE, size> & Data) noexcept {
STATIC_ASSERT(std::is_arithmetic<CONFDATATYPE>::value,
"Type of FuzzyAnd is not arithmetic");
STATIC_ASSERT(size > 1, "Number of Arguments is to little");
- for (auto tmp : Data)
- ASSERT(tmp <= 1 && tmp >= 0);
+ ASSERT(std::all_of(Data.begin(), Data.end(),
+ [](const auto &v) { return v <= 1 && v >= 0; }));
return *std::max_element(Data.begin(), Data.end());
}
-#if false // safer
+/// Disjuncts two or more values with each other. It's a wrapper for \c fuzzyOR() [array]
+///
+/// \param Data first data to get the type explicitly
+///
+/// \param Datan a package of data
+///
+/// \note the types of Datan must be the same type as Data
+///
+/// \return the disjunction of the values given as parameter.
template <typename CONFDATATYPE, typename... _CONFDATATYPE>
std::enable_if_t<
std::conjunction_v<std::is_same<CONFDATATYPE, _CONFDATATYPE>...>,
CONFDATATYPE>
-fuzzyOR(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept {
- return fuzzyOR(
- std::array<CONFDATATYPE, sizeof...(Datan) + 1>{Data, Datan...});
-}
-#else
-template <typename CONFDATATYPE, typename... _CONFDATATYPE>
-CONFDATATYPE fuzzyOR(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept {
+fuzzyOR(const CONFDATATYPE & Data, const _CONFDATATYPE&... Datan) noexcept {
return fuzzyOR(
std::array<CONFDATATYPE, sizeof...(Datan) + 1>{Data, Datan...});
}
-#endif
-
-#endif
template <typename INDATATYPE, typename PROCDATATYPE>
PROCDATATYPE relativeDistance(INDATATYPE NewValue,
INDATATYPE HistoryValue) noexcept {
PROCDATATYPE Dist = HistoryValue - NewValue;
if (Dist == 0) {
return 0;
} else {
Dist = Dist / NewValue;
if (Dist < 0) {
// TODO: I guess this multiplication here should not be done because
// it could be that the distance fuzzy functions are not symetrical
//(negative and positive side)
Dist = Dist * (-1);
}
return (Dist);
}
}
} // End namespace rosa
#endif // ROSA_SUPPORT_MATH_HPP

File Metadata

Mime Type
text/x-diff
Expires
Mon, Dec 1, 4:35 AM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
242599
Default Alt Text
(39 KB)

Event Timeline