diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index 6c9de2e..99b135b 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,473 +1,472 @@ //===-- 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/support/math.hpp" #include namespace rosa { namespace agent { /// Signal state conditions defining how the condition of a \c /// rosa::agent::SignalState is saved in \c rosa::agent::SignalStateInformation. enum class SignalStateCondition { STABLE, ///< The signal state is stable DRIFTING, ///< The signal state is drifting UNKNOWN ///< The signal state is unknown }; template struct SignalStateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// The signal state ID saved as an unsigned integer number unsigned int SignalStateID; /// The SignalStateConfidence shows the overall confidence value of the signal /// state. CONFDATATYPE SignalStateConfidence; /// The SignalStateCondition shows the condition of a signal state (stable or /// drifting) SignalStateCondition SignalStateCondition; /// The SignalStateIsValid saves the number of samples which have been /// inserted into the state after entering it. unsigned int NumberOfInsertedSamplesAfterEntrance; /// The SignalStateIsValid shows whether a signal state is valid or invalid. /// In this context, valid means that enough samples which are in close /// proximitry have been inserted into the signal state. bool SignalStateIsValid; /// The SignalStateJustGotValid shows whether a signal state got valid /// (toggled from invalid to valid) during the current inserted sample. bool SignalStateJustGotValid; /// The SignalStateIsValidAfterReentrance shows whether a signal state is /// valid after the variable changed back to it again. bool SignalStateIsValidAfterReentrance; /// The SignalIsStableNotDrifting shows whether a signa is stable and not /// drifting. bool SignalIsStable; }; /// \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"); private: // For the convinience to write a shorter data type name using PartFuncPointer = std::shared_ptr>; // @Benedikt: are INDATATYPE, CONFDATATYPE right here? using StepFuncPointer = std::shared_ptr>; /// SignalStateInfo is a struct SignalStateInformation that contains /// information about the current 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. PartFuncPointer FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. PartFuncPointer FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. StepFuncPointer FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sampe history mismatch the new /// sample. StepFuncPointer 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. PartFuncPointer 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). PartFuncPointer 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; public: // @Maxi doxygen per default doesn't display private attributes of a class. So // I copied them to the constructor. So the user has more information. /// 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(unsigned int SignalStateID, unsigned int SampleHistorySize, unsigned int DABSize, unsigned int DABHistorySize, PartFuncPointer FuzzyFunctionSampleMatches, PartFuncPointer FuzzyFunctionSampleMismatches, StepFuncPointer FuzzyFunctionNumOfSamplesMatches, StepFuncPointer FuzzyFunctionNumOfSamplesMismatches, PartFuncPointer FuzzyFunctionSignalIsDrifting, PartFuncPointer FuzzyFunctionSignalIsStable) noexcept : SignalStateInfo{SignalStateID, 0, SignalStateCondition::UNKNOWN, 0, false, false, false, //@maxi added the Signal is stable bool - false}, + true}, - FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), SampleHistory(SampleHistorySize), DAB(DABSize), DABHistory(DABHistorySize), - LowestConfidenceMatchingHistory(SampleHistorySize), + LowestConfidenceMatchingHistory(SampleHistorySize), HighestConfidenceMismatchingHistory(SampleHistorySize) {} /// Destroys \p this object. ~SignalState(void) = default; void leaveSignalState(void) noexcept { DAB.clear(); SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0; SignalStateInfo.SignalStateIsValidAfterReentrance = false; } SignalStateInformation insertSample(INDATATYPE Sample) noexcept { validateSignalState(Sample); SampleHistory.addEntry(Sample); DAB.addEntry(Sample); if (DAB.full()) { PROCDATATYPE AvgOfDAB = DAB.template average(); DABHistory.addEntry(AvgOfDAB); DAB.clear(); } //@Benedikt: Do I really have to cast here? FuzzyFunctionNumOfSamplesMatches->setRightLimit( static_cast(SampleHistory.numberOfEntries())); FuzzyFunctionNumOfSamplesMismatches->setRightLimit( static_cast(SampleHistory.numberOfEntries())); checkSignalStability(); 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. for (unsigned int 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 //@benedikt: check if your partialfunctions can take infinity as // argument //@benedikt: same as before "->operator()" ConfidenceFromRelativeDistance = 0; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMatches->operator()( RelativeDistanceHistory[Case]); } ConfidenceOfWorstFittingSample = fuzzyAND( 2, ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance); //@benedikt: do i have to pass the number 2 to tell the function how many // arguments are following? //@benedikt: same as before with "->operator()" ConfidenceOfBestCase = fuzzyOR( 2, ConfidenceOfBestCase, fuzzyAND(2, ConfidenceOfWorstFittingSample, FuzzyFunctionNumOfSamplesMatches->operator()( static_cast(Case) + 1))); } 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; // 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. // TODO (future): to accelerate -> don't go until end. Confidences will only // get higher. See comment in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)". for (unsigned int Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { ConfidenceFromRelativeDistance = 1; } else { //@benedikt: I had to change the following line. The outcommented line // was the original one. I think it is ugly like that (new line). Do you // have an idea how to make it better/more beautiful? ConfidenceFromRelativeDistance = FuzzyFunctionSampleMismatches->operator()( RelativeDistanceHistory[Case]); // FuzzyFunctionSampleMismatches(RelativeDistanceHistory[Case]); } //@benedikt: do i have to pass the number 2 to tell the function how many // arguments are following? ConfidenceOfBestFittingSample = fuzzyOR( 2, ConfidenceOfBestFittingSample, ConfidenceFromRelativeDistance); //@benedikt: do i have to pass the number 2 to tell the function how many // arguments are following? //@benedikt: same as before with "->operator()" ConfidenceOfWorstCase = fuzzyAND( 2, ConfidenceOfWorstCase, fuzzyOR(2, ConfidenceOfBestFittingSample, FuzzyFunctionNumOfSamplesMismatches->operator()( static_cast(Case) + 1))); } 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. //@benedikt: same with "->operator()" LowestConfidenceMatching = fuzzyAND(2, LowestConfidenceMatching, FuzzyFunctionSampleMatches->operator()( relativeDistance( Sample, HistorySample))); //@benedikt: same with "->operator()" HighestConfidenceMismatching = fuzzyOR(2, HighestConfidenceMismatching, FuzzyFunctionSampleMismatches->operator()( relativeDistance( Sample, HistorySample))); } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); //@benedikt: same with "->operator()" CONFDATATYPE ConfidenceSignalStateIsValid = fuzzyAND( 2, LowestConfidenceMatching, FuzzyFunctionNumOfSamplesMatches->operator()(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); //@benedikt: same with "->operator()" CONFDATATYPE ConfidenceSignalStateIsInvalid = fuzzyOR( 2, HighestConfidenceMismatching, FuzzyFunctionNumOfSamplesMismatches->operator()(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); if (ConfidenceSignalStateIsValid > ConfidenceSignalStateIsInvalid) { if (SignalStateInfo.SignalStateIsValid) { SignalStateInfo.SignalStateJustGotValid = false; } else { SignalStateInfo.SignalStateJustGotValid = true; } SignalStateInfo.SignalStateIsValid = true; SignalStateInfo.SignalStateIsValidAfterReentrance = true; } } void checkSignalStability(void) { CONFDATATYPE ConfidenceSignalIsStable; CONFDATATYPE ConfidenceSignalIsDrifting; if (DABHistory.numberOfEntries() >= 2) { //@benedikt: same "->operator()" ConfidenceSignalIsStable = FuzzyFunctionSignalIsStable->operator()( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); //@benedikt: same "->operator()" ConfidenceSignalIsDrifting = FuzzyFunctionSignalIsDrifting->operator()( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); } else { // QUESTION: is it ok to say stable = 1 and drift = 0, when I simply don't // know because the state is so new. Is there an option for saying don't // know? ConfidenceSignalIsStable = 1; ConfidenceSignalIsDrifting = 0; } SignalStateInfo.SignalIsStable = ConfidenceSignalIsStable >= ConfidenceSignalIsDrifting; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP diff --git a/include/rosa/agent/SystemStateDetector.hpp b/include/rosa/agent/SystemStateDetector.hpp index fe0d3fd..c159991 100644 --- a/include/rosa/agent/SystemStateDetector.hpp +++ b/include/rosa/agent/SystemStateDetector.hpp @@ -1,47 +1,51 @@ //===-- rosa/agent/SystemStateDetector.hpp ----------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SystemStateDetector.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *system state detector* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP #define ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP #include "rosa/agent/Functionality.h" #include "rosa/agent/History.hpp" #include namespace rosa { namespace agent { /// TODO TEXT template class SystemStateDetector : public Functionality { /* //TODO: STATIC_ASSERT // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT(std::is_arithmetic::value, "confidence abstraction type is not to arithmetic"); */ private: unsigned int NextSignalStateID; + bool SystemStateHasChanged; + + // DynamicLengthHistory DetectedSignalStates; + public: SystemStateDetector() : NextSignalStateID(1) {} }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP diff --git a/lib/agent/CMakeLists.txt b/lib/agent/CMakeLists.txt index 7edb556..4e70aa5 100644 --- a/lib/agent/CMakeLists.txt +++ b/lib/agent/CMakeLists.txt @@ -1,18 +1,26 @@ 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}/SignalState.hpp + SignalState.cpp + ${LIB_INCLUDE_DIR}/SignalStateDetector.hpp + SignalStateDetector.cpp + ${LIB_INCLUDE_DIR}/SystemState.hpp + SystemState.cpp + ${LIB_INCLUDE_DIR}/SystemStateDetector.hpp + SystemStateDetector.cpp ) diff --git a/lib/agent/SignalState.cpp b/lib/agent/SignalState.cpp new file mode 100644 index 0000000..ec6b7bd --- /dev/null +++ b/lib/agent/SignalState.cpp @@ -0,0 +1,20 @@ +//===-- rosa/agent/SignalState.cpp ----------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/agent/SignalState.cpp +/// +/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Implementation for rosa/agent/SignalState.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/agent/SignalState.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/agent/SignalState.hpp" diff --git a/lib/agent/SignalStateDetector.cpp b/lib/agent/SignalStateDetector.cpp new file mode 100644 index 0000000..3f45910 --- /dev/null +++ b/lib/agent/SignalStateDetector.cpp @@ -0,0 +1,20 @@ +//===-- rosa/agent/SignalStateDetector.cpp ----------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/agent/SignalStateDetector.cpp +/// +/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Implementation for rosa/agent/SignalStateDetector.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/agent/SignalStateDetector.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/agent/SignalStateDetector.hpp" diff --git a/lib/agent/SystemState.cpp b/lib/agent/SystemState.cpp new file mode 100644 index 0000000..86662c2 --- /dev/null +++ b/lib/agent/SystemState.cpp @@ -0,0 +1,20 @@ +//===-- rosa/agent/SystemState.cpp ----------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/agent/SystemState.cpp +/// +/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Implementation for rosa/agent/SystemState.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/agent/SystemState.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/agent/SystemState.hpp" diff --git a/lib/agent/SystemStateDetector.cpp b/lib/agent/SystemStateDetector.cpp new file mode 100644 index 0000000..e5ec9d5 --- /dev/null +++ b/lib/agent/SystemStateDetector.cpp @@ -0,0 +1,20 @@ +//===-- rosa/agent/SystemStateDetector.cpp ----------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file rosa/agent/SystemStateDetector.cpp +/// +/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief Implementation for rosa/agent/SystemStateDetector.hpp. +/// +/// \note Empty implementation, source file here to have a compile database +/// entry for rosa/agent/SystemStateDetector.hpp. +/// +//===----------------------------------------------------------------------===// + +#include "rosa/agent/SystemStateDetector.hpp"