Page MenuHomePhorge

No OneTemporary

Size
82 KB
Referenced Files
None
Subscribers
None
diff --git a/examples/agent-functionalities/agent-functionalities.cpp b/examples/agent-functionalities/agent-functionalities.cpp
index 2da67b8..8f111db 100644
--- a/examples/agent-functionalities/agent-functionalities.cpp
+++ b/examples/agent-functionalities/agent-functionalities.cpp
@@ -1,170 +1,211 @@
//===-- examples/agent-functionalities/agent-functionalities.cpp *-- C++-*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file examples/agent-functionalities/agent-functionalities.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief A simple example on defining \c rosa::Agent instances using
/// \c rosa::agent::Functionality object as components.
///
//===----------------------------------------------------------------------===//
#include "rosa/agent/Abstraction.hpp"
+#include "rosa/agent/Confidence.hpp"
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/RangeConfidence.hpp"
-#include "rosa/agent/Confidence.hpp"
#include "rosa/config/version.h"
#include "rosa/core/Agent.hpp"
#include "rosa/core/MessagingSystem.hpp"
#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"
#include <vector>
using namespace rosa;
using namespace rosa::agent;
using namespace rosa::terminal;
/// A dummy wrapper for testing \c rosa::MessagingSystem.
///
/// \note Since we test \c rosa::MessagingSystem directly here, we need to get
/// access to its protected members. That we do by imitating to be a decent
/// subclass of \c rosa::MessagingSystem, while calling protected member
/// functions on an object of a type from which we actually don't inherit.
struct SystemTester : protected MessagingSystem {
template <typename T, typename... Funs>
static AgentHandle createMyAgent(MessagingSystem *S, const std::string &Name,
Funs &&... Fs) {
return ((SystemTester *)S)->createAgent<T>(Name, std::move(Fs)...);
}
static void destroyMyAgent(MessagingSystem *S, const AgentHandle &H) {
((SystemTester *)S)->destroyUnit(unwrapAgent(H));
}
};
/// A special \c rosa::Agent with its own state.
class MyAgent : public Agent {
public:
using Tick = AtomConstant<atom("tick")>;
private:
enum class Categories { Bad, Normal, Good };
static const std::map<Categories, const char *> CategoryNames;
- History<uint8_t, 10, HistoryPolicy::FIFO> H;
+ StaticLengthHistory<uint8_t, 10, HistoryPolicy::FIFO> H;
Confidence<uint8_t> C;
RangeAbstraction<uint8_t, Categories> A;
PartialFunction<int, int> L;
- RangeConfidence<float, float> RCL;
- RangeConfidence<float, float> RCS;
+ RangeConfidence<float, Categories, float> RCL;
+ RangeConfidence<float, Categories, float> RCS;
public:
void handler(Tick, uint8_t V) noexcept {
// Record \p V to the \c rosa::agent::History, then print state info.
H << V;
ASSERT(H.entry() == V); // Sanity check.
LOG_INFO_STREAM << "\nNext value: " << PRINTABLE(V)
<< ", confidence: " << C(H)
<< ", category: " << CategoryNames.at(A(H.entry()))
<< ", partial: " << int(L(H.entry()))
<< ", range-confidence-linear: ";
- std::vector<float> res_lin = RCL(H.entry());
- for (auto i : res_lin){
- LOG_INFO_STREAM << " " << i;
+
+ std::map<Categories, float> ResLin = RCL(H.entry());
+ for (auto Con : ResLin) {
+ LOG_INFO_STREAM << " " << CategoryNames.at(Con.first) << " " << Con.second
+ << ",";
}
- LOG_INFO_STREAM << ", range-confidence-sine: ";
- std::vector<float> res_sine = RCS(H.entry());
- for (auto i : res_sine){
- LOG_INFO_STREAM << " " << i;
+ LOG_INFO_STREAM << " range-confidence-sine: ";
+ std::map<Categories, float> ResSine = RCS(H.entry());
+ for (auto Con : ResSine) {
+ LOG_INFO_STREAM << " " << CategoryNames.at(Con.first) << " " << Con.second
+ << ",";
}
LOG_INFO_STREAM << '\n';
}
MyAgent(const AtomValue Kind, const rosa::id_t Id, const std::string &Name,
MessagingSystem &S)
: Agent(Kind, Id, Name, S, THISMEMBER(handler)), H(), C(5, 20, 1),
A({{{(uint8_t)10, (uint8_t)14}, Categories::Normal},
{{(uint8_t)15, (uint8_t)17}, Categories::Good},
{{(uint8_t)18, (uint8_t)19}, Categories::Normal}},
Categories::Bad),
L({{{0, 2}, std::make_shared<LinearFunction<int, int>>(0, 1)},
{{2, 4}, std::make_shared<LinearFunction<int, int>>(2, 0)},
{{4, 6}, std::make_shared<LinearFunction<int, int>>(6, -1)}},
0),
- RCL({
- PartialFunction<float, float>({
- {{0, 3}, std::make_shared<LinearFunction<float, float>>(0, 1.0/3)},
- {{3, 6}, std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{6, 9}, std::make_shared<LinearFunction<float, float>>(3.0, -1.0/3)},
- },0),
- PartialFunction<float, float>({
- {{6, 9}, std::make_shared<LinearFunction<float, float>>(-2, 1.0/3)},
- {{9, 12}, std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{12, 15}, std::make_shared<LinearFunction<float, float>>(5, -1.0/3)},
- },0),
- PartialFunction<float, float>({
- {{12, 15}, std::make_shared<LinearFunction<float, float>>(-4, 1.0/3)},
- {{15, 18}, std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{18, 21}, std::make_shared<LinearFunction<float, float>>(7, -1.0/3)},
- },0)
- }),
- RCS({
- PartialFunction<float, float>({
- {{0, 3}, std::make_shared<SineFunction<float, float>>
- (M_PI/3, 0.5, -M_PI/2, 0.5)},
- {{3, 6}, std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{6, 9}, std::make_shared<SineFunction<float, float>>
- (M_PI/3, 0.5, -M_PI/2 + 3, 0.5)},
- },0),
- PartialFunction<float, float>({
- {{6, 9}, std::make_shared<SineFunction<float, float>>
- (M_PI/3, 0.5, -M_PI/2, 0.5)},
- {{9, 12}, std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{12, 15}, std::make_shared<SineFunction<float, float>>
- (M_PI/3, 0.5, -M_PI/2 + 3, 0.5)},
- },0),
- PartialFunction<float, float>({
- {{12, 15}, std::make_shared<SineFunction<float, float>>
- (M_PI/3, 0.5, -M_PI/2, 0.5)},
- {{15, 18}, std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{18, 21}, std::make_shared<SineFunction<float, float>>
- (M_PI/3, 0.5, -M_PI/2 + 3, 0.5)},
- },0)
- }){}
+ RCL({{Categories::Bad,
+ PartialFunction<float, float>(
+ {
+ {{0, 3},
+ std::make_shared<LinearFunction<float, float>>(0,
+ 1.0 / 3)},
+ {{3, 6},
+ std::make_shared<LinearFunction<float, float>>(1, 0)},
+ {{6, 9},
+ std::make_shared<LinearFunction<float, float>>(
+ 3.0, -1.0 / 3)},
+ },
+ 0)},
+ {Categories::Normal,
+ PartialFunction<float, float>(
+ {
+ {{6, 9},
+ std::make_shared<LinearFunction<float, float>>(-2,
+ 1.0 / 3)},
+ {{9, 12},
+ std::make_shared<LinearFunction<float, float>>(1, 0)},
+ {{12, 15},
+ std::make_shared<LinearFunction<float, float>>(
+ 5, -1.0 / 3)},
+ },
+ 0)},
+ {Categories::Good,
+ PartialFunction<float, float>(
+ {
+ {{12, 15},
+ std::make_shared<LinearFunction<float, float>>(-4,
+ 1.0 / 3)},
+ {{15, 18},
+ std::make_shared<LinearFunction<float, float>>(1, 0)},
+ {{18, 21},
+ std::make_shared<LinearFunction<float, float>>(
+ 7, -1.0 / 3)},
+ },
+ 0)}}),
+ RCS({{Categories::Bad,
+ PartialFunction<float, float>(
+ {
+ {{0, 3},
+ std::make_shared<SineFunction<float, float>>(
+ M_PI / 3, 0.5, -M_PI / 2, 0.5)},
+ {{3, 6},
+ std::make_shared<LinearFunction<float, float>>(1, 0)},
+ {{6, 9},
+ std::make_shared<SineFunction<float, float>>(
+ M_PI / 3, 0.5, -M_PI / 2 + 3, 0.5)},
+ },
+ 0)},
+ {Categories::Normal,
+ PartialFunction<float, float>(
+ {
+ {{6, 9},
+ std::make_shared<SineFunction<float, float>>(
+ M_PI / 3, 0.5, -M_PI / 2, 0.5)},
+ {{9, 12},
+ std::make_shared<LinearFunction<float, float>>(1, 0)},
+ {{12, 15},
+ std::make_shared<SineFunction<float, float>>(
+ M_PI / 3, 0.5, -M_PI / 2 + 3, 0.5)},
+ },
+ 0)},
+ {Categories::Good,
+ PartialFunction<float, float>(
+ {
+ {{12, 15},
+ std::make_shared<SineFunction<float, float>>(
+ M_PI / 3, 0.5, -M_PI / 2, 0.5)},
+ {{15, 18},
+ std::make_shared<LinearFunction<float, float>>(1, 0)},
+ {{18, 21},
+ std::make_shared<SineFunction<float, float>>(
+ M_PI / 3, 0.5, -M_PI / 2 + 3, 0.5)},
+ },
+ 0)}},
+ true) {}
};
const std::map<MyAgent::Categories, const char *> MyAgent::CategoryNames{
{Categories::Bad, "Bad"},
{Categories::Normal, "Normal"},
{Categories::Good, "Good"}};
int main(void) {
- LOG_INFO_STREAM << library_string() << " -- " << Color::Red
- << "agent-functionalities example" << Color::Default
- << '\n';
+ LOG_INFO_STREAM << library_string() << " -- " << Color::Red
+ << "agent-functionalities example" << Color::Default << '\n';
std::unique_ptr<MessagingSystem> S = MessagingSystem::createSystem("Sys");
MessagingSystem *SP = S.get();
AgentHandle A = SystemTester::createMyAgent<MyAgent>(SP, "MyAgent");
- std::vector<uint8_t> Vs{0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 13,
- 15, 14, 15, 16, 19, 20, 21};
+ std::vector<uint8_t> Vs{0, 1, 2, 3, 4, 5, 6, 7, 9, 10,
+ 11, 13, 15, 14, 15, 16, 19, 20, 21};
for (auto I = Vs.begin(); I != Vs.end(); ++I) {
A.send<MyAgent::Tick, uint8_t>(MyAgent::Tick::Value, *I);
}
SystemTester::destroyMyAgent(SP, A);
return 0;
}
diff --git a/include/rosa/agent/Abstraction.hpp b/include/rosa/agent/Abstraction.hpp
index fa9e03e..b44b2de 100644
--- a/include/rosa/agent/Abstraction.hpp
+++ b/include/rosa/agent/Abstraction.hpp
@@ -1,193 +1,238 @@
//===-- rosa/agent/Abstraction.hpp ------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/Abstraction.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Definition of *abstraction* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_ABSTRACTION_HPP
#define ROSA_AGENT_ABSTRACTION_HPP
#include "rosa/agent/Functionality.h"
#include "rosa/support/debug.hpp"
#include <algorithm>
#include <map>
namespace rosa {
namespace agent {
/// Abstracts values from a type to another one.
///
/// \tparam T type to abstract from
/// \tparam A type to abstract to
template <typename T, typename A> class Abstraction : public Functionality {
protected:
/// Value to abstract to by default.
const A Default;
-
public:
/// Creates an instance.
///
/// \param Default value to abstract to by default
Abstraction(const A Default) noexcept : Default(Default) {}
/// Destroys \p this object.
~Abstraction(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 true, the default implementation always falls back to the default
+ /// value
+ virtual bool isDefaultAt(const T &V) const noexcept{
+ (void)V;
+ return true;
+ }
+
/// Abstracts a value from type \p T to type \p A.
///
/// \note The default implementation always returns
/// \c rosa::agent::Abstraction::Default, hence the actual argument is
/// ignored.
///
/// \return the abstracted value
virtual A operator()(const T &) const noexcept { return Default; }
};
/// Implements \c rosa::agent::Abstraction as a \c std::map from a type to
/// another one.
///
/// \note This implementation is supposed to be used to abstract between
/// enumeration types, which is statically enforced.
///
/// \tparam T type to abstract from
/// \tparam A type to abstract to
template <typename T, typename A>
class MapAbstraction : public Abstraction<T, A>, private std::map<T, A> {
// Make sure the actual type arguments are enumerations.
STATIC_ASSERT((std::is_enum<T>::value && std::is_enum<A>::value),
"mapping not enumerations");
// Bringing into scope inherited members.
using Abstraction<T, A>::Default;
using std::map<T, A>::end;
using std::map<T, A>::find;
public:
/// Creates an instance by initializing the underlying \c std::map.
///
/// \param Map the mapping to do abstraction according to
/// \param Default value to abstract to by default
MapAbstraction(const std::map<T, A> &Map, const A Default) noexcept
: Abstraction<T, A>(Default),
std::map<T, A>(Map) {}
/// Destroys \p this object.
~MapAbstraction(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 true if the Abstraction falls back to the default value
+ bool isDefaultAt(const T &V) const noexcept override {
+ const auto I = find(V);
+ return I == end() ? true : false;
+ }
+
/// Abstracts a value from type \p T to type \p A based on the set mapping.
///
/// Results in the value associated by the set mapping to the argument, or
/// \c rosa::agent::MapAbstraction::Default if the actual argument is not
/// associated with anything by the set mapping.
///
/// \param V value to abstract
///
/// \return the abstracted value based on the set mapping
A operator()(const T &V) const noexcept override {
const auto I = find(V);
return I == end() ? Default : *I;
}
};
/// Implements \c rosa::agent::Abstraction as a \c std::map from ranges of a
/// type to values of another type.
///
/// \note This implementation is supposed to be used to abstract ranges of
/// arithmetic types into enumerations, which is statically enforced.
///
/// \invariant The keys in the underlying \c std::map define valid ranges
/// such that `first <= second` and there are no overlapping ranges defined by
/// the keys.
///
/// \tparam T type to abstract from
/// \tparam A type to abstract to
template <typename T, typename A>
class RangeAbstraction : public Abstraction<T, A>,
private std::map<std::pair<T, T>, A> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<T>::value), "abstracting not arithmetic");
/// \todo check if this compiles with the definition of abstractions as
/// self-aware properties
//STATIC_ASSERT((std::is_enum<A>::value), "abstracting not to enumeration");
// Bringing into scope inherited members.
using Abstraction<T, A>::Default;
using std::map<std::pair<T, T>, A>::begin;
using std::map<std::pair<T, T>, A>::end;
using std::map<std::pair<T, T>, A>::find;
public:
/// Creates an instance by Initializing the unserlying \c std::map.
///
/// \param Map the mapping to do abstraction according to
/// \param Default value 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.
RangeAbstraction(const std::map<std::pair<T, T>, A> &Map, const A &Default)
: Abstraction<T, A>(Default), std::map<std::pair<T, T>, A>(Map) {
// Sanity check.
ASSERT(std::all_of(
begin(), end(), [this](const std::pair<std::pair<T, T>, A> &P) {
return P.first.first <= P.first.second &&
std::all_of(++find(P.first), end(),
[&P](const std::pair<std::pair<T, T>, A> &R) {
// \note Values in \c Map are sorted.
return P.first.first < P.first.second &&
P.first.second <= R.first.first ||
P.first.first == P.first.second &&
P.first.second < R.first.first;
});
}));
}
/// Destroys \p this object.
~RangeAbstraction(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 true if the Abstraction falls back to the default value
+ bool isDefaultAt(const T &V) const noexcept override {
+ auto I = begin();
+ bool Found = false; // Indicates if \c I refers to a matching range.
+ bool Failed = false; // Indicates if it is pointless to continue searching.
+ while (!Found && !Failed && I != end()) {
+ if (V < I->first.first) {
+ // No match so far and \p V is below the next range, never will match.
+ // \note Keys are sorted in the map.
+ return true;
+ } else if (I->first.first <= V && V < I->first.second) {
+ // Matching range found.
+ return false;
+ } else {
+ // Cannot conclude in this step, move to the next range.
+ ++I;
+ }
+ }
+ return true;
+ }
+
/// Abstracts a value from type \p T to type \p A based on the set mapping.
///
/// Results in the value associated by the set mapping to the argument, or
/// \c rosa::agent::RangeAbstraction::Default if the actual argument is not
/// included in any of the ranges in the set mapping.
///
/// \param V value to abstract
///
/// \return the abstracted value based on the set mapping
A operator()(const T &V) const noexcept override {
auto I = begin();
bool Found = false; // Indicates if \c I refers to a matching range.
bool Failed = false; // Indicates if it is pointless to continue searching.
while (!Found && !Failed && I != end()) {
if (V < I->first.first) {
// No match so far and \p V is below the next range, never will match.
// \note Keys are sorted in the map.
Failed = true;
} else if (I->first.first <= V && V < I->first.second) {
// Matching range found.
Found = true;
} else {
// Cannot conclude in this step, move to the next range.
++I;
}
}
ASSERT(!Found || I != end());
return Found ? I->second : Default;
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_ABSTRACTION_HPP
diff --git a/include/rosa/agent/Confidence.hpp b/include/rosa/agent/Confidence.hpp
index 3d07606..35b7496 100644
--- a/include/rosa/agent/Confidence.hpp
+++ b/include/rosa/agent/Confidence.hpp
@@ -1,204 +1,202 @@
//===-- rosa/agent/Confidence.hpp -------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/Confidence.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Definition of *confidence* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_CONFIDENCE_HPP
#define ROSA_AGENT_CONFIDENCE_HPP
#include "rosa/agent/History.hpp"
#include "rosa/support/debug.hpp"
#include <limits>
namespace rosa {
namespace agent {
/// Confidence validator.
///
/// Checks the plausibility of given values by validating if a valid region
/// contains them. It also capable of checking consistency by validating the
/// rate of change recorded by a \c rosa::agent::History object against a
/// maximal absolute valid rate of change.
///
/// \tparam T type of values to validate
///
/// \note The template is defined only for arithmetic types.
///
/// \note The lower bound is inclusive and the upper bound is exclusive.
///
/// \invariant The bounds are defined in a meaningful way:\code
/// LowerBound <= UpperBound
/// \endcode
template <typename T> class Confidence : public Functionality {
// Make sure the actual type argument is an arithmetic type.
STATIC_ASSERT(std::is_arithmetic<T>::value, "not arithmetic Confidence");
public:
/// Unsigned type corresponding to \p T.
using UT = unsigned_t<T>;
/// The minimal value of type \p T.
/// \note Not exist \c V of type \p T such that `V < Min`.
static constexpr T Min = std::is_integral<T>::value
? std::numeric_limits<T>::min()
: std::numeric_limits<T>::lowest();
/// The maximal value of type \p T.
/// \note Not exist \c V of type \p T such that `V > Max`.
static constexpr T Max =
(std::is_integral<T>::value || !std::numeric_limits<T>::has_infinity)
? std::numeric_limits<T>::max()
: std::numeric_limits<T>::infinity();
/// The maximal value of type \c UT.
/// \note Not exist \c V of type \c UT such that `V > UnsignedMax`.
static constexpr UT UnsignedMax =
(std::is_integral<UT>::value || !std::numeric_limits<UT>::has_infinity)
? std::numeric_limits<UT>::max()
: std::numeric_limits<UT>::infinity();
private:
/// The inclusive lower bound for plausibility check.
T LowerBound;
/// The exclusive upper bound for plausibility check.
T UpperBound;
/// The maximal absolute rate of change for consistency check.
UT ChangeRate;
public:
/// Creates an instance by setting the validator variables.
///
/// \param LowerBound the lower bound for plausability check
/// \param UpperBound the upper bound for plausability check
/// \param ChangeRate maximal absolute rate of change for consistency check
///
/// \pre The bounds are defined in a meaningful way:\code
/// LowerBound <= UpperBound
/// \endcode
Confidence(const T LowerBound = Min, const T UpperBound = Max,
const UT ChangeRate = UnsignedMax) noexcept
- : LowerBound(LowerBound),
- UpperBound(UpperBound),
- ChangeRate(ChangeRate) {
+ : LowerBound(LowerBound), UpperBound(UpperBound), ChangeRate(ChangeRate) {
// Make sure Confidence is created in a valid state.
if (LowerBound > UpperBound) {
ROSA_CRITICAL("Confidence with LowerBound higher than UpperBound");
}
}
/// Destroys \p this object.
~Confidence(void) = default;
/// Gives a snapshot of the current state of the validator variables.
///
/// \param [out] LowerBound to copy \c rosa::agent::Confidence::LowerBound
/// into
/// \param [out] UpperBound to copy \c rosa::agent::Confidence::UpperBound
/// into
/// \param [out] ChangeRate to copy \c rosa::agent::Confidence::ChangeRate
/// into
void getParameters(T &LowerBound, T &UpperBound, UT &ChangeRate) const
noexcept {
// Copy members to the given references.
LowerBound = this->LowerBound;
UpperBound = this->UpperBound;
ChangeRate = this->ChangeRate;
}
/// Sets the lower bound for plausability check.
///
/// Beyond setting the lower bound, the function also adjusts the upper bound
/// to the given lower bound if the new lower bound would be higher than the
/// upper bound.
///
/// \param LowerBound the new lower bound to set
void setLowerBound(const T LowerBound) noexcept {
// Adjust UpperBound if necessary, then set LowerBound.
if (UpperBound < LowerBound) {
UpperBound = LowerBound;
}
this->LowerBound = LowerBound;
}
/// Sets the upper bound for plausability check.
///
/// Beyond setting the upper bound, the function also adjusts the lower bound
/// to the given upper bound if the new upper bound would be lower than the
/// lower bound.
///
/// \param UpperBound the new upper bound to set
void setUpperBound(const T UpperBound) noexcept {
// Adjust LowerBound if necessary, then set UpperBound.
if (UpperBound < LowerBound) {
LowerBound = UpperBound;
}
this->UpperBound = UpperBound;
}
/// Sets the maximal rate of change for consistency check.
///
/// \param ChangeRate the new rate of change to set
void setChangeRate(const UT ChangeRate) noexcept {
// Set ChangeRate.
this->ChangeRate = ChangeRate;
}
/// Tells the binary confidence on the plausibility of a value.
///
/// \param V value to check
///
/// \return whether \c V is within the range defined by
/// \c rosa::agent::Confidence::LowerBound and
/// \c rosa::agent::Confidence::UpperBound.
bool operator()(const T V) const noexcept {
// Return if \c V is plausible.
return LowerBound <= V && V < UpperBound;
}
/// Tells the binary confidence on the plausibility and consistency of the
/// last value recorded by a \c rosa::agent::History instance.
///
/// Consistency of the last value is checked by validating the difference with
/// its preceding entry.
///
/// \note The \c rosa::agent::History instance needs to store values of type
/// \p T.
///
/// \note An empty \c rosa::agent::History instance results in full
/// confidence.
///
/// \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 *history* whose last entry to check
template <size_t N, HistoryPolicy P>
- bool operator()(const History<T, N, P> &H) const noexcept {
+ bool operator()(const StaticLengthHistory<T, N, P> &H) const noexcept {
if (H.empty()) {
// No entry to validate.
return true;
} else {
// Validate the last entry and the one step average absolute difference.
return (*this)(H.entry()) && H.averageAbsDiff(1) <= ChangeRate;
}
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_CONFIDENCE_HPP
diff --git a/include/rosa/agent/FunctionAbstractions.hpp b/include/rosa/agent/FunctionAbstractions.hpp
index 1cd0d10..59200de 100644
--- a/include/rosa/agent/FunctionAbstractions.hpp
+++ b/include/rosa/agent/FunctionAbstractions.hpp
@@ -1,175 +1,222 @@
//===-- 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/Functionality.h"
#include "rosa/agent/Abstraction.hpp"
+#include "rosa/agent/Functionality.h"
#include "rosa/support/debug.hpp"
#include <algorithm>
-#include <vector>
#include <cmath>
#include <memory>
+#include <vector>
namespace rosa {
namespace agent {
-/// Evaluates a linear function at a given value.
+/// 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 T type of the functions domain
-/// \tparam A type of the functions range
-template <typename T, typename A> class LinearFunction :
- public Abstraction<T, A>{
+/// \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<T>::value),
- "LinearFunction not arithmetic T");
- STATIC_ASSERT((std::is_arithmetic<A>::value),
- "LinearFunction not to arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<D>::value),
+ "LinearFunction not arithmetic T");
+ STATIC_ASSERT((std::is_arithmetic<R>::value),
+ "LinearFunction not to arithmetic");
+
protected:
- const T Intercept;
- const T Coefficient;
+ /// 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
- /// domain
- LinearFunction(T Intercept, T Coefficient) noexcept
- : Abstraction<T, A>(Intercept),
- Intercept(Intercept),
+ LinearFunction(D Intercept, D Coefficient) noexcept
+ : Abstraction<D, R>(Intercept), Intercept(Intercept),
Coefficient(Coefficient) {}
/// 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;
+ }
+
/// Evaluates the linear function
///
/// \param X the value at which to evaluate the function
- /// \return the result
- virtual A operator()(const T &X) const noexcept override {
- return Intercept + X*Coefficient;
+ ///
+ /// \return Coefficient*X + Intercept
+ virtual R operator()(const D &X) const noexcept override {
+ return Intercept + X * Coefficient;
}
};
-/// Evaluates a sine function at a given value.
+/// Implements \c rosa::agent::Abstraction as a sine function,
+/// y = Amplitude * sin(Frequency * X + Phase) + Average.
///
-/// \tparam T type of the functions domain
-/// \tparam A type of the functions range
-template <typename T, typename A> class SineFunction :
- public Abstraction<T, A>{
+/// \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<T>::value),
- "SineFunction not arithmetic T");
- STATIC_ASSERT((std::is_arithmetic<A>::value),
- "SineFunction not to arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<D>::value),
+ "SineFunction not arithmetic T");
+ STATIC_ASSERT((std::is_arithmetic<R>::value),
+ "SineFunction not to arithmetic");
+
protected:
- const T Frequency;
- const T Amplitude;
- const T Phase;
- const T Average;
+ /// 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
- /// domain
- SineFunction(T Frequency, T Amplitude, T Phase, T Average) noexcept
- : Abstraction<T, A>(Average),
- Frequency(Frequency),
- Amplitude(Amplitude),
- Phase(Phase),
- Average(Average) {}
+ 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;
- /// Evaluates the linear function
+ /// 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 result
- virtual A operator()(const T &X) const noexcept override {
- return Amplitude*sin(Frequency * X + Phase) + Average;
+ /// \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;
}
};
-
-/// Implements \c rosa::agent::RangeAbstraction as an abstraction from
-/// \c std::map from ranges of a type to abstractions of that type to another
-/// type. The resulting abstractions are evaluated for the given values.
+/// Implements \c rosa::agent::Abstraction as a partial function from a domain
+// /to a range.
///
-/// \note This implementation is supposed to be used to abstract ranges of
-/// arithmetic types into abstractions from that type to another arithmetic
-/// type, which is statically enforced.
+/// \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.
///
-/// \invariant The keys in the underlying \c std::map define valid ranges
-/// such that `first <= second` and there are no overlapping ranges defined by
-/// the keys.
+/// 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 T type to abstract from
-/// \tparam A type to abstract to
-template <typename T, typename A>
-class PartialFunction : private Abstraction<T, A> {
+/// \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<T>::value), "abstracting not arithmetic");
- STATIC_ASSERT((std::is_arithmetic<A>::value),
- "abstracting not to arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<D>::value), "abstracting not arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<R>::value),
+ "abstracting not to arithmetic");
private:
- RangeAbstraction<T, std::shared_ptr<Abstraction<T, A>>> RA;
+ /// 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 RangeAbstraction.
+ /// 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<T, T>,
- std::shared_ptr<Abstraction<T, A>>> &Map,
- const A Default)
- : Abstraction<T, A>(Default),
- RA(Map, std::shared_ptr<Abstraction<T, A>>
- (new Abstraction<T, A>(Default))) {
+ 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;
- /// Evaluates an Abstraction from type \p T to type \p A based on the set
- /// mapping.
+ /// 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.
///
- /// Results in the value associated by the set mapping to the argument, or
- /// \c rosa::agent::RangeAbstraction::Default if the actual argument is not
- /// included in any of the ranges in the set mapping.
+ /// \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
- A operator()(const T &V) const noexcept override {
+ 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 1097ad0..5593cb7 100644
--- a/include/rosa/agent/History.hpp
+++ b/include/rosa/agent/History.hpp
@@ -1,292 +1,528 @@
//===-- 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 <array>
+#include <vector>
namespace rosa {
namespace agent {
/// 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
+ 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
};
-/// Implements *history* 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 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 History : public Functionality, 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;
+template <typename T, HistoryPolicy P> class History : public Functionality {
public:
- /// Creates an instances by initializing the indices for the circular buffer.
- History(void) noexcept : Data(0), Space(0) {}
+ History(void) noexcept {}
/// Destroys \p this object.
- ~History(void) = default;
+ virtual ~History(void) = default;
/// Tells the retention policy applied to \p this object.
///
/// \return \c rosa::agent::History::P
- static constexpr HistoryPolicy policyOfHistory(void) noexcept { return 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 \c rosa::agent::History::N
- static constexpr size_t lengthOfHistory(void) noexcept { return N; }
+ /// \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
- size_t numberOfEntries(void) const noexcept {
- return Data <= Space ? Space - Data : max_size() - Data + Space;
- }
+ 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()
+ /// 0 <= I && I < numberOfEntries()
/// \endcode
- 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];
- }
+ 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:
- /// Tells if the circular buffer is full.
+ /// Pushes a new entry into the history.
///
- /// \return if the circular buffer is full.
- bool full(void) const noexcept { return numberOfEntries() == N; }
-
- /// Pushes a new entry into the circular buffer.
+ /// \note The earliest entry gets overwritten if the history is full.
///
- /// \note The earliest entry gets overwritten if the buffer 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 push into the buffer
- 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();
- }
- }
+ /// \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 < N
+ /// 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 = N - 1) const noexcept {
+ trend(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
- ASSERT(0 <= D && D < N); // Boundary check.
+ 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 < N
+ /// 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 = N - 1) const noexcept {
+ averageAbsDiff(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
- ASSERT(0 <= D && D < N); // Boundary check.
+ 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>
-History<T, N, P> &operator<<(History<T, N, P> &H, const T &V) noexcept {
+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> {
+
+ // 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>::size;
+ using std::vector<T>::max_size;
+ using std::vector<T>::resize;
+ using std::vector<T>::push_back;
+ using std::vector<T>::pop_back;
+ using std::vector<T>::operator[];
+
+ /// The current length of the DynamicLengthHistory.
+ size_t Length;
+
+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 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 { 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()); }
+
+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/agent/RangeConfidence.hpp b/include/rosa/agent/RangeConfidence.hpp
index 0966a87..60a53c1 100644
--- a/include/rosa/agent/RangeConfidence.hpp
+++ b/include/rosa/agent/RangeConfidence.hpp
@@ -1,89 +1,108 @@
//===-- rosa/agent/RangeConfidence.hpp --------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/RangeConfidence.hpp
///
/// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *RangeConfidence* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_RANGECONFIDENCE_HPP
#define ROSA_AGENT_RANGECONFIDENCE_HPP
-#include "rosa/agent/Functionality.h"
#include "rosa/agent/Abstraction.hpp"
#include "rosa/agent/FunctionAbstractions.hpp"
+#include "rosa/agent/Functionality.h"
#include "rosa/support/debug.hpp"
#include <algorithm>
-#include <vector>
#include <cmath>
#include <memory>
+#include <vector>
namespace rosa {
namespace agent {
-/// Evaluates a vector of Abstractions at a given value and returns the results
-/// as a vector
+/// Evaluates a map of ID's to Abstractions at a given value and returns the
+/// results as a map from ID's to results of the corresponding Abstraction
///
/// \note This implementation is supposed to be used to abstract ranges of
-/// arithmetic types into vectors of another arithmetic type, which is
-/// statically enforced.
+/// arithmetic types into maps whose values are of another arithmetic type,
+/// which is statically enforced.
///
-/// \tparam T type to abstract from
-/// \tparam A type to abstract a vector of to
-template <typename T, typename A>
-class RangeConfidence : public Abstraction<T, std::vector<A>>,
- private std::vector<PartialFunction<T, A>>{
+/// \tparam D type to abstract from
+/// \tparam I type the type of the ID's
+/// \tparam R type of the range
+template <typename D, typename I, typename R>
+class RangeConfidence : protected Abstraction<D, std::map<I, R>>,
+ private std::map<I, PartialFunction<D, R>> {
// Make sure the actual type arguments are matching our expectations.
- STATIC_ASSERT((std::is_arithmetic<T>::value), "abstracting not arithmetic");
- STATIC_ASSERT((std::is_arithmetic<A>::value),
- "abstracting not to arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<D>::value), "abstracting not arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<R>::value),
+ "abstracting not to arithmetic");
- // Bringing into scope inherited members.
- using std::vector<PartialFunction<T, A>>::size;
- using std::vector<PartialFunction<T, A>>::begin;
- using std::vector<PartialFunction<T, A>>::end;
+private:
+ /// Wether to include default results in the result-map or not
+ bool IgnoreDefaults;
public:
- /// Creates an instance by Initializing the underlying \c RangeAbstraction.
+ /// Creates an instance by Initializing the underlying \c Abstraction and
+ /// \c std::map.
///
/// \param Abstractions the Abstractions to be evaluated
- RangeConfidence(const std::vector<PartialFunction<T, A>> &Abstractions)
- : Abstraction<T, std::vector<A>>({}),
- std::vector<PartialFunction<T, A>>(Abstractions) {
- }
+ /// \param IgnoreDefaults wether to include default results in the result-map
+ /// or not (defaults to false).
+ RangeConfidence(const std::map<I, PartialFunction<D, R>> &Abstractions,
+ bool IgnoreDefaults = false)
+ : Abstraction<D, std::map<I, R>>({}), std::map<I, PartialFunction<D, R>>(
+ Abstractions),
+ IgnoreDefaults(IgnoreDefaults) {}
/// Destroys \p this object.
~RangeConfidence(void) = default;
- /// Evaluates an Abstraction from type \p T to type \p A based on the set
- /// mapping.
+ /// Checks wether all Abstractions evaluate to default at the given position
///
- /// Results in the value associated by the set mapping to the argument, or
- /// \c rosa::agent::RangeAbstraction::Default if the actual argument is not
- /// included in any of the ranges in the set mapping.
+ /// \param V the value at which to check if the functions falls back to it's
+ /// default value.
+ ///
+ /// \return true, if all Abstractions evaluate to default
+ bool isDefaultAt(const D &V) const noexcept override {
+ for (auto const &P : ((std::map<I, PartialFunction<D, R>>)*this)) {
+ if (!P.second.isDefaultAt(V))
+ return false;
+ }
+ return true;
+ }
+
+ /// All Abstractions stored in the underlying \c std::map are evaluated for
+ /// the given value. Their results are stored in another map, with
+ /// corresponding keys.
+ /// If IgnoreDefaults is set, Abstractions that default for that value are not
+ /// evaluated and inserted into the resulting \c std::map
///
/// \param V value to abstract
///
- /// \return the abstracted value based on the set mapping
- std::vector<A> operator()(const T &V) const noexcept override {
- std::vector<A> ret;
- for (auto const& func : ((std::vector<PartialFunction<T, A>>)*this)){
- ret.push_back(func(V));
+ /// \return a \c std::map containing the results of the stored Abstractions,
+ /// indexable by the key's the Abstractions are associated with
+ std::map<I, R> operator()(const D &V) const noexcept override {
+ std::map<I, R> Ret;
+ for (auto const &P : ((std::map<I, PartialFunction<D, R>>)*this)) {
+ if (!IgnoreDefaults || !P.second.isDefaultAt(V))
+ Ret.insert(std::pair<I, R>(P.first, P.second(V)));
}
- return ret;
+ return Ret;
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_RANGECONFIDENCE_HPP
diff --git a/include/rosa/core/SystemBase.hpp b/include/rosa/core/SystemBase.hpp
index a5ca0d2..4b6720e 100644
--- a/include/rosa/core/SystemBase.hpp
+++ b/include/rosa/core/SystemBase.hpp
@@ -1,138 +1,138 @@
//===-- rosa/core/SystemBase.hpp -----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/core/SystemBase.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Base implementation of the \c rosa::System interface.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_CORE_SYSTEMBASE_HPP
#define ROSA_CORE_SYSTEMBASE_HPP
#include "rosa/core/System.hpp"
#include <atomic>
namespace rosa {
/// Base implementation of the \c rosa::System interface.
///
/// This implementation provides only equality checking and *name* for
/// \c rosa::System, identifiers for \c rosa::Unit instances, and marking the
/// \c rosa::System cleaned for destruction.
///
/// \note Actual implementations of \c rosa::System and derived interfaces are
/// supposed to inherit from this implementation.
class SystemBase : public System {
protected:
/// Creates an instance.
///
/// \note Protected constructor restrict instantiation for subclasses.
///
/// \param Name name of the new instance
SystemBase(const std::string &Name) noexcept;
public:
/// Destroys \p this object.
///
/// \pre \p this object is marked cleaned:\code
/// isSystemCleaned()
/// \endcode
~SystemBase(void);
/// Tells whether \p this object is the same as \p Other.
///
/// Two \c rosa::System instances are considered equal if they share a common
/// \c rosa::SystemBase::Name member field. That should do among various
/// subclasses.
///
/// \param Other another \c rosa::System instance to compare to
///
/// \return whether \p this object and \p Other is the same
bool operator==(const System &Other) const noexcept override;
protected:
/// The textual name of \p this object implementing \c rosa::System.
const std::string Name;
private:
/// Number of \c rosa::Unit instances constructed by \p this object.
///
/// \note Should never be decremented!
std::atomic<size_t> UnitCount;
/// Indicates that \p this object has been cleaned and is ready for
/// destruction.
///
/// The field is initialized as \c false and can be set by
/// \c rosa::SystemBase::markCleaned.
///
/// \note Subclasses must set the flag upon destructing their instances, which
/// indicates to the destructor of the base-class that all the managed
/// resources has been properly released.
std::atomic<bool> SystemIsCleaned;
public:
/// Tells the name of \p this object
///
/// \note The returned reference remains valid as long as \p this object is
/// not destroyed.
///
/// \return reference to \c rosa::SystemBase::Name
const std::string &name(void) const noexcept override;
protected:
/// Tells the next unique identifier to be used for a newly created
/// \c rosa::Unit.
///
/// The functions takes the current value of the internal counter
/// \c rosa::SystemBase::UnitCount and then increments it.
///
/// \note This is the only function modifying
/// \c rosa::SystemBase::UnitCount.
///
/// \return \c rosa::id_t which is unique within the context of \p this
/// object.
id_t nextId(void) noexcept override;
/// Tells if \p this object has been marked cleaned and is ready for
/// destruction.
///
/// \return if \p this object is marked clean.
bool isSystemCleaned(void) const noexcept override;
/// Marks \p this object cleaned by setting
/// \c rosa::SystemBase::SystemIsCleaned.
///
/// \note Can be called only once when the System does not have any live
/// \c rosa::Unit instances.
///
/// \pre \p this object has not yet been marked as cleaned and it has no
/// \c rosa::Unit instances registered:\code
/// !isSystemCleaned() && empty()
/// \endcode
///
/// \post \p this object is marked cleaned:\code
/// isSystemCleaned()
/// \endcode
void markCleaned(void) noexcept override;
/// Tells the number of \c rosa::Unit instances constructed in the context of
/// \p this object so far, including those being already destroyed.
///
/// \return current value of \c rosa::SystemBase::UnitCount that is the number
/// of \c rosa::Unit instances created so far
size_t numberOfConstructedUnits(void) const noexcept override;
};
} // End namespace rosa
-#endif // ROSA_LIB_CORE_SYSTEMBASE_HPP
+#endif // ROSA_CORE_SYSTEMBASE_HPP
diff --git a/include/rosa/deluxe/DeluxeSystem.hpp b/include/rosa/deluxe/DeluxeSystem.hpp
index 4388a4e..1be3bbd 100755
--- a/include/rosa/deluxe/DeluxeSystem.hpp
+++ b/include/rosa/deluxe/DeluxeSystem.hpp
@@ -1,211 +1,210 @@
//===-- rosa/deluxe/DeluxeSystem.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeSystem.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Specialization of \c rosa::MessagingSystem for the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXESYSTEM_HPP
#define ROSA_DELUXE_DELUXESYSTEM_HPP
#include "rosa/core/MessagingSystem.hpp"
#include "rosa/deluxe/DeluxeAgent.hpp"
#include "rosa/deluxe/DeluxeSensor.hpp"
namespace rosa {
namespace deluxe {
/// Implements and extends the \c rosa::MessagingSystem interface to be
/// used by \c rosa::deluxe::DeluxeContext.
///
/// The class is a specialization of \c rosa::MessagingSystem, where objects
/// of two specialized subtypes of \c rosa::Agent, \c rosa::deluxe::DeluxeSensor
/// and \c rosa::deluxe::DeluxeAgent, constitute a system. The class extends the
/// \c rosa::MessagingSystem interface with features required to implement the
/// *deluxe interface*.
///
/// \see rosa::deluxe::DeluxeContext
class DeluxeSystem : public MessagingSystem {
friend class DeluxeContext;
public:
/// Returns an object implementing the \c rosa::deluxe::DeluxeSystem
/// interface.
///
/// \param Name name of the new instance
///
/// \return \c std::unique_ptr for the new instance of
/// \c rosa::DeluxeSystem
static std::unique_ptr<DeluxeSystem>
createSystem(const std::string &Name) noexcept;
protected:
/// Creates a new instance.
///
/// \note Protected constructor restricts instantiation for subclasses.
DeluxeSystem(void) noexcept = default;
public:
/// Creates a \c rosa::deluxe::DeluxeSensor instance owned by \p this object
/// and returns a \p rosa::AgentHandle for it.
///
/// \tparam T type of data the new \c rosa::deluxe::DeluxeSensor operates on
///
/// \param Name name of the new \c rosa::deluxe::DeluxeSensor
/// \param F function to generate the next value with during normal operation
///
/// \return \c rosa::AgentHandle for new \c rosa::deluxe::DeluxeSensor
template <typename T>
AgentHandle createSensor(const std::string &Name,
DeluxeSensor::D<T> &&F) noexcept;
/// Creates a \c rosa::deluxe::DeluxeAgent instance owned by \p this object
/// and returns a \c rosa::AgentHandle for it.
///
/// \tparam T type of data the new \c rosa::deluxe::DeluxeAgent outputs
/// \tparam As types of inputs the new \c rosa::deluxe::DeluxeAgent takes
///
/// \param Name name of the new \c rosa::deluxe::DeluxeAgent
/// \param F function for the new \c rosa::deluxe::DeluxeAgent to process
/// input values and generate output with
///
/// \return \c rosa::AgentHandle for new \c rosa::deluxe::DeluxeAgent
template <typename T, typename... As>
AgentHandle createAgent(const std::string &Name,
DeluxeAgent::D<T, As...> &&F) noexcept;
protected:
/// Tells whether a \c rosa::AgentHandle refers to a
/// \c rosa::deluxe::DeluxeSensor owned by \p this object.
///
/// \param H \c rosa::AgentHandle to check
///
/// \return whether \p H refers to a \c rosa::deluxe::DeluxeSensor owned by
/// \p this object
virtual bool isDeluxeSensor(const AgentHandle &H) const noexcept = 0;
/// Extracts a const qualified \c rosa::deluxe::DeluxeSensor reference from a
/// const qualified \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a const
/// qualified reference to a \c rosa::deluxe::DeluxeSensor object extracted
/// from a const qualified \c rosa::AgentHandle instance if the referred
/// object is of type \c rosa::deluxeDeluxeSensor and owned by \p this object.
/// The returned \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeSensor
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeSensor
/// from
///
/// \return const qualified reference to \c rosa::deluxe::DeluxeSensor if
/// \p H refers to an object which is of that type and is owned by \p this
/// object
Optional<const DeluxeSensor &> getDeluxeSensor(const AgentHandle &H) const
noexcept;
/// Extracts a \c rosa::deluxe::DeluxeSensor reference from a
/// \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a reference to
/// a \c rosa::deluxe::DeluxeSensor object extracted from a
/// \c rosa::AgentHandle instance if the referred object is of type
/// \c rosa::deluxeDeluxeSensor and owned by \p this object. The returned
/// \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeSensor
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeSensor
/// from
///
/// \return reference to \c rosa::deluxe::DeluxeSensor if \p H refers to an
/// object which is of that type and is owned by \p this object
Optional<DeluxeSensor &> getDeluxeSensor(AgentHandle &H) const noexcept;
/// Tells whether a \c rosa::AgentHandle refers to a
/// \c rosa::deluxe::DeluxeAgent owned by \p this object.
///
/// \param H \c rosa::AgentHandle to check
///
/// \return whether \p H refers to a \c rosa::deluxe::DeluxeAgent owned by
/// \p this object
virtual bool isDeluxeAgent(const AgentHandle &H) const noexcept = 0;
/// Extracts a const qualified \c rosa::deluxe::DeluxeAgent reference from a
/// const qualified \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a const
/// qualified reference to a \c rosa::deluxe::DeluxeAgent object extracted
/// from a const qualified \c rosa::AgentHandle instance if the referred
/// object is of type \c rosa::deluxeDeluxeAgent and owned by \p this object.
/// The returned \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeAgent
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeAgent
/// from
///
/// \return const qualified reference to \c rosa::deluxe::DeluxeAgent if \p H
/// refers to an object which is of that type and is owned by \p this object
Optional<const DeluxeAgent &> getDeluxeAgent(const AgentHandle &H) const
noexcept;
/// Extracts a \c rosa::deluxe::DeluxeAgent reference from a
/// \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a reference to
/// a \c rosa::deluxe::DeluxeAgent object extracted from a
/// \c rosa::AgentHandle instance if the referred object is of type
/// \c rosa::deluxeDeluxeAgent and owned by \p this object. The returned
/// \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeAgent
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeAgent
/// from
///
/// \return reference to \c rosa::deluxe::DeluxeAgent if \p H refers to an
/// object which is of that type and is owned by \p this object
Optional<DeluxeAgent &> getDeluxeAgent(AgentHandle &H) const noexcept;
};
template <typename T>
AgentHandle DeluxeSystem::createSensor(const std::string &Name,
DeluxeSensor::D<T> &&F) noexcept {
Agent &DS = createUnit<DeluxeSensor, MessagingSystem>(
[&](const id_t Id, MessagingSystem &S) {
return new DeluxeSensor(atoms::SensorKind, Id, Name, S, std::move(F));
});
return {DS};
}
template <typename T, typename... As>
-AgentHandle
-DeluxeSystem::createAgent(const std::string &Name,
- DeluxeAgent::D<T, As...> &&F) noexcept {
-
+AgentHandle DeluxeSystem::createAgent(const std::string &Name,
+ DeluxeAgent::D<T, As...> &&F) noexcept {
+
Agent &DA = createUnit<DeluxeAgent, DeluxeSystem>(
[&](const id_t Id, DeluxeSystem &S) {
return new DeluxeAgent(atoms::AgentKind, Id, Name, S, std::move(F));
});
return {DA};
}
} // End namespace deluxe
} // End namespace rosa
-#endif // ROSA_LIB_DELUXE_DELUXESYSTEM_HPP
+#endif // ROSA_DELUXE_DELUXESYSTEM_HPP
diff --git a/lib/core/MessagingSystemImpl.hpp b/lib/core/MessagingSystemImpl.hpp
index 485711a..89a366b 100644
--- a/lib/core/MessagingSystemImpl.hpp
+++ b/lib/core/MessagingSystemImpl.hpp
@@ -1,109 +1,110 @@
//===-- core/MessagingSystemImpl.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file core/MessagingSystemImpl.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Declaration of a basic implementation of the \c rosa::MessagingSystem
/// interface.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP
#define ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP
#include "SystemImpl.hpp"
#include "rosa/core/MessagingSystem.hpp"
namespace rosa {
/// Implements \c rosa::MessagingSystem by extending \c rosa::SystemImpl with
/// adding a simple implementation of sending messages: directly invoking
/// \c rosa::Agent instances with given \c rosa::Message objects.
///
/// \note Keep in mind that sending a \c rosa::Message object with this
/// implementation translates into a direct function call.
class MessagingSystemImpl : public MessagingSystem, public SystemImpl {
/// Alies for the base-class \c rosa::SystemImpl.
using Base = SystemImpl;
public:
/// Creates an instance.
///
/// \param Name name of the new instance
MessagingSystemImpl(const std::string &Name) noexcept;
- /// \defgroup MessagingSystemImplCallForwarding Call forwardings of rosa::MessagingSystemImpl
+ /// \defgroup MessagingSystemImplCallForwarding Call forwardings of
+ /// rosa::MessagingSystemImpl
///
/// \c rosa::MessagingSystemImpl call forwardings
///
/// \note Simply forwarding calls to implementations provided by
/// \c rosa::MessagingSystem::Base for the \c rosa::System interface.
///
/// \todo How could we use the inherited implementations in a simpler way?
///@{
bool operator==(const System &Other) const noexcept override {
return Base::operator==(Other);
}
protected:
id_t nextId(void) noexcept override { return Base::nextId(); }
bool isSystemCleaned(void) const noexcept override {
return Base::isSystemCleaned();
}
void markCleaned(void) noexcept override { Base::markCleaned(); }
void registerUnit(Unit &U) noexcept override { Base::registerUnit(U); }
void destroyUnit(Unit &U) noexcept override { Base::destroyUnit(U); }
bool isUnitRegistered(const Unit &U) const noexcept override {
return Base::isUnitRegistered(U);
}
public:
const std::string &name(void) const noexcept override { return Base::name(); }
size_t numberOfConstructedUnits(void) const noexcept override {
return Base::numberOfConstructedUnits();
}
size_t numberOfLiveUnits(void) const noexcept override {
return Base::numberOfLiveUnits();
}
bool empty(void) const noexcept override { return Base::empty(); }
///@}
/// Sends a \c rosa::message_t instance to the \c rosa::Agent instance
/// referred by a \c rosa::AgentHandle -- by directly invoking the
/// \c rosa::Agent instance with the \c rosa::Message object.
///
/// \note If the given \c rosa::Message object cannot be handled by the
/// referred \c rosa::Agent instance, the \c rosa::Message object is simply
/// ignored.
///
/// \param H refers to the \c rosa::Agent instance to send to
/// \param M message to send
///
/// \pre The referred \c rosa::Agent instance is owned by \p this object and
/// also registered: \code
/// &unwrapSystem(H) == this && isUnitRegistered(unwrapAgent(H))
/// \endcode
void send(const AgentHandle &H, message_t &&M) noexcept override;
};
} // End namespace rosa
#endif // ROSA_LIB_CORE_MESSAGINGSYSTEMIMPL_HPP

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 10:30 PM (16 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157389
Default Alt Text
(82 KB)

Event Timeline