Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F543314
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
59 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp
index f177e5b..4b99535 100644
--- a/apps/ccam/ccam.cpp
+++ b/apps/ccam/ccam.cpp
@@ -1,309 +1,326 @@
//===-- 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 <iostream>
#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 <fstream>
#include <limits>
#include <memory>
#include <streambuf>
#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) {
// START MAXI TESTING
std::shared_ptr<PartialFunction<float, float>> TestPartFunc(
new PartialFunction<float, float>(
{
{{0.f, 3.f},
std::make_shared<LinearFunction<float, float>>(0.f, 1.f / 3)},
{{3.f, 6.f},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{6.f, 9.f},
std::make_shared<LinearFunction<float, float>>(3.f, -1.f / 3)},
},
0));
std::shared_ptr<StepFunction<float, float>> TestStepFunc(
new StepFunction<float, float>(1 / 10));
SystemStateDetector<float, float, float, HistoryPolicy::SRWF>
TestSystemStateDetector(1000, 5, TestPartFunc, TestPartFunc);
/*
SignalStateInformation<float> TestSigStateInfo(
0, SignalProperties::INPUT, 5, 5, 5, TestPartFunc, TestPartFunc,
TestStepFunc, TestStepFunc, TestPartFunc, TestPartFunc);
*/
std::vector<SignalStateInformation<float>> testVector;
TestSystemStateDetector.detectSystemState(testVector);
// END MAXI TESTING
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<DeluxeContext> C = DeluxeContext::create(AppName);
std::shared_ptr<PartialFunction<uint32_t, float>> BrokenDelayFunction(
new PartialFunction<uint32_t, float>(
{{{0, AppConfig.BrokenCounter},
std::make_shared<LinearFunction<uint32_t, float>>(
0, 0.f, AppConfig.BrokenCounter, 1.f)},
{{AppConfig.BrokenCounter, std::numeric_limits<uint32_t>::max()},
std::make_shared<LinearFunction<uint32_t, float>>(1.f, 0.f)}},
0.f));
std::shared_ptr<PartialFunction<uint32_t, float>> OkDelayFunction(
new PartialFunction<uint32_t, float>(
{{{0, AppConfig.BrokenCounter},
std::make_shared<LinearFunction<uint32_t, float>>(
0, 1.f, AppConfig.BrokenCounter, 0.f)},
{{AppConfig.BrokenCounter, std::numeric_limits<uint32_t>::max()},
std::make_shared<LinearFunction<uint32_t, float>>(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<AgentHandle> Sensors;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SampleMatchesFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SampleMismatchesFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SignalIsStableFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SignalIsDriftingFunctions;
std::vector<std::shared_ptr<StepFunction<float, float>>>
NumOfSamplesMatchFunctions;
std::vector<std::shared_ptr<StepFunction<float, float>>>
NumOfSamplesMismatchFunctions;
std::vector<std::shared_ptr<
SignalStateDetector<float, float, float, HistoryPolicy::FIFO>>>
SignalStateDetectors;
std::vector<AgentHandle> SignalStateDetectorAgents;
for (auto SignalConfiguration : AppConfig.SignalConfigurations) {
//
// Create deluxe sensors.
//
Sensors.emplace_back(C->createSensor<float>(SignalConfiguration.Name));
+ C->setExecutionPolicy(Sensors.back(), DeluxeExecutionPolicy::decimation(1));
//
// Create functionalities for SignalStateDetector.
//
SampleMatchesFunctions.emplace_back(new PartialFunction<float, float>(
{
{{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBound, 0.f,
-SignalConfiguration.InnerBound, 1.f)},
{{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound},
std::make_shared<LinearFunction<float, float>>(
SignalConfiguration.InnerBound, 1.f,
SignalConfiguration.OuterBound, 0.f)},
},
0));
SampleMismatchesFunctions.emplace_back(new PartialFunction<float, float>(
{
{{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBound, 1.f,
-SignalConfiguration.InnerBound, 0.f)},
{{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(0.f, 0.f)},
{{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound},
std::make_shared<LinearFunction<float, float>>(
SignalConfiguration.InnerBound, 0.f,
SignalConfiguration.OuterBound, 1.f)},
},
1));
SignalIsStableFunctions.emplace_back(new PartialFunction<float, float>(
{
{{-SignalConfiguration.OuterBoundDrift,
-SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBoundDrift, 0.f,
-SignalConfiguration.InnerBoundDrift, 1.f)},
{{-SignalConfiguration.InnerBoundDrift,
SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{SignalConfiguration.InnerBoundDrift,
SignalConfiguration.OuterBoundDrift},
std::make_shared<LinearFunction<float, float>>(
SignalConfiguration.InnerBoundDrift, 1.f,
SignalConfiguration.OuterBoundDrift, 0.f)},
},
0));
SignalIsDriftingFunctions.emplace_back(new PartialFunction<float, float>(
{
{{-SignalConfiguration.OuterBoundDrift,
-SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBoundDrift, 1.f,
-SignalConfiguration.InnerBoundDrift, 0.f)},
{{-SignalConfiguration.InnerBoundDrift,
SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(0.f, 0.f)},
{{SignalConfiguration.InnerBoundDrift,
SignalConfiguration.OuterBoundDrift},
std::make_shared<LinearFunction<float, float>>(
SignalConfiguration.InnerBoundDrift, 0.f,
SignalConfiguration.OuterBoundDrift, 1.f)},
},
1));
NumOfSamplesMatchFunctions.emplace_back(new StepFunction<float, float>(
1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp));
NumOfSamplesMismatchFunctions.emplace_back(new StepFunction<float, float>(
1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown));
//
// Create SignalStateDetector functionality
//
SignalStateDetectors.emplace_back(
new SignalStateDetector<float, float, float, HistoryPolicy::FIFO>(
SignalConfiguration.Output ? SignalProperties::OUTPUT
: SignalProperties::INPUT,
std::numeric_limits<int>::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.
//
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<float>(SensorData),
+ csv::CSVIterator<float>());
}
//
// 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<SystemStateTuple, bool>;
using Result = Optional<DeluxeTuple<unit_t>>;
using Handler = std::function<Result(Input)>;
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/configuration.h b/apps/ccam/configuration.h
index 4db55b4..cec43ad 100644
--- a/apps/ccam/configuration.h
+++ b/apps/ccam/configuration.h
@@ -1,85 +1,85 @@
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
// clang-tidy off
// clang-format off
#include "json.hpp"
// clang-format on
// clang-tidy on
#include "rosa/config/version.h"
#include "rosa/deluxe/DeluxeContext.hpp"
#include <fstream>
using namespace rosa;
using nlohmann::json;
struct SignalConfiguration {
std::string Name;
+ std::string InputPath;
bool Output;
float InnerBound;
float OuterBound;
float InnerBoundDrift;
float OuterBoundDrift;
uint32_t SampleHistorySize;
uint32_t DABSize;
uint32_t DABHistorySize;
};
struct AppConfiguration {
- std::string InputFilePath;
std::string OutputFilePath;
uint32_t BrokenCounter;
uint32_t NumberOfSimulationCycles;
std::vector<SignalConfiguration> SignalConfigurations;
};
void from_json(const json &J, SignalConfiguration &SC) {
J.at("Name").get_to(SC.Name);
+ J.at("InputPath").get_to(SC.InputPath);
J.at("Output").get_to(SC.Output);
J.at("InnerBound").get_to(SC.InnerBound);
J.at("OuterBound").get_to(SC.OuterBound);
J.at("InnerBoundDrift").get_to(SC.InnerBoundDrift);
J.at("OuterBoundDrift").get_to(SC.OuterBoundDrift);
J.at("SampleHistorySize").get_to(SC.SampleHistorySize);
J.at("DABSize").get_to(SC.DABSize);
J.at("DABHistorySize").get_to(SC.DABHistorySize);
}
void from_json(const json &J, AppConfiguration &AC) {
- J.at("InputFilePath").get_to(AC.InputFilePath);
J.at("OutputFilePath").get_to(AC.OutputFilePath);
J.at("BrokenCounter").get_to(AC.BrokenCounter);
J.at("NumberOfSimulationCycles").get_to(AC.NumberOfSimulationCycles);
J.at("SignalConfigurations").get_to(AC.SignalConfigurations);
}
AppConfiguration AppConfig;
bool readConfigFile(std::string ConfigPath) {
LOG_INFO("READING CONFIG FILE");
LOG_INFO_STREAM << "Looking for config file at \"" << ConfigPath << "\"\n";
std::ifstream ConfigFile;
ConfigFile.open(ConfigPath);
if (!ConfigFile) {
LOG_ERROR("Unable to open config file");
return false;
}
json ConfigObj;
ConfigFile >> ConfigObj;
LOG_INFO_STREAM << "Read JSON file as \"" << ConfigObj << "\"\n";
try {
ConfigObj.get_to(AppConfig);
} catch (nlohmann::detail::type_error ex) {
LOG_ERROR("Misformatted Config File");
return false;
}
return true;
}
#endif // CONFIGURATION_H
diff --git a/apps/ccam/statehandlerutils.h b/apps/ccam/statehandlerutils.h
index 73f25b0..9bf7ee4 100644
--- a/apps/ccam/statehandlerutils.h
+++ b/apps/ccam/statehandlerutils.h
@@ -1,186 +1,184 @@
#ifndef STATEHANDLERUTILS_H
#define STATEHANDLERUTILS_H
#include "rosa/agent/Abstraction.hpp"
#include "rosa/agent/Confidence.hpp"
#include "rosa/agent/FunctionAbstractions.hpp"
#include <functional>
#include <iostream>
#include <tuple>
#include <vector>
#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 <fstream>
#include <limits>
#include <memory>
#include <streambuf>
using namespace rosa;
using namespace rosa::agent;
using namespace rosa::deluxe;
using namespace rosa::terminal;
// Signal State
using SignalStateTuple =
DeluxeTuple<float, uint32_t, uint8_t, float, float, float, float, float,
- float, uint8_t, uint32_t, bool, bool, bool>;
+ float, uint8_t, uint32_t, uint8_t>;
AgentHandle createSignalStateDetectorAgent(
std::unique_ptr<DeluxeContext> &C, const std::string &Name,
std::shared_ptr<
SignalStateDetector<float, float, float, HistoryPolicy::FIFO>>
SigSD) {
using Input = std::pair<DeluxeTuple<float>, bool>;
using Result = Optional<SignalStateTuple>;
using Handler = std::function<Result(Input)>;
return C->createAgent(
Name, Handler([&Name, &SigSD](Input I) -> Result {
LOG_INFO_STREAM << "\n******\n"
<< Name << " " << (I.second ? "<New>" : "<Old>")
<< " 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,
- StateInfo.StateIsValid, StateInfo.StateJustGotValid,
- StateInfo.StateIsValidAfterReentrance};
+ (StateInfo.StateIsValid ? 4 : 0) +
+ (StateInfo.StateJustGotValid ? 2 : 0) +
+ (StateInfo.StateIsValidAfterReentrance ? 1 : 0)};
return Result(Res);
}
return Result();
}));
}
// System State
using SystemStateTuple = DeluxeTuple<std::string, uint32_t, float, uint8_t,
uint32_t, bool, bool, bool, bool>;
template <std::size_t size, typename ret, typename functype, typename... A>
struct Handler_helper;
template <typename B, typename func, typename A, typename... As>
struct function_helper {
static_assert(std::conjunction_v<std::is_same<A, As>...>,
"All types need to be identical");
static B function(A valA, As... valAs) {
std::vector<A> ar({valA, valAs...});
return func()(ar);
}
};
template <typename ret, typename typeA, typename functype, typename... B>
struct Handler_helper<0, ret, functype, typeA, B...> {
using handler = function_helper<ret, functype, B...>;
};
template <std::size_t size, typename ret, typename typeA, typename functype,
typename... B>
struct Handler_helper<size, ret, functype, typeA, B...> {
using handler =
typename Handler_helper<size - 1, ret, functype, typeA,
std::pair<typeA, bool>, B...>::handler;
};
template <std::size_t size, typename ret, typename functype, typename typeA>
using Handler = typename Handler_helper<size, ret, functype, typeA>::handler;
// todo: state-detector durschleifen
template <typename ret, typename A> struct function {
ret operator()(A a) {
// std::vector<SystemStateInformation> out;
for (auto tmp1 : a) {
// convert tuple to info struct out.push_back({});
(void)tmp1;
LOG_INFO_STREAM << "new SignalStateTuple!\n";
}
// feed state detector
// return result
return ret();
}
};
using arr = std::vector<std::pair<SignalStateTuple, bool>>;
template <size_t NumOfSlaves>
AgentHandle createSystemStateDetectorAgent(
std::unique_ptr<DeluxeContext> &C, const std::string &Name,
std::shared_ptr<PartialFunction<uint32_t, float>> BrokenDelayFunction,
std::shared_ptr<PartialFunction<uint32_t, float>> OkDelayFunction) {
LOG_TRACE("Creating fixed SystemStateDetectorAgent");
using Input = SignalStateTuple;
using Result = Optional<SystemStateTuple>;
auto HandlerFunction =
Handler<NumOfSlaves, Result, function<Optional<SystemStateTuple>, arr>,
Input>::function;
std::shared_ptr<
SystemStateDetector<uint32_t, float, float, HistoryPolicy::FIFO>>
- //@benedikt: I had to insert a dummy number for NumberOfSignals (I
- // inserted 5)
- SysSD(
- new SystemStateDetector<uint32_t, float, float, HistoryPolicy::FIFO>(
- std::numeric_limits<uint32_t>::max(), 5, BrokenDelayFunction,
- OkDelayFunction));
+ SysSD(new SystemStateDetector<uint32_t, float, float, HistoryPolicy::FIFO>(
+ std::numeric_limits<uint32_t>::max(), NumOfSlaves, BrokenDelayFunction,
+ OkDelayFunction));
return C->createAgent(Name, std::function(HandlerFunction));
}
AgentHandle createSystemStateDetectorAgent(
std::unique_ptr<DeluxeContext> &C, const std::string &Name,
size_t NumOfSlaves,
std::shared_ptr<PartialFunction<uint32_t, float>> BrokenDelayFunction,
std::shared_ptr<PartialFunction<uint32_t, float>> 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/SystemStateDetector.hpp b/include/rosa/agent/SystemStateDetector.hpp
index 9152dfa..bcff7b4 100644
--- a/include/rosa/agent/SystemStateDetector.hpp
+++ b/include/rosa/agent/SystemStateDetector.hpp
@@ -1,223 +1,222 @@
//===-- 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/SignalState.hpp"
#include "rosa/agent/StateDetector.hpp"
#include "rosa/agent/SystemState.hpp"
#include "rosa/support/debug.hpp"
namespace rosa {
namespace agent {
/*
/// System state conditions defining how the condition of a \c
/// rosa::agent::SystemState is saved in \c rosa::agent::SystemStateInformation.
// TODO: think about shifting this in SystemStateDetector and make a
// StateCondition with only stable, drifting, unknown
enum class SystemStateCondition : uint8_t {
STABLE = 0, ///< The system state is stable
DRIFTING = 1, ///< The system state is drifting
MALFUNCTIONING = 2, ///< The system state is malfunctioning
UNKNOWN = 3 ///< The system state is unknown
};
*/
/// TODO: write description
template <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE,
HistoryPolicy HP>
class SystemStateDetector
: public StateDetector<INDATATYPE, CONFDATATYPE, PROCDATATYPE, HP> {
using StateDetector =
StateDetector<INDATATYPE, CONFDATATYPE, PROCDATATYPE, HP>;
using PartFuncPointer = typename StateDetector::PartFuncPointer;
private:
// For the convinience to write a shorter data type name
using SystemStatePtr =
std::shared_ptr<SystemState<INDATATYPE, CONFDATATYPE, PROCDATATYPE>>;
/// TODO: description
uint32_t NumberOfSignals;
/// The CurrentSystemState is a pointer to the (saved) system state in which
/// the actual state of the observed system is.
SystemStatePtr CurrentSystemState;
/// The DetectedSystemStates is a history in that all detected system states
/// are saved.
DynamicLengthHistory<SystemStatePtr, HP> DetectedSystemStates;
/// TODO: description
unsigned int TimeOfDisparity;
/// The FuzzyFunctionDelayTimeToGetBroken is the fuzzy function that gives
/// the confidence whether the system is Broken because of an input change
/// without an output change or vice versa. A small time gap between the two
/// shall be allowed.
PartFuncPointer FuzzyFunctionDelayTimeToGetBroken;
/// The FuzzyFunctionDelayTimeToBeWorking is the fuzzy function that gives
/// the
/// confidence whether the system is still OK allthough an input change
/// without an output change or vice versa.
PartFuncPointer FuzzyFunctionDelayTimeToBeWorking;
public:
// todo zwei parameter für variablen anzahl
/// TODO: write description
SystemStateDetector(
uint32_t MaximumNumberOfSystemStates, uint32_t NumberOfSignals,
PartFuncPointer FuzzyFunctionDelayTimeToGetBroken,
PartFuncPointer FuzzyFunctionDelayTimeToBeWorking) noexcept
- : CurrentSystemState(nullptr),
- DetectedSystemStates(MaximumNumberOfSystemStates),
- NumberOfSignals(NumberOfSignals), TimeOfDisparity(0),
+ : NumberOfSignals(NumberOfSignals), CurrentSystemState(nullptr),
+ DetectedSystemStates(MaximumNumberOfSystemStates), TimeOfDisparity(0),
FuzzyFunctionDelayTimeToGetBroken(FuzzyFunctionDelayTimeToGetBroken),
FuzzyFunctionDelayTimeToBeWorking(FuzzyFunctionDelayTimeToBeWorking) {
//@Benedikt: if I write "NextStateID(1), StateHasChanged(false)" before the
//{}-brackets, the compiler tells me: "SystemStateDetector.hpp:72:9: error:
// member initializer 'NextStateID'/'StateHasChanged' does not name a
// non-static data member or base class"
this->NextStateID = 1;
this->StateHasChanged = false;
}
/// Destroys \p this object.
~SystemStateDetector(void) = default;
/// TODO: write description
SystemStateInformation<CONFDATATYPE>
detectSystemState(std::vector<SignalStateInformation<CONFDATATYPE>>
SignalStateInfos) noexcept {
SystemStateInformation<CONFDATATYPE> SystemStateInfo;
if (!CurrentSystemState) {
ASSERT(DetectedSystemStates.empty());
SystemStatePtr S = createNewSystemState();
CurrentSystemState = S;
SystemStateInfo =
CurrentSystemState->insertSignalStateInformation(SignalStateInfos);
} else {
SystemStateRelation SysStateRel =
CurrentSystemState->compareSignalStateInformation(SignalStateInfos);
if (SysStateRel == SystemStateRelation::STATEISMATCHING) {
TimeOfDisparity = 0;
SystemStateInfo =
CurrentSystemState->insertSignalStateInformation(SignalStateInfos);
} else { // ONLYINPUTISMATCHING, ONLYOUTPUTISMATCHING, STATEISMISMATCHING
if (!CurrentSystemState->systemStateInformation().StateIsValid)
DetectedSystemStates.deleteEntry(CurrentSystemState);
CurrentSystemState = nullptr;
SystemStatePtr potentialSystemState = nullptr;
// search all saved system states
for (auto &SavedSystemState : DetectedSystemStates) {
SysStateRel =
SavedSystemState->compareSignalStateInformation(SignalStateInfos);
if (SysStateRel == SystemStateRelation::STATEISMATCHING) {
CurrentSystemState = SavedSystemState;
break;
} else if (SysStateRel == SystemStateRelation::ONLYINPUTISMATCHING ||
SysStateRel == SystemStateRelation::ONLYOUTPUTISMATCHING) {
potentialSystemState = SavedSystemState;
}
}
// actions depending whether state is matchin fully or only half
if (CurrentSystemState) {
TimeOfDisparity = 0;
SystemStateInfo = CurrentSystemState->insertSignalStateInformation(
SignalStateInfos);
} else if (potentialSystemState) {
TimeOfDisparity++;
CurrentSystemState = potentialSystemState;
SystemStateInfo = CurrentSystemState->systemStateInformation();
} else {
SystemStatePtr S = createNewSystemState();
TimeOfDisparity = 0;
CurrentSystemState = S;
SystemStateInfo = CurrentSystemState->insertSignalStateInformation(
SignalStateInfos);
}
}
}
// TODO: is this right? if i don't insert if broke, it will never be valid?!
// right?
if (!SystemStateInfo.StateIsValid ||
!SystemStateInfo.StateIsValidAfterReentrance) {
TimeOfDisparity = 0;
}
// TODO: maybe make reference instead of pointer
CONFDATATYPE ConfidenceSystemIsMalfunctioning =
FuzzyFunctionDelayTimeToGetBroken->operator()(
static_cast<INDATATYPE>(TimeOfDisparity));
CONFDATATYPE ConfidenceSystemIsFunctioning =
FuzzyFunctionDelayTimeToBeWorking->operator()(
static_cast<INDATATYPE>(TimeOfDisparity));
if (ConfidenceSystemIsMalfunctioning > ConfidenceSystemIsFunctioning)
SystemStateInfo.StateCondition = StateConditions::MALFUNCTIONING;
// TODO: calculate overall confidence
if (SystemStateInfo.StateJustGotValid) {
this->NextStateID++;
}
return SystemStateInfo;
}
private:
/// Creates a new system state and adds it to the system state vector in
/// which
/// all known states are saved.
///
/// \return a pointer to the newly created signal state or NULL if no state
/// could be created.
SystemStatePtr createNewSystemState(void) noexcept {
SystemStatePtr S(new SystemState<INDATATYPE, CONFDATATYPE, PROCDATATYPE>(
this->NextStateID, this->NumberOfSignals));
DetectedSystemStates.addEntry(S);
return S;
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP
diff --git a/include/rosa/support/csv/CSVReader.hpp b/include/rosa/support/csv/CSVReader.hpp
index c5678ef..3b6ed7b 100755
--- a/include/rosa/support/csv/CSVReader.hpp
+++ b/include/rosa/support/csv/CSVReader.hpp
@@ -1,484 +1,484 @@
//===-- rosa/support/csv/CSVReader.hpp --------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/csv/CSVReader.hpp
///
/// \authors David Juhasz (david.juhasz@tuwien.ac.at), Edwin Willegger
/// (edwin.willegger@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facitilities to read CSV files.
///
/// \note The implementation is based on the solution at
/// https://stackoverflow.com/a/1120224
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_CSV_CSVREADER_HPP
#define ROSA_SUPPORT_CSV_CSVREADER_HPP
#include "rosa/support/debug.hpp"
#include "rosa/support/sequence.hpp"
#include <algorithm>
#include <istream>
#include <map>
#include <set>
#include <sstream>
#include <vector>
namespace rosa {
namespace csv {
/// Indicating it the CSV file contains any header or not
enum class HeaderInformation { HasHeader, HasNoHeader };
/// Anonymous namespace providing implementation details for
/// \c rosa::csv::CSVIterator, consider it private.
namespace {
/// Provides facility for parsing one value from a string.
///
/// \tparam T type of value to parse
/// \tparam IsSignedInt if \p T is a signed integral type, always use default
/// \tparam IsUnsignedInt if \p T is an unsigned integral type, always use
/// default
/// \tparam IsFloat if \p T is a floating-point type, always use default
/// \tparam IsString if \p T is \c std::string, always use default
///
/// \note Specializations of this struct are provided for arithmentic types
/// and \c std::string.
template <typename T,
bool IsSignedInt =
(std::is_integral<T>::value && std::is_signed<T>::value),
bool IsUnsignedInt =
(std::is_integral<T>::value && std::is_unsigned<T>::value),
bool IsFloat = std::is_floating_point<T>::value,
bool IsString = std::is_same<T, std::string>::value>
struct ValueParser {
///
///
/// \param Cell the \c std::string to parse
///
/// \return the parsed value
///
/// \note The function silently fails if cannot parse \p Cell for type \p T.
static T parse(const std::string &Cell) noexcept;
};
template <typename T> struct ValueParser<T, true, false, false, false> {
STATIC_ASSERT((std::is_integral<T>::value && std::is_signed<T>::value),
"wrong type"); // Sanity check.
static T parse(const std::string &Cell) noexcept {
return static_cast<T>(std::stoll(Cell));
}
};
template <typename T> struct ValueParser<T, false, true, false, false> {
STATIC_ASSERT((std::is_integral<T>::value && std::is_unsigned<T>::value),
"wrong type"); // Sanity check.
static T parse(const std::string &Cell) noexcept {
return static_cast<T>(std::stoull(Cell));
}
};
template <typename T> struct ValueParser<T, false, false, true, false> {
STATIC_ASSERT((std::is_floating_point<T>::value),
"wrong type"); // Sanity check.
static T parse(const std::string &Cell) noexcept {
return static_cast<T>(std::stold(Cell));
}
};
template <typename T> struct ValueParser<T, false, false, false, true> {
STATIC_ASSERT((std::is_same<T, std::string>::value),
"wrong type"); // Sanity check.
static T parse(const std::string &Cell) noexcept { return Cell; }
};
/// Parses and stores entries from a row of CSV data.
///
/// \tparam Ts types of values to parse and store, i.e. entries in the row
///
/// \note The implementation relies on \c rosa::csv::CSVRowParser, which is
/// implemented only for `arithmetic` types -- signed and unsigned integral
/// and floating-point types -- and for \c std::string. Those are the valid
/// values for \p Ts.
template <typename... Ts> class CSVRow {
private:
/// Parses a given row of CSV data into \c CSVRow::Data.
///
/// \ CSVRow::Data is filled with values parsed from \p LineStream. Entries
/// in the line are to be separated by commas, the character `,`.
///
/// \note Parsed values are silently converted to types \p Ts.
///
/// \note Parsing silently fails if values do not match \p Ts.
///
/// \tparam S0 indices to access tuple elements.
///
/// \param [in,out] LineStream the line to parse
///
/// \note The last argument is used only to get \p S0, the actual value of
/// the parameter is ignored.
template <size_t... S0>
- void parseRow(std::stringstream &LineStream, char Delimeter, Seq<S0...>) {
+ void parseRow(std::stringstream &LineStream, char Delimiter, Seq<S0...>) {
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0),
"Not matching template arguments.");
std::string Cell;
// Get fields and parse the values into the proper element of the tuple
// one by one in a fold expression.
- ((std::getline(LineStream, Cell, Delimeter),
+ ((std::getline(LineStream, Cell, Delimiter),
std::get<S0>(Data) = ValueParser<Ts>::parse(Cell)),
...);
}
public:
/// Constructor with all possible parameters
///
/// The function creates an instance of an CSVRow object and sets the
/// attributes of the
/// object to the values of the parameters.
///
/// \param SkipRows the number of data rows to skip, not taking header into
/// account.
/// \param HeaderInfo is the first line of the file a header row or not.
- /// \param Delimeter to seperate between the data entries within one row.
+ /// \param Delimiter to seperate between the data entries within one row.
CSVRow(const size_t SkipRows = 0,
const HeaderInformation HeaderInfo = HeaderInformation::HasHeader,
- const char Delimeter = ',')
- : SkipRows(SkipRows), HeaderInfo(HeaderInfo), Delimeter(Delimeter),
+ const char Delimiter = ',')
+ : SkipRows(SkipRows), HeaderInfo(HeaderInfo), Delimiter(Delimiter),
RowNumber(0), IsHeaderRead(false) {}
/// Parses and stores one row of CSV data.
///
/// The function reads one line from \p Str and parses it into
/// \c rosa::csv::CSVRow::Data using \c rosa::csv::CSVRowParser.
///
/// \param [in,out] Str input stream of a CSV file
void readNextRow(std::istream &Str) noexcept {
std::string Line;
std::getline(Str, Line);
if (Line.size() > 0) {
std::stringstream LineStream(Line);
- parseRow(LineStream, Delimeter, seq_t<sizeof...(Ts)>());
+ parseRow(LineStream, Delimiter, seq_t<sizeof...(Ts)>());
RowNumber = RowNumber + 1;
}
}
/// Read header row and stores it as \p std::string.
///
/// The function reads the first line of the csv file and stores the entries
/// in a vector.
///
/// \param [in,out] Str input stream of a CSV file
void readHeader(std::istream &Str) noexcept {
std::string Line;
std::getline(Str, Line);
std::stringstream LineStream(Line);
std::string Value;
- while (getline(LineStream, Value, Delimeter)) {
+ while (getline(LineStream, Value, Delimiter)) {
Header.push_back(Value);
}
IsHeaderRead = true;
}
/// The number of rows to skip once.
///
/// This function returns the number of data rows to skip
/// at the beginning of the file.
///
/// \return The number of rows to skip at the beginning of a csv file.
inline size_t SkipNumRows() const noexcept { return this->SkipRows; }
/// The current row number within the csv file.
///
/// This function returns the current row number. The header
/// row is not counted as a row.
///
/// \returns the current row number within the csv file.
inline size_t CurRow() const noexcept { return this->RowNumber; }
/// Indiciates if the header was already read.
///
/// This function returns true, if the header of a csv file which contains
/// a header file is already read.
/// The user has to pass in the attribute HeaderInfo the information if the
/// file has in the first row the header row or not.
///
/// \return if the header of a file is already read.
inline bool IsHeaderReadDone() const noexcept { return this->IsHeaderRead; }
/// Indicates if the file contains a header row in the first row.
///
/// This function returns if the file contains a header row.
/// The information if the file contains a header row or not, has to be passed
/// by the user.
/// The standard value is HeaderInformation::HasHeader
///
/// \return if the csv file contains a header row in the first line of the
/// file.
inline HeaderInformation HasFileHeader() const noexcept {
return this->HeaderInfo;
}
/// Set the number of rows to skip.
///
/// This function sets the number of rows to skip at the beginning of
/// the reading of the file.
///
- /// \param SkipRows the number of rows you want to skip at the beginning of
+ /// \param _SkipRows the number of rows you want to skip at the beginning of
/// the file.
// NOTE (Maxi): I had to change "SkipRows" to "_SkipRows" because otherwise:
// "warning: C4458: declaration of 'SkipRows' hides class member"
inline void SetSkipRows(const size_t _SkipRows) noexcept {
this->SkipRows = _SkipRows;
}
/// Is the first row a header row or not.
///
/// This function sets the information, if the first row of the csv file
/// is a header line or not.
///
- /// \param HeaderInfo if the first row is a header row or not.
+ /// \param _HeaderInfo if the first row is a header row or not.
// NOTE (Maxi): I had to change "HeaderInfo" to "_HeaderInfo", otherwise:
// "warning: C4458: declaration of 'HeaderInfo' hides class member"
inline void SetHeaderInfo(const HeaderInformation _HeaderInfo) noexcept {
this->HeaderInfo = _HeaderInfo;
}
/// Set the seperator between data entries.
///
/// This funcction sets the separator between the data entries of the csv
/// file.
///
- /// \param Delimeter the character that separates the data values.
- // NOTE (Maxi): I had to change "Delimeter" to "_Delimeter" because otherwise:
- // "warning: C4458: declaration of 'Delimeter' hides class member"
- inline void SetDelimeter(char _Delimeter) { this->Delimeter = _Delimeter; }
+ /// \param _Delimiter the character that separates the data values.
+ // NOTE (Maxi): I had to change "Delimiter" to "_Delimiter" because otherwise:
+ // "warning: C4458: declaration of 'Delimiter' hides class member"
+ inline void SetDelimiter(char _Delimiter) { this->Delimiter = _Delimiter; }
/// Gives a constant references for the \c std::tuple containing the values
/// read by \p this object.
///
/// \return \c CSVRow::Data
const std::tuple<Ts...> &tuple(void) const noexcept { return Data; }
private:
std::tuple<Ts...> Data; ///< Stores parsed entries
size_t SkipRows; ///< The number of rows to skip at the very beginning of the
/// file.
///< This number only applies on the number of data rows.
///< If your file contains a header row and data rows, the skiping
///< of the header row is not taken into account.
HeaderInformation HeaderInfo; ///< If the file contains a header row or not.
- char Delimeter; ///< The seperator between the data entries.
+ char Delimiter; ///< The seperator between the data entries.
size_t RowNumber; ///< Current row number, counts all row numbers including
/// the header row.
bool IsHeaderRead; ///< Was the header read or not.
std::vector<std::string> Header; ///< The content of the header row.
};
/// Reads a row of CSV data into \c rosa::csv::CSVRow.
///
/// The next line is read from \p Str by calling
/// \c rosa::csv::CSVRow::readNextRow on \p Data until all lines are
/// skipped.
///
/// If the function is called for the first time and the file contains
/// a header than is the header and the first data row read in after the
/// number of rows that the user wants to skip.
///
/// \tparam Ts type of values to read from the row
///
/// \note The CSV file should contain a line with fields matching \p Ts...
///
/// \param [in,out] Str input stream of a CSV file
/// \param [in,out] Data object to read the next line into
///
/// \return \p Str after reading one line from it
template <typename... Ts>
std::istream &operator>>(std::istream &Str, CSVRow<Ts...> &Data) {
if (Data.HasFileHeader() == HeaderInformation::HasHeader &&
!Data.IsHeaderReadDone()) {
Data.readHeader(Str);
}
while (Data.CurRow() < (Data.SkipNumRows())) {
Data.readNextRow(Str);
}
// read the lines after you skipped the number of rows you want to skip
Data.readNextRow(Str);
return Str;
}
} // End namespace
/// Provides `InputIterator` features for iterating over a CSV file.
///
/// The iterator parses rows into `std::tuple` values and iterates over the
/// file row by row.
///
/// \tparam Ts types of values stored in one row of the CSV file
///
/// \note The iterator expects each row to consists of fields matching \p Ts.
///
/// \note The implementation relies on \c rosa::csv::CSVRow, which in turn
/// relies on \c rosa::csv::CSVRowParser, which is implemented only for
/// `arithmetic` types -- signed and unsigned integral types and floating-point
/// types -- and for \c std::string. Those are the valid values for \p Ts
template <typename... Ts> class CSVIterator {
public:
/// \defgroup CSVIteratorTypedefs Typedefs of rosa::csv::CSVIterator
///
/// Standard `typedef`s for iterators.
///
///@{
typedef std::input_iterator_tag
iterator_category; ///< Category of the iterator.
typedef std::tuple<Ts...> value_type; ///< Type of values iterated over.
typedef std::size_t difference_type; ///< Type to identify distance.
typedef std::tuple<Ts...> *pointer; ///< Pointer to the type iterated over.
typedef std::tuple<Ts...>
&reference; ///< Reference to the type iterated over.
///@}
/// Creates a new instance.
///
/// \param [in,out] S input stream to iterate over
/// \param SkipRows the number of rows you want to skip only once at
/// the beginning of the file.
/// If you have an header in the file, it is supposed to be
/// the first row, and it will be always read out.
/// But after this header the next number of Rows will be
/// skipped.
/// \param HeaderInfo is used to know wheter the file contains an
/// header row or not.
/// The header has to be in the first row.
- /// \param Delimeter is the separator between the differnt values of
+ /// \param Delimiter is the separator between the differnt values of
/// the csv file.
CSVIterator(std::istream &S, const size_t SkipRows = 0,
const HeaderInformation HeaderInfo = HeaderInformation::HasHeader,
- const char Delimeter = ',')
+ const char Delimiter = ',')
: Str(S.good() ? &S : nullptr), SkipRows(SkipRows),
- HeaderInfo(HeaderInfo), Delimeter(Delimeter), Row() {
+ HeaderInfo(HeaderInfo), Delimiter(Delimiter), Row() {
Row.SetSkipRows(SkipRows);
Row.SetHeaderInfo(HeaderInfo);
- Row.SetDelimeter(Delimeter);
+ Row.SetDelimiter(Delimiter);
// \c rosa::csv::CSVIterator::Row is initialized empty so the first
// incrementation here will read the first row.
++(*this);
}
/// Creates an empty new instance.
CSVIterator(void) noexcept : Str(nullptr) {}
/// Pre-increment operator.
///
/// The implementation reads the next row. If the end of the input stream is
/// reached, the operator becomes empty and has no further effect.
///
/// \return \p this object after incrementing it.
CSVIterator &operator++() {
if (Str) {
if (!((*Str) >> Row)) {
Str = nullptr;
}
}
return *this;
}
/// Post-increment operator.
///
/// The implementation uses the pre-increment operator and returns a copy of
/// the original state of \p this object.
///
/// \return \p this object before incrementing it.
CSVIterator operator++(int) {
CSVIterator Tmp(*this);
++(*this);
return Tmp;
}
/// Returns a constant reference to the current entry.
///
/// \note Should not dereference the iterator when it is empty.
///
/// \return constant reference to the current entry.
const std::tuple<Ts...> &operator*(void)const noexcept { return Row.tuple(); }
/// Returns a constant pointer to the current entry.
///
/// \note Should not dereference the iterator when it is empty.
///
/// \return constant pointer to the current entry.
const std::tuple<Ts...> *operator->(void)const noexcept {
return &Row.tuple();
}
/// Tells if \p this object is equal to another one.
///
/// Two \c rosa::csv::CSVReader instances are equal if and only if they are
/// the same or both are empty.
///
/// \param RHS other object to compare to
///
/// \return whether \p this object is equal with \p RHS
bool operator==(const CSVIterator &RHS) const noexcept {
return ((this == &RHS) || ((this->Str == nullptr) && (RHS.Str == nullptr)));
}
/// Tells if \p this object is not equal to another one.
///
/// \see rosa::csv::CSVReader::operator==
///
/// \param RHS other object to compare to
///
/// \return whether \p this object is not equal with \p RHS.
bool operator!=(const CSVIterator &RHS) const noexcept {
return !((*this) == RHS);
}
- /// Set the delimeter used in the csv file.
- /// \param Delimeter the character which separates the values in the csv file.
- // NOTE (Maxi): I had to change "Delimeter" to "_Delimeter" because otherwise:
- // "warning: C4458: declaration of 'Delimeter' hides class member"
- inline void setDelimeter(char _Delimeter) noexcept {
- this->Delimeter = _Delimeter;
+ /// Set the delimiter used in the csv file.
+ /// \param _Delimiter the character which separates the values in the csv file.
+ // NOTE (Maxi): I had to change "Delimiter" to "_Delimiter" because otherwise:
+ // "warning: C4458: declaration of 'Delimiter' hides class member"
+ inline void setDelimiter(char _Delimiter) noexcept {
+ this->Delimiter = _Delimiter;
}
- /// get the delimeter currently set to separate the values in the csv file.
+ /// get the delimiter currently set to separate the values in the csv file.
/// \return the current character, which is used to separte teh values in the
/// csv file.
- inline char getDelimeter() const noexcept { return this->Delimeter; }
+ inline char getDelimiter() const noexcept { return this->Delimiter; }
private:
std::istream *Str; ///< Input stream of a CSV file to iterate over.
size_t SkipRows; ///< Number of Rows to skip only once at the beginning of the
/// file.
HeaderInformation HeaderInfo; ///< does the csv file contain a header or not,
/// if this information is
///< not given correclty, the reading of the header would result in
///< in an error.
- char Delimeter; ///< Delimeter between the entries in the csv file.
+ char Delimiter; ///< Delimiter between the entries in the csv file.
CSVRow<Ts...> Row; ///< Content of the current row
};
} // End namespace csv
} // End namespace rosa
#endif // ROSA_SUPPORT_CSV_CSVREADER_HPP
diff --git a/include/rosa/support/csv/CSVWriter.hpp b/include/rosa/support/csv/CSVWriter.hpp
index a077e3d..f1cf2ac 100755
--- a/include/rosa/support/csv/CSVWriter.hpp
+++ b/include/rosa/support/csv/CSVWriter.hpp
@@ -1,221 +1,221 @@
//===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/csv/CSVWriter.hpp
///
/// \authors David Juhasz (david.juhasz@tuwien.ac.at)
/// Edwin Willegger (edwin.willegger@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Facitilities to write CSV files.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_CSV_CSVWRITER_HPP
#define ROSA_SUPPORT_CSV_CSVWRITER_HPP
#include <iostream>
#include <ostream>
#include <tuple>
#include <vector>
#include <array>
#include "rosa/support/log.h"
namespace rosa {
namespace csv {
/// Provides facilities to write values into a CSV file.
///
/// The writer emits a comma, the character `,`, between each written values.
/// The resulted stream is a flat CSV file as it consists of onlyone row, no new
/// line is emitted.
///
/// \tparam T type of values to write
template <typename T>
class CSVWriter {
public:
/// Creates a new instance.
///
/// \param [in,out] S output stream to write to
///
/// \note The writer operates on non-binary outputs as long as \p S is in
/// good state.
CSVWriter(std::ostream &S)
: Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr),
IsFirst(true) {}
/// Tells if the last operation was successful.
///
/// \return if the last operation was successful
bool good(void) const noexcept {
return Str != nullptr;
}
/// Writes an entry to the output stream.
///
/// The implementation does anything only if the last operation was
/// successful. If so, \p V is written to \c rosa::csv::CSVWriter::Str.
/// The emitted value is preceded with a comma if the actual call is not the
/// first one for \p this object. Success of the operation is checked at the
/// end.
///
/// \param V value to write
void write(const T &V) {
if (Str) {
if (!IsFirst) {
*Str << ',';
} else {
IsFirst = false;
}
*Str << V;
if (!Str->good()) {
Str = nullptr;
}
}
}
private:
std::ostream *Str; ///< Output stream to write to.
bool IsFirst; ///< Denotes if the next write would be the first one.
};
/// Writes a tuple of values into a CSV file
///
/// \tparam Ts types of values to write
template <typename... Ts> class CSVTupleWriter {
public:
// typedef <Ts...> value_type ; ///< Type of values written.
typedef std::tuple<Ts...> value_type;
/// Creates a new instance.
///
/// \param [in,out] S output stream to write to
///
/// \note The writer operates on non-binary outputs as long as \p S is in
/// good state.
CSVTupleWriter(std::ostream &S)
: Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr),
IsHeaderWritten(false), IsDataWritten(false) {}
/// Tells if the last operation was successful.
///
/// \return if the last operation was successful
bool good(void) const noexcept {
return Str != nullptr;
}
/// Write the values of a tuple to a CSV file with \c rosa::csv::CSVTupleWriter.
///
/// \see rosa::csv::CSVTupleWriter
///
///
/// \param [in,out] values tuple, which values are written in a recusive fashion into a stream.
template<size_t i = 0>
void write(const std::tuple<Ts...> &values) {
constexpr size_t size = sizeof...(Ts);
LOG_TRACE_STREAM << "Writing tuple values into file \n";
LOG_TRACE_STREAM << " Tuple has " << std::to_string(size) << " elements. \n";
LOG_TRACE_STREAM << " Value is " << std::get<i>(values);
if(Str){
/// Write the current element of the tuple into the stream and add a separtor after it,
/// and call the function for the next element in the tuple.
if constexpr(i+1 != sizeof...(Ts)){
*Str << std::get<i>(values) << ", ";
write<i+1>(values);
/// If the last element is written into the stream than begin a new line.
}else if constexpr(i + 1 == sizeof...(Ts)){
*Str << std::get<i>(values) << '\n';
/// every time the last data value of a line is written, the flag indicates that data was already written into the file.
IsDataWritten = true;
}
}
}
/// Write the header values to a CSV file with \c rosa::csv::CSVTupleWriter.
///
/// \note The function has no effect if anything has already been written
/// to the output stream either by \c
/// rosa::csv::CSVTupleWriter::writeHeader() or \c
/// rosa::csv::CSVTupleWriter::write().
///
/// \see rosa::csv::CSVTupleWriter
///
/// \param header the content of the header line.
void writeHeader(const std::array<std::string, sizeof...(Ts)> &header){
size_t index = 0;
/// write into the stream only, if it is not a nullptr, and if no data and no header was already written into it.
if(Str && IsDataWritten == false && IsHeaderWritten == false){
index = 0;
for (auto i = header.begin(); i != header.end(); ++i){
index = index + 1;
- /// write into the stream every entry with a delimeter, in this case ", " until
+ /// write into the stream every entry with a delimiter, in this case ", " until
/// the last entry
if(index != header.size()){
*Str << *i << ", ";
- /// write the last entry into the stream, without any delimeter
+ /// write the last entry into the stream, without any delimiter
}else {
*Str << *i;
}
}
/// finish the header line and start a new line.
*Str << '\n';
/// now it is not possible to write additional header lines.
IsHeaderWritten = true;
}
}
private:
std::ostream *Str; ///< Output stream to write to.
bool IsHeaderWritten; ///< If an header line was already written into the stream. If set than no additional header could be written.
bool IsDataWritten; ///< If one line of data has already been written into the stream, than no headerline could be added.
};
/// Writes all values of a tuple to a CSV file with \c rosa::csv::CSVTupleWriter.
///
/// \see rosa::csv::CSVTupleWriter
///
/// \tparam Ts types of values to write
///
/// \param [in,out] W object to write with
/// \param V values to write
///
/// \return \p W after writing \p V with it
template <typename... Ts>
CSVTupleWriter<Ts...> &operator<<(CSVTupleWriter<Ts...> &W, const std::tuple<Ts...> &V)
{
W.write(V);
return W;
}
/// Writes a value to a CSV file with \c rosa::csv::CSVWriter.
///
/// \see rosa::csv::CSVWriter
///
/// \tparam T type of value to write
///
/// \param [in,out] W object to write with
/// \param V value to write
///
/// \return \p W after writing \p V with it
template <typename T>
CSVWriter<T> &operator<<(CSVWriter<T> &W, const T& V) {
W.write(V);
return W;
}
} // End namespace csv
} // End namespace rosa
#endif // ROSA_SUPPORT_CSV_CSVWRITER_HPP
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Nov 11, 12:43 PM (1 d, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
235885
Default Alt Text
(59 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment