diff --git a/include/rosa/agent/CrossReliability.h b/include/rosa/agent/CrossReliability.h index 45d541a..9df097b 100644 --- a/include/rosa/agent/CrossReliability.h +++ b/include/rosa/agent/CrossReliability.h @@ -1,378 +1,535 @@ //===-- 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/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 { + +/// 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"); + + /// typedef To shorten the writing. + /// \c ConfOrRel + typedef ConfOrRel ConfOrRel; + + /// 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. + /// + /// \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) { + + ReliabilityType combinedInputRel = 1; + ReliabilityType combinedCrossRel = 1; + ReliabilityType outputReliability; + + 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); + } + + 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->operator()( + {id, sc}, + Agents); // AVERAGE, MULTIPLICATION, CONJUNCTION (best to worst: + // AVERAGE = CONJUNCTION > MULTIPLICATION >> ) + + // 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->operator()(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}; + } + + /// This is the setter for CrossReliability Function + /// \param CrossReliability A pointer to the Functional for the + /// CrossReliability + /// \brief This is needed to calculate the Reliability. It uses this on all + /// values of all lowlevel Agnets. + void setCrossReliability( + std::unique_ptr> + &CrossReliability) { + this->CrossReliability = std::move(CrossReliability); + } + + /// This is the setter for CrossConfidence Function + /// \param CrossConfidence A pointer to the Functional for the \c + /// CrossConfidence \brief This is needed for the feedback for the \c + /// ReliabilityForLowLevelAgents. + void setCrossConfidence( + std::unique_ptr> + &CrossConfidence) { + this->CrossConfidence = std::move(CrossConfidence); + } + + /// 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}); + } + +private: + std::unique_ptr> + CrossReliability; + std::unique_ptr> CrossConfidence; + + std::map> States; +}; + + + + /// 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 coresponding Cross Reliability /// function have to be specified template class CrossReliability : public Abstraction { static_assert( std::is_arithmetic::value, "CrossReliability: has to be arithmetic type\n"); // sanitny check static_assert( std::is_arithmetic::value, "CrossReliability: has to be arithmetic type\n"); // sanitny // check using Abstraction = typename rosa::agent::Abstraction; struct Functionblock { bool exists = false; id_t A; id_t B; Abstraction *Funct; }; /// From Maxi in his code defined as 1 can be changed by set Type crossReliabilityParameter = 1; /// Stored Cross Reliability Functions std::vector Functions; /// Method which is used to combine the generated values Type (*Method)(std::vector values) = AVERAGE; //-------------------------------------------------------------------------------- // 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 for the /// LinerFunction \param nameB these two parameters are the unique identifiers /// for the LinerFunction /// /// \note If the block nameA nameB doesn't exist it logs the error and returns /// 0 /// \note it doesn't matter if they are swapped Type getCrossReliabilityFromProfile(id_t nameA, id_t nameB, 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); } public: /// 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(Type 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(Type (*Meth)(std::vector values)) { Method = Meth; } CrossReliability() : Abstraction(0) {} ~CrossReliability() { for (auto tmp : Functions) delete tmp.Funct; Functions.clear(); } /// Calculets the CrossReliability /// \note both Main and Slaveagents are represented by there data and an /// unique identifier /// /// \param MainAgent defines the value pair around which the Cross Reliability /// is calculated /// \param SlaveAgents defines all value pairs of the connected Agents it /// doesn't matter if Main agent exists inside this vector Type operator()(std::pair &&MainAgent, std::vector> &SlaveAgents); /// predefined combination method static Type CONJUNCTION(std::vector values) { return *std::min_element(values.begin(), values.end()); } /// predefined combination method static Type AVERAGE(std::vector values) { return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); } /// predefined combination method static Type DISJUNCTION(std::vector values) { return *std::max_element(values.begin(), values.end()); } }; template inline Type CrossReliability:: operator()(std::pair &&MainAgent, std::vector> &SlaveAgents) { Type 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 Type crossReliabilityFromProfile = getCrossReliabilityFromProfile( MainAgent.first, SlaveAgent.first, AbsuluteValue(MainAgent.second, SlaveAgent.second)); values.push_back( std::max(crossReliabiability, crossReliabilityFromProfile)); } return Method(values); } /// Calculates the \c CrossConfidence /// \brief It uses the a theoretical 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 this can be used to get a Confidence of /// the current state /// /// \note all combination of agents and there coresponding \c CrossReliability /// function have to be specified template class CrossConfidence : public Abstraction { static_assert(std::is_arithmetic::value, "CrossConfidence: has to be an arithmetic type\n"); static_assert(std::is_arithmetic::value, "CrossConfidence: has to be an arithmetic type\n"); using Abstraction = typename rosa::agent::Abstraction; struct Functionblock { bool exists = false; id_t A; id_t B; Abstraction *Funct; }; /// From Maxi in his code defined as 1 can be changed by set Type crossReliabilityParameter = 1; /// Stored Cross Reliability Functions std::vector Functions; /// Method which is used to combine the generated values Type (*Method)(std::vector values) = AVERAGE; //-------------------------------------------------------------------------------- // 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 Type getCrossReliabilityFromProfile(id_t nameA, id_t nameB, 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); } public: /// 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(Type 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(Type (*Meth)(std::vector values)) { Method = Meth; } CrossConfidence() : Abstraction(0) {} ~CrossConfidence() { for (auto tmp : Functions) delete tmp.Funct; Functions.clear(); } Type operator()(id_t MainAgent, StateType TheoreticalValue, std::vector> &SlaveAgents); /// predefined combination method static Type CONJUNCTION(std::vector values) { return *std::min_element(values.begin(), values.end()); } /// predefined combination method static Type AVERAGE(std::vector values) { return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); } /// predefined combination method static Type DISJUNCTION(std::vector values) { return *std::max_element(values.begin(), values.end()); } }; /// Calculats the CrossConfidence of the main agent compared to all other Agents /// \param MainAgent The id of the Main agent /// \param TheoreticalValue The throretical value it should use for calculation /// \param SlaveAgents The numerical Representation of all other Slave Agents template inline Type CrossConfidence:: operator()(id_t MainAgent, StateType TheoreticalValue, std::vector> &SlaveAgents) { Type 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 Type crossReliabilityFromProfile = getCrossReliabilityFromProfile( MainAgent, SlaveAgent.first, AbsuluteValue(TheoreticalValue, SlaveAgent.second)); values.push_back( std::max(crossReliabiability, crossReliabilityFromProfile)); } return Method(values); } } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_CROSSRELIABILITY_H \ No newline at end of file diff --git a/include/rosa/agent/Reliability.h b/include/rosa/agent/ReliabilityConfidenceCombinator.h similarity index 82% rename from include/rosa/agent/Reliability.h rename to include/rosa/agent/ReliabilityConfidenceCombinator.h index 72642b6..d06d7ee 100644 --- a/include/rosa/agent/Reliability.h +++ b/include/rosa/agent/ReliabilityConfidenceCombinator.h @@ -1,918 +1,762 @@ -//===-- rosa/agent/Reliability.h --------------------------------*- C++ -*-===// +//===-- rosa/agent/ReliabilityConfidenceCombinator.h ------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// -/// \file rosa/agent/Reliability.h +/// \file rosa/agent/ReliabilityConfidenceCombinator.h /// /// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at) /// /// \date 2019 /// -/// \brief Definition of *reliability* *functionality*. +/// \brief Definition of *ReliabilityConfidenceCombinator* *functionality*. /// /// \note based on Maximilian Goetzinger (maxgot@utu.fi) code in /// CAM_Dirty_include SA-EWS2_Version... inside Agent.cpp /// /// \note By defining and setting Reliability_trace_level it is possible to /// change the level to which it should be traced. \note All classes throw /// runtime errors if not all things are set /// /// \note should the Reliability be capped? /// /// //===----------------------------------------------------------------------===// -// make combination modular #ifndef ROSA_AGENT_RELIABILITY_H #define ROSA_AGENT_RELIABILITY_H #include "rosa/agent/CrossReliability.h" #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/RangeConfidence.hpp" #include #include #include /// 0 everything /// 1 vectors /// 2 outputs #define trace_everything 0 #define trace_vectors 1 #define trace_outputs 2 #ifndef Reliability_trace_level #define Reliability_trace_level 0 #endif #define trace_end "\n\n\n" namespace rosa { namespace agent { -/// This is a struct with a few methods that make lowlevel/highlevel Reliability +/// This is a struct with a few methods that make Reliability Combinator /// more readable \tparam StateType The datatype of the States \tparam /// ReliabilityType The datatype of the Reliability template struct ConfOrRel { /// making both Template Arguments readable to make a few things easier typedef StateType _StateType; /// making both Template Arguments readable to make a few things easier typedef ReliabilityType _ReliabilityType; /// The actual place where the data is stored StateType score; /// The actual place where the data is stored ReliabilityType Reliability; ConfOrRel(StateType _score, ReliabilityType _Reliability) : score(_score), Reliability(_Reliability){}; ConfOrRel(){}; /// Pushes the Data in a Human readable form /// \param out The stream where it is written to /// \param c The struct itself friend std::ostream &operator<<(std::ostream &out, const ConfOrRel &c) { out << "Score: " << c.score << "\t Reliability: " << c.Reliability << " "; return out; } /// needed or it throws an clang diagnosic error typedef std::map map; // needed or it throws an clang diagnosic error /// Filles the vector with the data inside the map /// \param me The vector to be filled /// \param data The data wich is to be pushed into the vector friend std::vector &operator<<(std::vector &me, map &&data) { for (auto tmp : data) { me.push_back(ConfOrRel(tmp.first, tmp.second)); #if Reliability_trace_level <= trace_everything LOG_TRACE_STREAM << "\n" << ConfOrRel(tmp.first, tmp.second) << trace_end; #endif } return me; } /// This is to push the data inside a vector in a human readable way into the /// ostream \param out The ostream \param c The vector which is read friend std::ostream &operator<<(std::ostream &out, const std::vector &c) { std::size_t index = 0; for (ConfOrRel data : c) { out << index << " : " << data << "\n"; index++; } return out; } }; /// This calculates the minimum of the Reliabilities & the given value /// \param me The vector with the Reliabilities /// \param value The comparing value template std::vector min(std::vector me, typename Conf::_ReliabilityType value) { static_assert(std::is_arithmetic::value); for (auto tmp : me) tmp.Reliability = std::min(tmp.Reliability, value); return me; } /// This calculates the maximum of the Reliabilities & the given value /// \param me The vector with the Reliabilities /// \param value The comparing value template std::vector max(std::vector me, typename Conf::_ReliabilityType value) { static_assert(std::is_arithmetic::value); for (auto tmp : me) tmp.Reliability = std::max(tmp.Reliability, value); return me; } /// This calculates the average of the Reliabilities & the given value /// \param me The vector with the Reliabilities /// \param value The comparing value template std::vector average(std::vector me, typename Conf::_ReliabilityType value) { static_assert(std::is_arithmetic::value); for (auto tmp : me) tmp.Reliability = (tmp.Reliability + value) / 2; return me; } /// This calculates the average of the Reliabilities & the given value /// \param me The vector with the Reliabilities /// \param value The comparing value template std::vector mult(std::vector me, typename Conf::_ReliabilityType value) { static_assert(std::is_arithmetic::value); for (auto tmp : me) tmp.Reliability = tmp.Reliability * value / 2; return me; } /// This average's the Reliabilities of the same Scores template std::vector average(std::vector A, std::vector B) { static_assert(std::is_arithmetic::value); for (auto &tmp_me : A) for (auto &tmp_other : B) { if (tmp_me.score == tmp_other.score) { tmp_me.Reliability = (tmp_me.Reliability + tmp_other.Reliability) / 2; } } return A; } /// This min's the Reliabilities of the same Scores template std::vector min(std::vector A, std::vector B) { static_assert(std::is_arithmetic::value); for (auto &tmp_me : A) for (auto &tmp_other : B) { if (tmp_me.score == tmp_other.score) { tmp_me.Reliability = std::min(tmp_me.Reliability + tmp_other.Reliability); } } return A; } /// This max's the Reliabilities of the same Scores template std::vector max(std::vector A, std::vector B) { static_assert(std::is_arithmetic::value); for (auto &tmp_me : A) for (auto &tmp_other : B) { if (tmp_me.score == tmp_other.score) { tmp_me.Reliability = std::max(tmp_me.Reliability + tmp_other.Reliability); } } return A; } /// This mult's the Reliabilities of the same Scores template std::vector mult(std::vector A, std::vector B) { static_assert(std::is_arithmetic::value); for (auto &tmp_me : A) for (auto &tmp_other : B) { if (tmp_me.score == tmp_other.score) { tmp_me.Reliability = tmp_me.Reliability * tmp_other.Reliability; } } return A; } /// This is the combinator for Reliability and confidences it takes the /// Sensor value, its "History" and feedback from \c /// CrossCombinator to calculate different Reliabilities. /// \tparam SensorValueType Datatype of the Sensor value ( Typically /// double or float) \tparam StateType Datatype of the State ( Typically long or /// int) /// \tparam ReliabilityType Datatype of the Reliability ( /// Typically double or float) /// /// \note more information about how it calculates /// the Reliabilities /// \verbatim ///---------------------------------------------------------------------------------- /// /// /// ->Reliability---> getInputReliability() /// | | /// | V /// Sensor Value ---| PossibleScoreCombinationMethod -> next line /// | A | /// | | V /// ->Confidence--- getPossibleScores() /// ///----------------------------------------------------------------------------------- /// /// feedback /// | /// V /// ValuesFromMaster /// | -> History ---| /// V | V /// here -> FeedbackCombinatorMethod --------> HistoryCombinatorMethod->nextline /// | | /// V V /// getpossibleScoresWithMasterFeedback() getPossibleScoresWithHistory() /// ///---------------------------------------------------------------------------------- /// /// here -> sort -> most likely -> mostLikelySoreAndReliability() /// /// --------------------------------------------------------------------------------- /// \endverbatim /// the mentioned methods are early outs so if two ore more of them are run in /// the same step they will be interpreted as different time steps ///
 /// Default values for Combinators:
 ///	InputReliabilityCombinator		= combinationMin;
 ///	PossibleScoreCombinationMethod	= PossibleScoreCombinationMethodMin;
 /// FeedbackCombinatorMethod		= FeedbackCombinatorMethodAverage;
 /// HistoryCombinatorMethod			= HistoryCombinatorMethodMax;
 ///	
