diff --git a/include/rosa/agent/State.hpp b/include/rosa/agent/State.hpp index 99365de..ef5b85a 100644 --- a/include/rosa/agent/State.hpp +++ b/include/rosa/agent/State.hpp @@ -1,165 +1,179 @@ //===-- rosa/agent/State.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/State.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_STATE_HPP #define ROSA_AGENT_STATE_HPP #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/History.hpp" namespace rosa { namespace agent { // QUESTION: I would like to define the variable nextID as static variable // inside the struct or the class but it is not possible because I cannot define // it there (initialize it with 0) because "no const variable". However, using a // global variable is not that nice in my opinion. unsigned int nextID = 0; /// State conditions defining how the condition of a \c rosa::agent::State is /// saved in \c rosa::agent::StateInformation. enum class StateCondition { STABLE, ///< The state is STABLE DRIFTING ///< The state is drifting }; template struct StateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// The state ID saved as an unsigned integer number unsigned int StateID; /// The StateConfidence shows the overall confidence value of the state. CONFTYPE StateConfidence; /// The StateCondition shows the condition of a state (stable or drifting) StateCondition StateCondition; /// The StateIsValid shows whether a state is valid or invalid. In this /// context, valid means that enough samples which are in close proximitry /// have been inserted into the state. bool StateIsValid; /// The StateIsValidAfterReentrance shows whether a state is valid after the /// variable changed back to it again. bool StateIsValidAfterReentrance; }; // TODO (1/2): change name of DABSTORETYPE to something else /// \tparam INDATATYPE type of input data, \tparam DABSTORETYPE type of data /// in which DABs are saved, template class State : 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), "DAB storage type is not to arithmetic"); private: + // For the convinience to write a shorter data type name using partFuncPointer = std::shared_ptr>; - // TODO (2/2): because here, DABSTORETYPE makes no sense - StateInformation StateInfo; + using stateInfoPtr = std::shared_ptr>; + + stateInfoPtr StateInfo; partFuncPointer PartialFunctionSampleMatches; partFuncPointer PartialFunctionSampleMismatches; partFuncPointer PartialFunctionNumOfSamplesMatches; partFuncPointer PartialFunctionNumOfSamplesMismatches; DynamicLengthHistory SampleHistory; DynamicLengthHistory DAB; DynamicLengthHistory DABHistory; /// The StateIsValid shows whether a state is valid or invalid. In this /// context, valid means that enough samples which are in close proximitry /// have been inserted into the state. bool StateIsValid; /// The StateIsValidAfterReentrance shows whether a state is valid after the /// variable changed back to it again. bool StateIsValidAfterReentrance; public: State(partFuncPointer PartialFunctionSampleMatches, partFuncPointer PartialFunctionSampleMismatches, partFuncPointer PartialFunctionNumOfSamplesMatches, partFuncPointer PartialFunctionNumOfSamplesMismatches, unsigned int sampleHistorySize, unsigned int DABSize, unsigned int DABHistorySize) noexcept : SampleHistory(sampleHistorySize), DAB(DABSize), DABHistory(DABHistorySize), PartialFunctionSampleMatches(PartialFunctionSampleMatches), PartialFunctionSampleMismatches(PartialFunctionSampleMismatches), PartialFunctionNumOfSamplesMatches(PartialFunctionNumOfSamplesMatches), PartialFunctionNumOfSamplesMismatches( PartialFunctionNumOfSamplesMismatches) { /* StateIsValid = false; StateIsValidAfterReentrance = false; */ } /// Destroys \p this object. ~State(void) = default; void leaveState(void) { DAB.clear(); StateIsValidAfterReentrance = false; } bool insertSample(INDATATYPE Sample) { bool workedForAll; // maybe ignor that //auc hnicht abchecken einfach kübeln workedForAll = SampleHistory.addEntry(Sample); // QUESTION: is it important to have this flag (workedForAll). What should I // do if it does not work at some point? if (workedForAll) { workedForAll &= DAB.addEntry(Sample); if (workedForAll) { if (DAB.full()) { DABSTORETYPE AvgOfDAB = DAB.average(); workedForAll &= DABHistory.addEntry(AvgOfDAB); if (workedForAll) { DAB.clear(); } // QUESTION: - what should be done if it has not worked? } if (workedForAll) { // TODO: calculate whether state is valid + + // TODO: check actual state whether it drifts + // TODO: write in StateInfo } } } return workedForAll; } DABSTORETYPE confSampleMatchesState(INDATATYPE sample) {} DABSTORETYPE confSampleMismatchesState(INDATATYPE sample) {} // unsigned int stateId(void) { return StateId; } + /// Gives information about the current state. + /// + /// \return a struct StateInformation that contains information about the + /// current state. + stateInfoPtr stateInformation(void) { + // TODO: check what happens when currentStateInformation(void) is called in + // the beginning when no state has recognized at all. + return StateInfo; + } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_STATE_HPP diff --git a/include/rosa/agent/StateDetector.hpp b/include/rosa/agent/StateDetector.hpp index 18486d5..052a60e 100644 --- a/include/rosa/agent/StateDetector.hpp +++ b/include/rosa/agent/StateDetector.hpp @@ -1,226 +1,232 @@ //===-- rosa/agent/StateDetector.hpp ----------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/StateDetector.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// -/// \brief Definition of *state detection* *functionality*. +/// \brief Definition of *state detector* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_STATEDETECTOR_HPP #define ROSA_AGENT_STATEDETECTOR_HPP #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/State.hpp" #include namespace rosa { namespace agent { /// Implements \c rosa::agent::StateDetector as a functionality that detects /// states given on input samples. /// /// \note This implementation is supposed to be used for samples of an /// arithmetic type. /// /// \tparam INDATATYPE is the type of input data, \tparam CONFTYPE is type of /// data in that the confidence values are given template class StateDetector : 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 abstraction type is not to arithmetic"); private: // For the convinience to write a shorter data type name using partFuncPointer = std::shared_ptr>; using statePtr = std::shared_ptr>; using stateInfoPtr = std::shared_ptr>; /// The StateHasChanged is a flag that show whether a state change has /// happened. bool StateHasChanged; /// The CurrentState is a pointer to the (saved) state in which the actual /// variable (signal) of the observed system is. std::shared_ptr CurrentState; /// The DetectedStates is vector in that all detected states are saved. std::vector DetectedStates; /// The PartialFunctionSampleMatches is the fuzzy function that gives the /// convidence how good the new sample matches another sample in the sample /// history. partFuncPointer PartialFunctionSampleMatches; /// The PartialFunctionSampleMatches is the fuzzy function that gives the /// convidence how bad the new sample matches another sample in the sample /// history. partFuncPointer PartialFunctionSampleMismatches; /// The PartialFunctionSampleMatches is the fuzzy function that gives the /// convidence how many samples from the sampe history match the new sample. partFuncPointer PartialFunctionNumOfSamplesMatches; /// The PartialFunctionSampleMatches is the fuzzy function that gives the /// convidence how many samples from the sampe history mismatch the new /// sample. partFuncPointer PartialFunctionNumOfSamplesMismatches; /// SampleHistorySize is the (maximum) size of the sample history. unsigned int SampleHistorySize; /// DABSize the size of a DAB (Discrete Average Block). unsigned int DABSize; /// DABHistorySize is the (maximum) size of the DAB history. unsigned int DABHistorySize; public: /// Creates an instance by setting all parameters StateDetector(partFuncPointer PartialFunctionSampleMatches, partFuncPointer PartialFunctionSampleMismatches, partFuncPointer PartialFunctionNumOfSamplesMatches, partFuncPointer PartialFunctionNumOfSamplesMismatches, unsigned int SampleHistorySize, unsigned int DABSize, unsigned int DABHistorySize) noexcept : StateHasChanged(false), CurrentState(NULL), PartialFunctionSampleMatches(PartialFunctionSampleMatches), PartialFunctionSampleMismatches(PartialFunctionSampleMismatches), PartialFunctionNumOfSamplesMatches(PartialFunctionNumOfSamplesMatches), PartialFunctionNumOfSamplesMismatches( PartialFunctionNumOfSamplesMismatches), SampleHistorySize(SampleHistorySize), DABSize(DABSize), DABHistorySize(DABHistorySize) {} /// Destroys \p this object. ~StateDetector(void) = default; /// Detects the state to which the new sample belongs or create a new state if /// the new sample does not match to any of the saved states. /// /// \param Sample /// /// \return the information of the actual state (state ID and other /// parameters) stateInfoPtr detectState(INDATATYPE Sample) { if (CurrentState == NULL) { ASSERT(DetectedStates.empty()); statePtr S = createNewState(); if (S) { CurrentState = S; } else { - // TODO: handle (or at least log) if now state could be created + // TODO: handle (or at least log) if now state could be created. + // However, this handling/logging could be also done in + // createNewState(). } } else { CONFTYPE ConfidenceSampleMatchesState = CurrentState->confSampleMatchesState(Sample); CONFTYPE ConfidenceSampleMismatchesState = CurrentState->confSampleMismatchesState(Sample); if (ConfidenceSampleMatchesState > ConfidenceSampleMismatchesState) { StateHasChanged = false; } else { StateHasChanged = true; - // TODO: check whether ActiveState is valid - - // TODO: if invalid -> deleteState (einfach pop weil shared pointer) - // a.erase(std::find(a.begin(),a.end(),2)); - // TODO: else leaveState + if (CurrentState->stateInformation()->StateIsValid) { + leaveState(); + } else { + DetectedStates.erase(std::find(DetectedStates.begin(), + DetectedStates.end(), CurrentState)); + } - // TODO FAR AWAY FUTURE: additionally save averages to enable fast - // iteration through recorded state vector - //- maybe sort vector based on these average values + // TODO (future): additionally save averages to enable fast + // iteration through recorded state vector (maybe sort vector based on + // these average values) CurrentState = NULL; for (auto &SavedState : DetectedStates) { - if (SavedState != CurrentState) { CONFTYPE ConfidenceSampleMatchesState = SavedState->confSampleMatchesState(Sample); CONFTYPE ConfidenceSampleMismatchesState = SavedState->confSampleMismatchesState(Sample); if (ConfidenceSampleMatchesState > ConfidenceSampleMismatchesState) { - - // QUESTION: maybe it would be better to compare - // ConfidenceSampleMatchesState - // of all states in the vector + // TODO (future): maybe it would be better to compare + // ConfidenceSampleMatchesState of all states in the vector in + // order to find the best matching state. CurrentState = SavedState; - break; } } } if (!CurrentState) { if (statePtr S = createNewState()) { - CurrentState = S; - - } // QUESTION: should there an output (log) when it was not - // successfull? + } else { + // TODO: handle (or at least log) if now state could be created. + // However, this handling/logging could be also done in + // createNewState(). + } } } } CurrentState->insertSample(Sample); - // TODO: check actual state whether it drifts - // TODO: write in StateInfo + return CurrentState->stateInfo(); + } + /// Gives information about the current state. + /// + /// \return a struct StateInformation that contains information about the + /// current state. + stateInfoPtr currentStateInformation(void) { + // TODO: check what happens when currentStateInformation(void) is called in + // the beginning when no state has recognized at all. return CurrentState->stateInfo(); } + /// Gives information whether a state change has happened or not. + /// + /// \return true if a state change has happened, and false if not. bool stateHasChanged(void) { return StateHasChanged; } - bool stateIsUnchanged(void) { return !StateHasChanged; } - - // TODO: get confidences, get drift/stable get, get active state number, - // TODO: maybe just return struct with everything - private: /// Creates a new state and adds this state to the state vector in which all /// known states are saved. /// /// \param SampleHistorySize the (maximum) size of the sample history. /// \param DABSize the size of a DAB. /// \param DABHistorySize the (maximum) size of the DAB history. /// \param PartialFunctionSampleMatches the /// \param PartialFunctionSampleMismatches /// \param PartialFunctionNumOfSamplesMatches /// \param PartialFunctionNumOfSamplesMismatches /// /// \return the new created state or NULL if no state could be created. statePtr createNewState(void) { statePtr S = new (std::nothrow) State(SampleHistorySize, DABSize, DABHistorySize, PartialFunctionSampleMatches, PartialFunctionSampleMismatches, PartialFunctionNumOfSamplesMatches, PartialFunctionNumOfSamplesMismatches); if (S) { DetectedStates.push_back(S); return S; } else { return NULL; } } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_STATEDETECTOR_HPP