diff --git a/examples/agent-functionalities/agent-functionalities.cpp b/examples/agent-functionalities/agent-functionalities.cpp index 2da67b8..c1d77a1 100644 --- a/examples/agent-functionalities/agent-functionalities.cpp +++ b/examples/agent-functionalities/agent-functionalities.cpp @@ -1,170 +1,183 @@ //===-- 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/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 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 static AgentHandle createMyAgent(MessagingSystem *S, const std::string &Name, Funs &&... Fs) { return ((SystemTester *)S)->createAgent(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; private: enum class Categories { Bad, Normal, Good }; static const std::map CategoryNames; History H; Confidence C; RangeAbstraction A; PartialFunction L; - RangeConfidence RCL; - RangeConfidence RCS; + RangeConfidence RCL; + RangeConfidence 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 res_lin = RCL(H.entry()); + + std::map res_lin = RCL(H.entry()); for (auto i : res_lin){ - LOG_INFO_STREAM << " " << i; + LOG_INFO_STREAM << " " << CategoryNames.at(i.first) + << " " << i.second << "," ; } - LOG_INFO_STREAM << ", range-confidence-sine: "; - std::vector res_sine = RCS(H.entry()); + LOG_INFO_STREAM << " range-confidence-sine: "; + std::map res_sine = RCS(H.entry()); for (auto i : res_sine){ - LOG_INFO_STREAM << " " << i; + LOG_INFO_STREAM << " " << CategoryNames.at(i.first) + << " " << i.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>(0, 1)}, {{2, 4}, std::make_shared>(2, 0)}, {{4, 6}, std::make_shared>(6, -1)}}, 0), RCL({ - PartialFunction({ - {{0, 3}, std::make_shared>(0, 1.0/3)}, - {{3, 6}, std::make_shared>(1, 0)}, - {{6, 9}, std::make_shared>(3.0, -1.0/3)}, - },0), - PartialFunction({ - {{6, 9}, std::make_shared>(-2, 1.0/3)}, - {{9, 12}, std::make_shared>(1, 0)}, - {{12, 15}, std::make_shared>(5, -1.0/3)}, - },0), - PartialFunction({ - {{12, 15}, std::make_shared>(-4, 1.0/3)}, - {{15, 18}, std::make_shared>(1, 0)}, - {{18, 21}, std::make_shared>(7, -1.0/3)}, - },0) + {Categories::Bad, PartialFunction({ + {{0, 3}, std::make_shared> + (0, 1.0/3)}, + {{3, 6}, std::make_shared> + (1, 0)}, + {{6, 9}, std::make_shared> + (3.0, -1.0/3)}, + },0)}, + {Categories::Normal, PartialFunction({ + {{6, 9}, std::make_shared> + (-2, 1.0/3)}, + {{9, 12}, std::make_shared> + (1, 0)}, + {{12, 15}, std::make_shared> + (5, -1.0/3)}, + },0)}, + {Categories::Good, PartialFunction({ + {{12, 15}, std::make_shared> + (-4, 1.0/3)}, + {{15, 18}, std::make_shared> + (1, 0)}, + {{18, 21}, std::make_shared> + (7, -1.0/3)}, + },0)} }), RCS({ - PartialFunction({ + {Categories::Bad, PartialFunction({ {{0, 3}, std::make_shared> (M_PI/3, 0.5, -M_PI/2, 0.5)}, {{3, 6}, std::make_shared>(1, 0)}, {{6, 9}, std::make_shared> (M_PI/3, 0.5, -M_PI/2 + 3, 0.5)}, - },0), - PartialFunction({ + },0)}, + {Categories::Normal, PartialFunction({ {{6, 9}, std::make_shared> (M_PI/3, 0.5, -M_PI/2, 0.5)}, {{9, 12}, std::make_shared>(1, 0)}, {{12, 15}, std::make_shared> (M_PI/3, 0.5, -M_PI/2 + 3, 0.5)}, - },0), - PartialFunction({ + },0)}, + {Categories::Good, PartialFunction({ {{12, 15}, std::make_shared> (M_PI/3, 0.5, -M_PI/2, 0.5)}, {{15, 18}, std::make_shared>(1, 0)}, {{18, 21}, std::make_shared> (M_PI/3, 0.5, -M_PI/2 + 3, 0.5)}, - },0) - }){} + },0)} + }, true){} }; const std::map 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'; std::unique_ptr S = MessagingSystem::createSystem("Sys"); MessagingSystem *SP = S.get(); AgentHandle A = SystemTester::createMyAgent(SP, "MyAgent"); std::vector 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::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 #include 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 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 class MapAbstraction : public Abstraction, private std::map { // Make sure the actual type arguments are enumerations. STATIC_ASSERT((std::is_enum::value && std::is_enum::value), "mapping not enumerations"); // Bringing into scope inherited members. using Abstraction::Default; using std::map::end; using std::map::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 &Map, const A Default) noexcept : Abstraction(Default), std::map(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 class RangeAbstraction : public Abstraction, private std::map, A> { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); /// \todo check if this compiles with the definition of abstractions as /// self-aware properties //STATIC_ASSERT((std::is_enum::value), "abstracting not to enumeration"); // Bringing into scope inherited members. using Abstraction::Default; using std::map, A>::begin; using std::map, A>::end; using std::map, 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, A> &Map, const A &Default) : Abstraction(Default), std::map, A>(Map) { // Sanity check. ASSERT(std::all_of( begin(), end(), [this](const std::pair, A> &P) { return P.first.first <= P.first.second && std::all_of(++find(P.first), end(), [&P](const std::pair, 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/FunctionAbstractions.hpp b/include/rosa/agent/FunctionAbstractions.hpp index 1cd0d10..9a7127a 100644 --- a/include/rosa/agent/FunctionAbstractions.hpp +++ b/include/rosa/agent/FunctionAbstractions.hpp @@ -1,175 +1,224 @@ //===-- 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/support/debug.hpp" #include #include #include #include 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. /// -/// \tparam T type of the functions domain -/// \tparam A type of the functions range -template class LinearFunction : - public Abstraction{ +/// \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 class LinearFunction : + public Abstraction{ // Make sure the actual type arguments are matching our expectations. - STATIC_ASSERT((std::is_arithmetic::value), + STATIC_ASSERT((std::is_arithmetic::value), "LinearFunction not arithmetic T"); - STATIC_ASSERT((std::is_arithmetic::value), + STATIC_ASSERT((std::is_arithmetic::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(Intercept), + LinearFunction(D Intercept, D Coefficient) noexcept + : Abstraction(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 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 class SineFunction : - public Abstraction{ +/// \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 class SineFunction : + public Abstraction{ // Make sure the actual type arguments are matching our expectations. - STATIC_ASSERT((std::is_arithmetic::value), + STATIC_ASSERT((std::is_arithmetic::value), "SineFunction not arithmetic T"); - STATIC_ASSERT((std::is_arithmetic::value), + STATIC_ASSERT((std::is_arithmetic::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(Average), + SineFunction(D Frequency, D Amplitude, D Phase, D Average) noexcept + : Abstraction(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 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 -class PartialFunction : private Abstraction { +/// \tparam D type of the functions domain +/// \tparam R type of the functions range +template +class PartialFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. - STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); - STATIC_ASSERT((std::is_arithmetic::value), + STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); + STATIC_ASSERT((std::is_arithmetic::value), "abstracting not to arithmetic"); private: - RangeAbstraction>> 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>> 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::shared_ptr>> &Map, - const A Default) - : Abstraction(Default), - RA(Map, std::shared_ptr> - (new Abstraction(Default))) { + PartialFunction(const std::map, + std::shared_ptr>> &Map, + const R Default) + : Abstraction(Default), + RA(Map, std::shared_ptr> + (new Abstraction(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/RangeConfidence.hpp b/include/rosa/agent/RangeConfidence.hpp index 0966a87..0d8732e 100644 --- a/include/rosa/agent/RangeConfidence.hpp +++ b/include/rosa/agent/RangeConfidence.hpp @@ -1,89 +1,109 @@ //===-- 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/support/debug.hpp" #include #include #include #include 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 -class RangeConfidence : public Abstraction>, - private std::vector>{ +/// \tparam D type to abstract from +/// \tparam I type the type of the ID's +/// \tparam R type of the range +template +class RangeConfidence : protected Abstraction>, + private std::map>{ // Make sure the actual type arguments are matching our expectations. - STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); - STATIC_ASSERT((std::is_arithmetic::value), + STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); + STATIC_ASSERT((std::is_arithmetic::value), "abstracting not to arithmetic"); - // Bringing into scope inherited members. - using std::vector>::size; - using std::vector>::begin; - using std::vector>::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> &Abstractions) - : Abstraction>({}), - std::vector>(Abstractions) { + /// \param IgnoreDefaults wether to include default results in the result-map + /// or not (defaults to false). + RangeConfidence(const std::map> &Abstractions, + bool IgnoreDefaults = false) + : Abstraction>({}), + std::map>(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>)*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 operator()(const T &V) const noexcept override { - std::vector ret; - for (auto const& func : ((std::vector>)*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 operator()(const D &V) const noexcept override { + std::map ret; + for (auto const& p : ((std::map>)*this)){ + if(!IgnoreDefaults || !p.second.isDefaultAt(V)) + ret.insert(std::pair(p.first, p.second(V))); } return ret; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_RANGECONFIDENCE_HPP