/// /// /// template class ReliabilityAndConfidenceCombinator { public: static_assert(std::is_arithmetic::value, "LowLevel: SensorValueType has to an arithmetic type\n"); static_assert(std::is_arithmetic::value, "LowLevel: StateType has to an arithmetic type\n"); static_assert(std::is_arithmetic::value, "LowLevel: ReliabilityType has to an arithmetic type\n"); /// Typedef to shorten the writing. /// \c ConfOrRel typedef ConfOrRel ConfOrRel; /// Calculates the input reliability by combining Reliability of the Sensor /// and the Slope Reliability \param SensorValue The sensor Value \note to set /// the combination method \c setInputReliabilityCombinator() auto getInputReliability(SensorValueType SensorValue) { auto inputReliability = getReliability(SensorValue, previousSensorValue, valueSetCounter); previousSensorValue = SensorValue; PreviousSensorValueExists = true; return inputReliability; } /// Calculates the Reliability /// \param SensorValue The current Values of the Sensor /// /// \return Reliability and Score of the current SensorValue /// ConfOrRel mostLikelySoreAndReliability(SensorValueType SensorValue) { #if Reliability_trace_level <= trace_outputs LOG_TRACE_STREAM << "\nTrace level is set to: " << Reliability_trace_level << "\n" << "Will trace: " << ((Reliability_trace_level == trace_outputs) ? "outputs" : (Reliability_trace_level == trace_vectors) ? "vectors" : (Reliability_trace_level == trace_everything) ? "everything" : "undefined") << trace_end; #endif std::vector ActuallPossibleScores; std::vector possibleScores; ReliabilityType inputReliability = getInputReliability(SensorValue); #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; #endif possibleScores << Confidence->operator()(SensorValue); possibleScores = PossibleScoreCombinationMethod(possibleScores, inputReliability); possibleScores = FeedbackCombinatorMethod(possibleScores, ValuesFromMaster); saveInHistory(possibleScores); #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\nActuallPossibleScores:\n" << possibleScores << trace_end; LOG_TRACE_STREAM << "\npossibleScores:\n" << possibleScores << trace_end; #endif possibleScores.clear(); possibleScores = getAllPossibleScoresBasedOnHistory(); std::sort(possibleScores.begin(), possibleScores.end(), [](ConfOrRel A, ConfOrRel B) -> bool { return A.Reliability > B.Reliability; }); #if Reliability_trace_level <= trace_outputs LOG_TRACE_STREAM << "\noutput lowlevel: " << possibleScores.at(0) << trace_end; #endif return possibleScores.at(0); } /// Calculates the possible Scores /// \param SensorValue the Sensor Value /// \brief it combines the input reliability and the confidence of the Sensor. /// The use combination method can be set using \c /// setPossibleScoreCombinationMethod() auto getPossibleScores(SensorValueType SensorValue) { std::vector possibleScores; ReliabilityType inputReliability = getInputReliability(SensorValue); // get input rel() #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; #endif possibleScores << Confidence->operator()(SensorValue); possibleScores = PossibleScoreCombinationMethod(possibleScores, inputReliability); return possibleScores; } /// return the Possible Values with the feedback in mind /// \param SensorValue The sensor Value /// \brief it combines the input reliability and the confidence of the Sensor. /// The combines them with FeedbackCombinatorMethod and returns the result. auto getpossibleScoresWithMasterFeedback(SensorValueType SensorValue) { std::vector possibleScores; ReliabilityType inputReliability = getInputReliability(SensorValue); // get input rel() #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; #endif possibleScores << Confidence->operator()(SensorValue); possibleScores = PossibleScoreCombinationMethod(possibleScores, inputReliability); // set comb method with values from master ( class :: min | max | average | // mult | [] ()-> {} ) possibleScores = FeedbackCombinatorMethod(possibleScores, ValuesFromMaster); return possibleScores; } /// returns all possible Scores and Reliabilities with the History in mind /// \param SensorValue the Sensor value /// how this is done is described at the class. auto getPossibleScoresWithHistory(SensorValueType SensorValue) { std::vector ActuallPossibleScores; std::vector possibleScores; ReliabilityType inputReliability = getInputReliability(SensorValue); // get input rel() #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; #endif possibleScores << Confidence->operator()(SensorValue); possibleScores = PossibleScoreCombinationMethod(possibleScores, inputReliability); possibleScores = FeedbackCombinatorMethod(possibleScores, ValuesFromMaster); saveInHistory(possibleScores); #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\nActuallPossibleScores:\n" << possibleScores << trace_end; LOG_TRACE_STREAM << "\npossibleScores:\n" << possibleScores << trace_end; #endif possibleScores.clear(); return getAllPossibleScoresBasedOnHistory(); } /// feedback for this functionality most commonly it comes from a Master Agent /// \param ValuesFromMaster The Scores + Reliability for the feedback /// \brief This input kind of resembles a confidence but not /// directly it more or less says: compared to the other Scores inside the /// System these are the Scores with the Reliability that you have. void feedback(std::vector ValuesFromMaster) { this->ValuesFromMaster = ValuesFromMaster; } // // ----------------------Reliability and Confidence Function setters---------- // /// This is the setter for Confidence Function /// \param Confidence A pointer to the Functional for the \c Confidence of the /// Sensor value void setConfidenceFunction( std::unique_ptr> &Confidence) { this->Confidence = std::move(Confidence); } /// This is the setter for Reliability Function /// \param Reliability A pointer to the Functional for the Reliability /// \brief The Reliability takes the current Sensor value and return the /// Reliability of the value. void setReliabilityFunction( std::unique_ptr> &Reliability) { this->Reliability = std::move(Reliability); } /// This is the setter for ReliabilitySlope Function /// \param ReliabilitySlope A pointer to the Functional for the /// ReliabilitySlope /// \brief The ReliabilitySlope takes the difference of the current Sensor /// Value to the last one and tells you how likely the change is. void setReliabilitySlopeFunction( std::unique_ptr> &ReliabilitySlope) { this->ReliabilitySlope = std::move(ReliabilitySlope); } /// This is the setter for TimeConfidence Function /// \param TimeConfidence A pointer to the Functional for the TimeConfidence /// \brief The time function takes the position in the History with greater /// equals older and return a Reliability of how "relevant" it is. void setTimeConfidenceFunction( std::unique_ptr> &TimeConfidence) { this->TimeConfidence = std::move(TimeConfidence); } /// This is the setter for all possible States /// \param states A vector containing all states /// \brief This exists even though \c State Type is an arithmetic Type because /// the states do not need to be "next" to each other ( ex. states={ 1 7 24 }) void setStates(std::vector states) { this->States = states; } /// This sets the Maximum length of the History /// \param length The length void setHistoryLength(std::size_t length) { this->HistoryMaxSize = length; } /// This sets the Value set Counter /// \param ValueSetCounter the new Value /// \note This might actually be only an artifact. It is only used to get the /// reliability from the \c ReliabilitySlope [ ReliabilitySlope->operator()( /// (lastValue - actualValue) / (SensorValueType)valueSetCounter) ] void setValueSetCounter(unsigned int ValueSetCounter) { this->valueSetCounter = ValueSetCounter; } // // ----------------combinator setters----------------------------------------- // /// This sets the combination method used by the History /// \param Meth the method which should be used. predefined \c /// HistoryCombinatorMethodMin() \c HistoryCombinatorMethodMax() \c /// HistoryCombinatorMethodMult() \c HistoryCombinatorMethodAverage() void setHistoryCombinatorMethod(ReliabilityType (*Meth)(ReliabilityType, ReliabilityType)) { HistoryCombinatorMethod = Meth; } /// sets the predefined method for the combination of the possible scores and /// the master \param Meth the method predefined ones are /// \c FeedbackCombinatorMethodAverage() \c FeedbackCombinatorMethodMin() \c /// FeedbackCombinatorMethodMax() \c FeedbackCombinatorMethodMult() void setFeedbackCombinatorMethod(std::vector (*Meth)( std::vector, std::vector)) { FeedbackCombinatorMethod = Meth; } /// Sets the used combination method for Possible Scores /// \param Meth a Pointer for the used Method. Predefined methods \c /// PossibleScoreCombinationMethodMin() \c PossibleScoreCombinationMethodMax() /// \c PossibleScoreCombinationMethodAverage() void setPossibleScoreCombinationMethod( std::vector (*Meth)(std::vector, ReliabilityType)) { PossibleScoreCombinationMethod = Meth; } /// sets the input reliability combinator method /// \param method the to be used method /// \note there are predefined methods \c combinationMin() \c combinationMax() /// \c combinationAverage() void setInputReliabilityCombinator( ReliabilityType (*method)(ReliabilityType, ReliabilityType)) { InputReliabilityCombinator = method; } // // ----------------predefined combinators------------------------------------ // /// predefined Method static ReliabilityType HistoryCombinatorMethodMin(ReliabilityType A, ReliabilityType B) { return std::min(A, B); } /// predefined Method static ReliabilityType HistoryCombinatorMethodMax(ReliabilityType A, ReliabilityType B) { return std::max(A, B); } /// predefined Method static ReliabilityType HistoryCombinatorMethodMult(ReliabilityType A, ReliabilityType B) { return A * B; } /// predefined Method static ReliabilityType HistoryCombinatorMethodAverage(ReliabilityType A, ReliabilityType B) { return (A + B) / 2; } /// predefined method static std::vector FeedbackCombinatorMethodAverage(std::vector A, std::vector B) { return average(A, B); } /// predefined method static std::vector FeedbackCombinatorMethodMin(std::vector A, std::vector B) { return min(A, B); } /// predefined method static std::vector FeedbackCombinatorMethodMax(std::vector A, std::vector B) { return max(A, B); } /// predefined method static std::vector FeedbackCombinatorMethodMult(std::vector A, std::vector B) { return mult(A, B); } /// Predefined combination method for possible Scores static std::vector PossibleScoreCombinationMethodMin(std::vector A, ReliabilityType B) { return min(A, B); } /// Predefined combination method for possible Scores static std::vector PossibleScoreCombinationMethodMax(std::vector A, ReliabilityType B) { return max(A, B); } /// Predefined combination method for possible Scores static std::vector PossibleScoreCombinationMethodAverage(std::vector A, ReliabilityType B) { return average(A, B); } /// Predefined combination method for possible Scores static std::vector PossibleScoreCombinationMethodMult(std::vector A, ReliabilityType B) { return mult(A, B); } /// The predefined min combinator method static ReliabilityType combinationMin(ReliabilityType A, ReliabilityType B) { return std::min(A, B); } /// The predefined max combinator method static ReliabilityType combinationMax(ReliabilityType A, ReliabilityType B) { return std::max(A, B); } /// The predefined average combinator method static ReliabilityType combinationAverage(ReliabilityType A, ReliabilityType B) { return (A + B) / 2; } /// The predefined average combinator method static ReliabilityType combinationMult(ReliabilityType A, ReliabilityType B) { return A * B; } private: std::vector> History; std::size_t HistoryMaxSize; std::vector ValuesFromMaster; SensorValueType previousSensorValue; unsigned int valueSetCounter; std::vector States; bool PreviousSensorValueExists = false; std::unique_ptr> Confidence; std::unique_ptr> Reliability; std::unique_ptr> ReliabilitySlope; std::unique_ptr> TimeConfidence; // combination functions ReliabilityType (*InputReliabilityCombinator)( ReliabilityType, ReliabilityType) = combinationMin; std::vector (*PossibleScoreCombinationMethod)( std::vector, ReliabilityType) = PossibleScoreCombinationMethodMin; std::vector (*FeedbackCombinatorMethod)(std::vector, std::vector) = FeedbackCombinatorMethodAverage; ReliabilityType (*HistoryCombinatorMethod)(ReliabilityType, ReliabilityType) = HistoryCombinatorMethodMax; /*--------------------------------- needed Functions * -----------------------------------------------------*/ /// returns the Reliability /// \param actualValue The Value of the Sensor /// \param lastValue of the Sensor this is stored in the class /// \param valueSetCounter It has an effect on the difference of the current /// and last value This might not be needed anymore /// \brief it returns the combination the \c Reliability function and \c /// ReliabilitySlope if the previous value exists. if it doesn't it only /// returns the \c Reliability function value. ReliabilityType getReliability(SensorValueType actualValue, SensorValueType lastValue, unsigned int valueSetCounter) { ReliabilityType relAbs = Reliability->operator()(actualValue); if (PreviousSensorValueExists) { ReliabilityType relSlo = ReliabilitySlope->operator()( (lastValue - actualValue) / (SensorValueType)valueSetCounter); return InputReliabilityCombinator(relAbs, relSlo); } else return relAbs; } /// adapts the possible Scores by checking the History and combines those /// values. currently with max /// \brief combines the historic values with the \c TimeConfidence function /// and returns the maximum Reliability for all Scores. std::vector getAllPossibleScoresBasedOnHistory() { // iterate through all history entries std::size_t posInHistory = 0; std::vector possibleScores; for (auto pShE = History.begin(); pShE < History.end(); pShE++, posInHistory++) { // iterate through all possible scores of each history entry for (ConfOrRel &pSh : *pShE) { StateType historyScore = pSh.score; ReliabilityType historyConf = pSh.Reliability; historyConf = historyConf * TimeConfidence->operator()(posInHistory); bool foundScore = false; for (ConfOrRel &pS : possibleScores) { if (pS.score == historyScore) { pS.Reliability = HistoryCombinatorMethod(pS.Reliability, historyConf); foundScore = true; } } if (foundScore == false) { ConfOrRel possibleScore; possibleScore.score = historyScore; possibleScore.Reliability = historyConf; possibleScores.push_back(possibleScore); } } } return possibleScores; } /// saves the Scores in the History /// \brief It checks the incoming scores if any have a Reliability greater /// than 0.5 all of them get saved inside the History and then the /// History get shortened to the maximal length. It only saves the Value if /// the History is empty. /// /// \param actualPossibleScores The Scores which should be saved /// /// \note Does the History really make sense if the values are to small it /// only stores something if it's empty and not if it isn't completely filled void saveInHistory(std::vector actualPossibleScores) { // check if the reliability of at least one possible score is high enough bool atLeastOneRelIsHigh = false; for (ConfOrRel pS : actualPossibleScores) { if (pS.Reliability > 0.5) { atLeastOneRelIsHigh = true; } } // save possible scores if at least one possible score is high enough (or if // the history is empty) if (History.size() < 1 || atLeastOneRelIsHigh == true) { History.insert(History.begin(), actualPossibleScores); // if history size is higher than allowed, save oldest element while (History.size() > HistoryMaxSize) { // delete possibleScoreHistory.back(); History.pop_back(); } } } }; - - -/// 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"); - - /// typedef To shorten the writing. - /// \c ConfOrRel - typedef ConfOrRel ConfOrRel; - - /// 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. - /// - /// \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) { - - ReliabilityType combinedInputRel = 1; - ReliabilityType combinedCrossRel = 1; - ReliabilityType outputReliability; - - 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); - } - - 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->operator()( - {id, sc}, - Agents); // AVERAGE, MULTIPLICATION, CONJUNCTION (best to worst: - // AVERAGE = CONJUNCTION > MULTIPLICATION >> ) - - // 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->operator()(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}; - } - - /// This is the setter for CrossReliability Function - /// \param CrossReliability A pointer to the Functional for the - /// CrossReliability - /// \brief This is needed to calculate the Reliability. It uses this on all - /// values of all lowlevel Agnets. - void setCrossReliability( - std::unique_ptr> - &CrossReliability) { - this->CrossReliability = std::move(CrossReliability); - } - - /// This is the setter for CrossConfidence Function - /// \param CrossConfidence A pointer to the Functional for the \c - /// CrossConfidence \brief This is needed for the feedback for the \c - /// ReliabilityForLowLevelAgents. - void setCrossConfidence( - std::unique_ptr> - &CrossConfidence) { - this->CrossConfidence = std::move(CrossConfidence); - } - - /// 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}); - } - -private: - std::unique_ptr> - CrossReliability; - std::unique_ptr> CrossConfidence; - - std::map> States; -}; - } // namespace agent } // namespace rosa #endif // !ROSA_AGENT_RELIABILITY_H diff --git a/lib/agent/Reliability.cpp b/lib/agent/ReliabilityConfidenceCombinator.cpp similarity index 65% rename from lib/agent/Reliability.cpp rename to lib/agent/ReliabilityConfidenceCombinator.cpp index e437136..d49b833 100644 --- a/lib/agent/Reliability.cpp +++ b/lib/agent/ReliabilityConfidenceCombinator.cpp @@ -1,20 +1,20 @@ //===-- agent/Reliability.cpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// -/// \file agent/Reliability.cpp +/// \file agent/ReliabilityConfidenceCombinator.cpp /// /// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at) /// /// \date 2019 /// -/// \brief Implementation for rosa/agent/Reliability.h +/// \brief Implementation for rosa/agent/ReliabilityConfidenceCombinator.h /// /// \note Empty implementation, source file here to have a compile database -/// entry for rosa/agent/Reliability.h +/// entry for rosa/agent/ReliabilityConfidenceCombinator.h /// //===----------------------------------------------------------------------===// -#include "rosa/agent/Reliability.h" +#include "rosa/agent/ReliabilityConfidenceCombinator.h"