diff --git a/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp b/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp index fcf63e0..975b95f 100644 --- a/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp +++ b/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp @@ -1,296 +1,334 @@ //===- 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 inside a /// master slave context. /// \note This is not finished /// //===----------------------------------------------------------------------===// #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 "rosa/deluxe/DeluxeContext.hpp" #include #include typedef double SensorValueType; typedef long StateType; typedef double ReliabilityType; #include "./helper.h" // just stuff from Rel-func to increase readability using namespace rosa::agent; using namespace rosa; using namespace rosa::deluxe; using namespace rosa::terminal; +#define NumberOfSimulationCycles 10 + // ------------------------------------------------------------------------------- // Bunch of recusive templates to simplify usage // ------------------------------------------------------------------------------- template struct conversion; template class A, typename... TypesB, template class B> struct conversion, B> { using type = typename conversion, std::tuple>::type; }; template class A, typename... TypesB, template class B> struct conversion<0, A, B> { using type = DeluxeTuple; }; template using unrolled_data_type = typename conversion, std::tuple<>>::type; //-------------------------------------------------------------------------------- template struct __convert_to_vector { void operator()(std::vector> &feedback, unrolled_data_type I) { __convert_to_vector()(feedback, I); feedback.push_back({std::get(I), std::get(I)}); } }; template struct __convert_to_vector { void operator()(std::vector> &feedback, unrolled_data_type I) { feedback.push_back({std::get<0>(I), std::get<1>(I)}); } }; template void convert_to_vector( std::vector> &feedback, unrolled_data_type I) { __convert_to_vector()(feedback, I); } //---------------------------------------------------------------------------- // template struct unrole_vector {}; // // template v, typename... vT, // template class T, typename... TT, typename... types> // struct unrole_vector,T, types...> { // void operator()(c vec, types... A) { // unrole_vector, T, auto>()(vec, // vec.at(size).score, // vec.at(size).score); // } //}; // --------------------------------------------------------------------------- // main // --------------------------------------------------------------------------- int main(void) { const std::size_t number_of_states = 3; std::unique_ptr C = DeluxeContext::create("Deluxe"); //---------------------- Sensors ------------------------------------- //-------------------------------------------------------------------- const std::string SensorName1 = "Sensor1"; const std::string SensorName2 = "Sensor2"; const std::string SensorName3 = "Sensor3"; AgentHandle Sensor1 = C->createSensor( SensorName1, [&SensorName1](std::pair I) { LOG_INFO_STREAM << "\n******\n" - << SensorName1 << " master-input " + << SensorName1 << " sensor-input " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; }); AgentHandle Sensor2 = C->createSensor( SensorName2, [&SensorName2](std::pair I) { LOG_INFO_STREAM << "\n******\n" - << SensorName2 << " master-input " + << SensorName2 << " sensor-input " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; }); AgentHandle Sensor3 = C->createSensor( SensorName3, [&SensorName3](std::pair I) { LOG_INFO_STREAM << "\n******\n" - << SensorName3 << " master-input " + << SensorName3 << " sensor-input " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; }); //------------------------- lowlevel agents -------------------------------- //-------------------------------------------------------------------------- const std::string LowLevelAgentName1 = "LowLevelAgent1"; const std::string LowLevelAgentName2 = "LowLevelAgent2"; const std::string LowLevelAgentName3 = "LowLevelAgent3"; using conf = unrolled_data_type< number_of_states, StateType, ReliabilityType>; // this is the confidence expressed as one tuple it // uses the format // (first.state,first.rel,second.sate...) using LowLevelAgentMasterResult = void; // no return using LowLevelReturnFromMaster = std::pair; using FloatMasterHandler = std::function; using FloatResult = Optional>; using FloatHandler = std::function, bool>)>; auto lowlevel1 = create_lowlevel_func(); auto lowlevel2 = create_lowlevel_func(); auto lowlevel3 = create_lowlevel_func(); - AgentHandle SlaveAgent = C->createAgent( + AgentHandle SlaveAgent1 = C->createAgent( LowLevelAgentName1, // Master-input handler. FloatMasterHandler( [&LowLevelAgentName1, lowlevel1](LowLevelReturnFromMaster I) -> LowLevelAgentMasterResult { LOG_INFO_STREAM << "inside: " << LowLevelAgentName1 << "feedback\n"; if (I.second) { std::vector> feedback; convert_to_vector(feedback, I.first); lowlevel1->feedback(feedback); } }), // Slave-input handler. FloatHandler( [&LowLevelAgentName1, lowlevel1]( std::pair, bool> I) -> FloatResult { LOG_INFO_STREAM << "\n******\n" << LowLevelAgentName1 << " " << (I.second ? "" : "") << " value: " << std::get<0>(I.first) << "\n******\n"; auto tmp = lowlevel1->operator()(std::get<0>(I.first)); DeluxeTuple ret(tmp.score, tmp.Reliability); return {ret}; })); AgentHandle SlaveAgent2 = C->createAgent( LowLevelAgentName2, // Master-input handler. FloatMasterHandler( [&LowLevelAgentName2, lowlevel2](LowLevelReturnFromMaster I) -> LowLevelAgentMasterResult { LOG_INFO_STREAM << "inside: " << LowLevelAgentName2 << "feedback\n"; if (I.second) { std::vector> feedback; convert_to_vector(feedback, I.first); lowlevel2->feedback(feedback); } }), // Slave-input handler. FloatHandler( [&LowLevelAgentName2, lowlevel2]( std::pair, bool> I) -> FloatResult { LOG_INFO_STREAM << "\n******\n" << LowLevelAgentName2 << " " << (I.second ? "" : "") << " value: " << std::get<0>(I.first) << "\n******\n"; auto tmp = lowlevel2->operator()(std::get<0>(I.first)); DeluxeTuple ret(tmp.score, tmp.Reliability); return {ret}; })); AgentHandle SlaveAgent3 = C->createAgent( LowLevelAgentName3, // Master-input handler. FloatMasterHandler( [&LowLevelAgentName3, lowlevel3](LowLevelReturnFromMaster I) -> LowLevelAgentMasterResult { LOG_INFO_STREAM << "inside: " << LowLevelAgentName3 << "feedback\n"; if (I.second) { std::vector> feedback; convert_to_vector(feedback, I.first); lowlevel3->feedback(feedback); } }), // Slave-input handler. FloatHandler( [&LowLevelAgentName3, lowlevel3]( std::pair, bool> I) -> FloatResult { LOG_INFO_STREAM << "\n******\n" << LowLevelAgentName3 << " " << (I.second ? "" : "") << " value: " << std::get<0>(I.first) << "\n******\n"; auto tmp = lowlevel3->operator()(std::get<0>(I.first)); DeluxeTuple ret(tmp.score, tmp.Reliability); return {ret}; })); - //------------------------- lookup copy of rel------------------------------ + //------------------------- high level rel --------------------------------- //-------------------------------------------------------------------------- auto highlevel = create_highlevel_func(); using conf1 = Optional>; // this is the confidence expressed as one tuple it // uses the format // (first.state,first.rel,second.sate...) using MasterResult = std::tuple>, conf1, conf1, conf1>; using SlaveOutputs = DeluxeTuple; using MasterHandler = std::function, std::pair, std::pair)>; - AgentHandle SumAgent = C->createAgent( + AgentHandle MasterAgent = C->createAgent( "Master Agent", MasterHandler([&](std::pair I0, std::pair I1, std::pair I2) -> MasterResult { ReliabilityForHighLevelAgents::InputType input; input.push_back({0, std::get<0>(I0.first), std::get<1>(I0.first)}); input.push_back({1, std::get<0>(I1.first), std::get<1>(I1.first)}); input.push_back({2, std::get<0>(I2.first), std::get<1>(I2.first)}); auto out = highlevel->operator()(input); DeluxeTuple rel(out.CrossReliability); conf c[3]; for (std::size_t at = 0; at < 3; at++) { std::get<0>(c[at]) = out.CrossConfidence.at(at).at(0).score; std::get<1>(c[at]) = out.CrossConfidence.at(at).at(0).Reliability; std::get<2>(c[at]) = out.CrossConfidence.at(at).at(1).score; std::get<3>(c[at]) = out.CrossConfidence.at(at).at(1).Reliability; std::get<4>(c[at]) = out.CrossConfidence.at(at).at(2).score; std::get<5>(c[at]) = out.CrossConfidence.at(at).at(2).Reliability; } return {{rel}, {c[0]}, {c[1]}, {c[2]}}; })); - // ------------------------------------------------------------------------- - // Input data into sensors and listen to output + // Sensors and connecting // ------------------------------------------------------------------------- - - + std::vector FloatValues(NumberOfSimulationCycles); + std::generate(FloatValues.begin(), FloatValues.end(), + [f = 0.5f](void) mutable { + f += 0.3f; + return std::floor(f) + 0.5f; + }); + C->registerSensorValues(Sensor1, FloatValues.begin(), FloatValues.end()); + C->registerSensorValues(Sensor2, FloatValues.begin(), FloatValues.end()); + C->registerSensorValues(Sensor3, FloatValues.begin(), FloatValues.end()); + + // Connection + C->connectSensor(SlaveAgent1, 0, Sensor1, "Sensor 1"); + C->connectSensor(SlaveAgent2, 0, Sensor2, "Sensor 2"); + C->connectSensor(SlaveAgent3, 0, Sensor3, "Sensor 3"); + + C->connectAgents(MasterAgent, 0, SlaveAgent1, "Slave1"); + C->connectAgents(MasterAgent, 1, SlaveAgent2, "Slave2"); + C->connectAgents(MasterAgent, 2, SlaveAgent3, "Slave3"); + + // Logger + AgentHandle LoggerAgent = C->createAgent( + "Logger Agent", std::function>( + std::pair, bool>)>( + [](std::pair, bool> Sum) + -> Optional> { + if (Sum.second) { + LOG_INFO_STREAM + << "Result: Rel: " << std::get<0>(Sum.first) + << "\n"; + } + return {}; + })); + + C->connectAgents(LoggerAgent, 0, MasterAgent, "Sum Agent Channel"); + // ------------------------------------------------------------------------------- + // Simulate + // ------------------------------------------------------------------------------- + + C->simulate(NumberOfSimulationCycles); delete highlevel; delete lowlevel1; delete lowlevel2; } \ No newline at end of file diff --git a/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h b/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h index 6055fb9..7de4fac 100644 --- a/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h +++ b/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h @@ -1,137 +1,170 @@ #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 "rosa/deluxe/DeluxeContext.hpp" #include #include using namespace rosa::agent; using namespace rosa; using namespace rosa::deluxe; using namespace rosa::terminal; auto create_lowlevel_func() { 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 ReliabilityForLowLevelAgents(); 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); return lowlevel; } auto create_highlevel_func(){ std::vector states; states.push_back(0); states.push_back(1); states.push_back(2); ReliabilityForHighLevelAgents *highlevel = new ReliabilityForHighLevelAgents(); std::unique_ptr> CrossReliability1(new CrossReliability()); std::unique_ptr> func1( new PartialFunction( { {{0, 1}, std::make_shared>(1, 0)}, {{1, 2}, std::make_shared>(2, -1.0)}, }, 0)); + std::unique_ptr> func2( + new PartialFunction( + { + {{0, 1}, std::make_shared>(1, 0)}, + {{1, 2}, std::make_shared>(2, -1.0)}, + }, + 0)); + std::unique_ptr> func3( + new PartialFunction( + { + {{0, 1}, std::make_shared>(1, 0)}, + {{1, 2}, std::make_shared>(2, -1.0)}, + }, + 0)); CrossReliability1->addCrossReliabilityProfile(0, 1, func1); + CrossReliability1->addCrossReliabilityProfile(0, 2, func2); + CrossReliability1->addCrossReliabilityProfile(2, 1, func3); CrossReliability1->setCrossReliabilityMethod( CrossReliability::AVERAGE); CrossReliability1->setCrossReliabilityParameter(1); std::unique_ptr> CrossConfidence1( new CrossConfidence()); - std::unique_ptr> func2( + std::unique_ptr> func4( + new PartialFunction( + { + {{0, 1}, std::make_shared>(1, 0)}, + {{1, 2}, std::make_shared>(2, -1.0)}, + }, + 0)); + std::unique_ptr> func5( + new PartialFunction( + { + {{0, 1}, std::make_shared>(1, 0)}, + {{1, 2}, std::make_shared>(2, -1.0)}, + }, + 0)); + std::unique_ptr> func6( new PartialFunction( { {{0, 1}, std::make_shared>(1, 0)}, {{1, 2}, std::make_shared>(2, -1.0)}, }, 0)); - CrossConfidence1->addCrossReliabilityProfile(0, 1, func2); + CrossConfidence1->addCrossReliabilityProfile(0, 1, func4); + CrossConfidence1->addCrossReliabilityProfile(0, 2, func5); + CrossConfidence1->addCrossReliabilityProfile(2, 1, func6); CrossConfidence1->setCrossReliabilityMethod( CrossConfidence::AVERAGE); CrossConfidence1->setCrossReliabilityParameter(1); highlevel->setCrossConfidence(CrossConfidence1); highlevel->setCrossReliability(CrossReliability1); highlevel->addStates(0, states); highlevel->addStates(1, states); + highlevel->addStates(2, states); return highlevel; } \ No newline at end of file diff --git a/include/rosa/agent/Reliability.h b/include/rosa/agent/Reliability.h index 5dfb11d..6baacb0 100644 --- a/include/rosa/agent/Reliability.h +++ b/include/rosa/agent/Reliability.h @@ -1,578 +1,825 @@ //===-- rosa/agent/Reliability.h --------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/Reliability.h /// /// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *reliability* *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 /// 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 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 Reliabilites +/// \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 : me) + for (auto &tmp_other : other) { + if (tmp_me.score == tmp_other.score) { + tmp_me.Reliability = (tmp_me.Reliability + tmp_other.Reliability) / 2; + } + } + return me; +} +/// 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 : me) + for (auto &tmp_other : other) { + if (tmp_me.score == tmp_other.score) { + tmp_me.Reliability = + std::min(tmp_me.Reliability + tmp_other.Reliability); + } + } + return me; +} +/// 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 : me) + for (auto &tmp_other : other) { + if (tmp_me.score == tmp_other.score) { + tmp_me.Reliability = + std::max(tmp_me.Reliability + tmp_other.Reliability); + } + } + return me; +} +/// 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 : 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 the Reliability Functionality for a low level Agent it takes the +/// This is the combinator for Reliability and confidences it takes the /// Sensor value, its "History" and feedback from \c -/// ReliabilityForHighLevelAgents to calculate the Reliability. +/// 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 A lowlevel Agent is close to the sensor and uses the Sensor value to -/// as part of its calculation. \note more information about how it calculates -/// the Reliability at the \c operator()() +/// \note more information about how it calculates +/// the Reliabilities at the \c mostLikelySoreAndReliability()() /// \note more information about the needed feedback at \c feedback() template -class ReliabilityForLowLevelAgents { +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 Reliability /// \param SensorValue The current Values of the Sensor /// /// \return Reliability and Score of the current SensorValue /// /// \brief It calculates the input Reliability of the Sensor and combines [ /// min() ] it with the Confidence of Sensor value. Then it combines [ \c /// std::vector::operator+=() [ addition ] ] it with the feedback /// from the highlevel Agent and stores it inside the history at the first /// location. Afterwards its combines[ private: \c /// getAllPossibleScoresBasedOnHistory() ] the whole History and return the /// most likely pair of values. - ConfOrRel operator()(SensorValueType 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 = - getRelibility(SensorValue, previousSensorValue, valueSetCounter); + 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 = min(possibleScores, inputReliability); + possibleScores = + PossibleScoreCombinationMethod(possibleScores, inputReliability); - possibleScores += ValuesFromMaster; + // set comb method with values from master ( class :: min | max | average | + // mult | [] ()-> {} ) + possibleScores = possibleScores + ValuesFromMaster; + // get 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(); + // get all possible scores () std::sort(possibleScores.begin(), possibleScores.end(), [](ConfOrRel A, ConfOrRel B) -> bool { 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); } + /// Calculates the input reliability by combining Reliability of the Sensor + /// and the Slope Reliability \parem 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; + } + + /// 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; + } + + /// 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; + } + + /// 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); + + // define from outside + // set Combination method ( class :: min | max | average | mult | []()->{}) + possibleScores = + PossibleScoreCombinationMethod(possibleScores, inputReliability); + // get possible scores(Sensor val) + return possibleScores; + } + + /// 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; + } + + /// 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 + PossibleScoreCombinationMethodAverage(std::vector A, + ReliabilityType B) { + return mult(A, B); + } + + 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 = FeedbackCombinatorMehtod(possibleScores, ValuesFromMaster); + return possibleScores; + } + /// sets the predefined method for the combination of the possible scores and + /// the master \param Meth the method predefined ones are \c + /// FeedbackCombinatorMehtodAverage() \c FeedbackCombinatorMehtodMin() \c + /// FeedbackCombinatorMehtodMax() \c FeedbackCombinatorMehtodMult() + void setFeedbackCombinatorMehtod(std::vector (*Meth)( + std::vector, std::vector)) { + FeedbackCombinatorMehtod = Meth; + } + /// predefined method + std::vector + FeedbackCombinatorMehtodAverage(std::vector A, + std::vector B) { + return average(A, B); + } + /// predefined method + std::vector FeedbackCombinatorMehtodMin(std::vector A, + std::vector B) { + return min(A, B); + } + /// predefined method + std::vector FeedbackCombinatorMehtodMax(std::vector A, + std::vector B) { + return max(A, B); + } + /// predefined method + std::vector + FeedbackCombinatorMehtodMult(std::vector A, + std::vector B) { + return mult(A, B); + } + /// Needed feedback from the Master - /// \param ValuesFromMaster The Scores + Reliability from the Master for this - /// Agent - /// \brief This input kind of resembles a confidence but not directly it more - /// or less says: compared to the other lowlevel Agents these are the Scores - /// with the Reliability that you have. + /// \param ValuesFromMaster The Scores + Reliability from the Master for + /// this Agent \brief This input kind of resembles a confidence but not + /// directly it more or less says: compared to the other lowlevel Agents + /// these are the Scores with the Reliability that you have. void feedback(std::vector ValuesFromMaster) { this->ValuesFromMaster = ValuesFromMaster; } /// 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; } 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 (*MeFeedbackCombinatorMehtodth)( + std::vector, std::vector) = average; + /*--------------------------------- 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 getRelibility(SensorValueType actualValue, SensorValueType lastValue, unsigned int valueSetCounter) { 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); + 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; // 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; + // set combination method() 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 /// \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()() -template -class ReliabilityForHighLevelAgents { +// 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) { - 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; - + // 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({std::get<0>(Value), output_temporary}); + 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