diff --git a/include/rosa/agent/CrossCombinator.h b/include/rosa/agent/CrossCombinator.h index 699e783..61526aa 100644 --- a/include/rosa/agent/CrossCombinator.h +++ b/include/rosa/agent/CrossCombinator.h @@ -1,558 +1,559 @@ //===-- rosa/delux/CrossCombinator.h ----------------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/CrossCombinator.h /// /// \author Daniel Schnoell /// -/// \date 2019 +/// \date 2019-2020 +/// /// \note based on Maximilian Goetzinger(maxgot @utu.fi) code in /// CAM_Dirty_include SA-EWS2_Version... inside Agent.cpp /// /// \brief /// /// \todo there is 1 exception that needs to be handled correctly. /// \note the default search function is extremely slow maybe this could be done /// via template for storage class and the functions/methods to efficiently find /// the correct LinearFunction //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_CROSSCOMBINATOR_H #define ROSA_AGENT_CROSSCOMBINATOR_H #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/ReliabilityConfidenceCombination.h" #include "rosa/core/forward_declarations.h" // needed for id_t #include "rosa/support/log.h" // needed for error "handling" // nedded headers #include #include //assert #include // for static methods #include #include namespace rosa { namespace agent { template std::vector> &operator<<( std::vector> &me, std::vector> Values) { for (auto tmp : Values) { std::pair tmp2; tmp2.first = std::get<0>(tmp); tmp2.second = std::get<1>(tmp); me.push_back(tmp2); } return me; } /// This is the Combinator class for cross Reliabilities. It has many functions /// with different purposes /// \brief It takes the Identifiers and Reliabilities of all given ids and /// calculates the Likeliness of them together. Also it can creates the /// feedback that is needed by the \c ReliabilityConfidenceCombination, which /// is a kind of confidence. /// /// \tparam IdentifierType Data type of the Identifier ( Typically double /// or float) \tparam LikelinessType Data type of the Likeliness ( Typically /// long or int) // this might be swapped /// /// \note This class is commonly in a master slave relationship as master with /// \c ReliabilityConfidenceCombination. The \c operator()() combines the /// Likeliness of all connected Slaves and uses that as its own Likeliness /// also creates the feedback for the Slaves. /// /// \note more information about how the Likeliness and feedback is /// created at \c operator()() , \c getCombinedCrossLikeliness() , \c /// getCombinedInputLikeliness() , \c getOutputLikeliness() [ this is the /// used Likeliness ], \c getCrossLikeliness() [ this is the feedback /// for all Compares ] /// /// a bit more special Methods \c CrossConfidence() ,\c CrossLikeliness() template class CrossCombinator { public: static_assert(std::is_arithmetic::value, "HighLevel: IdentifierType has to be an arithmetic type\n"); static_assert(std::is_arithmetic::value, "HighLevel: LikelinessType has to be an arithmetic type\n"); // --------------------------------------------------------------------------- // useful definitions // --------------------------------------------------------------------------- /// typedef To shorten the writing. /// \c Symbol using Symbol = Symbol; /// To shorten the writing. using Abstraction = typename rosa::agent::Abstraction; /// The return type for the \c operator()() Method struct returnType { LikelinessType CrossLikeliness; std::map> Likeliness; }; // ------------------------------------------------------------------------- // Relevant Methods // ------------------------------------------------------------------------- /// Calculates the CrossLikeliness and the Likeliness for each id for all /// of there Identifiers. /// /// \param Values It gets the Identifiers and Reliabilities of /// all connected Compare Agentss inside a vector. /// /// \return it returns a struct \c returnType containing the \c /// getCombinedCrossLikeliness() and \c getCrossLikeliness() returnType operator()( std::vector> Values) { return {getOutputLikeliness(Values), getCrossLikeliness(Values)}; } /// returns the combined Cross Likeliness via \c /// LikelinessCombinationMethod \c /// setLikelinessCombinationMethod() for all ids \c /// CrossLikeliness() \param Values the used Values LikelinessType getCombinedCrossLikeliness( const std::vector> &Values) noexcept { LikelinessType Likeliness = -1; std::vector> Agents; Agents << Values; for (auto Value : Values) { id_t id = std::get<0>(Value); IdentifierType sc = std::get<1>(Value); // calculate the cross Likeliness for this Compare agent LikelinessType realCrossLikelinessOfCompareInput = CrossLikeliness({id, sc}, Agents); if (Likeliness != -1) Likeliness = LikelinessCombinationMethod( Likeliness, realCrossLikelinessOfCompareInput); else Likeliness = realCrossLikelinessOfCompareInput; } return Likeliness; } /// returns the combined via \c CombinedInputLikelinessCombinationMethod \c /// setCombinedInputLikelinessCombinationMethod() input Likeliness \param Values /// the used Values LikelinessType getCombinedInputLikeliness( const std::vector> &Values) noexcept { LikelinessType combinedInputRel = -1; std::vector> Agents; Agents << Values; for (auto Value : Values) { LikelinessType rel = std::get<2>(Value); if (combinedInputRel != -1) combinedInputRel = CombinedInputLikelinessCombinationMethod(combinedInputRel, rel); else combinedInputRel = rel; } return combinedInputRel; } /// returns the combination via \c OutputLikelinessCombinationMethod \c /// setOutputLikelinessCombinationMethod() of the Cross Likeliness and /// input Likeliness \param Values the used Values LikelinessType getOutputLikeliness( const std::vector> &Values) noexcept { return OutputLikelinessCombinationMethod( getCombinedInputLikeliness(Values), getCombinedCrossLikeliness(Values)); } /// returns the crossConfidence for all ids \c CrossConfidence() /// \param Values the used Values std::map> getCrossLikeliness( const std::vector> &Values) noexcept { std::vector> Agents; std::map> output; std::vector output_temporary; Agents << Values; for (auto Value : Values) { id_t id = std::get<0>(Value); output_temporary.clear(); for (IdentifierType thoIdentifier : Identifiers[id]) { Symbol data; data.Identifier = thoIdentifier; data.Likeliness = CrossConfidence(id, thoIdentifier, Agents); output_temporary.push_back(data); } output.insert({id, output_temporary}); } return output; } /// Calculates the Cross Confidence /// \brief it uses the Identifier value and calculates /// the Confidence of a given agent( represented by their id ) for a given /// Identifiers in connection to all other given agents /// /// \note all combination of agents and there corresponding Cross Likeliness /// function have to be specified LikelinessType CrossConfidence(const id_t &MainAgent, const IdentifierType &TheoreticalValue, const std::vector> &CompareInputs) noexcept { LikelinessType crossReliabiability; std::vector values; for (std::pair CompareInput : CompareInputs) { if (CompareInput.first == MainAgent) continue; if (TheoreticalValue == CompareInput.second) crossReliabiability = 1; else crossReliabiability = 1 / (crossLikelinessParameter * std::abs(TheoreticalValue - CompareInput.second)); // profile Likeliness LikelinessType crossLikelinessFromProfile = getCrossLikelinessFromProfile( MainAgent, CompareInput.first, std::abs(TheoreticalValue - CompareInput.second)); values.push_back( std::max(crossReliabiability, crossLikelinessFromProfile)); } return Method(values); } /// Calculates the Cross Likeliness /// \brief it uses the Identifier value and calculates /// the Likeliness of a given agent( represented by their id ) in connection /// to all other given agents /// /// \note all combination of agents and there corresponding Cross Likeliness /// function have to be specified LikelinessType CrossLikeliness(const std::pair &MainAgent, const std::vector> &CompareInputs) noexcept { LikelinessType crossReliabiability; std::vector values; for (std::pair CompareInput : CompareInputs) { if (CompareInput.first == MainAgent.first) continue; if (MainAgent.second == CompareInput.second) crossReliabiability = 1; else crossReliabiability = 1 / (crossLikelinessParameter * std::abs(MainAgent.second - CompareInput.second)); // profile Likeliness - LikelinessType crossLikelinessFromProfile = - getCrossLikelinessFromProfile( - MainAgent.first, CompareInput.first, - std::abs(MainAgent.second - CompareInput.second)); + LikelinessType crossLikelinessFromProfile = getCrossLikelinessFromProfile( + MainAgent.first, CompareInput.first, + (IdentifierType)std::abs(MainAgent.second - CompareInput.second)); values.push_back( std::max(crossReliabiability, crossLikelinessFromProfile)); } return Method(values); } // -------------------------------------------------------------------------- // Defining the class // -------------------------------------------------------------------------- /// adds a Cross Likeliness Profile used to get the Likeliness of the /// Identifier difference /// /// \param idA The id of the one \c Agent ( ideally the id of \c Unit to make /// it absolutely unique ) /// /// \param idB The id of the other \c Agent /// /// \param Function A shared pointer to an \c Abstraction it would use the /// difference in Identifier for its input void addCrossLikelinessProfile( //conf const id_t &idA, const id_t &idB, const std::shared_ptr &Function) noexcept { Functions.push_back({true, idA, idB, Function}); //confidence Profiles } /// sets the cross Likeliness parameter void setCrossLikelinessParameter(const LikelinessType &val) noexcept { crossLikelinessParameter = val; } /// This is the adder for the Identifiers /// \param id The id of the Agent of the Identifiers /// \param _Identifiers id specific Identifiers. This will be copied So that if /// Compares have different Identifiers they can be used correctly. \brief The /// Identifiers of all connected Compare Agents has to be known to be able to /// iterate over them void addIdentifiers(const id_t &id, //add IdentifierIdentifiers const std::vector &_Identifiers) noexcept { Identifiers.insert({id, _Identifiers}); } // ------------------------------------------------------------------------- // Combinator Settings // ------------------------------------------------------------------------- /// sets the used method to combine the values /// \param Meth the method which should be used. predefined functions in the /// struct \c predefinedMethods \c /// CONJUNCTION() \c AVERAGE() \c DISJUNCTION() void setCrossLikelinessCombinatorMethod( const std::function values)> &Meth) noexcept { Method = Meth; } /// sets the combination method for the combined cross Likeliness /// \param Meth the method which should be used. predefined functions in the /// struct \c predefinedMethods LikelinessCombinationMethod() void setLikelinessCombinationMethod( const std::function &Meth) noexcept { LikelinessCombinationMethod = Meth; } /// sets the combined input rel method /// \param Meth the method which should be used. predefined functions in the /// struct \c predefinedMethods CombinedInputLikelinessCombinationMethod() void setCombinedInputLikelinessCombinationMethod( const std::function &Meth) noexcept { CombinedInputLikelinessCombinationMethod = Meth; } /// sets the used OutputLikelinessCombinationMethod /// \param Meth the method which should be used. predefined functions in the /// struct \c predefinedMethods OutputLikelinessCombinationMethod() void setOutputLikelinessCombinationMethod( const std::function &Meth) noexcept { OutputLikelinessCombinationMethod = Meth; } // ------------------------------------------------------------------------- // Predefined Functions // ------------------------------------------------------------------------- /// This struct is a pseudo name space to have easier access to all predefined /// methods while still not overcrowding the class it self struct predefinedMethods { /// predefined combination method static LikelinessType CONJUNCTION(std::vector values) { return *std::min_element(values.begin(), values.end()); } /// predefined combination method static LikelinessType AVERAGE(std::vector values) { - return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); + return std::accumulate(values.begin(), values.end(), (LikelinessType)0) / + values.size(); } /// predefined combination method static LikelinessType DISJUNCTION(std::vector values) { return *std::max_element(values.begin(), values.end()); } /// predefined combination Method static LikelinessType LikelinessCombinationMethodMin(LikelinessType A, LikelinessType B) { return std::min(A, B); } /// predefined combination Method static LikelinessType LikelinessCombinationMethodMax(LikelinessType A, LikelinessType B) { return std::max(A, B); } /// predefined combination Method static LikelinessType LikelinessCombinationMethodMult(LikelinessType A, LikelinessType B) { return A * B; } /// predefined combination Method static LikelinessType LikelinessCombinationMethodAverage(LikelinessType A, LikelinessType B) { return (A + B) / 2; } /// predefined combination Method static LikelinessType CombinedInputLikelinessCombinationMethodMin(LikelinessType A, LikelinessType B) { return std::min(A, B); } /// predefined combination Method static LikelinessType CombinedInputLikelinessCombinationMethodMax(LikelinessType A, LikelinessType B) { return std::max(A, B); } /// predefined combination Method static LikelinessType CombinedInputLikelinessCombinationMethodMult(LikelinessType A, LikelinessType B) { return A * B; } /// predefined combination Method static LikelinessType CombinedInputLikelinessCombinationMethodAverage(LikelinessType A, LikelinessType B) { return (A + B) / 2; } /// predefined combination method static LikelinessType OutputLikelinessCombinationMethodMin(LikelinessType A, LikelinessType B) { return std::min(A, B); } /// predefined combination method static LikelinessType OutputLikelinessCombinationMethodMax(LikelinessType A, LikelinessType B) { return std::max(A, B); } /// predefined combination method static LikelinessType OutputLikelinessCombinationMethodMult(LikelinessType A, LikelinessType B) { return A * B; } /// predefined combination method static LikelinessType OutputLikelinessCombinationMethodAverage(LikelinessType A, LikelinessType B) { return (A + B) / 2; } }; // ------------------------------------------------------------------------- // Cleanup // ------------------------------------------------------------------------- ~CrossCombinator() { Functions.clear(); } // -------------------------------------------------------------------------- // Parameters // -------------------------------------------------------------------------- private: struct Functionblock { bool exists = false; id_t A; id_t B; std::shared_ptr Funct; }; std::map> Identifiers; /// From Maxi in his code defined as 1 can be changed by set LikelinessType crossLikelinessParameter = 1; /// Stored Cross Likeliness Functions std::vector Functions; /// Method which is used to combine the generated values std::function)> Method = predefinedMethods::AVERAGE; std::function LikelinessCombinationMethod = predefinedMethods::LikelinessCombinationMethodMin; std::function CombinedInputLikelinessCombinationMethod = predefinedMethods::CombinedInputLikelinessCombinationMethodMin; std::function OutputLikelinessCombinationMethod = predefinedMethods::OutputLikelinessCombinationMethodMin; //-------------------------------------------------------------------------------- // helper function /// very inefficient searchFunction Functionblock (*searchFunction)(std::vector vect, const id_t nameA, const id_t nameB) = [](std::vector vect, const id_t nameA, const id_t nameB) -> Functionblock { for (Functionblock tmp : vect) { if (tmp.A == nameA && tmp.B == nameB) return tmp; if (tmp.A == nameB && tmp.B == nameA) return tmp; } return Functionblock(); }; /// evaluates the corresponding LinearFunction with the Identifier difference /// \param nameA these two parameters are the unique Identifiers /// \param nameB these two parameters are the unique Identifiers /// for the LinerFunction /// /// \note it doesn't matter if they are swapped LikelinessType getCrossLikelinessFromProfile( const id_t &nameA, const id_t &nameB, const IdentifierType &IdentifierDifference) noexcept { Functionblock block = searchFunction(Functions, nameA, nameB); if (!block.exists) { LOG_ERROR(("CrossLikeliness: Block:" + std::to_string(nameA) + "," + std::to_string(nameB) + "doesn't exist returning 0")); return 0; } return block.Funct->operator()(IdentifierDifference); } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_CROSSCOMBINATOR_H