diff --git a/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp b/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp index 538f0b2..9725b1a 100644 --- a/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp +++ b/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp @@ -1,247 +1,247 @@ //===- examples/agent-functionalities/Reliability-functionality.cpp *C++-*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/agent-functionalities/Reliability-functionality.cpp /// /// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at ) /// /// \date 2019 /// /// \brief A simple example on defining Relianility Functionalities. /// //===----------------------------------------------------------------------===// #define Reliability_trace_level 5 #include "rosa/config/version.h" #include "rosa/support/log.h" #include "rosa/agent/CrossReliability.h" #include "rosa/agent/RangeConfidence.hpp" #include "rosa/agent/ReliabilityConfidenceCombinator.h" #include #include using namespace rosa::agent; int main(void) { typedef double SensorValueType; typedef long StateType; typedef double ReliabilityType; std::unique_ptr> Confidence(new RangeConfidence( {{0, PartialFunction( { {{0, 3}, std::make_shared>( 0, 1.0 / 3)}, {{3, 6}, std::make_shared>(1, 0)}, {{6, 9}, std::make_shared>( 3.0, -1.0 / 3)}, }, 0)}, {1, PartialFunction( { {{6, 9}, std::make_shared>( -2, 1.0 / 3)}, {{9, 12}, std::make_shared>(1, 0)}, {{12, 15}, std::make_shared>( 5, -1.0 / 3)}, }, 0)}, {2, PartialFunction( { {{12, 15}, std::make_shared>( -4, 1.0 / 3)}, {{15, 18}, std::make_shared>(1, 0)}, {{18, 21}, std::make_shared>( 7, -1.0 / 3)}, }, 0)}})); std::unique_ptr> Reliability( new LinearFunction(1, -1.0 / 3)); std::unique_ptr> ReliabilitySlope( new LinearFunction(1, -1.0 / 3)); std::unique_ptr> TimeConfidence( new LinearFunction(1, -1.0 / 3)); auto lowlevel = new ReliabilityAndConfidenceCombinator(); std::vector states; states.push_back(0); states.push_back(1); states.push_back(2); lowlevel->setConfidenceFunction(Confidence); lowlevel->setReliabilityFunction(Reliability); lowlevel->setReliabilitySlopeFunction(ReliabilitySlope); lowlevel->setTimeConfidenceFunction(TimeConfidence); lowlevel->setStates(states); lowlevel->setHistoryLength(2); lowlevel->setValueSetCounter(1); /* ----------------------------- Do Something * ---------------------------------------------------------------- */ std::cout << "Testing the lowlevel component with static feedback telling it " "that the most lickely state is 2.\n"; for (int a = 0; a < 30; a++) std::cout << "a: " << a << "\n" << (lowlevel->feedback({{0, 0}, {1, 0.3}, {2, 0.8}}), lowlevel->mostLikelySoreAndReliability(a)) << "\n"; std::cout << "---------------------------------------------------------------" "---------------------------------\n"; std::cout << "------------------------------------High level " "Test---------------------------------------------\n"; std::cout << "Configured in a way that the Master thinks that both Sensors " "should have the same State.\n While feeding both the \"opposite\" " "values one acending the other decending from the maximum.\n"; std::unique_ptr> Confidence2(new RangeConfidence( {{0, PartialFunction( { {{0, 3}, std::make_shared>( 0, 1.0 / 3)}, {{3, 6}, std::make_shared>(1, 0)}, {{6, 9}, std::make_shared>( 3.0, -1.0 / 3)}, }, 0)}, {1, PartialFunction( { {{6, 9}, std::make_shared>( -2, 1.0 / 3)}, {{9, 12}, std::make_shared>(1, 0)}, {{12, 15}, std::make_shared>( 5, -1.0 / 3)}, }, 0)}, {2, PartialFunction( { {{12, 15}, std::make_shared>( -4, 1.0 / 3)}, {{15, 18}, std::make_shared>(1, 0)}, {{18, 21}, std::make_shared>( 7, -1.0 / 3)}, }, 0)}})); std::unique_ptr> Reliability2( new LinearFunction(1, -1.0 / 9)); std::unique_ptr> ReliabilitySlope2( new LinearFunction(1, -1.0 / 9)); std::unique_ptr> TimeConfidence2( new LinearFunction(1, -1.0 / 9)); auto lowlevel2 = new ReliabilityAndConfidenceCombinator(); std::vector states2; states2.push_back(0); states2.push_back(1); states2.push_back(2); lowlevel2->setConfidenceFunction(Confidence2); lowlevel2->setReliabilityFunction(Reliability2); lowlevel2->setReliabilitySlopeFunction(ReliabilitySlope2); lowlevel2->setTimeConfidenceFunction(TimeConfidence2); lowlevel2->setStates(states2); lowlevel2->setHistoryLength(2); lowlevel2->setValueSetCounter(1); CrossCombinator *highlevel = new CrossCombinator(); std::unique_ptr> func1(new PartialFunction( { {{0, 1}, std::make_shared>(1, 0)}, {{1, 2}, std::make_shared>(2, -1.0)}, }, 0)); highlevel->addCrossReliabilityProfile(0, 1, func1); - highlevel->setCrossReliabilityMethod( + highlevel->setCrossReliabilityCombinatorMethod( CrossCombinator::AVERAGE); highlevel->setCrossReliabilityParameter(1); highlevel->addStates(0, states); highlevel->addStates(1, states); for (int a = 0; a < 21; a++) { auto out1 = lowlevel->mostLikelySoreAndReliability(a), out2 = lowlevel2->mostLikelySoreAndReliability((int)21 - a); std::cout << "s1: " << out1 << "\ns2:" << out2 << "\n"; std::vector> tmp2; tmp2.push_back({0, out1.score, out1.Reliability}); tmp2.push_back({1, out2.score, out2.Reliability}); auto out_o = highlevel->operator()(tmp2); std::cout << "it: " << a << "\t rel: " << out_o.CrossReliability << "\n"; std::cout << "\t subs:\n"; for (auto q : out_o.CrossConfidence) { std::cout << "\t\t id:" << q.first << "\n"; /* for(auto z: q.second) { std::cout << "\t\t\t score: " << z.score << "\tRel: " << z.Reliability << "\n"; tmp.push_back({z.score,z.Reliability}); } */ for (auto z : q.second) { std::cout << "\t\t\t score: " << z.score << "\tRel: " << z.Reliability << "\n"; } if (q.first == 0) lowlevel->feedback(q.second); else lowlevel2->feedback(q.second); } } /* ----------------------------- Cleanup * --------------------------------------------------------------------- */ delete highlevel; delete lowlevel; delete lowlevel2; } \ No newline at end of file diff --git a/include/rosa/agent/CrossReliability.h b/include/rosa/agent/CrossReliability.h index b9771b0..0ba055c 100644 --- a/include/rosa/agent/CrossReliability.h +++ b/include/rosa/agent/CrossReliability.h @@ -1,538 +1,541 @@ //===-- 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 +/// \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_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. +/// This is the Combinator class for cross reliabilities it has many functions +/// with different purposes +/// \brief It takes the scores and reliabilities of all given ids and calculates +/// the Reliability of them together. Also it can creates the feedback that is +/// needed by the \c ReliabilityAndConfidenceCombinator, 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 This class is commonly in a master slave relationship as master with +/// \c ReliabilityAndConfidenceCombinator. The \c operator()() combines the +/// Reliability of all connected Slaves and uses that as its own Reliability +/// also creates the feedback for the Slaves. /// /// \note more information about how the Reliability and feedback is -/// created at \c operator()() -// State Type rename -// merge cross rel/conf darein +/// created at \c operator()() , \c getCombinedCrossReliability() , \c +/// getCombinedInputReliability() , \c getOutputReliability() [ this is the +/// commonly used Reliability ], \c getCrossConfidence() [ this is the feedback +/// for all Slaves ] 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; + /// To shorten the writing. 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; }; // ------------------------------------------------------------------------- // 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 \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 Values the used Values + /// returns the combined via \c CombinedCrossRelCombinationMethod \c + /// setCombinedCrossRelCombinationMethod() Cross Reliability for all ids \c + /// CrossReliability() \param Values the used Values ReliabilityType getCombinedCrossReliability( std::vector> Values) { ReliabilityType combinedCrossRel = -1; std::vector> Agents; Agents << Values; for (auto Value : Values) { id_t id = std::get<0>(Value); StateType sc = std::get<1>(Value); // 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 + /// returns the combined via \c CombinedInputRelCombinationMethod \c + /// setCombinedInputRelCombinationMethod() 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; } return combinedInputRel; } - /// returns the combination of the Cross reliability and input reliability - /// \param Values the used Values + /// returns the combination via \c OutputReliabilityCombinationMethod \c set + /// OutputReliabilityCombinationMethod() of the Cross reliability and input + /// reliability \param Values the used Values ReliabilityType getOutputReliability( std::vector> Values) { - return std::min(getCombinedInputReliability(Values), - getCombinedCrossReliability(Values)); + return OutputReliabilityCombinationMethod( + getCombinedInputReliability(Values), + getCombinedCrossReliability(Values)); } /// retruns the cross Confidence for all ids \c CrossConfidence() /// \param Values the used Values std::map> 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}); } 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) { 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)); values.push_back( std::max(crossReliabiability, crossReliabilityFromProfile)); } return Method(values); } - /// Calculates the Cross Reliability + /// 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)); 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 + /// sets the used method to combine the values + /// \param Meth The Function which defines the combination method. predef: \c + /// CONJUNCTION() \c AVERAGE() \c DISJUNCTION() + void setCrossReliabilityCombinatorMethod( + ReliabilityType (*Meth)(std::vector values)) { + Method = Meth; + } + + /// sets 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 + /// sets 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()); } /// 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; ReliabilityType (*OutputReliabilityCombinationMethod)( ReliabilityType, ReliabilityType) = OutputReliabilityCombinationMethodMin; //-------------------------------------------------------------------------------- // helper function - /// evalues the absolute distance between two values - /// \note this is actually the absolute distance but to ceep it somewhat + /// evaluates the absolute Value of two values + /// \note this is actually the absolute distance but to keep 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 + /// 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(); }; - /// evaluest the corisponding LinearFunction thith the score difference + /// evaluates the corresponding LinearFunction with 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) { 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