diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp index 91db629..b8d7a38 100644 --- a/apps/ccam/ccam.cpp +++ b/apps/ccam/ccam.cpp @@ -1,296 +1,292 @@ //===-- apps/ccam/ccam.cpp --------------------------------------*- C++ -*-===// // // The RoSA Framework -- Application CCAM // //===----------------------------------------------------------------------===// /// /// \file apps/ccam/ccam.cpp /// /// \author Maximilian Goetzinger (maximilian.goetzinger@tuwien.ac.at) /// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at) /// /// \date 2019 /// /// \brief The application CCAM implements the case study from the paper: /// M. Goetzinger, N. TaheriNejad, H. A. Kholerdi, A. Jantsch, E. Willegger, /// T. Glatzl, A.M. Rahmani, T.Sauter, P. Liljeberg: Model - Free Condition /// Monitoring with Confidence //===----------------------------------------------------------------------===// #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/deluxe/DeluxeContext.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include #include #include #include #include "configuration.h" #include "statehandlerutils.h" using namespace rosa; using namespace rosa::agent; using namespace rosa::deluxe; using namespace rosa::terminal; const std::string AppName = "CCAM"; int main(int argc, char **argv) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << AppName << "app" << Color::Default << '\n'; if (argc < 2) { LOG_ERROR("Specify config File!\nUsage:\n\tccam config.json"); return 1; } std::string ConfigPath = argv[1]; if (!readConfigFile(ConfigPath)) { LOG_ERROR_STREAM << "Could not read config from \"" << ConfigPath << "\"\n"; return 2; } std::string InputFilePath, OutputFilePath; LOG_INFO("Creating Context"); std::unique_ptr C = DeluxeContext::create(AppName); std::shared_ptr> BrokenDelayFunction( new PartialFunction( {{{0, AppConfig.BrokenCounter}, std::make_shared>( 0, 0.f, AppConfig.BrokenCounter, 1.f)}, {{AppConfig.BrokenCounter, std::numeric_limits::max()}, std::make_shared>(1.f, 0.f)}}, 0.f)); std::shared_ptr> OkDelayFunction( new PartialFunction( {{{0, AppConfig.BrokenCounter}, std::make_shared>( 0, 1.f, AppConfig.BrokenCounter, 0.f)}, {{AppConfig.BrokenCounter, std::numeric_limits::max()}, std::make_shared>(0.f, 0.f)}}, 1.f)); // // Create a DeluxeAgent with SystemStateDetector functionality. // LOG_INFO("Create SystemStateDetector agent."); AgentHandle SystemStateDetectorAgent = createSystemStateDetectorAgent( C, "SystemStateDetector", AppConfig.SignalConfigurations.size(), BrokenDelayFunction, OkDelayFunction); C->setExecutionPolicy(SystemStateDetectorAgent, DeluxeExecutionPolicy::awaitAll({})); LOG_INFO("Creating sensors, SignalStateDetector functionalities and their " "Abstractions."); std::vector Sensors; std::vector>> SampleMatchesFunctions; std::vector>> SampleMismatchesFunctions; std::vector>> SignalIsStableFunctions; std::vector>> SignalIsDriftingFunctions; std::vector>> NumOfSamplesMatchFunctions; std::vector>> NumOfSamplesMismatchFunctions; std::vector>> SignalStateDetectors; std::vector SignalStateDetectorAgents; for (auto SignalConfiguration : AppConfig.SignalConfigurations) { // // Create deluxe sensors. // Sensors.emplace_back(C->createSensor(SignalConfiguration.Name)); - C->setExecutionPolicy(Sensors.back(), DeluxeExecutionPolicy::decimation(1)); // // Create functionalities for SignalStateDetector. // SampleMatchesFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 0.f, -SignalConfiguration.InnerBound, 1.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 1.f, SignalConfiguration.OuterBound, 0.f)}, }, 0)); SampleMismatchesFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 1.f, -SignalConfiguration.InnerBound, 0.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 0.f, SignalConfiguration.OuterBound, 1.f)}, }, 1)); SignalIsStableFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared>( -SignalConfiguration.OuterBoundDrift, 0.f, -SignalConfiguration.InnerBoundDrift, 1.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared>( SignalConfiguration.InnerBoundDrift, 1.f, SignalConfiguration.OuterBoundDrift, 0.f)}, }, 0)); SignalIsDriftingFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared>( -SignalConfiguration.OuterBoundDrift, 1.f, -SignalConfiguration.InnerBoundDrift, 0.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared>( SignalConfiguration.InnerBoundDrift, 0.f, SignalConfiguration.OuterBoundDrift, 1.f)}, }, 1)); NumOfSamplesMatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); NumOfSamplesMismatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); // // Create SignalStateDetector functionality // SignalStateDetectors.emplace_back( new SignalStateDetector( SignalConfiguration.Output ? SignalProperties::OUTPUT : SignalProperties::INPUT, std::numeric_limits::max(), SampleMatchesFunctions.back(), SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(), NumOfSamplesMismatchFunctions.back(), SignalIsDriftingFunctions.back(), SignalIsStableFunctions.back(), SignalConfiguration.SampleHistorySize, SignalConfiguration.DABSize, SignalConfiguration.DABHistorySize)); // // Create low-level deluxe agents // SignalStateDetectorAgents.push_back(createSignalStateDetectorAgent( C, SignalConfiguration.Name, SignalStateDetectors.back())); - C->setExecutionPolicy(SignalStateDetectorAgents.back(), - DeluxeExecutionPolicy::awaitAny({})); // - // Connect sensors to low-level agents. + // Open CSV files and register them for their corresponding sensors. // - LOG_INFO("Connect sensors to their corresponding low-level agents."); - - C->connectSensor(SignalStateDetectorAgents.back(), 0, Sensors.back(), - SignalConfiguration.Name); - - C->connectAgents(SystemStateDetectorAgent, SignalStateDetectors.size() - 1, - SignalStateDetectorAgents.back(), - SignalConfiguration.Name); - std::ifstream SensorData(SignalConfiguration.InputPath); if (!SensorData) { LOG_ERROR_STREAM << "Cannot open Input File \"" << SignalConfiguration.InputPath << "\" for Signal \"" << SignalConfiguration.Name << "\"" << std::endl; return 3; } C->registerSensorValues(Sensors.back(), csv::CSVIterator(SensorData), csv::CSVIterator()); + + // + // Connect sensors to low-level agents. + // + LOG_INFO("Connect sensors to their corresponding low-level agents."); + + C->connectSensor(SignalStateDetectorAgents.back(), 0, Sensors.back(), + SignalConfiguration.Name); + + C->connectAgents(SystemStateDetectorAgent, SignalStateDetectors.size() - 1, + SignalStateDetectorAgents.back(), + SignalConfiguration.Name); } // // For simulation output, create a logger agent writing the output of the // high-level agent into a CSV file. // LOG_INFO("Create a logger agent."); // Create CSV writer. std::ofstream OutputCSV(AppConfig.OutputFilePath); // The agent writes each new input value into a CSV file and produces nothing. using Input = std::pair; using Result = Optional>; using Handler = std::function; std::string Name = "Logger Agent"; AgentHandle LoggerAgent = C->createAgent("Logger Agent", Handler([&OutputCSV](Input I) -> Result { OutputCSV << std::get<0>(I.first) << std::endl; return Result(); })); C->setExecutionPolicy(LoggerAgent, DeluxeExecutionPolicy::awaitAny({})); // // Connect the high-level agent to the logger agent. // LOG_INFO("Connect the high-level agent to the logger agent."); C->connectAgents(LoggerAgent, 0, SystemStateDetectorAgent, "SystemStateDetector Channel"); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize deluxe context for simulation. // C->initializeSimulation(); - // - // Open CSV files and register them for their corresponding sensors. - // - // // Simulate. // C->simulate(AppConfig.NumberOfSimulationCycles); return 0; } diff --git a/apps/ccam/sample_data/.~lock.in1.csv# b/apps/ccam/sample_data/.~lock.in1.csv# new file mode 100644 index 0000000..b94dc35 --- /dev/null +++ b/apps/ccam/sample_data/.~lock.in1.csv# @@ -0,0 +1 @@ +,benedikt,pc80-73.ICT.TUWIEN.AC.AT,11.07.2019 16:59,file:///home/benedikt/.config/libreoffice/4; \ No newline at end of file diff --git a/apps/ccam/sample_data/in1.csv b/apps/ccam/sample_data/in1.csv new file mode 100644 index 0000000..591c18c --- /dev/null +++ b/apps/ccam/sample_data/in1.csv @@ -0,0 +1,99 @@ +1.00092637855679 +1.0684190878191 +1.02810801913231 +0.919000276724945 +0.943251565157285 +1.0673083821227 +1.00478806202118 +1.03003739351774 +0.935803555791724 +0.915115988597241 +0.993705530463948 +1.01913848981603 +1.07575850547493 +1.09434496551336 +1.07517203808885 +0.934186505165392 +1.03597552982793 +0.946414558921609 +1.09077619397548 +0.937422306881499 +1.04025759458117 +0.953766068948048 +1.0220146735354 +0.945386311036124 +1.06874654600219 +1.08189482835294 +1.09471327339474 +0.997766816782878 +1.08249052586382 +0.980897423629193 +0.912525216564887 +1.01372830088446 +1.06301100164778 +0.954611398899798 +1.08882613398729 +0.929102332430527 +0.922853868564958 +0.916169223719992 +1.07542926597468 +0.952682775112019 +0.946923126637042 +1.02533001563823 +0.98000162285915 +0.943330241903967 +1.05670630068715 +1.00785095967723 +1.05878566260128 +1.08556887596959 +1.01674529482655 +0.961273507450319 +1.03264674265977 +1.06062171515438 +1.04551666887125 +1.08410951161761 +1.08402421925395 +0.987534405747127 +0.923876174437775 +0.972287310336838 +1.08312955950651 +0.985578427054398 +1.03558369622544 +1.04101672999734 +0.99352383758243 +0.99410500366067 +0.971399086444277 +0.925045641664989 +1.02935253874119 +1.00157578979235 +1.07471412992712 +1.07472627148258 +1.08713981155546 +1.00727502532395 +1.0280458178824 +0.93407010413228 +1.0037114548083 +1.00187148446296 +0.925961212840559 +1.07202022825656 +1.01071793991323 +1.0306490880833 +1.07436163529235 +0.95425466535745 +1.07385916085333 +0.92467285584664 +0.919083994601565 +1.05389817205938 +1.0945513132114 +0.929475954301933 +1.08572986354845 +1.06115342260273 +1.07016495486098 +1.03483066490236 +1.0282067965835 +1.04321565497961 +0.980982509875021 +0.923315546975167 +1.00066500619371 +1.07205423410099 +0.996924126125663 diff --git a/apps/ccam/sample_data/out.csv b/apps/ccam/sample_data/out.csv new file mode 100644 index 0000000..e69de29 diff --git a/apps/ccam/sample_data/sample_config.json b/apps/ccam/sample_data/sample_config.json new file mode 100644 index 0000000..bb2d3f9 --- /dev/null +++ b/apps/ccam/sample_data/sample_config.json @@ -0,0 +1,20 @@ +{ + "OutputFilePath": "./out.csv", + "BrokenCounter": 10, + "NumberOfSimulationCycles": 100, + "SignalConfigurations": + [ + { + "Name" : "Sig1", + "InputPath" : "./in1.csv", + "Output" : false, + "InnerBound" : 0.1, + "OuterBound" : 0.2, + "InnerBoundDrift" : 0.3, + "OuterBoundDrift" : 0.4, + "SampleHistorySize" : 10, + "DABSize" : 10, + "DABHistorySize" : 5 + } + ] +} diff --git a/apps/ccam/statehandlerutils.h b/apps/ccam/statehandlerutils.h index fb7b640..b95c737 100644 --- a/apps/ccam/statehandlerutils.h +++ b/apps/ccam/statehandlerutils.h @@ -1,184 +1,223 @@ #ifndef STATEHANDLERUTILS_H #define STATEHANDLERUTILS_H #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include #include #include #include #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/deluxe/DeluxeContext.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include #include #include #include using namespace rosa; using namespace rosa::agent; using namespace rosa::deluxe; using namespace rosa::terminal; // Signal State using SignalStateTuple = DeluxeTuple; AgentHandle createSignalStateDetectorAgent( std::unique_ptr &C, const std::string &Name, std::shared_ptr< SignalStateDetector> SigSD) { using Input = std::pair, bool>; using Result = Optional; using Handler = std::function; return C->createAgent( Name, Handler([&Name, &SigSD](Input I) -> Result { LOG_INFO_STREAM << "\n******\n" << Name << " " << (I.second ? "" : "") << " value: " << std::get<0>(I.first) << "\n******\n"; auto StateInfo = SigSD->detectSignalState(std::get<0>(I.first)); if (I.second) { SignalStateTuple Res = { std::get<0>(I.first), StateInfo.StateID, StateInfo.SignalProperty, //@benedikt: I changed this // StateInfo.SignalStateConfidence, StateInfo.ConfidenceOfMatchingState, StateInfo.ConfidenceOfMismatchingState, StateInfo.ConfidenceStateIsValid, StateInfo.ConfidenceStateIsInvalid, StateInfo.ConfidenceStateIsStable, StateInfo.ConfidenceStateIsDrifting, StateInfo.StateCondition, StateInfo.NumberOfInsertedSamplesAfterEntrance, (uint8_t)((StateInfo.StateIsValid ? 4 : 0) + (StateInfo.StateJustGotValid ? 2 : 0) + (StateInfo.StateIsValidAfterReentrance ? 1 : 0))}; return Result(Res); } return Result(); })); } // System State - -using SystemStateTuple = DeluxeTuple; +using SystemStateTuple = DeluxeTuple; template struct Handler_helper; template struct function_helper { static_assert(std::conjunction_v...>, "All types need to be identical"); static B function(A valA, As... valAs) { std::vector ar({valA, valAs...}); return func()(ar); } }; template struct Handler_helper<0, ret, functype, typeA, B...> { using handler = function_helper; }; template struct Handler_helper { using handler = typename Handler_helper, B...>::handler; }; template using Handler = typename Handler_helper::handler; +// TODO: This is UGLY! +std::shared_ptr< + SystemStateDetector> + SysSD; + // todo: state-detector durschleifen template struct function { + ret operator()(A a) { - // std::vector out; - for (auto tmp1 : a) { + std::vector> SignalStateInfos; + std::stringstream OutString; + + for (auto _SignalStateTuple : a) { // convert tuple to info struct out.push_back({}); - (void)tmp1; - LOG_INFO_STREAM << "new SignalStateTuple!\n"; + OutString << std::get<0>(_SignalStateTuple.first) << ","; + SignalStateInformation Info; + Info.StateID = std::get<1>(_SignalStateTuple.first); + Info.SignalProperty = + static_cast(std::get<2>(_SignalStateTuple.first)); + Info.ConfidenceOfMatchingState = std::get<3>(_SignalStateTuple.first); + Info.ConfidenceOfMismatchingState = std::get<4>(_SignalStateTuple.first); + Info.ConfidenceStateIsValid = std::get<5>(_SignalStateTuple.first); + Info.ConfidenceStateIsInvalid = std::get<6>(_SignalStateTuple.first); + Info.ConfidenceStateIsStable = std::get<7>(_SignalStateTuple.first); + Info.ConfidenceStateIsDrifting = std::get<8>(_SignalStateTuple.first); + Info.StateCondition = + static_cast(std::get<9>(_SignalStateTuple.first)); + Info.NumberOfInsertedSamplesAfterEntrance = + std::get<10>(_SignalStateTuple.first); + Info.StateIsValid = (std::get<11>(_SignalStateTuple.first) & 4) > 0; + Info.StateJustGotValid = (std::get<11>(_SignalStateTuple.first) & 2) > 0; + Info.StateIsValidAfterReentrance = + (std::get<11>(_SignalStateTuple.first) & 1) > 0; + SignalStateInfos.push_back(Info); } - // feed state detector - // return result - return ret(); + SystemStateInformation SystemStateInfo = + SysSD->detectSystemState(SignalStateInfos); + + OutString << SystemStateInfo.StateID << ","; + OutString << SystemStateInfo.ConfidenceStateIsValid << ","; + OutString << SystemStateInfo.ConfidenceStateIsInvalid << ","; + OutString << SystemStateInfo.ConfidenceOfInputsMatchingState << ","; + OutString << SystemStateInfo.ConfidenceOfInputsMismatchingState << ","; + OutString << SystemStateInfo.ConfidenceOfOutputsMatchingState << ","; + OutString << SystemStateInfo.ConfidenceOfOutputsMismatchingState << ","; + OutString << SystemStateInfo.StateCondition << ","; + OutString << SystemStateInfo.ConfidenceSystemIsFunctioning << ","; + OutString << SystemStateInfo.ConfidenceSystemIsMalfunctioning << ","; + OutString << SystemStateInfo.ConfidenceOfAllDecisions << ","; + + return ret(std::make_tuple(OutString.str())); } }; using arr = std::vector>; template AgentHandle createSystemStateDetectorAgent( std::unique_ptr &C, const std::string &Name, std::shared_ptr> BrokenDelayFunction, std::shared_ptr> OkDelayFunction) { LOG_TRACE("Creating fixed SystemStateDetectorAgent"); using Input = SignalStateTuple; using Result = Optional; - auto HandlerFunction = - Handler, arr>, - Input>::function; std::shared_ptr< SystemStateDetector> - SysSD(new SystemStateDetector( + _SysSD(new SystemStateDetector( std::numeric_limits::max(), NumOfSlaves, BrokenDelayFunction, OkDelayFunction)); + SysSD = _SysSD; + + auto HandlerFunction = + Handler, arr>, + Input>::function; return C->createAgent(Name, std::function(HandlerFunction)); } AgentHandle createSystemStateDetectorAgent( std::unique_ptr &C, const std::string &Name, size_t NumOfSlaves, std::shared_ptr> BrokenDelayFunction, std::shared_ptr> OkDelayFunction) { LOG_TRACE("Creating dynamic SystemStateDetectorAgent"); switch (NumOfSlaves) { // clang-format off case 2: return createSystemStateDetectorAgent< 2>(C, Name, BrokenDelayFunction, OkDelayFunction); case 3: return createSystemStateDetectorAgent< 3>(C, Name, BrokenDelayFunction, OkDelayFunction); case 4: return createSystemStateDetectorAgent< 4>(C, Name, BrokenDelayFunction, OkDelayFunction); case 5: return createSystemStateDetectorAgent< 5>(C, Name, BrokenDelayFunction, OkDelayFunction); case 6: return createSystemStateDetectorAgent< 6>(C, Name, BrokenDelayFunction, OkDelayFunction); case 7: return createSystemStateDetectorAgent< 7>(C, Name, BrokenDelayFunction, OkDelayFunction); case 8: return createSystemStateDetectorAgent< 8>(C, Name, BrokenDelayFunction, OkDelayFunction); case 9: return createSystemStateDetectorAgent< 9>(C, Name, BrokenDelayFunction, OkDelayFunction); case 10: return createSystemStateDetectorAgent<10>(C, Name, BrokenDelayFunction, OkDelayFunction); case 11: return createSystemStateDetectorAgent<11>(C, Name, BrokenDelayFunction, OkDelayFunction); case 12: return createSystemStateDetectorAgent<12>(C, Name, BrokenDelayFunction, OkDelayFunction); case 13: return createSystemStateDetectorAgent<13>(C, Name, BrokenDelayFunction, OkDelayFunction); case 14: return createSystemStateDetectorAgent<14>(C, Name, BrokenDelayFunction, OkDelayFunction); case 15: return createSystemStateDetectorAgent<15>(C, Name, BrokenDelayFunction, OkDelayFunction); case 16: return createSystemStateDetectorAgent<16>(C, Name, BrokenDelayFunction, OkDelayFunction); case 17: return createSystemStateDetectorAgent<17>(C, Name, BrokenDelayFunction, OkDelayFunction); case 18: return createSystemStateDetectorAgent<18>(C, Name, BrokenDelayFunction, OkDelayFunction); case 19: return createSystemStateDetectorAgent<19>(C, Name, BrokenDelayFunction, OkDelayFunction); case 20: return createSystemStateDetectorAgent<20>(C, Name, BrokenDelayFunction, OkDelayFunction); case 21: return createSystemStateDetectorAgent<21>(C, Name, BrokenDelayFunction, OkDelayFunction); case 22: return createSystemStateDetectorAgent<22>(C, Name, BrokenDelayFunction, OkDelayFunction); case 23: return createSystemStateDetectorAgent<23>(C, Name, BrokenDelayFunction, OkDelayFunction); case 24: return createSystemStateDetectorAgent<24>(C, Name, BrokenDelayFunction, OkDelayFunction); case 25: return createSystemStateDetectorAgent<25>(C, Name, BrokenDelayFunction, OkDelayFunction); case 1: default: return createSystemStateDetectorAgent<1>(C, Name, BrokenDelayFunction, OkDelayFunction); // clang-format on } } #endif // STATEHANDLERUTILS_H diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index ff09a42..9b86769 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,479 +1,481 @@ //===-- rosa/agent/SignalState.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SignalState.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *signal state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SIGNALSTATE_HPP #define ROSA_AGENT_SIGNALSTATE_HPP #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/History.hpp" #include "rosa/agent/State.hpp" #include "rosa/support/math.hpp" namespace rosa { namespace agent { /// Signal properties defining the properties of the signal which is monitored /// by \c rosa::agent::SignalStateDetector and is saved in \c /// rosa::agent::SignalStateInformation. enum SignalProperties : uint8_t { INPUT = 0, ///< The signal is an input signal OUTPUT = 1 ///< The signal is an output signal }; /// TODO: write description template struct SignalStateInformation : StateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// TODO: describe CONFDATATYPE ConfidenceOfMatchingState; CONFDATATYPE ConfidenceOfMismatchingState; /// The SignalProperty saves whether the monitored signal is an input our /// output signal. SignalProperties SignalProperty; /// The SignalStateIsValid saves the number of samples which have been /// inserted into the state after entering it. uint32_t NumberOfInsertedSamplesAfterEntrance; public: SignalStateInformation(unsigned int SignalStateID, SignalProperties _SignalProperty) { this->StateID = SignalStateID; this->SignalProperty = _SignalProperty; this->StateCondition = StateConditions::UNKNOWN; this->StateIsValid = false; this->StateJustGotValid = false; this->StateIsValidAfterReentrance = false; this->ConfidenceStateIsValid = 0; this->ConfidenceStateIsInvalid = 0; this->ConfidenceStateIsStable = 0; this->ConfidenceStateIsDrifting = 0; } + + SignalStateInformation() {} }; /// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of /// data in that the confidence values are given, \tparam PROCDATATYPE type of /// the relative distance and the type of data in which DABs are saved. template class SignalState : public Functionality { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "input data type not arithmetic"); STATIC_ASSERT((std::is_arithmetic::value), "confidence data type is not to arithmetic"); STATIC_ASSERT( (std::is_arithmetic::value), "process data type (DAB and Relative Distance) is not to arithmetic"); public: // For the convinience to write a shorter data type name using PartFuncReference = PartialFunction &; using StepFuncReference = StepFunction &; private: /// SignalStateInfo is a struct of SignalStateInformation that contains /// information about the current signal state. SignalStateInformation SignalStateInfo; /// The FuzzyFunctionSampleMatches is the fuzzy function that gives the /// confidence how good the new sample matches another sample in the sample /// history. PartFuncReference FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. PartFuncReference FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. StepFuncReference FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sampe history mismatch the new /// sample. StepFuncReference FuzzyFunctionNumOfSamplesMismatches; /// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is drifting. PartFuncReference FuzzyFunctionSignalIsDrifting; /// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is stable (not drifting). PartFuncReference FuzzyFunctionSignalIsStable; /// SampleHistory is a history in that the last sample values are stored. DynamicLengthHistory SampleHistory; /// DAB is a (usually) small history of the last sample values of which a /// average is calculated if the DAB is full. DynamicLengthHistory DAB; /// DABHistory is a history in that the last DABs (to be exact, the averages /// of the last DABs) are stored. DynamicLengthHistory DABHistory; /// LowestConfidenceMatchingHistory is a history in that the lowest confidence /// for the current sample matches all history samples are saved. DynamicLengthHistory LowestConfidenceMatchingHistory; /// HighestConfidenceMatchingHistory is a history in that the highest /// confidence for the current sample matches all history samples are saved. DynamicLengthHistory HighestConfidenceMismatchingHistory; //@benedikt: neu (passt das so?) CONFDATATYPE TempConfidenceMatching; CONFDATATYPE TempConfidenceMismatching; public: /// Creates an instance by setting all parameters /// \param SignalStateID The Id of the SignalStateinfo \c /// SignalStateInformation. /// /// \param FuzzyFunctionSampleMatches The FuzzyFunctionSampleMatches is the /// fuzzy function that gives the confidence how good the new sample matches /// another sample in the sample history. /// /// \param FuzzyFunctionSampleMismatches The FuzzyFunctionSampleMismatches is /// the fuzzy function that gives the confidence how bad the new sample /// matches another sample in the sample history. /// /// \param FuzzyFunctionNumOfSamplesMatches The /// FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. /// /// \param FuzzyFunctionNumOfSamplesMismatches The /// FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives the /// confidence how many samples from the sampe history mismatch the new /// sample. /// /// \param FuzzyFunctionSignalIsDrifting The FuzzyFunctionSignalIsDrifting is /// the fuzzy function that gives the confidence how likely it is that the /// signal (resp. the state of a signal) is drifting. /// /// \param FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the /// fuzzy function that gives the confidence how likely it is that the signal /// (resp. the state of a signal) is stable (not drifting). /// /// \param SampleHistorySize Size of the Sample History \c /// DynamicLengthHistory . SampleHistory is a history in that the last sample /// values are stored. /// /// \param DABSize Size of DAB \c DynamicLengthHistory . DAB is a (usually) /// small history of the last sample values of which a average is calculated /// if the DAB is full. /// /// \param DABHistorySize Size of the DABHistory \c DynamicLengthHistory . /// DABHistory is a history in that the last DABs (to be exact, the averages /// of the last DABs) are stored. /// SignalState(uint32_t SignalStateID, SignalProperties SignalProperty, uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize, PartFuncReference FuzzyFunctionSampleMatches, PartFuncReference FuzzyFunctionSampleMismatches, StepFuncReference FuzzyFunctionNumOfSamplesMatches, StepFuncReference FuzzyFunctionNumOfSamplesMismatches, PartFuncReference FuzzyFunctionSignalIsDrifting, PartFuncReference FuzzyFunctionSignalIsStable) noexcept : //@benedikt/@david: I don't know if i am allowed to initialize it like // that because the struct is a derivate of another struct SignalStateInfo{SignalStateID, SignalProperty}, FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), SampleHistory(SampleHistorySize), DAB(DABSize), DABHistory(DABHistorySize), LowestConfidenceMatchingHistory(SampleHistorySize), HighestConfidenceMismatchingHistory(SampleHistorySize) {} /// Destroys \p this object. ~SignalState(void) = default; void leaveSignalState(void) noexcept { DAB.clear(); SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0; SignalStateInfo.StateIsValidAfterReentrance = false; } SignalStateInformation insertSample(INDATATYPE Sample) noexcept { SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++; validateSignalState(Sample); SampleHistory.addEntry(Sample); DAB.addEntry(Sample); if (DAB.full()) { PROCDATATYPE AvgOfDAB = DAB.template average(); DABHistory.addEntry(AvgOfDAB); DAB.clear(); } FuzzyFunctionNumOfSamplesMatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); FuzzyFunctionNumOfSamplesMismatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); checkSignalStability(); //@benedikt (das gehört dazu) SignalStateInfo.ConfidenceOfMatchingState = TempConfidenceMatching; SignalStateInfo.ConfidenceOfMismatchingState = TempConfidenceMismatching; return SignalStateInfo; } /// Gives the confidence how likely the new sample matches the signal state. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the confidence of the new sample is matching the signal state. CONFDATATYPE confidenceSampleMatchesSignalState(INDATATYPE Sample) noexcept { CONFDATATYPE ConfidenceOfBestCase = 0; DynamicLengthHistory RelativeDistanceHistory(SampleHistory.maxLength()); // calculate distances to all history samples for (auto &HistorySample : SampleHistory) { PROCDATATYPE RelativeDistance = relativeDistance(Sample, HistorySample); RelativeDistanceHistory.addEntry(RelativeDistance); } // sort all calculated distances so that the lowest distance (will get the // highest confidence) is at the beginning. RelativeDistanceHistory.sortAscending(); CONFDATATYPE ConfidenceOfWorstFittingSample = 1; // Case 1 means that one (the best fitting) sample of the history is // compared with the new sample. Case 2 means the two best history samples // are compared with the new sample. And so on. // TODO (future): to accelerate . don't start with 1 start with some higher // number because a low number (i guess lower than 5) will definetely lead // to a low confidence. except the history is not full. // // Case 1 means that one (the best fitting) sample of the history is // compared with the new sample. Case 2 means the two best history samples // are compared with the new sample. And so on. for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { // TODO (future) if fuzzy is defined in a way that infinity is not 0 it // would be a problem ConfidenceFromRelativeDistance = 0; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMatches(RelativeDistanceHistory[Case]); } ConfidenceOfWorstFittingSample = fuzzyAND(ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance); ConfidenceOfBestCase = fuzzyOR(ConfidenceOfBestCase, fuzzyAND(ConfidenceOfWorstFittingSample, FuzzyFunctionNumOfSamplesMatches( static_cast(Case) + 1))); } //@benedikt (das gehört dazu) TempConfidenceMatching = ConfidenceOfBestCase; return ConfidenceOfBestCase; } /// Gives the confidence how likely the new sample mismatches the signal /// state. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the confidence of the new sample is mismatching the signal state. CONFDATATYPE confidenceSampleMismatchesSignalState(INDATATYPE Sample) noexcept { float ConfidenceOfWorstCase = 1; DynamicLengthHistory RelativeDistanceHistory(SampleHistory.maxLength()); // calculate distances to all history samples for (auto &HistorySample : SampleHistory) { RelativeDistanceHistory.addEntry( relativeDistance(Sample, HistorySample)); } // sort all calculated distances so that the highest distance (will get the // lowest confidence) is at the beginning. RelativeDistanceHistory.sortDescending(); CONFDATATYPE ConfidenceOfBestFittingSample = 0; // TODO (future): to accelerate -> don't go until end. Confidences will only // get higher. See comment in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)". // // Case 1 means that one (the worst fitting) sample of the history is // compared with the new sample. Case 2 means the two worst history samples // are compared with the new sample. And so on. for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { ConfidenceFromRelativeDistance = 1; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMismatches(RelativeDistanceHistory[Case]); } ConfidenceOfBestFittingSample = fuzzyOR(ConfidenceOfBestFittingSample, ConfidenceFromRelativeDistance); ConfidenceOfWorstCase = fuzzyAND(ConfidenceOfWorstCase, fuzzyOR(ConfidenceOfBestFittingSample, FuzzyFunctionNumOfSamplesMismatches( static_cast(Case) + 1))); } //@benedikt (das gehört dazu) TempConfidenceMismatching = ConfidenceOfWorstCase; return ConfidenceOfWorstCase; } /// Gives information about the current signal state. /// /// \return a struct SignalStateInformation that contains information about /// the current signal state. SignalStateInformation signalStateInformation(void) noexcept { return SignalStateInfo; } private: void validateSignalState(INDATATYPE Sample) { // TODO (future): WorstConfidenceDistance and BestConfidenceDistance could // be set already in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)" and "CONFDATATYPE // confidenceSampleMismatchesSignalState(INDATATYPE Sample)" when the new // sample is compared to all history samples. This would save a lot time // because the comparisons are done only once. However, it has to be asured // that the these two functions are called before the insertation, and the // FuzzyFunctions for validation and matching have to be the same! CONFDATATYPE LowestConfidenceMatching = 1; CONFDATATYPE HighestConfidenceMismatching = 0; for (auto &HistorySample : SampleHistory) { // TODO (future): think about using different fuzzy functions for // validation and matching. LowestConfidenceMatching = fuzzyAND( LowestConfidenceMatching, FuzzyFunctionSampleMatches(relativeDistance( Sample, HistorySample))); HighestConfidenceMismatching = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionSampleMismatches( relativeDistance( Sample, HistorySample))); } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); SignalStateInfo.ConfidenceStateIsValid = fuzzyAND(LowestConfidenceMatching, FuzzyFunctionNumOfSamplesMatches(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); SignalStateInfo.ConfidenceStateIsInvalid = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionNumOfSamplesMismatches(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); if (SignalStateInfo.ConfidenceStateIsValid > SignalStateInfo.ConfidenceStateIsInvalid) { if (SignalStateInfo.StateIsValid) { SignalStateInfo.StateJustGotValid = false; } else { SignalStateInfo.StateJustGotValid = true; } SignalStateInfo.StateIsValid = true; SignalStateInfo.StateIsValidAfterReentrance = true; } } void checkSignalStability(void) { if (DABHistory.numberOfEntries() >= 2) { SignalStateInfo.ConfidenceStateIsStable = FuzzyFunctionSignalIsStable( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); SignalStateInfo.ConfidenceStateIsDrifting = FuzzyFunctionSignalIsDrifting( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); } else { // @benedikt: I do not know if this "initializing" is the best, but I // think it makes sense because we do not know if it is stable or // drifting. SignalStateInfo.ConfidenceStateIsStable = 0; SignalStateInfo.ConfidenceStateIsDrifting = 0; } //@benedikt: before it was "ConfidenceSignalIsStable >= // ConfidenceSignalIsDrifting" -> stable. However, I think like that it // makes // more sense. What do you mean? if (SignalStateInfo.ConfidenceStateIsStable > SignalStateInfo.ConfidenceStateIsDrifting) { SignalStateInfo.StateCondition = StateConditions::STABLE; } else if (SignalStateInfo.ConfidenceStateIsStable < SignalStateInfo.ConfidenceStateIsDrifting) { SignalStateInfo.StateCondition = StateConditions::DRIFTING; } else { SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP diff --git a/include/rosa/agent/SystemState.hpp b/include/rosa/agent/SystemState.hpp index 07841e0..34e52b7 100644 --- a/include/rosa/agent/SystemState.hpp +++ b/include/rosa/agent/SystemState.hpp @@ -1,272 +1,283 @@ //===-- rosa/agent/SystemState.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SystemState.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *system state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SYSTEMSTATE_HPP #define ROSA_AGENT_SYSTEMSTATE_HPP #include "rosa/agent/Functionality.h" #include "rosa/agent/SignalState.hpp" #include "rosa/agent/State.hpp" #include "rosa/support/debug.hpp" #include namespace rosa { namespace agent { enum class SystemStateRelation : uint8_t { STATEISMATCHING = 0, ///< The system state is matching ONLYINPUTISMATCHING = 1, ///< Only inputs of the system state are matching ONLYOUTPUTISMATCHING = 2, ///< Only outputs of the system state are matching STATEISMISMATCHING = 3 ///< The system state is mismatching }; /// TODO: write description template struct SystemStateInformation : StateInformation { /// TODO: describe CONFDATATYPE ConfidenceOfInputsMatchingState; CONFDATATYPE ConfidenceOfInputsMismatchingState; CONFDATATYPE ConfidenceOfOutputsMatchingState; CONFDATATYPE ConfidenceOfOutputsMismatchingState; CONFDATATYPE ConfidenceSystemIsFunctioning; CONFDATATYPE ConfidenceSystemIsMalfunctioning; CONFDATATYPE ConfidenceOfAllDecisions; + +public: + SystemStateInformation() {} + + SystemStateInformation(unsigned int _SystemStateID, + StateConditions _StateCondition) { + this->StateID = _SystemStateID; + this->StateCondition = _StateCondition; + this->StateIsValid = false; + this->StateJustGotValid = false; + this->StateIsValidAfterReentrance = false; + this->ConfidenceOfInputsMatchingState = 0; + this->ConfidenceOfInputsMismatchingState = 0; + this->ConfidenceOfOutputsMatchingState = 0; + this->ConfidenceOfOutputsMismatchingState = 0; + this->ConfidenceSystemIsFunctioning = 0; + this->ConfidenceSystemIsMalfunctioning = 0; + this->ConfidenceOfAllDecisions = 0; + } }; // todo: do we need PROCDATATYPE? /// TODO TEXT template class SystemState : public State { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT(std::is_arithmetic::value, "input data type is not to arithmetic"); STATIC_ASSERT(std::is_arithmetic::value, "confidence abstraction type is not to arithmetic"); STATIC_ASSERT(std::is_arithmetic::value, "process data type is not to arithmetic"); private: /// SignalStateInfo is a struct of SignalStateInformation that contains /// information about the current signal state. SystemStateInformation SystemStateInfo; std::vector> SignalStateInfos; uint32_t NumberOfSignals; public: /// TODO: write description SystemState(uint32_t StateID, uint32_t NumberOfSignals) noexcept - : SystemStateInfo{StateID, StateConditions::UNKNOWN, - false, false, - false, 0, - 0, 0, - 0, 0, - 0, 0, - 0, 0}, + : SystemStateInfo(StateID, StateConditions::UNKNOWN), NumberOfSignals(NumberOfSignals) { - //@benedikt: there is now possibility to not doing the resize within these - //{}-brackets, right? SignalStateInfos.resize(NumberOfSignals); } /// Destroys \p this object. ~SystemState(void) = default; /// TODO: write description SystemStateInformation insertSignalStateInformation( const std::vector> _SignalStateInfos) noexcept { ASSERT(_SignalStateInfos.size() < NumberOfSignals); bool AllSignalsAreValid = true; bool AtLeastOneSignalJustGotValid = false; bool AllSignalsAreValidAfterReentrance = true; bool AtLeastOneSignalIsUnknown = false; bool AllSignalsAreStable = true; // TODO: change this SystemStateInfo.ConfidenceOfInputsMatchingState = 1; SystemStateInfo.ConfidenceOfInputsMismatchingState = 0; SystemStateInfo.ConfidenceOfOutputsMatchingState = 1; SystemStateInfo.ConfidenceOfOutputsMismatchingState = 0; SystemStateInfo.ConfidenceStateIsValid = 1; SystemStateInfo.ConfidenceStateIsInvalid = 0; SystemStateInfo.ConfidenceStateIsStable = 1; SystemStateInfo.ConfidenceStateIsDrifting = 0; std::size_t counter = 0; for (auto SSI : _SignalStateInfos) { if (!SSI.StateIsValid) AllSignalsAreValid = false; if (SSI.StateJustGotValid) AtLeastOneSignalJustGotValid = true; if (!SSI.StateIsValidAfterReentrance) AllSignalsAreValidAfterReentrance = false; if (SSI.StateCondition == StateConditions::UNKNOWN) AtLeastOneSignalIsUnknown = true; if (SSI.StateCondition == StateConditions::DRIFTING) AllSignalsAreStable = false; if (SSI.SignalProperty == SignalProperties::INPUT) { SystemStateInfo.ConfidenceOfInputsMatchingState = fuzzyAND(SystemStateInfo.ConfidenceOfInputsMatchingState, SSI.ConfidenceOfMatchingState); SystemStateInfo.ConfidenceOfInputsMismatchingState = fuzzyOR(SystemStateInfo.ConfidenceOfInputsMismatchingState, SSI.ConfidenceOfMismatchingState); } else { SystemStateInfo.ConfidenceOfOutputsMatchingState = fuzzyAND(SystemStateInfo.ConfidenceOfOutputsMatchingState, SSI.ConfidenceOfMatchingState); SystemStateInfo.ConfidenceOfOutputsMismatchingState = fuzzyOR(SystemStateInfo.ConfidenceOfOutputsMismatchingState, SSI.ConfidenceOfMismatchingState); } SystemStateInfo.ConfidenceStateIsValid = fuzzyAND( SystemStateInfo.ConfidenceStateIsValid, SSI.ConfidenceStateIsValid); SystemStateInfo.ConfidenceStateIsInvalid = fuzzyOR(SystemStateInfo.ConfidenceStateIsInvalid, SSI.ConfidenceStateIsInvalid); SystemStateInfo.ConfidenceStateIsStable = fuzzyAND( SystemStateInfo.ConfidenceStateIsStable, SSI.ConfidenceStateIsStable); SystemStateInfo.ConfidenceStateIsDrifting = fuzzyOR(SystemStateInfo.ConfidenceStateIsDrifting, SSI.ConfidenceStateIsDrifting); this->SignalStateInfos.at(counter) = SSI; counter++; } SystemStateInfo.StateIsValid = AllSignalsAreValid; SystemStateInfo.StateJustGotValid = AllSignalsAreValid && AtLeastOneSignalJustGotValid; SystemStateInfo.StateIsValidAfterReentrance = AllSignalsAreValidAfterReentrance; if (AtLeastOneSignalIsUnknown) SystemStateInfo.StateCondition = StateConditions::UNKNOWN; else if (AllSignalsAreStable) SystemStateInfo.StateCondition = StateConditions::STABLE; else SystemStateInfo.StateCondition = StateConditions::DRIFTING; return SystemStateInfo; } /// TODO: write description // TODO (future): think about saving the state information in a history SystemStateRelation compareSignalStateInformation( const std::vector> _SignalStateInfos) noexcept { bool inputsAreMatching = true; bool outputsAreMatching = true; std::size_t counter = 0; for (auto SSI : _SignalStateInfos) { if (this->SignalStateInfos.at(counter).StateID != SSI.StateID) { if (SSI.SignalProperty == SignalProperties::INPUT) inputsAreMatching = false; else // SignalProperties::OUTPUT outputsAreMatching = false; } counter++; } if (inputsAreMatching && outputsAreMatching) return SystemStateRelation::STATEISMATCHING; else if (inputsAreMatching && !outputsAreMatching) return SystemStateRelation::ONLYINPUTISMATCHING; else if (!inputsAreMatching && outputsAreMatching) return SystemStateRelation::ONLYOUTPUTISMATCHING; else return SystemStateRelation::STATEISMISMATCHING; } #ifdef ADDITIONAL_FUNCTIONS /// TODO: write description template void insertSignalStateInformation( const std::array, size> &Data) noexcept { ASSERT(size <= NumberOfSignals); std::size_t counter = 0; for (auto tmp : Data) { Signals.at(counter) = tmp; counter++; } } /// TODO: write description template std::enable_if_t>...>, void> insertSignalStateInformation(Types... Data) { // TODO (future): think about saving the state information in a history insertSignalStateInfos( std::array, sizeof...(Data)>( {Data...})); } // returns true if they are identical /// TODO: write description template bool compareSignalStateInformation( const std::array, size> &Data) noexcept { // TODO (future): think about saving the state information in a history std::size_t counter = 0; for (auto tmp : Data) { if (Signals.at(counter) != tmp) return false; counter++; } return true; } // checks only the given amount /// TODO: write description template std::enable_if_t>...>, bool> compareSignalStateInformation(Types... Data) { return compareSignalStateInfos( std::array, sizeof...(Data)>( {Data...})); } #endif /// Gives information about the current signal state. /// /// \return a struct SignalStateInformation that contains information about /// the current signal state. SystemStateInformation systemStateInformation(void) noexcept { return SystemStateInfo; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SYSTEMSTATE_HPP