diff --git a/include/rosa/agent/CrossReliability.h b/include/rosa/agent/CrossReliability.h index 3142089..0b97806 100644 --- a/include/rosa/agent/CrossReliability.h +++ b/include/rosa/agent/CrossReliability.h @@ -1,353 +1,534 @@ //===-- rosa/delux/CrossReliability.h ---------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/delux/CrossReliability.h /// /// \author Daniel Schnoell /// /// \date 2019 /// /// \brief /// /// \todo there is 1 exception that needs to be handled correctly. /// \note the default search function is extremely slow maby this could be done /// via template for storage class and the functions/methods to efficiently find /// the correct LinearFunction //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_CROSSRELIABILITY_H #define ROSA_AGENT_CROSSRELIABILITY_H #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/ReliabilityConfidenceCombinator.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 Reliability Functionality for the highlevel Agent. /// \brief It takes the scores and reliabilities of all connected lowlevel /// Agents and calculates the Reliability of them together. Also it creates the /// feedback that is needed by the \c ReliabilityForLowLevelAgents, which is a /// kind of confidence. /// /// \tparam StateType Datatype of the State ( Typically double or float) /// \tparam ReliabilityType Datatype of the Reliability ( /// Typically long or int) /// /// \note A highlevel Agent is commonly in a master slave relationship with the /// lowlevel Agents as the master. It combines the Reliability of all connected /// Slaves and uses that as its own Reliability. /// /// \note more information about how the Reliability and feedback is /// created at \c operator()() // State Type rename // merge cross rel/conf darein template class CrossCombinator { public: static_assert(std::is_arithmetic::value, "HighLevel: StateType has to be an arithmetic type\n"); static_assert(std::is_arithmetic::value, "HighLevel: ReliabilityType has to be an arithmetic type\n"); + // --------------------------------------------------------------------------- + // useful definitions + // --------------------------------------------------------------------------- /// typedef To shorten the writing. /// \c ConfOrRel typedef ConfOrRel ConfOrRel; + using Abstraction = + typename rosa::agent::Abstraction; + /// typedef of the input type for the operator() defined explicitly to /// simplify interaction /// typedef std::vector> InputType; /// The return type for the \c operator()() Method struct returnType { ReliabilityType CrossReliability; std::map> CrossConfidence; }; - /// Calculates the Reliability and the Cross Confidences for each lowlevel - /// Agent for all of there states. + // ------------------------------------------------------------------------- + // Relevant Methods + // ------------------------------------------------------------------------- + /// Calculates the Reliability and the Cross Confidences for each id for all + /// of there states. /// /// \param Values It gets the States and Reliabilities of /// all connected Slaves inside a vector. /// - /// \return it returns a struct \c returnType containing the CrossReliability - /// and all CrossConfidence's - /// - /// \brief To calculate the Reliability it combines [\c std::min() ] the \c - /// CrossReliability of all connected Agents. To calculate the feedback it - /// iterates over all Agents and their states and uses the \c CrossConfidence - /// Function to play what if with the states. - returnType operator()( - std::vector> &Values) { + /// \return it returns a struct \c returnType containing the \c getCombinedCrossReliability() + /// and \c getCrossConfidence() + returnType + operator()(std::vector> Values) { + return {getOutputReliability(Values), getCrossConfidence(Values)}; + } + + /// returns the combined Cross Reliability for all ids \c CrossReliability() + /// \param Vales the used Values + ReliabilityType getCombinedCrossReliability( + std::vector> Values) { - ReliabilityType combinedInputRel = 1; - ReliabilityType combinedCrossRel = 1; - ReliabilityType outputReliability; + ReliabilityType combinedCrossRel = -1; std::vector> Agents; - std::map> output; - std::vector output_temporary; - for (auto tmp : Values) { - std::pair tmp2; - tmp2.first = std::get<0>(tmp); - tmp2.second = std::get<1>(tmp); - Agents.push_back(tmp2); - } + Agents << Values; for (auto Value : Values) { id_t id = std::get<0>(Value); StateType sc = std::get<1>(Value); - ReliabilityType rel = std::get<2>(Value); - - // combination method ([]) - // get input reliability - combinedInputRel = std::min(combinedInputRel, rel); // calculate the cross reliability for this slave agent ReliabilityType realCrossReliabilityOfSlaveAgent = CrossReliability( {id, sc}, Agents); // AVERAGE, MULTIPLICATION, CONJUNCTION (best to worst: // AVERAGE = CONJUNCTION > MULTIPLICATION >> ) + if (combinedCrossRel != -1) + combinedCrossRel = CombinedCrossRelCombinationMethod( + combinedCrossRel, realCrossReliabilityOfSlaveAgent); + else + combinedCrossRel = realCrossReliabilityOfSlaveAgent; + } + return combinedCrossRel; + } + + /// returns the combined input relibility + /// \param Values the used Values + ReliabilityType getCombinedInputReliability( + std::vector> Values) { + ReliabilityType combinedInputRel = -1; + + std::vector> Agents; + + Agents << Values; + + for (auto Value : Values) { + ReliabilityType rel = std::get<2>(Value); + + if (combinedInputRel != -1) + combinedInputRel = + CombinedInputRelCombinationMethod(combinedInputRel, rel); + else + combinedInputRel = rel; + } + } + + /// returns the combination of the Cross reliability and input reliability + /// \param Values the used Values + ReliabilityType getOutputReliability( + std::vector> Values) { + return std::min(getCombinedInputReliability(Values), + getCombinedCrossReliability(Values)); + } + + /// retruns the cross Confidence for all ids \c CrossConfidence() + /// \param Values the used Values + void getCrossConfidence( + std::vector> Values) { + + std::vector> Agents; + std::map> output; + std::vector output_temporary; + + Agents << Values; + + for (auto Value : Values) { + id_t id = std::get<0>(Value); + // get cross confidence output_temporary.clear(); for (StateType thoScore : States[id]) { // calculate the cross reliability for this slave agent ConfOrRel data; data.score = thoScore; data.Reliability = CrossConfidence(id, thoScore, Agents); output_temporary.push_back(data); } output.insert({id, output_temporary}); - // set combination method - // get combined cross reliability - combinedCrossRel = - std::min(combinedCrossRel, realCrossReliabilityOfSlaveAgent); } - // combine cross reliabilites and input reliabilites of all slave agents - // NOTE: options would be multiply, average, AND (best to worst: ) - // outputReliability = combinedInputRel * combinedCrossRel; - // outputReliability = (combinedInputRel + combinedCrossRel) / 2; - // set combination method - // get output reliability - outputReliability = std::min(combinedInputRel, combinedCrossRel); - return {outputReliability, output}; - } - - using Abstraction = - typename rosa::agent::Abstraction; - - struct Functionblock { - bool exists = false; - id_t A; - id_t B; - Abstraction *Funct; - }; - - /// adds a Cross Reliability Profile used to get the Reliability of the state - /// difference - /// \param idA The id of the one \c Agent ( idealy the id of \c Unit to make - /// it absolutly unique ) - /// - /// \param idB The id of the other \c Agent - /// - /// \param Function A unique pointer to an \c Abstraction it would use the - /// difference in score for its input - void addCrossReliabilityProfile(id_t idA, id_t idB, - std::unique_ptr &Function) { - Abstraction *ptr = Function.release(); - Functions.push_back({true, idA, idB, ptr}); - } - - /// sets the cross reliability parameter - void setCrossReliabilityParameter(ReliabilityType val) { - crossReliabilityParameter = val; - } - /// sets the used method to combine the values - /// \param Meth The Function which defines the combination method. - /// \note Inside \c CrossReliability there are static methods defined which - /// can be used. - void setCrossReliabilityMethod( - ReliabilityType (*Meth)(std::vector values)) { - Method = Meth; - } - - ~CrossCombinator() { - for (auto tmp : Functions) - delete tmp.Funct; - Functions.clear(); + return output; } /// Calculates the Cross Confidence /// \brief it uses the state represented by a numerical value and calculates /// the Confidence of a given agent( represented by there id ) for a given /// state in connection to all other given agents /// /// \note all combination of agents and there corresponding Cross Reliability /// function have to be specified ReliabilityType CrossConfidence(id_t MainAgent, StateType TheoreticalValue, - std::vector> &SlaveAgents) { + std::vector> &SlaveAgents) { ReliabilityType crossReliabiability; std::vector values; for (std::pair SlaveAgent : SlaveAgents) { if (SlaveAgent.first == MainAgent) continue; if (TheoreticalValue == SlaveAgent.second) crossReliabiability = 1; else crossReliabiability = 1 / (crossReliabilityParameter * AbsuluteValue(TheoreticalValue, SlaveAgent.second)); // profile reliability - ReliabilityType crossReliabilityFromProfile = getCrossReliabilityFromProfile( - MainAgent, SlaveAgent.first, - AbsuluteValue(TheoreticalValue, SlaveAgent.second)); + ReliabilityType crossReliabilityFromProfile = + getCrossReliabilityFromProfile( + MainAgent, SlaveAgent.first, + AbsuluteValue(TheoreticalValue, SlaveAgent.second)); values.push_back( std::max(crossReliabiability, crossReliabilityFromProfile)); } return Method(values); } /// Calculates the Cross Reliability /// \brief it uses the state represented by a numerical value and calculates /// the Reliability of a given agent( represented by there id ) in connection /// to all other given agents /// /// \note all combination of agents and there corresponding Cross Reliability /// function have to be specified ReliabilityType CrossReliability(std::pair &&MainAgent, std::vector> &SlaveAgents) { ReliabilityType crossReliabiability; std::vector values; for (std::pair SlaveAgent : SlaveAgents) { if (SlaveAgent.first == MainAgent.first) continue; if (MainAgent.second == SlaveAgent.second) crossReliabiability = 1; else crossReliabiability = 1 / (crossReliabilityParameter * AbsuluteValue(MainAgent.second, SlaveAgent.second)); // profile reliability ReliabilityType crossReliabilityFromProfile = getCrossReliabilityFromProfile( - MainAgent.first, SlaveAgent.first, - AbsuluteValue(MainAgent.second, SlaveAgent.second)); + MainAgent.first, SlaveAgent.first, + AbsuluteValue(MainAgent.second, SlaveAgent.second)); values.push_back( std::max(crossReliabiability, crossReliabilityFromProfile)); } return Method(values); } + // -------------------------------------------------------------------------- + // Defining the class + // -------------------------------------------------------------------------- + + /// adds a Cross Reliability Profile used to get the Reliability of the state + /// difference + /// \param idA The id of the one \c Agent ( idealy the id of \c Unit to make + /// it absolutly unique ) + /// + /// \param idB The id of the other \c Agent + /// + /// \param Function A unique pointer to an \c Abstraction it would use the + /// difference in score for its input + void addCrossReliabilityProfile(id_t idA, id_t idB, + std::unique_ptr &Function) { + Abstraction *ptr = Function.release(); + Functions.push_back({true, idA, idB, ptr}); + } + + /// sets the cross reliability parameter + void setCrossReliabilityParameter(ReliabilityType val) { + crossReliabilityParameter = val; + } + /// sets the used method to combine the values + /// \param Meth The Function which defines the combination method. + /// \note Inside \c CrossReliability there are static methods defined which + /// can be used. + void setCrossReliabilityMethod( + ReliabilityType (*Meth)(std::vector values)) { + Method = Meth; + } + + /// This is the adder for the states + /// \param id The id of the Agent of the states + /// \param States id specific states. this will be copied So that if Slaves + /// have different States they can be used correctly. + /// \brief The States of all connected lowlevel Agents has to be known to be + /// able to iterate over them + void addStates(id_t id, std::vector States) { + this->States.insert({id, States}); + } + + // ------------------------------------------------------------------------- + // Combinator Settings + // ------------------------------------------------------------------------- + + /// stes the combination method for the combined cross reliability + /// \param Meth the method which should be used. predef: \c + /// CombinedCrossRelCombinationMethodMin() \c + /// CombinedCrossRelCombinationMethodMax() \c + /// CombinedCrossRelCombinationMethodMult() \c + /// CombinedCrossRelCombinationMethodAverage() + void setCombinedCrossRelCombinationMethod( + ReliabilityType (*Meth)(ReliabilityType, ReliabilityType)) { + CombinedCrossRelCombinationMethod = Meth; + } + + /// stets the combined input rel method + /// \param Meth the method which should be used predef: \c + /// CombinedInputRelCombinationMethodMin() \c + /// CombinedInputRelCombinationMethodMax() \c + /// CombinedInputRelCombinationMethodMult() \c + /// CombinedInputRelCombinationMethodAverage() + void setCombinedInputRelCombinationMethod( + ReliabilityType (*Meth)(ReliabilityType, ReliabilityType)) { + CombinedInputRelCombinationMethod = Meth; + } + + /// sets the used OutputReliabilityCombinationMethod + /// \param Meth the used Method. predef: \c + /// OutputReliabilityCombinationMethodMin() \c + /// OutputReliabilityCombinationMethodMax() \c + /// OutputReliabilityCombinationMethodMult() \c + /// OutputReliabilityCombinationMethodAverage() + void setOutputReliabilityCombinationMethod( + ReliabilityType (*Meth)(ReliabilityType, ReliabilityType)) { + OutputReliabilityCombinationMethod = Meth; + } + + // ------------------------------------------------------------------------- + // Predefined Functions + // ------------------------------------------------------------------------- /// predefined combination method static ReliabilityType CONJUNCTION(std::vector values) { return *std::min_element(values.begin(), values.end()); } /// predefined combination method static ReliabilityType AVERAGE(std::vector values) { return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); } /// predefined combination method static ReliabilityType DISJUNCTION(std::vector values) { return *std::max_element(values.begin(), values.end()); } - /// This is the adder for the states - /// \param id The id of the Agent of the states - /// \param States id specific states. this will be copied So that if Slaves - /// have different States they can be used correctly. - /// \brief The States of all connected lowlevel Agents has to be known to be - /// able to iterate over them - void addStates(id_t id, std::vector States) { - this->States.insert({id, States}); + /// predefined combination Method + static ReliabilityType + CombinedCrossRelCombinationMethodMin(ReliabilityType A, ReliabilityType B) { + return std::min(A, B); + } + + /// predefined combination Method + static ReliabilityType + CombinedCrossRelCombinationMethodMax(ReliabilityType A, ReliabilityType B) { + return std::max(A, B); + } + + /// predefined combination Method + static ReliabilityType + CombinedCrossRelCombinationMethodMult(ReliabilityType A, ReliabilityType B) { + return A * B; + } + + /// predefined combination Method + static ReliabilityType + CombinedCrossRelCombinationMethodAverage(ReliabilityType A, + ReliabilityType B) { + return (A + B) / 2; + } + + /// predefined combination Method + static ReliabilityType + CombinedInputRelCombinationMethodMin(ReliabilityType A, ReliabilityType B) { + return std::min(A, B); + } + + /// predefined combination Method + static ReliabilityType + CombinedInputRelCombinationMethodMax(ReliabilityType A, ReliabilityType B) { + return std::max(A, B); + } + + /// predefined combination Method + static ReliabilityType + CombinedInputRelCombinationMethodMult(ReliabilityType A, ReliabilityType B) { + return A * B; + } + + /// predefined combination Method + static ReliabilityType + CombinedInputRelCombinationMethodAverage(ReliabilityType A, + ReliabilityType B) { + return (A + B) / 2; + } + + /// predefined combination method + static ReliabilityType + OutputReliabilityCombinationMethodMin(ReliabilityType A, ReliabilityType B) { + return std::min(A, B); + } + + /// predefined combination method + static ReliabilityType + OutputReliabilityCombinationMethodMax(ReliabilityType A, ReliabilityType B) { + return std::max(A, B); } + /// predefined combination method + static ReliabilityType + OutputReliabilityCombinationMethodMult(ReliabilityType A, ReliabilityType B) { + return A * B; + } + + /// predefined combination method + static ReliabilityType + OutputReliabilityCombinationMethodAverage(ReliabilityType A, + ReliabilityType B) { + return (A + B) / 2; + } + + // ------------------------------------------------------------------------- + // Cleanup + // ------------------------------------------------------------------------- + + ~CrossCombinator() { + for (auto tmp : Functions) + delete tmp.Funct; + Functions.clear(); + } + + // -------------------------------------------------------------------------- + // Needed stuff and stored stuff + // -------------------------------------------------------------------------- private: + struct Functionblock { + bool exists = false; + id_t A; + id_t B; + Abstraction *Funct; + }; + std::map> States; /// From Maxi in his code defined as 1 can be changed by set ReliabilityType crossReliabilityParameter = 1; /// Stored Cross Reliability Functions std::vector Functions; /// Method which is used to combine the generated values ReliabilityType (*Method)(std::vector values) = AVERAGE; + ReliabilityType (*CombinedCrossRelCombinationMethod)( + ReliabilityType, ReliabilityType) = CombinedCrossRelCombinationMethodMin; + + ReliabilityType (*CombinedInputRelCombinationMethod)( + ReliabilityType, ReliabilityType) = CombinedInputRelCombinationMethodMin; + //-------------------------------------------------------------------------------- // helper function /// evalues the absolute distance between two values /// \note this is actually the absolute distance but to ceep it somewhat /// conform with maxis code template Type_t AbsuluteValue(Type_t A, Type_t B) { return ((A - B) < 0) ? B - A : A - B; } /// verry 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(); }; /// evaluest the corisponding LinearFunction thith the score 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 ReliabilityType getCrossReliabilityFromProfile(id_t nameA, id_t nameB, - StateType scoreDifference) { + StateType scoreDifference) { Functionblock block = searchFunction(Functions, nameA, nameB); if (!block.exists) { LOG_ERROR(("CrossReliability: Block:" + std::to_string(nameA) + "," + std::to_string(nameB) + "doesn't exist returning 0")); return 0; } return block.Funct->operator()(scoreDifference); } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_CROSSRELIABILITY_H \ No newline at end of file