diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index eceb893..f39a687 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,7 @@ # Add the different subdirectories add_subdirectory(basic-system) add_subdirectory(type-facilities) add_subdirectory(messaging) add_subdirectory(messaging-system) +add_subdirectory(agent-modules) diff --git a/examples/agent-modules/CMakeLists.txt b/examples/agent-modules/CMakeLists.txt new file mode 100644 index 0000000..83c83ac --- /dev/null +++ b/examples/agent-modules/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(agent-modules agent-modules.cpp) +ROSA_add_library_dependencies(agent-modules ROSAConfig) +ROSA_add_library_dependencies(agent-modules ROSACore) +ROSA_add_library_dependencies(agent-modules ROSAAgent) + diff --git a/examples/agent-modules/agent-modules.cpp b/examples/agent-modules/agent-modules.cpp new file mode 100644 index 0000000..1256051 --- /dev/null +++ b/examples/agent-modules/agent-modules.cpp @@ -0,0 +1,106 @@ +/******************************************************************************* + * + * File: agent-modules.cpp + * + * Contents: A simple example on how to define Agents with Modules. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#include "rosa/agent/Abstraction.hpp" +#include "rosa/agent/Confidence.hpp" + +#include "rosa/config/version.h" + +#include "rosa/core/Agent.hpp" +#include "rosa/core/MessagingSystem.hpp" + +#include "rosa/support/log.h" +#include "rosa/support/terminal_colors.h" + +#include +#include + +using namespace rosa; +using namespace rosa::agent; +using namespace rosa::terminal; + +// A dummy wrapper for testing MessagingSystem. +// NOTE: Since we test MessagingSystem directly here, we need to get access to +// its protected members. That we do by imitating to be a decent subclass of +// MessagingSystem, while calling protected member functions on an object of a +// type from which we actually don't inherit. +struct SystemTester : protected MessagingSystem { + template + static AgentHandle createMyAgent(MessagingSystem *S, const std::string &Name, + Funs &&... Fs) { + return ((SystemTester *)S)->createAgent(Name, std::move(Fs)...); + } + + static void destroyMyAgent(MessagingSystem *S, const AgentHandle &H) { + ((SystemTester *)S)->destroyUnit(unwrapAgent(H)); + } +}; + +// A special Agent with its own state. +class MyAgent : public Agent { +public: + using Tick = AtomConstant; + +private: + enum class Categories { Bad, Normal, Good }; + + static const std::map CategoryNames; + History H; + Confidence C; + RangeAbstraction A; + +public: + void handler(Tick, uint8_t V) noexcept { + // Record V to the History, then print state info. + H << V; + ASSERT(H.entry() == V); // Sanity check. + LOG_INFO_STREAM << std::endl + << "Next value: " << PRINTABLE(V) + << ", confidence: " << C(H) + << ", category: " << CategoryNames.at(A(H.entry())) + << std::endl; + } + + MyAgent(const AtomValue Kind, const rosa::id_t Id, const std::string &Name, + MessagingSystem &S) + : Agent(Kind, Id, Name, S, THISMEMBER(handler)), H(), C(5, 20, 1), + A({{{10, 14}, Categories::Normal}, + {{15, 17}, Categories::Good}, + {{18, 19}, Categories::Normal}}, + Categories::Bad) {} +}; + +const std::map MyAgent::CategoryNames{ + {Categories::Bad, "Bad"}, + {Categories::Normal, "Normal"}, + {Categories::Good, "Good"}}; + +int main(void) { + LOG_INFO_STREAM << library_string() << " -- " << Color::Red + << "agent-modules example" << Color::Default << std::endl; + + std::unique_ptr S = MessagingSystem::createSystem("Sys"); + MessagingSystem *SP = S.get(); + + AgentHandle A = SystemTester::createMyAgent(SP, "MyAgent"); + + std::vector Vs{4, 5, 6, 7, 9, 10, 11, 13, + 15, 14, 15, 16, 19, 20, 21}; + for (auto I = Vs.begin(); I != Vs.end(); ++I) { + A.send(MyAgent::Tick::Value, *I); + } + + SystemTester::destroyMyAgent(SP, A); + + return 0; +} + diff --git a/include/rosa/agent/Abstraction.hpp b/include/rosa/agent/Abstraction.hpp new file mode 100644 index 0000000..88c4eec --- /dev/null +++ b/include/rosa/agent/Abstraction.hpp @@ -0,0 +1,145 @@ +/******************************************************************************* + * + * File: Abstraction.hpp + * + * Contents: Definition of Abstraction Module. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#ifndef ROSA_AGENT_ABSTRACTION_HPP +#define ROSA_AGENT_ABSTRACTION_HPP + +#include "rosa/agent/Module.h" + +#include "rosa/support/debug.hpp" + +#include +#include + +namespace rosa { +namespace agent { + +// Abstracts values from type T to type A. +template class Abstraction : public Module { +protected: + // Value to be returned if by default. + const A Default; + +public: + // Ctor. + Abstraction(const A Default) noexcept : Default(Default) {} + + // Dtor. + ~Abstraction(void) = default; + + // Abstracts the given value of type T into a value of type A. + virtual A operator()(const T &) const noexcept { return Default; } +}; + +// Implements Abstraction as a map from T to A. This implementation is supposed +// to be used to abstract between enumeration types. +template +class MapAbstraction : public Abstraction, private std::map { + // Make sure the actual type arguments are enumerations. + STATIC_ASSERT((std::is_enum::value && std::is_enum::value), + "mapping not enumerations"); + + // Bringing into scope inherited members. + using Abstraction::Default; + using std::map::end; + using std::map::find; + +public: + // Ctor. Initializes the mapping. + MapAbstraction(const std::map &Map, const A Default) noexcept + : Abstraction(Default), + std::map(Map) {} + + // Dtor. + ~MapAbstraction(void) = default; + + // Gives a value of type A associated by the underlying map to V of type T, + // or Default if no mapping is defined for V. + A operator()(const T &V) const noexcept override { + const auto I = find(V); + return I == end() ? Default : *I; + } + +}; + +// Implements Abstraction as a map from ranges of T to A. This implementation +// is supposed to be used to abstract ranges of arithmetic types into +// enumerations. +// INV: The keys in the underlying map define valid ranges (first <= second) +// and there are no overlapping ranges defined by the keys. +template +class RangeAbstraction : public Abstraction, + private std::map, A> { + // Make sure the actual type arguments are matching our expectations. + STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); + STATIC_ASSERT((std::is_enum::value), "abstracting not to enumeration"); + + // Bringing into scope inherited members. + using Abstraction::Default; + using std::map, A>::begin; + using std::map, A>::end; + using std::map, A>::find; + +public: + // Ctor. Initializes and validates the mapping. + // PRE: Each key defines a valid range (first <= second) and there are no + // overlapping ranges defined by the keys. + RangeAbstraction(const std::map, A> &Map, const A &Default) + : Abstraction(Default), std::map, A>(Map) { + // Sanity check. + ASSERT(std::all_of( + begin(), end(), [this](const std::pair, A> &P) { + return P.first.first <= P.first.second && + std::all_of(++find(P.first), end(), + [&P](const std::pair, A> &R) { + // NOTE: Values in Map are sorted. + return P.first.first < P.first.second && + P.first.second <= R.first.first || + P.first.first == P.first.second && + P.first.second < R.first.first; + }); + })); + } + + // Dtor. + ~RangeAbstraction(void) = default; + + // Gives a value of type A associated by the underlying map to V of type T, + // or Default if no range containing V is defined. + A operator()(const T &V) const noexcept override { + auto I = begin(); + bool found = false; // Indicates if I refers to a matching range. + bool failed = false; // Indicates if it is pointless to continue searching. + while (!found && !failed && I != end()) { + if (V < I->first.first) { + // No match so far and V is below the next range, never will match. + // NOTE: Keys are sorted in the map. + failed = true; + } else if (I->first.first <= V && V < I->first.second) { + // Matching range found. + found = true; + } else { + // Cannot conclude in this step, move to the next range. + ++I; + } + } + ASSERT(!found || I != end()); + return found ? I->second : Default; + } + +}; + +} // End namespace agent +} // End namespace rosa + +#endif // ROSA_AGENT_ABSTRACTION_HPP + diff --git a/include/rosa/agent/Confidence.hpp b/include/rosa/agent/Confidence.hpp new file mode 100644 index 0000000..9251f26 --- /dev/null +++ b/include/rosa/agent/Confidence.hpp @@ -0,0 +1,151 @@ +/******************************************************************************* + * + * File: Confidence.hpp + * + * Contents: Definition of Confidence Module. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#ifndef ROSA_AGENT_CONFIDENCE_HPP +#define ROSA_AGENT_CONFIDENCE_HPP + +#include "rosa/agent/History.hpp" + +#include "rosa/support/debug.hpp" + +#include + +namespace rosa { +namespace agent { + +// Confidence validator. It checks plausibility of given values by validating +// if a valid region contains them. It also capable of checking consistency by +// validating the change rate recorded by a History Module against a maximal +// absolute valid rate of change. +// NOTE: The template is defined only for arithmetic types. +// NOTE: The lower bound is inclusive and the upper bound is exclusive. +// INV: LowerBound <= UpperBound +template class Confidence : public Module { + // Make sure the actual type argument is an arithmetic type. + STATIC_ASSERT(std::is_arithmetic::value, "not arithmetic Confidence"); + +public: + + // Unsigned type corresponding to T if any. + using UT = unsigned_t; + + // The minimal value of type T. + // NOTE: Not exist V of type T such that V < Min. + static constexpr T Min = std::is_integral::value + ? std::numeric_limits::min() + : std::numeric_limits::lowest(); + + // The maximal value of type T. + // NOTE: Not exist V of type T such that V > Max. + static constexpr T Max = + (std::is_integral::value || !std::numeric_limits::has_infinity) + ? std::numeric_limits::max() + : std::numeric_limits::infinity(); + + // The maximal value of type UT. + // NOTE: Not exist V of type UT such that V > UnsignedMax + static constexpr UT UnsignedMax = + (std::is_integral::value || !std::numeric_limits::has_infinity) + ? std::numeric_limits::max() + : std::numeric_limits::infinity(); + +private: + // The inclusive lower bound for plausibility check. + T LowerBound; + + // The exclusive upper bound for plausibility check. + T UpperBound; + + // The maximal absolute rate of change for consistency check. + UT ChangeRate; + +public: + // Ctor. + // NOTE: A Confidence Module must be created with a valid state. + // PRE: LowerBound <= UpperBound + Confidence(const T LowerBound = Min, const T UpperBound = Max, + const UT ChangeRate = UnsignedMax) noexcept + : LowerBound(LowerBound), + UpperBound(UpperBound), + ChangeRate(ChangeRate) { + // Make sure Confidence is created in a valid state. + if (LowerBound > UpperBound) { + ROSA_CRITICAL("Confidence with LowerBound higher than UpperBound"); + } + } + + // Dtor. + ~Confidence(void) = default; + + // Puts the actual parameters of the instance into the given variables. + void getParameters(T &LowerBound, T &UpperBound, UT &ChangeRate) const + noexcept { + // Copy members to the given references. + LowerBound = this->LowerBound; + UpperBound = this->UpperBound; + ChangeRate = this->ChangeRate; + } + + // Sets the lower bound, and adjusts the upper bound to the given lower bound + // if the new lower bound would be higher than the upper bound. + void setLowerBound(const T LowerBound) noexcept { + // Adjust UpperBound if necessary, then set LowerBound. + if (UpperBound < LowerBound) { + UpperBound = LowerBound; + } + this->LowerBound = LowerBound; + } + + // Sets the upper bound, and adjusts the lower bound to the given upper bound + // if the new upper bound would be lower than the lower bound. + void setUpperBound(const T UpperBound) noexcept { + // Adjust LowerBound if necessary, then set UpperBound. + if (UpperBound < LowerBound) { + LowerBound = UpperBound; + } + this->UpperBound = UpperBound; + } + + // Sets the maximal rate of change. + void setChangeRate(const UT ChangeRate) noexcept { + // Set ChangeRate. + this->ChangeRate = ChangeRate; + } + + // Tells the binary confidence on the plausibility of the given value. + bool operator()(const T V) const noexcept { + // Return if V is plausible. + return LowerBound <= V && V < UpperBound; + } + + // Tells the binary confidence on the plausibility and consistency of the + // last value recorded by the History. The latter is done by validating the + // difference with the preceding entry. + // NOTE: An empty History results in full confidence. + template + bool operator()(const History &H) const noexcept { + if (H.empty()) { + // No entry to validate. + return true; + } else { + // Validate the last entry and the one step average absolute difference. + return (*this)(H.entry()) && H.averageAbsDiff(1) <= ChangeRate; + } + } + +}; + +} // End namespace agent +} // End namespace rosa + +#endif // ROSA_AGENT_CONFIDENCE_HPP + diff --git a/include/rosa/agent/History.hpp b/include/rosa/agent/History.hpp new file mode 100644 index 0000000..080cede --- /dev/null +++ b/include/rosa/agent/History.hpp @@ -0,0 +1,214 @@ +/******************************************************************************* + * + * File: History.hpp + * + * Contents: Definition of History Module. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#ifndef ROSA_AGENT_HISTORY_HPP +#define ROSA_AGENT_HISTORY_HPP + +#include "rosa/agent/Module.h" + +#include "rosa/config/config.h" + +#include "rosa/support/debug.hpp" +#include "rosa/support/type_helper.hpp" + +#include + +namespace rosa { +namespace agent { + +// Retention policies defining what a History instance should do when the +// number of recorded entries reached its capacity. +enum class HistoryPolicy { + SRWF, // Stop Recording When Full -- no new entry is recorded when full + FIFO // First In First Out -- overwrite the earliest entry with a new one +}; + +// NOTE: Not thread-safe implementation, which should not be a problem as a +// Module instance is an internal component of an Agent, which is the basic +// unit of concurrency. +template +class History : public Module, private std::array { + + // Bring into scope inherited functions that are used. + // INV: max_size() == N + 1 && N == max_size() - 1 + using std::array::max_size; + using std::array::operator[]; + + // The indices of the first data element and the first empty slot in the + // circular buffer. + size_t Data, Space; + +public: + // Ctor. Initializes indices. + History(void) noexcept : Data(0), Space(0) {} + + // Dtor. + ~History(void) = default; + + // Tells the policy applied to the History. + static constexpr HistoryPolicy policyOfHistory(void) noexcept { return P; } + + // Tells how many entries may be recorded by the History. + // NOTE: The number of entries that are actually recorded may be smaller. + static constexpr size_t lengthOfHistory(void) noexcept { return N; } + + // Tells how many entries are currently recorded by the History. + // POST: 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory() + inline size_t numberOfEntries(void) const noexcept { + return Data <= Space ? Space - Data : max_size() - Data + Space; + } + + // Tells if the History has not recorded any entries yet. + inline bool empty(void) const noexcept { + return numberOfEntries() == 0; + } + + // Gives a constant lvalue reference to the I-th latest entry stored in the + // History. + // PRE: 0 <= I && I <= numberOfEntries() + const T &entry(const size_t I = 0) const noexcept { + ASSERT(0 <= I && I < numberOfEntries()); // Boundary check. + // Position counted back from the last recorded entry. + typename std::make_signed::type Pos = Space - (1 + I); + // Actual index wrapped around to the end of the buffer if negative. + return (*this)[Pos >= 0 ? Pos : max_size() + Pos]; + } + +private: + // Tells if the circular buffer is full. + inline bool full(void) const noexcept { return numberOfEntries() == N; } + + // Pushes a new entry into the circular buffer, removing the earliest entry + // if the buffer is full. + void pushBack(const T& V) noexcept { + // Store value to the first empty slot and step Space index. + (*this)[Space] = V; + Space = (Space + 1) % max_size(); + if (Data == Space) { + // Buffer was full, step Data index. + Data = (Data + 1) % max_size(); + } + } + +public: + // Adds a new entry to the History and tells if the operation was successful. + // NOTE: Success of the operation depends on the actual policy. + bool addEntry(const T &V) noexcept { + switch (P) { + default: + ROSA_CRITICAL("unkown HistoryPolicy"); + case HistoryPolicy::SRWF: + if (full()) { + return false; + } + // NOTE: Fall through to FIFO which unconditionally pushes the new entry. + case HistoryPolicy::FIFO: + // FIFO and SRWF not full. + pushBack(V); + return true; + } + } + + // Tells the trend set by the entries recorded by the History. The number of + // steps to go back in the History is given as argument. + // NOTE: The number of steps that can be made is limited by the number of + // entries recorded by the History. + // NOTE: The function is made a template only to be able to use enable_if. + // STATIC PRE: std::is_arithmetic::value && std::is_signed::value + // PRE: 0 <= D && D < N + template + typename std::enable_if< + std::is_arithmetic::value && std::is_signed::value, X>::type + trend(const size_t D = N - 1) const noexcept { + STATIC_ASSERT((std::is_same::value), "not default template arg"); + ASSERT(0 <= D && D < N); // Boundary check. + if (numberOfEntries() < 2 || D < 1) { + // No entries for computing trend. + return {}; // Zero element of T + } else { + // Here at least two entries. + // S is the number of steps that can be done. + const size_t S = std::min(numberOfEntries() - 1, D); + size_t I = S; + + // Compute trend with linear regression. + size_t SumIndices = 0; + T SumEntries = {}; + T SumSquareEntries = {}; + T SumProduct = {}; + while (I > 0) { + // NOTE: Indexing for the regression starts in the past. + const size_t Index = S - I; + const T Entry = entry(--I); + SumIndices += Index; + SumEntries += Entry; + SumSquareEntries += Entry * Entry; + SumProduct += Entry * Index; + } + + return (SumProduct * S - SumEntries * SumIndices) / + (SumSquareEntries * S - SumEntries * SumEntries); + } + } + + // Tells the average absolute difference between consequtive entries recorded + // by the History. The number of steps to go back in the History is given as + // argument. + // NOTE: The number of steps that can be made is limited by the number of + // entries recorded by the History. + // NOTE: The function is made a template only to be able to use enable_if. + // STATIC PRE: std::is_arithmetic::value + // PRE: 0 <= D && D < N + template + typename std::enable_if::value, unsigned_t>::type + averageAbsDiff(const size_t D = N - 1) const noexcept { + STATIC_ASSERT((std::is_same::value), "not default template arg"); + ASSERT(0 <= D && D < N); // Boundary check. + if (numberOfEntries() < 2 || D < 1) { + // No difference to average. + return {}; // Zero element of T + } else { + // Here at least two entries. + // S is the number of steps that can be done. + const size_t S = std::min(numberOfEntries() - 1, D); + + // Sum up differences as non-negative values only, hence using an + // unsigned variable for that. + unsigned_t Diffs = {}; // Init to zero. + // Count down entry indices and sum up all the absolute differences. + size_t I = S; + T Last = entry(I); + while (I > 0) { + T Next = entry(--I); + Diffs += Last < Next ? Next - Last : Last - Next; + Last = Next; + } + // Return the average of the summed differences. + return Diffs / S; + } + } + +}; + +// Convenience operator to add new entries to a History instance. +// NOTE: The result of the member function addEntry is ignored by the operator. +template +History &operator<<(History &H, const T &V) noexcept { + H.addEntry(V); + return H; +} + +} // End namespace agent +} // End namespace rosa + +#endif // ROSA_AGENT_HISTORY_HPP + diff --git a/include/rosa/agent/Module.h b/include/rosa/agent/Module.h new file mode 100644 index 0000000..662a801 --- /dev/null +++ b/include/rosa/agent/Module.h @@ -0,0 +1,31 @@ +/******************************************************************************* + * + * File: Module.h + * + * Contents: Declaration of Module base-class + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#ifndef ROSA_AGENT_MODULE_H +#define ROSA_AGENT_MODULE_H + +namespace rosa { +namespace agent { + +// Base class for actual Modules that implement various concepts of +// self-awareness and are supposed to be used in the implementation of Agents. +class Module { +public: + Module(void) noexcept = default; + virtual ~Module(void) = default; +}; + +} // End namespace agent +} // End namespace rosa + +#endif // ROSA_AGENT_MODULE_H + diff --git a/include/rosa/support/type_helper.hpp b/include/rosa/support/type_helper.hpp index d2aef8e..fee7a92 100644 --- a/include/rosa/support/type_helper.hpp +++ b/include/rosa/support/type_helper.hpp @@ -1,79 +1,99 @@ /******************************************************************************* * * File: type_helper.hpp * * Contents: Helper facilities for type-related stuff. * * Copyright 2017 * * Author: David Juhasz (david.juhasz@tuwien.ac.at) * ******************************************************************************/ #ifndef ROSA_SUPPORT_TYPE_HELPER_HPP #define ROSA_SUPPORT_TYPE_HELPER_HPP #include #include namespace rosa { /* ************************************************************************** * * Printable * * ************************************************************************** */ // A value of type [u]int8_t is treated as a character when being put to an // output stream, which can result in invisible characters being printed. To // avoid that, such a value needs to be casted to a wider type. It can be done // by using the following template to find a target type to cast our value to. // The template also turns enumerations into their underlying types. Moreover, // any reference type is turned into the referred type and any non-const type // is turned into their const-qualified type. // NOTE: It is important to remove references before checking // const-qualification because constant references are not const-qualified // types. template ::value, bool IsConst = std::is_const::value, bool IsEnum = std::is_enum::value> struct PrintableType { using Type = T; }; template struct PrintableType { using Type = typename PrintableType::type>::Type; }; template struct PrintableType { using Type = typename PrintableType::Type; }; template struct PrintableType { using Type = typename PrintableType::type>::Type; }; template <> struct PrintableType { using Type = const unsigned int; }; template <> struct PrintableType { using Type = const int; }; // Convenience template alias for using PrintableType. template using printable_t = typename PrintableType::Type; // Helper preprocessor macro to cast values to their printable types. #define PRINTABLE(V) static_cast>(V) +/* ************************************************************************** * + * Unsigned * + * ************************************************************************** */ + +// Provides the unsigned integer type corresponding to T if T is an integral +// (except bool) or enumeration type. Keeps T otherwise. +template ::value> +struct Unsigned { + using Type = T; +}; + +template +struct Unsigned { + using Type = typename std::make_unsigned::type; +}; + +// Convenience template alias for using Unsigned. +template +using unsigned_t = typename Unsigned::Type; + } // End namespace rosa #endif // ROSA_SUPPORT_TYPE_HELPER_HPP diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4fd95b8..6a6246c 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,9 +1,10 @@ # Add the different subdirectories. add_subdirectory(config) add_subdirectory(support) add_subdirectory(core) +add_subdirectory(agent) # Refactor the content into a proper structure # and remove this eventually: add_subdirectory(gen_agent_test2) diff --git a/lib/agent/Abstraction.cpp b/lib/agent/Abstraction.cpp new file mode 100644 index 0000000..5dcd618 --- /dev/null +++ b/lib/agent/Abstraction.cpp @@ -0,0 +1,17 @@ +/******************************************************************************* + * + * File: Abstraction.cpp + * + * Contents: Implementation of ABstraction. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#include "rosa/agent/Abstraction.hpp" + +// NOTE: Empty implementation, source file here to have a compile database +// entry for Abstraction. + diff --git a/lib/agent/CMakeLists.txt b/lib/agent/CMakeLists.txt new file mode 100644 index 0000000..5927d8d --- /dev/null +++ b/lib/agent/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(ROSAAgent + Module.cpp + Abstraction.cpp + History.cpp + Confidence.cpp + ) + diff --git a/lib/agent/Confidence.cpp b/lib/agent/Confidence.cpp new file mode 100644 index 0000000..66d04b1 --- /dev/null +++ b/lib/agent/Confidence.cpp @@ -0,0 +1,17 @@ +/******************************************************************************* + * + * File: Confidence.cpp + * + * Contents: Implementation of Confidence. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#include "rosa/agent/Confidence.hpp" + +// NOTE: Empty implementation, source file here to have a compile database +// entry for Confidence. + diff --git a/lib/agent/History.cpp b/lib/agent/History.cpp new file mode 100644 index 0000000..b4f6778 --- /dev/null +++ b/lib/agent/History.cpp @@ -0,0 +1,17 @@ +/******************************************************************************* + * + * File: History.cpp + * + * Contents: Implementation of History. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#include "rosa/agent/History.hpp" + +// NOTE: Empty implementation, source file here to have a compile database +// entry for History. + diff --git a/lib/agent/Module.cpp b/lib/agent/Module.cpp new file mode 100644 index 0000000..b11be75 --- /dev/null +++ b/lib/agent/Module.cpp @@ -0,0 +1,17 @@ +/******************************************************************************* + * + * File: Module.cpp + * + * Contents: Implementation of Module. + * + * Copyright 2017 + * + * Author: David Juhasz (david.juhasz@tuwien.ac.at) + * + ******************************************************************************/ + +#include "rosa/agent/Module.h" + +// NOTE: Empty implementation, source file here to have a compile database +// entry for Module. +