diff --git a/examples/agent-functionalities/Reliability-functionality.cpp b/examples/agent-functionalities/Reliability-functionality.cpp index e89f571..fa96cdf 100644 --- a/examples/agent-functionalities/Reliability-functionality.cpp +++ b/examples/agent-functionalities/Reliability-functionality.cpp @@ -1,262 +1,262 @@ //===- 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/Reliability.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 LowLevel(); 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->operator()(a)) << "\n"; /* ----------------------------- Cleanup * --------------------------------------------------------------------- */ 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 LowLevel(); 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); HighLevel *highlevel = new HighLevel(); std::unique_ptr> CrossReliability1(new CrossReliability()); - Abstraction *func1 = new PartialFunction( + std::unique_ptr> func1(new PartialFunction( { {{0, 1}, std::make_shared>(1, 0)}, {{1, 2}, std::make_shared>(2, -1.0)}, }, - 0); + 0)); CrossReliability1->addCrossReliabilityProfile(0, 1, func1); CrossReliability1->setCrossReliabilityMethod( CrossReliability::AVERAGE); CrossReliability1->setCrossReliabilityParameter(1); std::unique_ptr> CrossConfidence1( new CrossConfidence()); - Abstraction *func2 = new PartialFunction( + std::unique_ptr> func2(new PartialFunction( { {{0, 1}, std::make_shared>(1, 0)}, {{1, 2}, std::make_shared>(2, -1.0)}, }, - 0); + 0)); CrossConfidence1->addCrossReliabilityProfile(0, 1, func2); CrossConfidence1->setCrossReliabilityMethod( CrossConfidence::AVERAGE); CrossConfidence1->setCrossReliabilityParameter(1); highlevel->setFunction(CrossConfidence1); highlevel->setFunction(CrossReliability1); highlevel->addStates(0, states); highlevel->addStates(1, states); for (int a = 0; a < 21; a++) { - auto out1 = lowlevel->operator()(a), out2 = lowlevel2->operator()(21 - a); + auto out1 = lowlevel->operator()(a), out2 = lowlevel2->operator()((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); } } 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 8306d1d..b712775 100644 --- a/include/rosa/agent/CrossReliability.h +++ b/include/rosa/agent/CrossReliability.h @@ -1,371 +1,390 @@ //===-- 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 { /// 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) { - static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); 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 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 pointer to an \c Abstraction it would use the difference + /// \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, Abstraction *Function) { - Functions.push_back({true, idA, idB, Function}); + 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) { - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check return *std::min_element(values.begin(), values.end()); } /// predefined combination method static Type AVERAGE(std::vector values) { - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); } /// predefined combination method static Type DISJUNCTION(std::vector values) { - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check return *std::max_element(values.begin(), values.end()); } }; template inline Type CrossReliability:: operator()(std::pair &&MainAgent, std::vector> &SlaveAgents) { - static_assert(std::is_arithmetic::value); // sanitny check - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check 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) { - static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); 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 pointer to an \c Abstraction it would use the difference + /// \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, Abstraction *Function) { - Functions.push_back({true, idA, idB, Function}); + 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) { - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check return *std::min_element(values.begin(), values.end()); } /// predefined combination method static Type AVERAGE(std::vector values) { - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); } /// predefined combination method static Type DISJUNCTION(std::vector values) { - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check return *std::max_element(values.begin(), values.end()); } }; -/// Calculats the CrossConfidence of the main agent compared to all other Agents +/// 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) { - static_assert(std::is_arithmetic::value); // sanitny check - static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check + // static_assert(std::is_arithmetic::value); // sanitny check 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/Reliability.h index 438fc78..7041f9f 100644 --- a/include/rosa/agent/Reliability.h +++ b/include/rosa/agent/Reliability.h @@ -1,506 +1,514 @@ //===-- rosa/agent/Reliability.h --------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/Reliability.h /// /// \author Daniel Schnoell (danielschnoell@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *reliability* *functionality*. /// /// \note By defining and seeting 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 /// //===----------------------------------------------------------------------===// #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 /// 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 adds the Reliabilities of the same Scores /// \param me The vector to wich is written to /// \param other The other data vector friend std::vector operator+=(std::vector &me, std::vector other) { static_assert(std::is_arithmetic::value); for (auto& tmp_me : me) for (auto& tmp_other : other) { if (tmp_me.score == tmp_other.score) { tmp_me.Reliability = tmp_me.Reliability + tmp_other.Reliability; } } return me; } /// This is to push the data inside a vector in a humanreadable 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 Reliabilites /// \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 is the Reliability Functionality for a low level Agent /// \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) /// /// use the \c operator() to get the reliability and \c feedback() the /// information from the master back to this template class LowLevel { 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 Conf/ Reliability /// \param SensorValue The current Values of the Sensor /// /// \return Reliability of the current Value ConfOrRel operator()(SensorValueType SensorValue) { - static_assert(std::is_arithmetic::value); - static_assert(std::is_arithmetic::value); - static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); #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 = getRelibility(SensorValue, previousSensorValue, valueSetCounter); #if Reliability_trace_level <= trace_vectors LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; #endif possibleScores << Confidence->operator()(SensorValue); possibleScores = min(possibleScores, inputReliability); 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 { - static_assert(std::is_arithmetic::value); + //static_assert(std::is_arithmetic::value); return A.Reliability > B.Reliability; }); previousSensorValue = SensorValue; PreviousSensorValueExists = true; #if Reliability_trace_level <= trace_outputs LOG_TRACE_STREAM << "\noutput lowlevel: " << possibleScores.at(0) << trace_end; #endif return possibleScores.at(0); } /// Needed feedback from the Master /// \param ValuesFromMaster The Scores + Reliability from the Master for this /// Agent void feedback(std::vector ValuesFromMaster) { this->ValuesFromMaster = ValuesFromMaster; } /// This is the setter for Confidence Function /// \param Confidence A pointer to the Functional for the Confidence 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 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 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 void setTimeConfidenceFunction( std::unique_ptr> &TimeConfidence) { this->TimeConfidence = std::move(TimeConfidence); } /// This is the setter for all possible States /// \param states A vertor containing all states void setStates(std::vector states) { this->States = states; } /// This sets the Maximum length of the Histpory /// \param length The length void setHistoryLength(std::size_t length) { this->HistoryMaxSize = length; } /// This sets the Value set Counter /// \param ValueSetCounter the new Value void setValueSetCounter(unsigned int ValueSetCounter) { this->valueSetCounter = ValueSetCounter; } 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; /*--------------------------------- needed Funktions * -----------------------------------------------------*/ /// 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 ReliabilityType getRelibility(SensorValueType actualValue, SensorValueType lastValue, unsigned int valueSetCounter) { - static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); ReliabilityType relAbs = Reliability->operator()(actualValue); if (PreviousSensorValueExists) { ReliabilityType relSlo = ReliabilitySlope->operator()( (lastValue - actualValue) / (SensorValueType)valueSetCounter); // calculate signal input reliability // NOTE: options would be multiply, average, AND (best to worst: // average = AND > multiply) rel = relAbs * relSlo; rel = (relAbs + // relSlo)/2; return std::min(relAbs, relSlo); } else return relAbs; } /// adabts the possible Scores by checking the History and combines those /// values currently with max 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; // combine each history score with the confidence of time // NOTE: multiplication, AND, or average would be alternatives (best to // worst: multiplication = AND = average) historyConf = historyConf * TimeConfidence->operator()(posInHistory); // historyConf = (historyConf + TimeConfidence(posInHistory)) / 2; // historyConf = std::min(historyConf, TimeConfidence(posInHistory)); bool foundScore = false; for (ConfOrRel &pS : possibleScores) { if (pS.score == historyScore) { // calculate confidence for score // NOTE: multiplication, AND, or average would be alternatives (best // to worst: AND >> average = multiplication ) pS->confOrRel = // pS->confOrRel * historyConf; pS->confOrRel = (pS->confOrRel + // historyConf) / 2; pS.Reliability = std::max(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 /// \param actualPossibleScores The Scores which should be saved /// /// \note Does the History realy make sence if the values are to smal it only /// stores something if its empty and not if it isn't completly 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, savo oldest element while (History.size() > HistoryMaxSize) { // delete possibleScoreHistory.back(); History.pop_back(); } } } }; /// This is the Reliability Functionality for the Highlevel Agent /// \tparam StateType Datatype of the State ( /// Typically double or float) \tparam ReliabilityType Datatype of the /// Reliability ( Typically long or int) /// /// use the () operator to calculate the Reliability and all cross confidences /// for all slaves. template class HighLevel { 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; /// The return type for the \c HighLevel::operator() Method struct returnType { ReliabilityType CrossReliability; std::map> CrossConfidence; }; /// Calculates the Reliability and the Cross Confidenceses for each slave 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 returnType operator()( std::vector> &Values) { - static_assert(std::is_arithmetic::value); - static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); + // static_assert(std::is_arithmetic::value); StateType EWS = 0; 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); EWS = EWS + sc; 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 >> ) 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({std::get<0>(Value), output_temporary}); 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; 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 void setFunction(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 CrossConfidence void setFunction(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 spezific states. this will be copied So that if Slaves /// have different States they can be used correctly. 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