diff --git a/include/rosa/agent/FunctionAbstractions.hpp b/include/rosa/agent/FunctionAbstractions.hpp index a0f8585..b0c9002 100644 --- a/include/rosa/agent/FunctionAbstractions.hpp +++ b/include/rosa/agent/FunctionAbstractions.hpp @@ -1,354 +1,354 @@ //===-- rosa/agent/FunctionAbstractions.hpp ---------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/FunctionAbstractions.hpp /// /// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *FunctionAbstractions* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP #define ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Functionality.h" #include "rosa/support/debug.hpp" #include #include #include #include namespace rosa { namespace agent { /// Implements \c rosa::agent::Abstraction as a linear function, /// y = Coefficient * X + Intercept. /// /// \note This implementation is supposed to be used to represent a linear /// function from an arithmetic domain to an arithmetic range. This is enforced /// statically. /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class LinearFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "LinearFunction not arithmetic T"); STATIC_ASSERT((std::is_arithmetic::value), "LinearFunction not to arithmetic"); protected: /// The Intercept of the linear function const D Intercept; /// The Coefficient of the linear function const D Coefficient; public: /// Creates an instance given the intercept and the coefficient of a linear /// function. /// /// \param Intercept the intercept of the linear function /// \param Coefficient the coefficient of the linear function LinearFunction(D Intercept, D Coefficient) noexcept : Abstraction(Intercept), Intercept(Intercept), Coefficient(Coefficient) {} /// Creates an instance given the two points on a linear function. /// /// \param x1 The x-value of the first point /// \param y1 The x-value of the first point /// \param x2 The y-value of the second point /// \param y2 The y-value of the second point LinearFunction(D x1, R y1, D x2, R y2) noexcept : Abstraction(y1 - x1 * (y1 - y2) / (x1 - x2), (y1 - y2) / (x1 - x2)) {} /// Creates an instance given the two points on a linear function. /// /// \param p1 The coordinates of the first point /// \param p2 The coordinates of the second point LinearFunction(std::pair p1, std::pair p2) noexcept : LinearFunction(p1.first, p1.second, p2.first, p2.second) {} /// Destroys \p this object. ~LinearFunction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// As LinearFunctions can be evaluated everythwere, this is always false /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false bool isDefaultAt(const D &V) const noexcept override { (void)V; return false; } /// Getter for member variable Intercept /// /// \return Intercept D getIntercept() const { return Intercept; } /// Setter for member variable Intercept /// /// \param Intercept the new Intercept void setIntercept(const D &Intercept) { this->Intercept = Intercept; } /// Getter for member variable Coefficient /// /// \return Coefficient D getCoefficient() const { return Coefficient; } /// Setter for member variable Coefficient /// /// \param Coefficient the new Intercept void setCoefficient(const D &Coefficient) { this->Coefficient = Coefficient; } /// Set Intercept and Coefficient from two points on the linear function /// /// \param x1 The x-value of the first point /// \param y1 The x-value of the first point /// \param x2 The y-value of the second point /// \param y2 The y-value of the second point void setFromPoints(D x1, R y1, D x2, R y2) { Coefficient = (y1 - y2) / (x1 - x2); Intercept = y1 - Coefficient * x1; } /// Set Intercept and Coefficient from two points on the linear function /// /// \param p1 The coordinates of the first point /// \param p2 The coordinates of the second point inline void setFromPoints(std::pair p1, std::pair p2) { setFromPoints(p1.first, p1.second, p2.first, p2.second); } /// Evaluates the linear function /// /// \param X the value at which to evaluate the function /// /// \return Coefficient*X + Intercept virtual R operator()(const D &X) const noexcept override { return Intercept + X * Coefficient; } }; /// Implements \c rosa::agent::Abstraction as a sine function, /// y = Amplitude * sin(Frequency * X + Phase) + Average. /// /// \note This implementation is supposed to be used to represent a sine /// function from an arithmetic domain to an arithmetic range. This is enforced /// statically. /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class SineFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "SineFunction not arithmetic T"); STATIC_ASSERT((std::is_arithmetic::value), "SineFunction not to arithmetic"); protected: /// The frequency of the sine wave const D Frequency; /// The Ampiltude of the sine wave const D Amplitude; /// The Phase-shift of the sine wave const D Phase; /// The y-shift of the sine wave const D Average; public: /// Creates an instance. /// /// \param Frequency the frequency of the sine wave /// \param Amplitude the amplitude of the sine wave /// \param Phase the phase of the sine wave /// \param Average the average of the sine wave SineFunction(D Frequency, D Amplitude, D Phase, D Average) noexcept : Abstraction(Average), Frequency(Frequency), Amplitude(Amplitude), Phase(Phase), Average(Average) {} /// Destroys \p this object. ~SineFunction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// As SineFunctions can be evaluated everythwere, this is always false /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false bool isDefaultAt(const D &V) const noexcept override { (void)V; return false; } /// Evaluates the sine function /// /// \param X the value at which to evaluate the function /// \return the value of the sine-function at X virtual R operator()(const D &X) const noexcept override { return Amplitude * sin(Frequency * X + Phase) + Average; } }; /// Implements \c rosa::agent::PartialFunction as a step function from 0 to 1 /// with a ramp in between /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class StepFunction : 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), "abstracting not to arithmetic"); private: D Coefficient; D RightLimit; public: /// Creates an instance by Initializing the underlying \c Abstraction. /// /// \param Coefficient Coefficient of the ramp /// /// \pre Coefficient > 0 StepFunction(D Coefficient) : Abstraction(0), Coefficient(Coefficient), RightLimit(1.0f / Coefficient) { ASSERT(Coefficient > 0); } /// Destroys \p this object. ~StepFunction(void) = default; /// Setter for Coefficient /// /// \param Coefficient the new Coefficient void setCoefficient(const D &Coefficient) { ASSERT(Coefficient > 0); this->Coefficient = Coefficient; this->RightLimit = 1 / Coefficient; } /// Setter for RightLimit /// - /// \param RightLimit the new RightLimit + /// \param RightLimit_ the new RightLimit //@Benedikt: I had to change the name of the parameter from RightLimit to // RightLimit_, because otherwise there was a "warning treaded as error: // warning: C4458: declaration of 'RightLimit' hides class member" void setRightLimit(const D &RightLimit_) { ASSERT(RightLimit_ > 0); this->RightLimit = RightLimit_; this->Coefficient = 1 / RightLimit_; } /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false if the is negative, true otherwise bool isDefaultAt(const D &V) const noexcept override { return V > 0; } /// Executes the Abstraction /// /// \param V value to abstract /// /// \return the abstracted value R operator()(const D &V) const noexcept override { if (V <= 0) return 0; if (V >= RightLimit) return 1; return V * Coefficient; } }; /// Implements \c rosa::agent::Abstraction as a partial function from a domain /// to a range. /// /// \note This implementation is supposed to be used to represent a partial /// function from an arithmetic domain to an arithmetic range. This is enforced /// statically. /// /// A partial function is defined as a list of abstractions, where each /// abstraction is associated a range in which it is defined. These ranges must /// be mutually exclusive. /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template 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), "abstracting not to arithmetic"); private: /// A \c rosa::agent::RangeAbstraction RA is used to represent the association /// from ranges to Abstractions. /// This returns the Abstraction that is defined for any given value, or /// a default Abstraction if no Abstraction is defined for that value. RangeAbstraction>> RA; public: /// Creates an instance by Initializing the underlying \c Abstraction. /// /// \param Map the mapping to do abstraction according to /// \param Default abstraction to abstract to by default /// /// \pre Each key defines a valid range such that `first <= second` and /// there are no overlapping ranges defined by the keys. PartialFunction( const std::map, std::shared_ptr>> &Map, const R Default) : Abstraction(Default), RA(Map, std::shared_ptr>(new Abstraction(Default))) { } /// Destroys \p this object. ~PartialFunction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false if the value falls into a defined range and the Abstraction /// defined for that range does not fall back to it's default value. bool isDefaultAt(const D &V) const noexcept override { return RA.isDefaultAt(V) ? true : RA(V)->isDefaultAt(V); } /// Searches for an Abstraction for the given value and executes it for that /// value, if such an Abstraction is found. The default Abstraction is /// evaluated otherwise. /// /// \param V value to abstract /// /// \return the abstracted value based on the set mapping R operator()(const D &V) const noexcept override { return RA(V)->operator()(V); } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp index 8483f65..a356c93 100644 --- a/include/rosa/support/math.hpp +++ b/include/rosa/support/math.hpp @@ -1,201 +1,201 @@ //===-- rosa/support/math.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/math.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Math helpers. /// //===----------------------------------------------------------------------===// // !!!!!! Please check lines 60 - 180 forward !!!!!!!!!!!!!! #ifndef ROSA_SUPPORT_MATH_HPP #define ROSA_SUPPORT_MATH_HPP #include "debug.hpp" #include #include #include #include #include #include #include namespace rosa { /// Computes log base 2 of a number. /// /// \param N the number to compute log base 2 for /// /// \return log base 2 of \p N constexpr size_t log2(const size_t N) { return ((N < 2) ? 1 : 1 + log2(N / 2)); } /// Tells the next representable floating point value. /// /// \tparam T type to operate on /// /// \note The second type argument enforces \p T being a floating point type, /// always use the default value! /// /// \param V value to which find the next representable one /// /// \return the next representable value of type \p T after value \p V /// /// \pre Type \p T must be a floating point type, which is enforced by /// `std::enable_if` in the second type argument. template ::value>> T nextRepresentableFloatingPoint(const T V) { return std::nextafter(V, std::numeric_limits::infinity()); } -#if false +#if false //can't compile original // copied from the internet and adapted // (https://stackoverflow.com/questions/1657883/variable-number-of-arguments-in-c) /// Conjuncts two or more values with each other. /// /// \param two or more values of the same datatype /// /// \return the conjunction of the values given as parameter. template CONFDATATYPE fuzzyAND(int n_args, ...) noexcept { // TODO: check datatype, if there are at least two arguments, and if they are // between 0 and 1 // David suggests: nstead of a variadic argument, you could pass the values as // an std::array (with a template argument for the length). When you pass the // values as a container, you can simply use std::max_element and // std::min_element to have a one-liner implementation of the these fuzzy // functions. va_list ap; va_start(ap, n_args); CONFDATATYPE min = va_arg(ap, CONFDATATYPE); for (int i = 2; i <= n_args; i++) { CONFDATATYPE a = va_arg(ap, CONFDATATYPE); min = std::min(a, min); } va_end(ap); return min; } #else template CONFDATATYPE fuzzyAND(std::array Data) noexcept { STATIC_ASSERT(std::is_arithmetic::value, "Type of FuzzyAnd is not arithmetic"); STATIC_ASSERT(size > 1, "Number of Arguments is to little"); for (auto tmp : Data) ASSERT(tmp <= 1 && tmp >= 0); return *std::min_element(Data.begin(), Data.end()); } #if false // safer template std::enable_if_t< std::conjunction_v...>, CONFDATATYPE> fuzzyAND(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept { return fuzzyAND( std::array{Data, Datan...}); } #else template CONFDATATYPE fuzzyAND(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept { return fuzzyAND( std::array{Data, Datan...}); } #endif #endif -#if false //can't compile +#if false //can't compile original /// Disjuncts two or more values with each other. /// /// /// /// \return the disjunction of the values given as parameter. // copied from the internet // (https://stackoverflow.com/questions/1657883/variable-number-of-arguments-in-c) template CONFDATATYPE fuzzyOR(int n_args, ...) noexcept { // TODO: check datatype and if they are between 0 and 1 // David suggests: nstead of a variadic argument, you could pass the values as // an std::array (with a template argument for the length). When you pass the // values as a container, you can simply use std::max_element and // std::min_element to have a one-liner implementation of the these fuzzy // functions. va_list ap; va_start(ap, n_args); CONFDATATYPE max = va_arg(ap, CONFDATATYPE); for (int i = 2; i <= n_args; i++) { CONFDATATYPE a = va_arg(ap, CONFDATATYPE); max = std::max(a, max); } va_end(ap); return max; } #else template CONFDATATYPE fuzzyOR(std::array Data) noexcept { STATIC_ASSERT(std::is_arithmetic::value, "Type of FuzzyAnd is not arithmetic"); STATIC_ASSERT(size > 1, "Number of Arguments is to little"); for (auto tmp : Data) ASSERT(tmp <= 1 && tmp >= 0); return *std::max_element(Data.begin(), Data.end()); } #if false // safer template std::enable_if_t< std::conjunction_v...>, CONFDATATYPE> fuzzyOR(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept { return fuzzyOR( std::array{Data, Datan...}); } #else template CONFDATATYPE fuzzyOR(CONFDATATYPE Data, _CONFDATATYPE... Datan) noexcept { return fuzzyOR( std::array{Data, Datan...}); } #endif #endif template PROCDATATYPE relativeDistance(INDATATYPE NewValue, INDATATYPE HistoryValue) noexcept { PROCDATATYPE Dist = HistoryValue - NewValue; if (Dist == 0) { return 0; } else { Dist = Dist / NewValue; if (Dist < 0) { // TODO: I guess this multiplication here should not be done because // it could be that the distance fuzzy functions are not symetrical //(negative and positive side) Dist = Dist * (-1); } return (Dist); } } } // End namespace rosa #endif // ROSA_SUPPORT_MATH_HPP