diff --git a/examples/agent-functionalities/CMakeLists.txt b/examples/agent-functionalities/CMakeLists.txt index 077f183..2c6bf6c 100644 --- a/examples/agent-functionalities/CMakeLists.txt +++ b/examples/agent-functionalities/CMakeLists.txt @@ -1,5 +1,4 @@ -add_executable(agent-functionalities agent-functionalities.cpp) -ROSA_add_library_dependencies(agent-functionalities ROSAConfig) -ROSA_add_library_dependencies(agent-functionalities ROSACore) -ROSA_add_library_dependencies(agent-functionalities ROSAAgent) + +# Add the different subdirectories +ADDALLSUBDIRS() diff --git a/examples/agent-functionalities/Reliability-functionality-agent-context/CMakeLists.txt b/examples/agent-functionalities/Reliability-functionality-agent-context/CMakeLists.txt new file mode 100644 index 0000000..4571f33 --- /dev/null +++ b/examples/agent-functionalities/Reliability-functionality-agent-context/CMakeLists.txt @@ -0,0 +1,6 @@ + +#add_executable(Reliability-agents Reliability-agents.cpp) +#ROSA_add_library_dependencies(Reliability-agents ROSAConfig) +#ROSA_add_library_dependencies(Reliability-agents ROSACore) +#ROSA_add_library_dependencies(Reliability-agents ROSAAgent) +#ROSA_add_library_dependencies(Reliability-agents ROSADeluxe) diff --git a/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp b/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp new file mode 100644 index 0000000..03c5bef --- /dev/null +++ b/examples/agent-functionalities/Reliability-functionality-agent-context/Reliability-agents.cpp @@ -0,0 +1,340 @@ +//===- examples/agent-functionalities/Reliability-functionality.cpp *C++-*-===// +// +// The RoSA Framework +// +// Distributed under the terms and conditions of the Boost Software License 1.0. +// See accompanying file LICENSE. +// +// If you did not receive a copy of the license file, see +// http://www.boost.org/LICENSE_1_0.txt. +// +//===----------------------------------------------------------------------===// +/// +/// \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. and is currently inactive +/// +//===----------------------------------------------------------------------===// + +#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 << " sensor-input " + << (I.second ? "" : "") + << " value: " << I.first << "\n******\n"; + }); + AgentHandle Sensor2 = C->createSensor( + SensorName2, [&SensorName2](std::pair I) { + LOG_INFO_STREAM << "\n******\n" + << 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 << " 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 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.Likeliness); + 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.Likeliness); + 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.Likeliness); + return {ret}; + })); + + //------------------------- 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 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.CrossLikeliness); + + conf c[3]; + for (std::size_t at = 0; at < 3; at++) { + std::get<0>(c[at]) = out.Likeliness.at(at).at(0).score; + std::get<1>(c[at]) = out.Likeliness.at(at).at(0).Likeliness; + std::get<2>(c[at]) = out.Likeliness.at(at).at(1).score; + std::get<3>(c[at]) = out.Likeliness.at(at).at(1).Likeliness; + std::get<4>(c[at]) = out.Likeliness.at(at).at(2).score; + std::get<5>(c[at]) = out.Likeliness.at(at).at(2).Likeliness; + } + return {{rel}, {c[0]}, {c[1]}, {c[2]}}; + })); + // ------------------------------------------------------------------------- + // 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; +} diff --git a/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h b/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h new file mode 100644 index 0000000..472fbcc --- /dev/null +++ b/examples/agent-functionalities/Reliability-functionality-agent-context/helper.h @@ -0,0 +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->setAbsoluteReliabilityFunction(Reliability); + lowlevel->setReliabilitySlopeFunction(ReliabilitySlope); + lowlevel->setTimeFunctionForLikelinessFunction(TimeConfidence); + lowlevel->setIdentifiers(states); + lowlevel->setHistoryLength(2); + lowlevel->setTimeStep(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->addCrossLikelinessProfile(0, 1, func1); + CrossReliability1->addCrossLikelinessProfile(0, 2, func2); + CrossReliability1->addCrossLikelinessProfile(2, 1, func3); + CrossReliability1->setCrossReliabilityMethod( + CrossReliability::AVERAGE); + CrossReliability1->setCrossLikelinessParameter(1); + + std::unique_ptr> CrossConfidence1( + new CrossConfidence()); + + 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->addCrossLikelinessProfile(0, 1, func4); + CrossConfidence1->addCrossLikelinessProfile(0, 2, func5); + CrossConfidence1->addCrossLikelinessProfile(2, 1, func6); + CrossConfidence1->setCrossReliabilityMethod( + CrossConfidence::AVERAGE); + CrossConfidence1->setCrossLikelinessParameter(1); + + highlevel->setCrossConfidence(CrossConfidence1); + highlevel->setCrossReliability(CrossReliability1); + + highlevel->addStates(0, states); + highlevel->addStates(1, states); + highlevel->addStates(2, states); + + return highlevel; +} diff --git a/examples/agent-functionalities/Reliability-functionality/CMakeLists.txt b/examples/agent-functionalities/Reliability-functionality/CMakeLists.txt new file mode 100644 index 0000000..746b1cd --- /dev/null +++ b/examples/agent-functionalities/Reliability-functionality/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(Reliability-functionalities Reliability-functionality.cpp) +ROSA_add_library_dependencies(Reliability-functionalities ROSAConfig) +ROSA_add_library_dependencies(Reliability-functionalities ROSACore) +ROSA_add_library_dependencies(Reliability-functionalities ROSAAgent) diff --git a/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp b/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp new file mode 100644 index 0000000..593db3f --- /dev/null +++ b/examples/agent-functionalities/Reliability-functionality/Reliability-functionality.cpp @@ -0,0 +1,253 @@ +//===- examples/agent-functionalities/Reliability-functionality.cpp *C++-*-===// +// +// The RoSA Framework +// +// Distributed under the terms and conditions of the Boost Software License 1.0. +// See accompanying file LICENSE. +// +// If you did not receive a copy of the license file, see +// http://www.boost.org/LICENSE_1_0.txt. +// +//===----------------------------------------------------------------------===// +/// +/// \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/CrossCombinator.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::shared_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::shared_ptr> Reliability( + new LinearFunction(1, -1.0 / 3)); + + std::shared_ptr> + ReliabilitySlope( + new LinearFunction(1, -1.0 / 3)); + + std::shared_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->setAbsoluteReliabilityFunction(Reliability); + lowlevel->setReliabilitySlopeFunction(ReliabilitySlope); + lowlevel->setTimeFunctionForLikelinessFunction(TimeConfidence); + lowlevel->setIdentifiers(states); + lowlevel->setHistoryLength(2); + lowlevel->setTimeStep(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->bestSymbol(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::shared_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::shared_ptr> Reliability2( + new LinearFunction(1, -1.0 / 9)); + + std::shared_ptr> + ReliabilitySlope2( + new LinearFunction(1, -1.0 / 9)); + + std::shared_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->setAbsoluteReliabilityFunction(Reliability2); + lowlevel2->setReliabilitySlopeFunction(ReliabilitySlope2); + lowlevel2->setTimeFunctionForLikelinessFunction(TimeConfidence2); + lowlevel2->setIdentifiers(states2); + lowlevel2->setHistoryLength(2); + lowlevel2->setTimeStep(1); + + CrossCombinator *highlevel = + new CrossCombinator(); + + std::shared_ptr> func1(new PartialFunction( + { + {{0, 1}, std::make_shared>(1, 0)}, + {{1, 2}, std::make_shared>(2, -1.0)}, + }, + 0)); + + highlevel->addCrossLikelinessProfile(0, 1, func1); + highlevel->setCrossLikelinessCombinatorMethod( + CrossCombinator::predefinedMethods::AVERAGE); + highlevel->setCrossLikelinessParameter(1); + + highlevel->addIdentifiers(0, states); + highlevel->addIdentifiers(1, states); + + for (int a = 0; a < 21; a++) { + auto out1 = lowlevel->bestSymbol(a), + out2 = lowlevel2->bestSymbol((int)21 - a); + std::cout << "s1: " << out1 << "\ns2:" << out2 << "\n"; + std::vector> tmp2; + tmp2.push_back({0, out1.Identifier, out1.Likeliness}); + tmp2.push_back({1, out2.Identifier, out2.Likeliness}); + + auto out_o = highlevel->operator()(tmp2); + std::cout << "it: " << a << "\t rel: " << out_o.CrossLikeliness << "\n"; + std::cout << "\t subs:\n"; + for (auto q : out_o.Likeliness) { + std::cout << "\t\t id:" << q.first << "\n"; + /* + for(auto z: q.second) + { + std::cout << "\t\t\t Identifier: " << z.Identifier << "\tRel: " << z.Likeliness + << "\n"; tmp.push_back({z.Identifier,z.Likeliness}); + } + */ + for (auto z : q.second) { + std::cout << "\t\t\t Identifier: " << z.Identifier << "\tRel: " << z.Likeliness + << "\n"; + } + + if (q.first == 0) + lowlevel->feedback(q.second); + else + lowlevel2->feedback(q.second); + } + } + /* ----------------------------- Cleanup + * --------------------------------------------------------------------- */ + + delete highlevel; + delete lowlevel; + delete lowlevel2; +} diff --git a/examples/agent-functionalities/CMakeLists.txt b/examples/agent-functionalities/basic-agent-functionalities/CMakeLists.txt similarity index 100% copy from examples/agent-functionalities/CMakeLists.txt copy to examples/agent-functionalities/basic-agent-functionalities/CMakeLists.txt diff --git a/examples/agent-functionalities/agent-functionalities.cpp b/examples/agent-functionalities/basic-agent-functionalities/agent-functionalities.cpp similarity index 100% rename from examples/agent-functionalities/agent-functionalities.cpp rename to examples/agent-functionalities/basic-agent-functionalities/agent-functionalities.cpp diff --git a/include/rosa/agent/CrossCombinator.h b/include/rosa/agent/CrossCombinator.h new file mode 100644 index 0000000..ead61f1 --- /dev/null +++ b/include/rosa/agent/CrossCombinator.h @@ -0,0 +1,558 @@ +//===-- rosa/delux/CrossCombinator.h ----------------------------*- C++ -*-===// +// +// The RoSA Framework +// +// Distributed under the terms and conditions of the Boost Software License 1.0. +// See accompanying file LICENSE. +// +// If you did not receive a copy of the license file, see +// http://www.boost.org/LICENSE_1_0.txt. +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/agent/CrossCombinator.h +/// +/// \author Daniel Schnoell +/// +/// \date 2019 +/// \note based on Maximilian Goetzinger(maxgot @utu.fi) code in +/// CAM_Dirty_include SA-EWS2_Version... inside Agent.cpp +/// +/// \brief +/// +/// \todo there is 1 exception that needs to be handled correctly. +/// \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_CROSSCOMBINATOR_H +#define ROSA_AGENT_CROSSCOMBINATOR_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 Combinator class for cross Reliabilities. It has many functions +/// with different purposes +/// \brief It takes the Identifiers and Reliabilities of all given ids and +/// calculates the Likeliness of them together. Also it can creates the +/// feedback that is needed by the \c LikelinessAndConfidenceCombinator, which +/// is a kind of confidence. +/// +/// \tparam IdentifierType Data type of the Identifier ( Typically double +/// or float) \tparam LikelinessType Data type of the Likeliness ( Typically +/// long or int) // this might be swapped +/// +/// \note This class is commonly in a master slave relationship as master with +/// \c LikelinessAndConfidenceCombinator. The \c operator()() combines the +/// Likeliness of all connected Slaves and uses that as its own Likeliness +/// also creates the feedback for the Slaves. +/// +/// \note more information about how the Likeliness and feedback is +/// created at \c operator()() , \c getCombinedCrossLikeliness() , \c +/// getCombinedInputLikeliness() , \c getOutputLikeliness() [ this is the +/// used Likeliness ], \c getCrossLikeliness() [ this is the feedback +/// for all Compares ] +/// +/// a bit more special Methods \c CrossConfidence() ,\c CrossLikeliness() +template +class CrossCombinator { +public: + static_assert(std::is_arithmetic::value, + "HighLevel: IdentifierType has to be an arithmetic type\n"); + static_assert(std::is_arithmetic::value, + "HighLevel: LikelinessType has to be an arithmetic type\n"); + + // --------------------------------------------------------------------------- + // useful definitions + // --------------------------------------------------------------------------- + /// typedef To shorten the writing. + /// \c Symbol + using Symbol = Symbol; + + /// To shorten the writing. + using Abstraction = + typename rosa::agent::Abstraction; + + /// The return type for the \c operator()() Method + struct returnType { + LikelinessType CrossLikeliness; + std::map> Likeliness; + }; + + // ------------------------------------------------------------------------- + // Relevant Methods + // ------------------------------------------------------------------------- + /// Calculates the CrossLikeliness and the Likeliness for each id for all + /// of there Identifiers. + /// + /// \param Values It gets the Identifiers and Reliabilities of + /// all connected Compare Agentss inside a vector. + /// + /// \return it returns a struct \c returnType containing the \c + /// getCombinedCrossLikeliness() and \c getCrossLikeliness() + returnType operator()( + std::vector> Values) { + return {getOutputLikeliness(Values), getCrossLikeliness(Values)}; + } + + /// returns the combined Cross Likeliness via \c + /// LikelinessCombinationMethod \c + /// setLikelinessCombinationMethod() for all ids \c + /// CrossLikeliness() \param Values the used Values + LikelinessType getCombinedCrossLikeliness( + const std::vector> + &Values) noexcept { + + LikelinessType Likeliness = -1; + + std::vector> Agents; + + Agents << Values; + + for (auto Value : Values) { + id_t id = std::get<0>(Value); + IdentifierType sc = std::get<1>(Value); + + // calculate the cross Likeliness for this Compare agent + LikelinessType realCrossLikelinessOfCompareInput = + CrossLikeliness({id, sc}, Agents); + + if (Likeliness != -1) + Likeliness = LikelinessCombinationMethod( + Likeliness, realCrossLikelinessOfCompareInput); + else + Likeliness = realCrossLikelinessOfCompareInput; + } + return Likeliness; + } + + /// returns the combined via \c CombinedInputLikelinessCombinationMethod \c + /// setCombinedInputLikelinessCombinationMethod() input Likeliness \param Values + /// the used Values + LikelinessType getCombinedInputLikeliness( + const std::vector> + &Values) noexcept { + LikelinessType combinedInputRel = -1; + + std::vector> Agents; + + Agents << Values; + + for (auto Value : Values) { + LikelinessType rel = std::get<2>(Value); + + if (combinedInputRel != -1) + combinedInputRel = + CombinedInputLikelinessCombinationMethod(combinedInputRel, rel); + else + combinedInputRel = rel; + } + return combinedInputRel; + } + + /// returns the combination via \c OutputLikelinessCombinationMethod \c + /// setOutputLikelinessCombinationMethod() of the Cross Likeliness and + /// input Likeliness \param Values the used Values + LikelinessType getOutputLikeliness( + const std::vector> + &Values) noexcept { + return OutputLikelinessCombinationMethod( + getCombinedInputLikeliness(Values), + getCombinedCrossLikeliness(Values)); + } + + /// returns the crossConfidence for all ids \c CrossConfidence() + /// \param Values the used Values + std::map> getCrossLikeliness( + const std::vector> + &Values) noexcept { + + std::vector> Agents; + std::map> output; + std::vector output_temporary; + + Agents << Values; + + for (auto Value : Values) { + id_t id = std::get<0>(Value); + + output_temporary.clear(); + for (IdentifierType thoIdentifier : Identifiers[id]) { + Symbol data; + data.Identifier = thoIdentifier; + data.Likeliness = CrossConfidence(id, thoIdentifier, Agents); + output_temporary.push_back(data); + } + + output.insert({id, output_temporary}); + } + + return output; + } + + /// Calculates the Cross Confidence + /// \brief it uses the Identifier value and calculates + /// the Confidence of a given agent( represented by their id ) for a given + /// Identifiers in connection to all other given agents + /// + /// \note all combination of agents and there corresponding Cross Likeliness + /// function have to be specified + LikelinessType + CrossConfidence(const id_t &MainAgent, const IdentifierType &TheoreticalValue, + const std::vector> + &CompareInputs) noexcept { + + LikelinessType crossReliabiability; + + std::vector values; + + for (std::pair CompareInput : CompareInputs) { + + if (CompareInput.first == MainAgent) + continue; + + if (TheoreticalValue == CompareInput.second) + crossReliabiability = 1; + else + crossReliabiability = + 1 / (crossLikelinessParameter * + std::abs(TheoreticalValue - CompareInput.second)); + + // profile Likeliness + LikelinessType crossLikelinessFromProfile = + getCrossLikelinessFromProfile( + MainAgent, CompareInput.first, + std::abs(TheoreticalValue - CompareInput.second)); + values.push_back( + std::max(crossReliabiability, crossLikelinessFromProfile)); + } + return Method(values); + } + + /// Calculates the Cross Likeliness + /// \brief it uses the Identifier value and calculates + /// the Likeliness of a given agent( represented by their id ) in connection + /// to all other given agents + /// + /// \note all combination of agents and there corresponding Cross Likeliness + /// function have to be specified + LikelinessType + CrossLikeliness(const std::pair &MainAgent, + const std::vector> + &CompareInputs) noexcept { + + LikelinessType crossReliabiability; + std::vector values; + + for (std::pair CompareInput : CompareInputs) { + + if (CompareInput.first == MainAgent.first) + continue; + + if (MainAgent.second == CompareInput.second) + crossReliabiability = 1; + else + crossReliabiability = + 1 / (crossLikelinessParameter * + std::abs(MainAgent.second - CompareInput.second)); + + // profile Likeliness + LikelinessType crossLikelinessFromProfile = + getCrossLikelinessFromProfile( + MainAgent.first, CompareInput.first, + std::abs(MainAgent.second - CompareInput.second)); + values.push_back( + std::max(crossReliabiability, crossLikelinessFromProfile)); + } + return Method(values); + } + + // -------------------------------------------------------------------------- + // Defining the class + // -------------------------------------------------------------------------- + + /// adds a Cross Likeliness Profile used to get the Likeliness of the + /// Identifier difference + /// + /// \param idA The id of the one \c Agent ( ideally the id of \c Unit to make + /// it absolutely unique ) + /// + /// \param idB The id of the other \c Agent + /// + /// \param Function A shared pointer to an \c Abstraction it would use the + /// difference in Identifier for its input + void addCrossLikelinessProfile( //conf + const id_t &idA, const id_t &idB, + const std::shared_ptr &Function) noexcept { + Functions.push_back({true, idA, idB, Function}); //confidence Profiles + } + + /// sets the cross Likeliness parameter + void setCrossLikelinessParameter(const LikelinessType &val) noexcept { + crossLikelinessParameter = val; + } + + /// This is the adder for the Identifiers + /// \param id The id of the Agent of the Identifiers + /// \param _Identifiers id specific Identifiers. This will be copied So that if + /// Compares have different Identifiers they can be used correctly. \brief The + /// Identifiers of all connected Compare Agents has to be known to be able to + /// iterate over them + void + addIdentifiers(const id_t &id, //add IdentifierIdentifiers + const std::vector &_Identifiers) noexcept { + Identifiers.insert({id, _Identifiers}); + } + + // ------------------------------------------------------------------------- + // Combinator Settings + // ------------------------------------------------------------------------- + + /// sets the used method to combine the values + /// \param Meth the method which should be used. predefined functions in the + /// struct \c predefinedMethods \c + /// CONJUNCTION() \c AVERAGE() \c DISJUNCTION() + void setCrossLikelinessCombinatorMethod( + const std::function values)> + &Meth) noexcept { + Method = Meth; + } + + /// sets the combination method for the combined cross Likeliness + /// \param Meth the method which should be used. predefined functions in the + /// struct \c predefinedMethods LikelinessCombinationMethod() + void setLikelinessCombinationMethod( + const std::function + &Meth) noexcept { + LikelinessCombinationMethod = Meth; + } + + /// sets the combined input rel method + /// \param Meth the method which should be used. predefined functions in the + /// struct \c predefinedMethods CombinedInputLikelinessCombinationMethod() + void setCombinedInputLikelinessCombinationMethod( + const std::function + &Meth) noexcept { + CombinedInputLikelinessCombinationMethod = Meth; + } + + /// sets the used OutputLikelinessCombinationMethod + /// \param Meth the method which should be used. predefined functions in the + /// struct \c predefinedMethods OutputLikelinessCombinationMethod() + void setOutputLikelinessCombinationMethod( + const std::function + &Meth) noexcept { + OutputLikelinessCombinationMethod = Meth; + } + + // ------------------------------------------------------------------------- + // Predefined Functions + // ------------------------------------------------------------------------- + /// This struct is a pseudo name space to have easier access to all predefined + /// methods while still not overcrowding the class it self + struct predefinedMethods { + /// predefined combination method + static LikelinessType CONJUNCTION(std::vector values) { + return *std::min_element(values.begin(), values.end()); + } + + /// predefined combination method + static LikelinessType AVERAGE(std::vector values) { + return std::accumulate(values.begin(), values.end(), 0.0) / values.size(); + } + + /// predefined combination method + static LikelinessType DISJUNCTION(std::vector values) { + return *std::max_element(values.begin(), values.end()); + } + + /// predefined combination Method + static LikelinessType + LikelinessCombinationMethodMin(LikelinessType A, LikelinessType B) { + return std::min(A, B); + } + + /// predefined combination Method + static LikelinessType + LikelinessCombinationMethodMax(LikelinessType A, LikelinessType B) { + return std::max(A, B); + } + + /// predefined combination Method + static LikelinessType + LikelinessCombinationMethodMult(LikelinessType A, + LikelinessType B) { + return A * B; + } + + /// predefined combination Method + static LikelinessType + LikelinessCombinationMethodAverage(LikelinessType A, + LikelinessType B) { + return (A + B) / 2; + } + + /// predefined combination Method + static LikelinessType + CombinedInputLikelinessCombinationMethodMin(LikelinessType A, LikelinessType B) { + return std::min(A, B); + } + + /// predefined combination Method + static LikelinessType + CombinedInputLikelinessCombinationMethodMax(LikelinessType A, LikelinessType B) { + return std::max(A, B); + } + + /// predefined combination Method + static LikelinessType + CombinedInputLikelinessCombinationMethodMult(LikelinessType A, + LikelinessType B) { + return A * B; + } + + /// predefined combination Method + static LikelinessType + CombinedInputLikelinessCombinationMethodAverage(LikelinessType A, + LikelinessType B) { + return (A + B) / 2; + } + + /// predefined combination method + static LikelinessType + OutputLikelinessCombinationMethodMin(LikelinessType A, + LikelinessType B) { + return std::min(A, B); + } + + /// predefined combination method + static LikelinessType + OutputLikelinessCombinationMethodMax(LikelinessType A, + LikelinessType B) { + return std::max(A, B); + } + + /// predefined combination method + static LikelinessType + OutputLikelinessCombinationMethodMult(LikelinessType A, + LikelinessType B) { + return A * B; + } + + /// predefined combination method + static LikelinessType + OutputLikelinessCombinationMethodAverage(LikelinessType A, + LikelinessType B) { + return (A + B) / 2; + } + }; + + // ------------------------------------------------------------------------- + // Cleanup + // ------------------------------------------------------------------------- + + ~CrossCombinator() { Functions.clear(); } + + // -------------------------------------------------------------------------- + // Parameters + // -------------------------------------------------------------------------- +private: + struct Functionblock { + bool exists = false; + id_t A; + id_t B; + std::shared_ptr Funct; + }; + + std::map> Identifiers; + + /// From Maxi in his code defined as 1 can be changed by set + LikelinessType crossLikelinessParameter = 1; + + /// Stored Cross Likeliness Functions + std::vector Functions; + + /// Method which is used to combine the generated values + std::function)> Method = + predefinedMethods::AVERAGE; + + std::function + LikelinessCombinationMethod = + predefinedMethods::LikelinessCombinationMethodMin; + + std::function + CombinedInputLikelinessCombinationMethod = + predefinedMethods::CombinedInputLikelinessCombinationMethodMin; + + std::function + OutputLikelinessCombinationMethod = + predefinedMethods::OutputLikelinessCombinationMethodMin; + + //-------------------------------------------------------------------------------- + // helper function + + /// 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(); + }; + + /// evaluates the corresponding LinearFunction with the Identifier 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 + LikelinessType getCrossLikelinessFromProfile( + const id_t &nameA, const id_t &nameB, + const IdentifierType &IdentifierDifference) noexcept { + Functionblock block = searchFunction(Functions, nameA, nameB); + if (!block.exists) { + LOG_ERROR(("CrossLikeliness: Block:" + std::to_string(nameA) + "," + + std::to_string(nameB) + "doesn't exist returning 0")); + return 0; + } + return block.Funct->operator()(IdentifierDifference); + } +}; + +} // End namespace agent +} // End namespace rosa + +#endif // ROSA_AGENT_CROSSCOMBINATOR_H \ No newline at end of file diff --git a/include/rosa/agent/CrossReliability.h b/include/rosa/agent/CrossReliability.h deleted file mode 100644 index 21f3df7..0000000 --- a/include/rosa/agent/CrossReliability.h +++ /dev/null @@ -1,353 +0,0 @@ -//===-- rosa/delux/CrossReliability.h ---------------------------*- C++ -*-===// -// -// The RoSA Framework -// -// Distributed under the terms and conditions of the Boost Software License 1.0. -// See accompanying file LICENSE. -// -// If you did not receive a copy of the license file, see -// http://www.boost.org/LICENSE_1_0.txt. -// -//===----------------------------------------------------------------------===// -/// -/// \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 - -// FIXME: ROSA_LOG_LEVEL is defined by the build system, this should be -// removed. -//#define ROSA_LOG_LEVEL 100 - -#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 { - 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); - 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 - void addCrossReliabilityProfile(id_t idA, id_t idB, Abstraction *Function) { - Functions.push_back({true, idA, idB, Function}); - } - - /// sets the cross reliability parameter - void setCrossReliabilityParameter(Type val) { - crossReliabilityParameter = val; - } - /// sets the used method to combine the values - void setCrossReliabilityMethod(Type (*Meth)(std::vector values)) { - Method = Meth; - } - - ~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 - 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 - 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 - 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 - - 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 Cross Confidence -/// \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 Cross Reliability -/// function have to be specified -template -class CrossConfidence : public Abstraction { - 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); - 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 - void addCrossReliabilityProfile(id_t idA, id_t idB, Abstraction *Function) { - Functions.push_back({true, idA, idB, Function}); - } - - /// sets the cross reliability parameter - void setCrossReliabilityParameter(Type val) { - crossReliabilityParameter = val; - } - /// sets the used method to combine the values - void setCrossReliabilityMethod(Type (*Meth)(std::vector values)) { - Method = Meth; - } - - ~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 - 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 - 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 - return *std::max_element(values.begin(), values.end()); - } -}; - -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 - - 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 diff --git a/include/rosa/agent/FunctionAbstractions.hpp b/include/rosa/agent/FunctionAbstractions.hpp index 2fa6912..b0c1ce4 100644 --- a/include/rosa/agent/FunctionAbstractions.hpp +++ b/include/rosa/agent/FunctionAbstractions.hpp @@ -1,364 +1,364 @@ //===-- rosa/agent/FunctionAbstractions.hpp ---------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/FunctionAbstractions.hpp /// /// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *FunctionAbstractions* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP #define ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Functionality.h" #include "rosa/support/debug.hpp" #include #include #include #include namespace rosa { namespace agent { /// Implements \c rosa::agent::Abstraction as a linear function, /// y = Coefficient * X + Intercept. /// /// \note This implementation is supposed to be used to represent a linear /// function from an arithmetic domain to an arithmetic range. This is enforced /// statically. /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class LinearFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "LinearFunction not arithmetic T"); STATIC_ASSERT((std::is_arithmetic::value), "LinearFunction not to arithmetic"); protected: /// The Intercept of the linear function - const D Intercept; + const R Intercept; /// The Coefficient of the linear function - const D Coefficient; + const R Coefficient; public: /// Creates an instance given the intercept and the coefficient of a linear /// function. /// /// \param Intercept the intercept of the linear function /// \param Coefficient the coefficient of the linear function - LinearFunction(D Intercept, D Coefficient) noexcept + LinearFunction(R Intercept, R Coefficient) noexcept : Abstraction(Intercept), Intercept(Intercept), Coefficient(Coefficient) {} /// Creates an instance given the two points on a linear function. /// /// \param x1 The x-value of the first point /// \param y1 The x-value of the first point /// \param x2 The y-value of the second point /// \param y2 The y-value of the second point LinearFunction(D x1, R y1, D x2, R y2) noexcept : Abstraction(y1 - x1 * (y1 - y2) / (x1 - x2), (y1 - y2) / (x1 - x2)) {} /// Creates an instance given the two points on a linear function. /// /// \param p1 The coordinates of the first point /// \param p2 The coordinates of the second point LinearFunction(std::pair p1, std::pair p2) noexcept : LinearFunction(p1.first, p1.second, p2.first, p2.second) {} /// Destroys \p this object. ~LinearFunction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// As LinearFunctions can be evaluated everythwere, this is always false /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false bool isDefaultAt(const D &V) const noexcept override { (void)V; return false; } /// Getter for member variable Intercept /// /// \return Intercept D getIntercept() const { return Intercept; } /// Setter for member variable Intercept /// /// \param Intercept the new Intercept void setIntercept(const D &Intercept) { this->Intercept = Intercept; } /// Getter for member variable Coefficient /// /// \return Coefficient D getCoefficient() const { return Coefficient; } /// Setter for member variable Coefficient /// /// \param Coefficient the new Intercept void setCoefficient(const D &Coefficient) { this->Coefficient = Coefficient; } /// Set Intercept and Coefficient from two points on the linear function /// /// \param x1 The x-value of the first point /// \param y1 The x-value of the first point /// \param x2 The y-value of the second point /// \param y2 The y-value of the second point void setFromPoints(D x1, R y1, D x2, R y2) { Coefficient = (y1 - y2) / (x1 - x2); Intercept = y1 - Coefficient * x1; } /// Set Intercept and Coefficient from two points on the linear function /// /// \param p1 The coordinates of the first point /// \param p2 The coordinates of the second point inline void setFromPoints(std::pair p1, std::pair p2) { setFromPoints(p1.first, p1.second, p2.first, p2.second); } /// Evaluates the linear function /// /// \param X the value at which to evaluate the function /// /// \return Coefficient*X + Intercept virtual R operator()(const D &X) const noexcept override { return Intercept + X * Coefficient; } }; /// Implements \c rosa::agent::Abstraction as a sine function, /// y = Amplitude * sin(Frequency * X + Phase) + Average. /// /// \note This implementation is supposed to be used to represent a sine /// function from an arithmetic domain to an arithmetic range. This is enforced /// statically. /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class SineFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "SineFunction not arithmetic T"); STATIC_ASSERT((std::is_arithmetic::value), "SineFunction not to arithmetic"); protected: /// The frequency of the sine wave const D Frequency; /// The Ampiltude of the sine wave const D Amplitude; /// The Phase-shift of the sine wave const D Phase; /// The y-shift of the sine wave const D Average; public: /// Creates an instance. /// /// \param Frequency the frequency of the sine wave /// \param Amplitude the amplitude of the sine wave /// \param Phase the phase of the sine wave /// \param Average the average of the sine wave SineFunction(D Frequency, D Amplitude, D Phase, D Average) noexcept : Abstraction(Average), Frequency(Frequency), Amplitude(Amplitude), Phase(Phase), Average(Average) {} /// Destroys \p this object. ~SineFunction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// As SineFunctions can be evaluated everythwere, this is always false /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false bool isDefaultAt(const D &V) const noexcept override { (void)V; return false; } /// Evaluates the sine function /// /// \param X the value at which to evaluate the function /// \return the value of the sine-function at X virtual R operator()(const D &X) const noexcept override { return Amplitude * sin(Frequency * X + Phase) + Average; } }; enum StepDirection { StepUp, StepDown }; /// Implements \c rosa::agent::PartialFunction as a step function from 0 to 1 /// with a ramp in between /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class StepFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); STATIC_ASSERT((std::is_arithmetic::value), "abstracting not to arithmetic"); private: D Coefficient; D RightLimit; StepDirection Direction; public: /// Creates an instance by Initializing the underlying \c Abstraction. /// /// \param Coefficient Coefficient of the ramp /// \param Direction wether to step up or down /// /// \pre Coefficient > 0 StepFunction(D Coefficient, StepDirection Direction = StepUp) : Abstraction(0), Coefficient(Coefficient), RightLimit(1.0f / Coefficient), Direction(Direction) { ASSERT(Coefficient > 0); } /// Destroys \p this object. ~StepFunction(void) = default; /// Setter for Coefficient /// /// \param Coefficient the new Coefficient void setCoefficient(const D &Coefficient) { ASSERT(Coefficient > 0); this->Coefficient = Coefficient; this->RightLimit = 1 / Coefficient; } /// Setter for RightLimit /// /// \param RightLimit the new RightLimit void setRightLimit(const D &RightLimit) { ASSERT(RightLimit > 0); this->RightLimit = RightLimit; this->Coefficient = 1 / RightLimit; } /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false if the is negative, true otherwise bool isDefaultAt(const D &V) const noexcept override { return V > 0; } /// Executes the Abstraction /// /// \param V value to abstract /// /// \return the abstracted value R operator()(const D &V) const noexcept override { R ret = 0; if (V <= 0) ret = 0; else if (V >= RightLimit) ret = 1; else ret = V * Coefficient; return Direction == StepDirection::StepUp ? ret : 1 - ret; } }; /// Implements \c rosa::agent::Abstraction as a partial function from a domain /// to a range. /// /// \note This implementation is supposed to be used to represent a partial /// function from an arithmetic domain to an arithmetic range. This is enforced /// statically. /// /// A partial function is defined as a list of abstractions, where each /// abstraction is associated a range in which it is defined. These ranges must /// be mutually exclusive. /// /// \tparam D type of the functions domain /// \tparam R type of the functions range template class PartialFunction : public Abstraction { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); STATIC_ASSERT((std::is_arithmetic::value), "abstracting not to arithmetic"); private: /// A \c rosa::agent::RangeAbstraction RA is used to represent the association /// from ranges to Abstractions. /// This returns the Abstraction that is defined for any given value, or /// a default Abstraction if no Abstraction is defined for that value. RangeAbstraction>> RA; public: /// Creates an instance by Initializing the underlying \c Abstraction. /// /// \param Map the mapping to do abstraction according to /// \param Default abstraction to abstract to by default /// /// \pre Each key defines a valid range such that `first <= second` and /// there are no overlapping ranges defined by the keys. PartialFunction( const std::map, std::shared_ptr>> &Map, const R Default) : Abstraction(Default), RA(Map, std::shared_ptr>(new Abstraction(Default))) { } /// Destroys \p this object. ~PartialFunction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// /// \return false if the value falls into a defined range and the Abstraction /// defined for that range does not fall back to it's default value. bool isDefaultAt(const D &V) const noexcept override { return RA.isDefaultAt(V) ? true : RA(V)->isDefaultAt(V); } /// Searches for an Abstraction for the given value and executes it for that /// value, if such an Abstraction is found. The default Abstraction is /// evaluated otherwise. /// /// \param V value to abstract /// /// \return the abstracted value based on the set mapping R operator()(const D &V) const noexcept override { return RA(V)->operator()(V); } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_FUNCTIONABSTRACTIONS_HPP diff --git a/include/rosa/agent/ReliabilityConfidenceCombinator.h b/include/rosa/agent/ReliabilityConfidenceCombinator.h new file mode 100644 index 0000000..3048d3f --- /dev/null +++ b/include/rosa/agent/ReliabilityConfidenceCombinator.h @@ -0,0 +1,761 @@ +//===-- rosa/agent/ReliabilityConfidenceCombinator.h ------------*- C++ -*-===// +// +// The RoSA Framework +// +// Distributed under the terms and conditions of the Boost Software License 1.0. +// See accompanying file LICENSE. +// +// If you did not receive a copy of the license file, see +// http://www.boost.org/LICENSE_1_0.txt. +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/agent/ReliabilityConfidenceCombinator.h +/// +/// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Definition of *ReliabilityConfidenceCombinator* *functionality*. +/// +/// \note based on Maximilian Goetzinger (maxgot@utu.fi) code in +/// CAM_Dirty_include SA-EWS2_Version... inside Agent.cpp +/// +/// \note By defining and setting Reliability_trace_level it is possible to +/// change the level to which it should be traced. \note All classes throw +/// runtime errors if not all things are set +/// +/// \note should the Reliability be capped? +/// +/// +//===----------------------------------------------------------------------===// + +#ifndef ROSA_AGENT_ReliabilityConfidenceCombinator_H +#define ROSA_AGENT_ReliabilityConfidenceCombinator_H + +#include "rosa/core/forward_declarations.h" // needed for id_t +#include "rosa/support/log.h" + +#include "rosa/agent/FunctionAbstractions.hpp" +#include "rosa/agent/Functionality.h" +#include "rosa/agent/RangeConfidence.hpp" + +#include +#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 Likeliness Combinator +/// more readable \tparam IdentifierType The Data-type of the Identifiers \tparam +/// LikelinessType The Data-type of the Likeliness +/// \note this should/will be changed into a std::pair because it isn't needed +/// anymore +template struct Symbol { + /// making both Template Arguments readable to make a few things easier + using _IdentifierType = IdentifierType; + /// making both Template Arguments readable to make a few things easier + using _LikelinessType = LikelinessType; + + /// The actual place where the data is stored + IdentifierType Identifier; + /// The actual place where the data is stored + LikelinessType Likeliness; + + Symbol(IdentifierType _Identifier, LikelinessType _Likeliness) + : Identifier(_Identifier), Likeliness(_Likeliness){}; + Symbol(){}; + + /// 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 Symbol &c) { + out << "Identifier: " << c.Identifier << "\t Likeliness: " << c.Likeliness + << " "; + return out; + } + + /// needed or it throws an clang diagnosic error + using map = + std::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(Symbol(tmp.first, tmp.second)); +#if Reliability_trace_level <= trace_everything + LOG_TRACE_STREAM << "\n" << Symbol(tmp.first, tmp.second) << trace_end; +#endif + } + return me; + } + + /// This is to push the data inside a vector in a human readable way into the + /// ostream \param out The ostream \param c The vector which is read + friend std::ostream &operator<<(std::ostream &out, + const std::vector &c) { + std::size_t index = 0; + for (Symbol data : c) { + out << index << " : " << data << "\n"; + index++; + } + return out; + } +}; + +/// This is the combinator for Reliability and confidences it takes the +/// Value, its "History" and feedback from \c +/// CrossCombinator to calculate different Reliabilities. +/// \tparam ValueType Data-type of the Value ( Typically +/// double or float) \tparam IdentifierType Data-type of the Identifier ( Typically +/// long or int) +/// \tparam ReliabilityType Data-type of the Reliability ( +/// Typically double or float) +/// +/// \note more information about how it calculates +/// the Reliabilities it should be considered feedback is a sort of Confidence +/// \verbatim +///---------------------------------------------------------------------------------- +/// +/// +/// ->AbsoluteReliabilityFunction---> getInputReliability() +/// | | +/// | V +/// Sensor Value ---| ReliabilityAndConfidenceCombinator -> next line +/// | A | +/// | | V +/// ->ConfidenceFunction getPossibleIdentifiers() +/// +///----------------------------------------------------------------------------------- +/// +/// feedback +/// | +/// V +/// FeedbackSymbols +/// | -> History -------| +/// V | V +/// here -> LikelinessFeedbackCombinator ------>LikelinessHistoryCombinator->next line +/// | | +/// V V +/// getpossibleIdentifiersWithMasterFeedback() SymbolsWithHistory() +/// +///---------------------------------------------------------------------------------- +/// +/// here -> sort -> most likely -> bestSymbol() +/// +///--------------------------------------------------------------------------------- +/// \endverbatim +/// the mentioned methods are early outs so if two ore more of them are run in +/// the same step they will be interpreted as different time steps +///
+/// Default values for Combinators:
+///	AbsoluteAndSlopeReliabilityCombinationMethod		= combinationMin;
+///	ReliabilityAndConfidenceCombinator=ReliabilityAndConfidenceCombinatorMin;
+/// LikelinessFeedbackCombinator		= LikelinessFeedbackCombinatorAverage;
+/// LikelinessHistoryCombinator			= LikelinessHistoryCombinatorMax;
+///	
+/// To understand the place where the combinator methods come into play a list +/// for each early exit and which Methods are used. +/// +///
+/// \c getInputReliability():
+///		-AbsoluteAndSlopeReliabilityCombinationMethod
+/// \c getPossibleIdentifiers():
+///		-AbsoluteAndSlopeReliabilityCombinationMethod
+///		-ReliabilityAndConfidenceCombinator
+/// \c getpossibleIdentifiersWithMasterFeedback():
+///		-AbsoluteAndSlopeReliabilityCombinationMethod
+///		-ReliabilityAndConfidenceCombinator
+///		-LikelinessFeedbackCombinator
+/// \c SymbolsWithHistory():
+///		-AbsoluteAndSlopeReliabilityCombinationMethod
+///		-ReliabilityAndConfidenceCombinator
+///		-LikelinessFeedbackCombinator
+///		-LikelinessHistoryCombinator
+/// \c bestSymbol():
+///		-AbsoluteAndSlopeReliabilityCombinationMethod
+///		-ReliabilityAndConfidenceCombinator
+///		-LikelinessFeedbackCombinator
+///		-LikelinessHistoryCombinator
+/// 
+template +class ReliabilityAndConfidenceCombinator { +public: + static_assert(std::is_arithmetic::value, + "LowLevel: ValueType has to an arithmetic type\n"); + static_assert(std::is_arithmetic::value, + "LowLevel: IdentifierType 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 Symbol + using Symbol = Symbol; + + /// Calculates the input Reliability by combining Reliability of the Sensor + /// and the Slope Reliability \param SensorValue The sensor Value \note to set + /// the combination method \c setAbsoluteAndSlopeReliabilityCombinationMethod() + ReliabilityType + getInputReliability(const ValueType &SensorValue) noexcept { + ReliabilityType inputReliability = + getReliability(SensorValue, previousSensorValue, timeStep); + previousSensorValue = SensorValue; + PreviousSensorValueExists = true; + return inputReliability; + } + + /// Calculates the possible Identifiers + /// \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 + /// setReliabilityAndConfidenceCombinator() + std::vector + getPossibleIdentifiers(const ValueType &SensorValue) noexcept { + std::vector possibleIdentifiers; + ReliabilityType inputReliability = getInputReliability(SensorValue); + +#if Reliability_trace_level <= trace_vectors + LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; +#endif + + possibleIdentifiers << ConfidenceFunction->operator()(SensorValue); + possibleIdentifiers = ReliabilityAndConfidenceCombinator( + possibleIdentifiers, inputReliability); + return possibleIdentifiers; + } + + /// return the Possible Values with the feedback in mind + /// \param SensorValue The sensor Value + /// \brief it combines the input reliability and the confidence of the Sensor. + /// The combines them with LikelinessFeedbackCombinator and returns the result. + std::vector getpossibleIdentifiersWithMasterFeedback( + const ValueType &SensorValue) noexcept { + std::vector possibleIdentifiers; + ReliabilityType inputReliability = getInputReliability(SensorValue); + +#if Reliability_trace_level <= trace_vectors + LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; +#endif + + possibleIdentifiers << ConfidenceFunction->operator()(SensorValue); + + possibleIdentifiers = ReliabilityAndConfidenceCombinator( + possibleIdentifiers, inputReliability); + + possibleIdentifiers = + LikelinessFeedbackCombinator(possibleIdentifiers, FeedbackSymbols); + return possibleIdentifiers; + } + + /// returns all possible Identifiers and Reliabilities with the History in + /// mind \param SensorValue the Sensor value how this is done is described at + /// the class. + std::vector SymbolsWithHistory( + const ValueType &SensorValue) noexcept { + std::vector ActuallPossibleIdentifiers; + std::vector possibleIdentifiers; + ReliabilityType inputReliability = getInputReliability(SensorValue); + +#if Reliability_trace_level <= trace_vectors + LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; +#endif + + possibleIdentifiers << ConfidenceFunction->operator()(SensorValue); + + possibleIdentifiers = ReliabilityAndConfidenceCombinator( + possibleIdentifiers, inputReliability); + possibleIdentifiers = + LikelinessFeedbackCombinator(possibleIdentifiers, FeedbackSymbols); + + saveInHistory(possibleIdentifiers); +#if Reliability_trace_level <= trace_vectors + LOG_TRACE_STREAM << "\nActuallPossibleIdentifiers:\n" + << possibleIdentifiers << trace_end; + LOG_TRACE_STREAM << "\npossibleIdentifiers:\n" + << possibleIdentifiers << trace_end; +#endif + possibleIdentifiers.clear(); + + return SymbolsFromHistory(); + } + + /// Calculates the Reliability + /// \param SensorValue The current Values of the Sensor + /// + /// \return Reliability and Identifier of the current SensorValue + /// + Symbol bestSymbol( + const ValueType &SensorValue) noexcept { +#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 ActuallPossibleIdentifiers; + std::vector possibleIdentifiers; + ReliabilityType inputReliability = getInputReliability(SensorValue); + +#if Reliability_trace_level <= trace_vectors + LOG_TRACE_STREAM << "\ninput Rel: " << inputReliability << trace_end; +#endif + + possibleIdentifiers << ConfidenceFunction->operator()(SensorValue); + + possibleIdentifiers = ReliabilityAndConfidenceCombinator( + possibleIdentifiers, inputReliability); + possibleIdentifiers = + LikelinessFeedbackCombinator(possibleIdentifiers, FeedbackSymbols); + + saveInHistory(possibleIdentifiers); +#if Reliability_trace_level <= trace_vectors + LOG_TRACE_STREAM << "\nActuallPossibleIdentifiers:\n" + << possibleIdentifiers << trace_end; + LOG_TRACE_STREAM << "\npossibleIdentifiers:\n" + << possibleIdentifiers << trace_end; +#endif + possibleIdentifiers.clear(); + + possibleIdentifiers = SymbolsFromHistory(); + + std::sort(possibleIdentifiers.begin(), possibleIdentifiers.end(), + [](Symbol A, Symbol B) -> bool { + return A.Likeliness > B.Likeliness; + }); + +#if Reliability_trace_level <= trace_outputs + LOG_TRACE_STREAM << "\noutput lowlevel: " << possibleIdentifiers.at(0) + << trace_end; +#endif + return possibleIdentifiers.at(0); + } + + /// feedback for this functionality most commonly it comes from a Master Agent + /// \param _FeedbackSymbols The Identifiers + Reliability for the feedback + /// \brief This input kind of resembles a confidence but not + /// directly it more or less says: compared to the other Identifiers inside + /// the System these are the Identifiers with the Reliability that you have. + void feedback( + const std::vector + &_FeedbackSymbols) noexcept // it is being copied internally anyway + { + FeedbackSymbols = _FeedbackSymbols; + } + + // + // ----------------------Reliability and Confidence Function setters---------- + // + /// This is the setter for Confidence Function + /// \param _ConfidenceFunction A pointer to the Functional for the + /// \c Confidence of the Sensor value + void setConfidenceFunction( + std::shared_ptr> &_ConfidenceFunction) noexcept { + ConfidenceFunction = _ConfidenceFunction; + } + + /// This is the setter for AbsoluteReliabilityFunction + /// \param _AbsoluteReliabilityFunction A pointer to the Functional for the AbsoluteReliabilityFunction + /// \brief The AbsoluteReliabilityFunction takes the current Sensor value and return the + /// AbsoluteReliabilityFunction of the value. + void setAbsoluteReliabilityFunction( + std::shared_ptr> + &_AbsoluteReliabilityFunction) noexcept { + AbsoluteReliabilityFunction = _AbsoluteReliabilityFunction; + } + + /// This is the setter for ReliabilitySlopeFunction Function + /// \param _ReliabilitySlopeFunction A pointer to the Functional for the + /// ReliabilitySlopeFunction + /// \brief The ReliabilitySlopeFunction takes the difference of the current Sensor + /// Value to the last one and tells you how likely the change is. + void setReliabilitySlopeFunction( + std::shared_ptr> + &_ReliabilitySlopeFunction) noexcept { + ReliabilitySlopeFunction = _ReliabilitySlopeFunction; + } + + /// This is the setter for TimeFunctionForLikeliness Function + /// \param _TimeFunctionForLikeliness A pointer to the Functional for the TimeFunctionForLikeliness + /// \brief The time function takes the position in the History with greater + /// equals older and return a Reliability of how "relevant" it is. + void setTimeFunctionForLikelinessFunction( + std::shared_ptr> + &_TimeFunctionForLikeliness) noexcept { + TimeFunctionForLikeliness = _TimeFunctionForLikeliness; + } + + /// This is the setter for all possible Identifiers + /// \param Identifiers A vector containing all Identifiers + /// \brief This exists even though \c Identifier Type is an arithmetic Type because + /// the Identifiers do not need to be "next" to each other ( ex. Identifiers={ 1 7 24 }) + void setIdentifiers(const std::vector &Identifiers) noexcept { + this->Identifiers = Identifiers; + } + + /// This sets the Maximum length of the History + /// \param length The length + void setHistoryLength(const std::size_t &length) noexcept { + this->HistoryMaxSize = length; + } + + /// This sets the Value set Counter + /// \param timeStep the new Value + /// \note This might actually be only an artifact. It is only used to get the + /// reliability from the \c ReliabilitySlopeFunction [ ReliabilitySlopeFunction->operator()( + /// (lastValue - actualValue) / (ValueType)timeStep) ] + void setTimeStep(const unsigned int &timeStep) noexcept { + this->timeStep = timeStep; + } + + // + // ----------------combinator setters----------------------------------------- + // + + /// This sets the combination method used by the History + /// \param Meth the method which should be used. predefined inside the \c + /// predefinedMethods struct LikelinessHistoryCombinator() + void setLikelinessHistoryCombinator( + const std::function + &Meth) noexcept { + LikelinessHistoryCombinator = Meth; + } + + /// sets the predefined method for the combination of the possible Identifiers + /// and the master + /// \param Meth the method which should be used. predefined inside the \c + /// predefinedMethods struct LikelinessFeedbackCombinator() + void setLikelinessFeedbackCombinator( + const std::function( + std::vector, std::vector)> &Meth) noexcept { + LikelinessFeedbackCombinator = Meth; + } + + /// Sets the used combination method for Possible Identifiers + /// \param Meth the method which should be used. predefined inside the \c + /// predefinedMethods struct setReliabilityAndConfidenceCombinator() + void setReliabilityAndConfidenceCombinator( + const std::function( + std::vector, ReliabilityType)> &Meth) noexcept { + ReliabilityAndConfidenceCombinator = Meth; + } + + /// sets the input reliability combinator method + /// \param method the method which should be used. predefined inside the \c + /// predefinedMethods struct combination() + void setAbsoluteAndSlopeReliabilityCombinationMethod( + const std::function + &&method) noexcept { + AbsoluteAndSlopeReliabilityCombinationMethod = method; + } + + // + // ----------------predefined combinators------------------------------------ + // + /// This struct is a pseudo name space to have easier access to all predefined + /// methods while still not overcrowding the class it self + struct predefinedMethods { + /// predefined Method + static ReliabilityType + LikelinessHistoryCombinatorMin(ReliabilityType A, ReliabilityType B) noexcept { + return std::min(A, B); + } + /// predefined Method + static ReliabilityType + LikelinessHistoryCombinatorMax(ReliabilityType A, ReliabilityType B) noexcept { + return std::max(A, B); + } + /// predefined Method + static ReliabilityType + LikelinessHistoryCombinatorMult(ReliabilityType A, ReliabilityType B) noexcept { + return A * B; + } + /// predefined Method + static ReliabilityType + LikelinessHistoryCombinatorAverage(ReliabilityType A, + ReliabilityType B) noexcept { + return (A + B) / 2; + } + + /// predefined method + static std::vector + LikelinessFeedbackCombinatorAverage(std::vector A, + std::vector B) noexcept { + for (auto &tmp_me : A) + for (auto &tmp_other : B) { + if (tmp_me.Identifier == tmp_other.Identifier) { + tmp_me.Likeliness = + (tmp_me.Likeliness + tmp_other.Likeliness) / 2; + } + } + return A; + } + /// predefined method + static std::vector + LikelinessFeedbackCombinatorMin(std::vector A, + std::vector B) noexcept { + for (auto &tmp_me : A) + for (auto &tmp_other : B) { + if (tmp_me.Identifier == tmp_other.Identifier) { + tmp_me.Likeliness = + std::min(tmp_me.Likeliness + tmp_other.Likeliness); + } + } + return A; + } + /// predefined method + static std::vector + LikelinessFeedbackCombinatorMax(std::vector A, + std::vector B) noexcept { + for (auto &tmp_me : A) + for (auto &tmp_other : B) { + if (tmp_me.Identifier == tmp_other.Identifier) { + tmp_me.Likeliness = + std::max(tmp_me.Likeliness + tmp_other.Likeliness); + } + } + return A; + } + /// predefined method + static std::vector + LikelinessFeedbackCombinatorMult(std::vector A, + std::vector B) noexcept { + for (auto &tmp_me : A) + for (auto &tmp_other : B) { + if (tmp_me.Identifier == tmp_other.Identifier) { + tmp_me.Likeliness = tmp_me.Likeliness * tmp_other.Likeliness; + } + } + return A; + } + + /// Predefined combination method for possible Identifiers + static std::vector + ReliabilityAndConfidenceCombinatorMin(std::vector A, + ReliabilityType B) noexcept { + for (auto tmp : A) + tmp.Likeliness = std::min(tmp.Likeliness, B); + return A; + } + /// Predefined combination method for possible Identifiers + static std::vector + ReliabilityAndConfidenceCombinatorMax(std::vector A, + ReliabilityType B) noexcept { + for (auto tmp : A) + tmp.Likeliness = std::max(tmp.Likeliness, B); + return A; + } + + /// Predefined combination method for possible Identifiers + static std::vector + ReliabilityAndConfidenceCombinatorAverage(std::vector A, + ReliabilityType B) noexcept { + for (auto tmp : A) + tmp.Likeliness = (tmp.Likeliness + B) / 2; + return A; + } + + /// Predefined combination method for possible Identifiers + static std::vector + ReliabilityAndConfidenceCombinatorMult(std::vector A, + ReliabilityType B) noexcept { + for (auto tmp : A) + tmp.Likeliness = tmp.Likeliness * B / 2; + return A; + } + + /// The predefined min combinator method + static ReliabilityType combinationMin(ReliabilityType A, + ReliabilityType B) noexcept { + return std::min(A, B); + } + + /// The predefined max combinator method + static ReliabilityType combinationMax(ReliabilityType A, + ReliabilityType B) noexcept { + return std::max(A, B); + } + + /// The predefined average combinator method + static ReliabilityType combinationAverage(ReliabilityType A, + ReliabilityType B) noexcept { + return (A + B) / 2; + } + + /// The predefined average combinator method + static ReliabilityType combinationMult(ReliabilityType A, + ReliabilityType B) noexcept { + return A * B; + } + }; + + // ---------------------------------------------------------------- + // Stored Values + // ---------------------------------------------------------------- +private: + std::vector> History; + std::size_t HistoryMaxSize; + std::vector FeedbackSymbols; + + ValueType previousSensorValue; + unsigned int timeStep; + std::vector Identifiers; + bool PreviousSensorValueExists = false; + + std::shared_ptr< + RangeConfidence> + ConfidenceFunction; + std::shared_ptr> AbsoluteReliabilityFunction; + std::shared_ptr> + ReliabilitySlopeFunction; + std::shared_ptr> TimeFunctionForLikeliness; + + // combination functions + std::function + AbsoluteAndSlopeReliabilityCombinationMethod = predefinedMethods::combinationMin; + + std::function(std::vector, ReliabilityType)> + ReliabilityAndConfidenceCombinator = + predefinedMethods::ReliabilityAndConfidenceCombinatorMin; + + std::function(std::vector, + std::vector)> + LikelinessFeedbackCombinator = + predefinedMethods::LikelinessFeedbackCombinatorAverage; + std::function + LikelinessHistoryCombinator = predefinedMethods::LikelinessHistoryCombinatorMax; + + // --------------------------------------------------------------------------- + // needed Functions + // --------------------------------------------------------------------------- + + /// returns the Reliability + /// \param actualValue The Value of the Sensor + /// \param lastValue of the Sensor this is stored in the class + /// \param _timeStep 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 + /// ReliabilitySlopeFunction if the previous value exists. if it doesn't it only + /// returns the \c Reliability function value. + ReliabilityType getReliability(const ValueType &actualValue, + const ValueType &lastValue, + const unsigned int &_timeStep) noexcept { + ReliabilityType relAbs = AbsoluteReliabilityFunction->operator()(actualValue); + if (PreviousSensorValueExists) { + ReliabilityType relSlo = ReliabilitySlopeFunction->operator()( + (lastValue - actualValue) / (ValueType)_timeStep); + + return AbsoluteAndSlopeReliabilityCombinationMethod(relAbs, relSlo); + } else + return relAbs; + } + + /// adapts the possible Identifiers by checking the History and combines those + /// values. + /// \brief combines the historic values with the \c TimeFunctionForLikeliness function + /// and returns the maximum Reliability for all Identifiers. + std::vector SymbolsFromHistory() noexcept { + // iterate through all history entries + std::size_t posInHistory = 0; + std::vector symbolFromHistory; //History Symbols + for (auto timeStep = History.begin(); timeStep < History.end(); + timeStep++, posInHistory++) { + + // iterate through all possible Identifiers of each history entry + for (Symbol &symbol : *timeStep) { + + IdentifierType historyIdentifier = symbol.Identifier; + ReliabilityType historyConf = symbol.Likeliness; + + historyConf = historyConf * TimeFunctionForLikeliness->operator()(posInHistory); + + bool foundIdentifier = false; + for (Symbol &pS : symbolFromHistory) { + + if (pS.Identifier == historyIdentifier) { + + pS.Likeliness = + LikelinessHistoryCombinator(pS.Likeliness, historyConf); + + foundIdentifier = true; + } + } + + if (foundIdentifier == false) { + + Symbol possibleIdentifier; // Symbol + possibleIdentifier.Identifier = historyIdentifier; + possibleIdentifier.Likeliness = historyConf; + + symbolFromHistory.push_back(possibleIdentifier); + } + } + } + + return symbolFromHistory; + } + + /// saves the Identifiers in the History + /// \brief It checks the incoming Identifiers 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 actualPossibleIdentifiers The Identifiers 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( + const std::vector &actualPossibleIdentifiers) noexcept { // Symbols + + // check if the reliability of at least one possible Identifier is high + // enough + bool atLeastOneRelIsHigh = false; + for (Symbol pS : actualPossibleIdentifiers) { + if (pS.Likeliness > 0.5) { + atLeastOneRelIsHigh = true; + } + } + // save possible Identifiers if at least one possible Identifier is high + // enough (or if the history is empty) + if (History.size() < 1 || atLeastOneRelIsHigh == true) { + History.insert(History.begin(), actualPossibleIdentifiers); + + // if history size is higher than allowed, save oldest element + while (History.size() > HistoryMaxSize) { + // delete possibleIdentifierHistory.back(); + History.pop_back(); + } + } + } +}; + +} // namespace agent +} // namespace rosa +#endif // !ROSA_AGENT_ReliabilityConfidenceCombinator_H diff --git a/lib/agent/CMakeLists.txt b/lib/agent/CMakeLists.txt index d4bdebc..9f887f9 100644 --- a/lib/agent/CMakeLists.txt +++ b/lib/agent/CMakeLists.txt @@ -1,20 +1,22 @@ set(LIB_INCLUDE_DIR ${ROSA_MAIN_INCLUDE_DIR}/rosa/agent) add_library(ROSAAgent ${LIB_INCLUDE_DIR}/namespace.h namespace.cpp ${LIB_INCLUDE_DIR}/Functionality.h Functionality.cpp ${LIB_INCLUDE_DIR}/Abstraction.hpp Abstraction.cpp ${LIB_INCLUDE_DIR}/FunctionAbstractions.hpp FunctionAbstractions.cpp ${LIB_INCLUDE_DIR}/RangeConfidence.hpp RangeConfidence.cpp ${LIB_INCLUDE_DIR}/History.hpp History.cpp ${LIB_INCLUDE_DIR}/Confidence.hpp Confidence.cpp - ${LIB_INCLUDE_DIR}/CrossReliability.h - CrossReliability.cpp + ${LIB_INCLUDE_DIR}/CrossCombinator.h + CrossCombinator.cpp + ${LIB_INCLUDE_DIR}/ReliabilityConfidenceCombinator.h + ReliabilityConfidenceCombinator.cpp ) diff --git a/lib/agent/CrossReliability.cpp b/lib/agent/CrossCombinator.cpp similarity index 69% copy from lib/agent/CrossReliability.cpp copy to lib/agent/CrossCombinator.cpp index 7b3a527..9270ea0 100644 --- a/lib/agent/CrossReliability.cpp +++ b/lib/agent/CrossCombinator.cpp @@ -1,26 +1,26 @@ -//===-- agent/CrossReliability.cpp ------------------------------*- C++ -*-===// +//===-- agent/CrossCombinator.cpp ------------------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// -/// \file agent/CrossReliability.cpp +/// \file agent/CrossCombinator.cpp /// /// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at) /// /// \date 2019 /// -/// \brief Implementation for rosa/agent/CrossReliability.cpp +/// \brief Implementation for rosa/agent/CrossCombinator.cpp /// /// \note Empty implementation, source file here to have a compile database -/// entry for rosa/agent/CrossReliability.h +/// entry for rosa/agent/CrossCombinator.h /// //===----------------------------------------------------------------------===// -#include "rosa/agent/CrossReliability.h" +#include "rosa/agent/CrossCombinator.h" diff --git a/lib/agent/CrossReliability.cpp b/lib/agent/ReliabilityConfidenceCombinator.cpp similarity index 67% rename from lib/agent/CrossReliability.cpp rename to lib/agent/ReliabilityConfidenceCombinator.cpp index 7b3a527..ca5daa9 100644 --- a/lib/agent/CrossReliability.cpp +++ b/lib/agent/ReliabilityConfidenceCombinator.cpp @@ -1,26 +1,26 @@ -//===-- agent/CrossReliability.cpp ------------------------------*- C++ -*-===// +//===-- agent/Reliability.cpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// -/// \file agent/CrossReliability.cpp +/// \file agent/ReliabilityConfidenceCombinator.cpp /// /// \author Daniel Schnoell (daniel.schnoell@tuwien.ac.at) /// /// \date 2019 /// -/// \brief Implementation for rosa/agent/CrossReliability.cpp +/// \brief Implementation for rosa/agent/ReliabilityConfidenceCombinator.h /// /// \note Empty implementation, source file here to have a compile database -/// entry for rosa/agent/CrossReliability.h +/// entry for rosa/agent/ReliabilityConfidenceCombinator.h /// //===----------------------------------------------------------------------===// -#include "rosa/agent/CrossReliability.h" +#include "rosa/agent/ReliabilityConfidenceCombinator.h"