Parcourir la source

Add new pdvs extension with state machines

Eric Ramat il y a 1 an
Parent
commit
fc1e35578b

+ 5 - 6
CMakeLists.txt

@@ -91,10 +91,9 @@ find_package(Boost 1.71.0 COMPONENTS mpi serialization)
 CHECK_INCLUDE_FILE_CXX(cxxabi.h ARTIS_STAR_ADDONS_HAVE_GCC_ABI_DEMANGLE)
 CHECK_INCLUDE_FILE_CXX(execinfo.h ARTIS_STAR_ADDONS_HAVE_EXECINFO)
 CHECK_INCLUDE_FILE_CXX(signal.h ARTIS_STAR_ADDONS_HAVE_SIGNAL)
-INCLUDE_DIRECTORIES(${ARTIS_STAR_ADDONS_STAR_BINARY_DIR})
 
 #
-# Generate the artis.pc pkg-config file.
+# Generate the artis-star-addons.pc pkg-config file.
 #
 
 SET(ARTIS_STAR_ADDONS_PKGCONFIG_PREFIXPATH "${CMAKE_INSTALL_PREFIX}")
@@ -154,12 +153,12 @@ MESSAGE(STATUS "- - - -")
 MESSAGE(STATUS "${ARTIS_STAR_ADDONS_NAME} configured successfully")
 MESSAGE(STATUS "Using ${CMAKE_INSTALL_PREFIX} for installation")
 MESSAGE(STATUS "Build type ${CMAKE_BUILD_TYPE}")
-IF (ARTIS_HAVE_GCC_ABI_DEMANGLE)
+IF (ARTIS_STAR_ADDONS_HAVE_GCC_ABI_DEMANGLE)
     MESSAGE(STATUS "Build with GCC ABI Demangle...: yes")
-ENDIF (ARTIS_HAVE_GCC_ABI_DEMANGLE)
-IF (ARTIS_HAVE_EXECINFO)
+ENDIF (ARTIS_STAR_ADDONS_HAVE_GCC_ABI_DEMANGLE)
+IF (ARTIS_STAR_ADDONS_HAVE_EXECINFO)
     MESSAGE(STATUS "Build with execinfo.h.........: yes")
-ENDIF (ARTIS_HAVE_EXECINFO)
+ENDIF (ARTIS_STAR_ADDONS_HAVE_EXECINFO)
 IF (Boost_FOUND)
     MESSAGE(STATUS "Build with boost..............: yes")
 ENDIF (Boost_FOUND)

+ 3 - 1
src/CMakeLists.txt

@@ -1 +1,3 @@
-add_subdirectory(qss)
+add_subdirectory(pdevs)
+add_subdirectory(qss)
+add_subdirectory(utils)

+ 1 - 1
src/artis-star-addons.pc.in

@@ -5,7 +5,7 @@ includedir=${prefix}/include
 
 Name: artis-star-addons
 Description: Addons for ARTIS* Multimodeling and Simulation tools
-Requires: artis-star-1.0
+Requires:
 Version: @ARTIS_STAR_ADDONS_VERSION@
 Libs:	-L${libdir}
 Cflags: -I${includedir}/artis-star-addons-@ARTIS_STAR_ADDONS_VERSION_SHORT@ -I@ARTIS_STAR_ADDONS_PKGCONFIG_BOOSTINCLUDE_DIRS@

+ 10 - 0
src/pdevs/CMakeLists.txt

@@ -0,0 +1,10 @@
+INCLUDE_DIRECTORIES(
+        ${ARTIS_STAR_ADDONS_SOURCE_DIR}/src
+        ${Boost_INCLUDE_DIRS})
+
+LINK_DIRECTORIES(
+        ${Boost_LIBRARY_DIRS})
+
+SET(PDEVS_HPP StateMachineDynamics.hpp)
+
+INSTALL(FILES ${PDEVS_HPP} DESTINATION ${ARTIS_STAR_ADDONS_INCLUDE_DIRS}/pdevs)

+ 81 - 0
src/pdevs/StateMachineDynamics.hpp

@@ -0,0 +1,81 @@
+/**
+ * @file pdevs/StateMachineDynamics.hpp
+ * @author The ARTIS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * ARTIS - the multimodeling and simulation environment
+ * This file is a part of the ARTIS environment
+ *
+ * Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ARTIS_STAR_ADDONS_STATE_MACHINE_DYNAMICS_HPP
+#define ARTIS_STAR_ADDONS_STATE_MACHINE_DYNAMICS_HPP
+
+#include <artis-star/kernel/pdevs/Dynamics.hpp>
+
+namespace artis::addons::pdevs {
+
+template<class Time, class Model, class Parameters, class RootStateMachine>
+class StateMachineDynamics : public artis::pdevs::Dynamics<Time, Model, Parameters> {
+public:
+  StateMachineDynamics(const std::string &name, const artis::pdevs::Context<Time, Model, Parameters> &context) :
+    artis::pdevs::Dynamics<Time, Model, Parameters>(name, context), _root() {
+    _root.build(context.parameters());
+  }
+
+  virtual ~StateMachineDynamics() = default;
+
+  void
+  dconf(const typename Time::type &t, const typename Time::type &e, const common::event::Bag <Time> &bag) override {
+    dint(t);
+    dext(t, e, bag);
+  }
+
+  void dint(const typename Time::type &t) override {
+    _root.transition(t);
+  }
+
+  void dext(const typename Time::type & /* t */, const typename Time::type & /* e */,
+            const common::event::Bag <Time> & /* bag*/) override {}
+
+  void start(const typename Time::type &t) override {
+    _root.start(t);
+  }
+
+  typename Time::type ta(const typename Time::type &t) const override {
+    return _root.ta(t);
+  }
+
+  common::event::Bag <Time> lambda(const typename Time::type & /* t */) const override { return {}; }
+
+  artis::common::event::Value
+  observe(const typename Time::type & /* t */, unsigned int /* index */) const override { return {}; }
+
+protected:
+  const RootStateMachine &root() const { return _root; }
+
+  RootStateMachine &root() { return _root; }
+
+private:
+  RootStateMachine _root;
+};
+
+}
+
+#endif //ARTIS_STAR_ADDONS_STATE_MACHINE_DYNAMICS_HPP

+ 5 - 7
src/qss/GraphManager.hpp

@@ -1,5 +1,5 @@
 /**
- * @file kernel/qss/GraphManager.hpp
+ * @file qss/GraphManager.hpp
  * @author The ARTIS Development Team
  * See the AUTHORS or Authors.txt file
  */
@@ -8,7 +8,7 @@
  * ARTIS - the multimodeling and simulation environment
  * This file is a part of the ARTIS environment
  *
- * Copyright (C) 2013-2019 ULCO http://www.univ-littoral.fr
+ * Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,16 +24,15 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef QSS_GRAPH_MANAGER
-#define QSS_GRAPH_MANAGER
+#ifndef ARTIS_STAR_ADDONS_QSS_GRAPH_MANAGER
+#define ARTIS_STAR_ADDONS_QSS_GRAPH_MANAGER
 
 #include <artis-star/kernel/pdevs/GraphManager.hpp>
 #include <artis-star/kernel/qss/Derivative.hpp>
 #include <artis-star/kernel/qss/Integrator.hpp>
 #include <artis-star/kernel/qss/Quantifier.hpp>
 
-namespace artis {
-namespace qss {
+namespace artis::addons::qss {
 
 template<class DerivativeParameters>
 struct QSSParameters
@@ -131,7 +130,6 @@ private:
       _quantifier;
 };
 
-}
 }
 
 #endif

+ 37 - 54
src/qss/MultiGraphManager.hpp

@@ -1,5 +1,5 @@
 /**
- * @file kernel/qss/MultiGraphManager.hpp
+ * @file qss/MultiGraphManager.hpp
  * @author The ARTIS Development Team
  * See the AUTHORS or Authors.txt file
  */
@@ -8,7 +8,7 @@
  * ARTIS - the multimodeling and simulation environment
  * This file is a part of the ARTIS environment
  *
- * Copyright (C) 2013-2019 ULCO http://www.univ-littoral.fr
+ * Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -24,46 +24,39 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef QSS_MULTI_GRAPH_MANAGER
-#define QSS_MULTI_GRAPH_MANAGER
+#ifndef ARTIS_STAR_ADDONS_QSS_MULTI_GRAPH_MANAGER
+#define ARTIS_STAR_ADDONS_QSS_MULTI_GRAPH_MANAGER
 
 #include <artis-star/kernel/pdevs/GraphManager.hpp>
 #include <artis-star/kernel/qss/MultiDerivative.hpp>
 #include <artis-star/kernel/qss/Integrator.hpp>
 #include <artis-star/kernel/qss/Quantifier.hpp>
 
-namespace artis {
-namespace qss {
+namespace artis::addons::qss {
 
 template<class DerivativeParameters>
-struct MultiQSSParameters
-{
+struct MultiQSSParameters {
   std::vector <artis::qss::IntegratorParameters> integrators;
   std::vector <artis::qss::QuantifierParameters> quantifiers;
   DerivativeParameters derivative;
 };
 
 template<class Time,
-    class Derivative,
-    class DerivativeParameters = artis::common::NoParameters>
+  class Derivative,
+  class DerivativeParameters = artis::common::NoParameters>
 class MultiGraphManager :
-    public artis::pdevs::GraphManager<Time,
-                                      MultiQSSParameters<DerivativeParameters>,
-                                      artis::common::NoParameters>
-{
+  public artis::pdevs::GraphManager<Time,
+    MultiQSSParameters<DerivativeParameters>,
+    artis::common::NoParameters> {
 public:
-  struct submodel
-  {
-    enum values
-    {
+  struct submodel {
+    enum values {
       S_Derivative = 0, S_Integrator = 1, S_Quantifier = 1000
     };
   };
 
-  struct input
-  {
-    enum values
-    {
+  struct input {
+    enum values {
       RESET
     };
   };
@@ -71,17 +64,16 @@ public:
   MultiGraphManager(common::Coordinator <Time> *coordinator,
                     const MultiQSSParameters<DerivativeParameters> &parameters,
                     const artis::common::NoParameters &graph_parameters)
-      :
-      artis::pdevs::GraphManager<Time,
-                                 MultiQSSParameters<DerivativeParameters>,
-                                 artis::common::NoParameters>(
-          coordinator, parameters, graph_parameters),
-      _derivative("d", parameters.derivative)
-  {
+    :
+    artis::pdevs::GraphManager<Time,
+      MultiQSSParameters<DerivativeParameters>,
+      artis::common::NoParameters>(
+      coordinator, parameters, graph_parameters),
+    _derivative("d", parameters.derivative) {
     this->add_child(submodel::S_Derivative, &_derivative);
     coordinator->input_port({input::RESET, "reset"});
     this->in({coordinator, input::RESET})
-        >> this->in({&_derivative, Derivative::input::RESET});
+      >> this->in({&_derivative, Derivative::input::RESET});
     for (unsigned int index = 0; index < _derivative.dynamics().variable_number(); ++index) {
       _integrators.push_back(new IntegratorSimulator("i_" + std::to_string(index),
                                                      parameters.integrators[index]));
@@ -91,44 +83,36 @@ public:
       this->add_child(submodel::S_Quantifier + index, _quantifiers.back());
       coordinator->output_port({index, "out_" + std::to_string(index)});
       this->in({coordinator, input::RESET})
-          >> this->in({_integrators.back(), Integrator<Time>::input::RESET});
+        >> this->in({_integrators.back(), Integrator<Time>::input::RESET});
       this->in({coordinator, input::RESET})
-          >> this->in({_quantifiers.back(), Quantifier<Time>::input::RESET});
+        >> this->in({_quantifiers.back(), Quantifier<Time>::input::RESET});
 
       this->out({&_derivative, index})
-          >> this->in({_integrators.back(), Integrator<Time>::input::X_DOT});
+        >> this->in({_integrators.back(), Integrator<Time>::input::X_DOT});
       this->out({_integrators.back(), Integrator<Time>::output::OUT})
-          >> this->in({_quantifiers.back(), Quantifier<Time>::input::IN});
+        >> this->in({_quantifiers.back(), Quantifier<Time>::input::IN});
       this->out({_quantifiers.back(), Quantifier<Time>::output::OUT})
-          >> this->in({_integrators.back(), Integrator<Time>::input::QUANTA});
+        >> this->in({_integrators.back(), Integrator<Time>::input::QUANTA});
       this->out({_integrators.back(), Integrator<Time>::output::OUT})
-          >> this->out({coordinator, index});
+        >> this->out({coordinator, index});
       this->out({_integrators.back(), Integrator<Time>::output::OUT})
-          >> this->in({&_derivative, Derivative::input::INTERNAL + index});
+        >> this->in({&_derivative, Derivative::input::INTERNAL + index});
     }
   }
 
-  ~MultiGraphManager() override
-  {
-    std::for_each(_integrators.begin(),
-                  _integrators.end(),
-                  std::default_delete<IntegratorSimulator>());
-    std::for_each(_quantifiers.begin(),
-                  _quantifiers.end(),
-                  std::default_delete<QuantifierSimulator>());
+  ~MultiGraphManager() override {
+    std::for_each(_integrators.begin(), _integrators.end(), std::default_delete<IntegratorSimulator>());
+    std::for_each(_quantifiers.begin(), _quantifiers.end(), std::default_delete<QuantifierSimulator>());
   }
 
-  artis::pdevs::Simulator<Time, Derivative, DerivativeParameters> *derivative()
-  { return &_derivative; }
+  artis::pdevs::Simulator<Time, Derivative, DerivativeParameters> *derivative() { return &_derivative; }
 
 private:
-  typedef artis::pdevs::Simulator<Time,
-                                  artis::qss::Integrator<Time>,
-                                  artis::qss::IntegratorParameters> IntegratorSimulator;
+  typedef artis::pdevs::Simulator<Time, artis::qss::Integrator<Time>,
+    artis::qss::IntegratorParameters> IntegratorSimulator;
   typedef std::vector<IntegratorSimulator *> IntegratorSimulators;
-  typedef artis::pdevs::Simulator<Time,
-                                  artis::qss::Quantifier<Time>,
-                                  artis::qss::QuantifierParameters> QuantifierSimulator;
+  typedef artis::pdevs::Simulator<Time, artis::qss::Quantifier<Time>,
+    artis::qss::QuantifierParameters> QuantifierSimulator;
   typedef std::vector<QuantifierSimulator *> QuantifierSimulators;
 
   artis::pdevs::Simulator<Time, Derivative, DerivativeParameters> _derivative;
@@ -136,7 +120,6 @@ private:
   QuantifierSimulators _quantifiers;
 };
 
-}
 }
 
 #endif

+ 10 - 0
src/utils/CMakeLists.txt

@@ -0,0 +1,10 @@
+INCLUDE_DIRECTORIES(
+        ${ARTIS_STAR_ADDONS_SOURCE_DIR}/src
+        ${Boost_INCLUDE_DIRS})
+
+LINK_DIRECTORIES(
+        ${Boost_LIBRARY_DIRS})
+
+SET(UTILS_HPP RootStateMachine.hpp StateMachine.hpp)
+
+INSTALL(FILES ${UTILS_HPP} DESTINATION ${ARTIS_STAR_ADDONS_INCLUDE_DIRS}/utils)

+ 179 - 0
src/utils/RootStateMachine.hpp

@@ -0,0 +1,179 @@
+/**
+ * @file utils/RootStateMachine.hpp
+ * @author The ARTIS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * ARTIS - the multimodeling and simulation environment
+ * This file is a part of the ARTIS environment
+ *
+ * Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ARTIS_STAR_ADDONS_UTILS_ROOT_STATE_MACHINE_HPP
+#define ARTIS_STAR_ADDONS_UTILS_ROOT_STATE_MACHINE_HPP
+
+#include <artis-star-addons/utils/StateMachine.hpp>
+
+#include <memory>
+#include <vector>
+
+namespace artis::addons::utils {
+
+template<class Time, class Types, class Parameters, class StateMachineTypes>
+class RootStateMachine {
+public:
+  typedef std::vector<typename Types::state_machine_type::ExternalEvent> external_events_type;
+
+  RootStateMachine() = default;
+
+  virtual ~RootStateMachine() = default;
+
+  virtual void build(const Parameters &parameters) = 0;
+
+  template<class RootStateMachineType, size_t N>
+  constexpr void build_machines(const Parameters &parameters) {
+    if constexpr(N == 1)
+    {
+      this->template build_machine<RootStateMachineType, std::tuple_element_t < 0, StateMachineTypes>>
+      (0, parameters);
+    } else {
+      this->template build_machine<RootStateMachineType, std::tuple_element_t < N - 1, StateMachineTypes>>
+      (N - 1, parameters);
+      build_machines<RootStateMachineType, N - 1>(parameters);
+    }
+  }
+
+  int current_state(int machine_id) const {
+    typename Types::state_machine_IDs_type::values key =
+      static_cast<typename Types::state_machine_IDs_type::values>(machine_id);
+
+    return _machines.find(key)->second->current_state()->_id;
+  }
+
+  const std::shared_ptr<typename Types::state_machine_type> &
+  machine(const int machine_id) {
+    typename Types::state_machine_IDs_type::values key =
+      static_cast<typename Types::state_machine_IDs_type::values>(machine_id);
+
+    return _machines.find(key)->second;
+  }
+
+  const external_events_type &outbox() const { return _outbox; }
+
+  void start(const typename Time::type &t) {
+    std::for_each(_machines.begin(), _machines.end(), [t](const auto &e) {
+      e.second->start(t);
+    });
+    _last_time = t;
+  }
+
+  template<class StateType>
+  const StateType &state_(int machine_id) const {
+    typename Types::state_machine_IDs_type::values key =
+      static_cast<typename Types::state_machine_IDs_type::values>(machine_id);
+
+    return std::dynamic_pointer_cast < StateMachine < Time, Types, StateType >> (_machines.at(key))->state_();
+  }
+
+  typename Time::type ta(const typename Time::type &t) const {
+    if (_outbox.empty()) {
+      typename Time::type min = Time::infinity;
+
+      std::for_each(_machines.cbegin(), _machines.cend(), [t, &min](const auto &e) {
+        typename Time::type ta = e.second->ta(t);
+
+        min = min < ta ? min : ta;
+      });
+      return min;
+    } else return 0;
+  }
+
+  void transition(const typename Time::type &t) {
+    if (_outbox.empty()) {
+      std::for_each(_machines.cbegin(), _machines.cend(), [t, this](const auto &e) {
+        if (e.second->is_ready(t)) {
+          typename Types::state_machine_type::Events events = e.second->transition(t);
+
+          dispatch(t, events.internals);
+          appendEvents(events.externals);
+        }
+      });
+    } else {
+      _outbox.clear();
+    }
+    _last_time = t;
+    std::for_each(_machines.cbegin(), _machines.cend(), [t](const auto &e) {
+      e.second->update_sigma(t);
+    });
+  }
+
+  void transition(const typename Time::type &t, int machine_id,
+                  const typename Types::state_machine_type::ExternalEvent &e) {
+    typename Types::state_machine_IDs_type::values key =
+      static_cast<typename Types::state_machine_IDs_type::values>(machine_id);
+    typename Types::state_machine_type::Events events = _machines.at(key)->transition(t, e);
+
+    dispatch(t, events.internals);
+    appendEvents(events.externals);
+    std::for_each(_machines.cbegin(), _machines.cend(), [t](const auto &e) {
+      e.second->update_sigma(t);
+    });
+  }
+
+protected:
+  template<class RootStateMachineType, class FinalStateMachine>
+  void build_machine(int machine_id, const Parameters &parameters) {
+    auto machine = std::make_shared<FinalStateMachine>(*dynamic_cast<RootStateMachineType *>(this), parameters);
+    typename Types::state_machine_IDs_type::values key =
+      static_cast<typename Types::state_machine_IDs_type::values>(machine_id);
+
+    machine->build(machine);
+    this->_machines[key] = std::dynamic_pointer_cast<typename Types::state_machine_type>(machine);
+  }
+
+private:
+  void appendEvents(const std::vector<typename Types::state_machine_type::ExternalEvent> &events) {
+    _outbox.insert(_outbox.end(), events.cbegin(), events.cend());
+  }
+
+  void
+  dispatch(const typename Time::type &t, const std::vector<typename Types::state_machine_type::InternalEvent> &events) {
+    std::for_each(events.cbegin(), events.cend(),
+                  [t, this](const auto &e) {
+                    typename Types::state_machine_IDs_type::values key =
+                      static_cast<typename Types::state_machine_IDs_type::values>(e.machine_id);
+                    auto it = _machines.find(key);
+
+                    if (it != _machines.end()) {
+                      typename Types::state_machine_type::Events events = it->second->transition(t, e);
+
+                      dispatch(t, events.internals);
+                      appendEvents(events.externals);
+                    }
+                  });
+  }
+
+  std::map<typename Types::state_machine_IDs_type::values, std::shared_ptr<typename Types::state_machine_type>> _machines;
+
+  external_events_type _outbox;
+  typename Time::type _last_time{};
+};
+
+}
+
+#endif //ARTIS_STAR_ADDONS_UTILS_ROOT_STATE_MACHINE_HPP

+ 319 - 0
src/utils/StateMachine.hpp

@@ -0,0 +1,319 @@
+/**
+ * @file utils/StateMachine.hpp
+ * @author The ARTIS Development Team
+ * See the AUTHORS or Authors.txt file
+ */
+
+/*
+ * ARTIS - the multimodeling and simulation environment
+ * This file is a part of the ARTIS environment
+ *
+ * Copyright (C) 2013-2023 ULCO http://www.univ-littoral.fr
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ARTIS_STAR_ADDONS_UTILS_STATE_MACHINE_HPP
+#define ARTIS_STAR_ADDONS_UTILS_STATE_MACHINE_HPP
+
+#include <artis-star/common/event/Value.hpp>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace artis::addons::utils {
+
+template<class Time, class Types, class Parameters, class StateMachineTypes>
+class RootStateMachine;
+
+template<class Time, class Types>
+class AbstractStateMachine {
+public:
+  struct Event {
+    int id;
+    artis::common::event::Value data;
+  };
+
+  struct InternalEvent : Event {
+    int machine_id;
+  };
+
+  struct ExternalEvent : Event {
+  };
+
+  struct Events {
+    std::vector <InternalEvent> internals;
+    std::vector <ExternalEvent> externals;
+  };
+
+  struct AbstractState {
+    int _id;
+
+    AbstractState(int id) : _id(id) {}
+
+    virtual typename Time::type ta(const typename Time::type & /* t */) const = 0;
+
+    virtual ~AbstractState() = default;
+  };
+
+  template<class Machine>
+  struct State : AbstractState {
+    std::shared_ptr <Machine> _machine;
+
+    State(int id, const std::shared_ptr <Machine> &machine) :
+      AbstractState(id), _machine(machine) {}
+
+    typename Time::type ta(const typename Time::type & /* t */) const override { return Time::infinity; }
+  };
+
+  struct AbstractTransition {
+    virtual void action(const typename Time::type & /* t */,
+                        const artis::common::event::Value & /* value */) = 0;
+
+    virtual bool event(const typename Time::type & /* t */, int  /* event */) = 0;
+
+    virtual bool guard(const typename Time::type & /* t */) const = 0;
+
+    virtual bool no_event() const = 0;
+
+    virtual Events output(const typename Time::type & /* t */) const = 0;
+
+    virtual ~AbstractTransition() = default;
+  };
+
+  template<class Machine>
+  struct Transition : AbstractTransition {
+    std::shared_ptr <Machine> _machine;
+
+    Transition(const std::shared_ptr <Machine> &machine) : _machine(machine) {}
+
+    void action(const typename Time::type & /* t */,
+                const artis::common::event::Value & /* value */) override {}
+
+    bool event(const typename Time::type & /* t */,
+               int  /* event */) override { return false; }
+
+    bool guard(const typename Time::type & /* t */) const override { return true; }
+
+    bool no_event() const override { return false; }
+
+    Events output(const typename Time::type & /* t */) const override { return {}; }
+  };
+
+  AbstractStateMachine(const typename Types::root_state_machine_type &root) : _root(root) {}
+
+  virtual ~AbstractStateMachine() = default;
+
+//  virtual void build(const std::shared_ptr<StateMachine<Types>> &machine) = 0;
+
+  const std::unique_ptr <AbstractState> &current_state() const {
+    return _states.at(_current_state);
+  }
+
+  int current_state(int machine_id) const {
+    return _root.current_state(machine_id);
+  }
+
+  void initial_state(int state) {
+    _initial_state = state;
+  }
+
+  bool is_ready(const typename Time::type &t) const {
+    return std::abs(_sigma - (t - _last_time)) < 1e-6;
+  }
+
+  const typename Types::root_state_machine_type &root() const { return _root; }
+
+  void start(const typename Time::type &t) {
+    _current_state = _initial_state;
+    _last_time = t;
+    compute_sigma(t);
+  }
+
+  void state(AbstractState *state) {
+    _states.insert(std::make_pair(state->_id, std::unique_ptr<AbstractState>(state)));
+    _transitions.insert(std::make_pair(state->_id, _transitions_type{}));
+  }
+
+  void switch_transition(int state, int next_state, size_t index, AbstractTransition *transition) {
+    auto it = std::find_if(_transitions[state].begin(), _transitions[state].end(), [next_state](const auto &e) {
+      return e.second == next_state;
+    });
+
+    assert(it != _transitions[state].end());
+
+    while (it + 1 != _transitions[state].end() and index > 0) {
+      it = std::find_if(it + 1, _transitions[state].end(), [next_state](const auto &e) {
+        return e.second == next_state;
+      });
+      --index;
+    }
+
+    assert(it != _transitions[state].end());
+
+    it->first.reset(transition);
+  }
+
+  typename Time::type ta(const typename Time::type & /* t */) const {
+    return _sigma;
+  }
+
+  void transition(int state, int next_state, AbstractTransition *transition) {
+    _transitions[state].push_back(std::make_pair(std::unique_ptr<AbstractTransition>(transition), next_state));
+  }
+
+  // without event
+  Events transition(const typename Time::type &t) {
+    typename std::map<int, _transitions_type>::const_iterator it = _transitions.find(_current_state);
+    Events events{};
+    uint unique = 0;
+
+    if (it != _transitions.cend()) {
+      AbstractTransition *select = nullptr;
+      int stateID{};
+
+      std::for_each(it->second.cbegin(), it->second.cend(),
+                    [t, &unique, &select, &stateID](
+                      const std::pair<std::unique_ptr<AbstractTransition>, int> &e) {
+                      if (e.first->no_event() and e.first->guard(t)) {
+                        select = e.first.get();
+                        stateID = e.second;
+                        ++unique;
+                      }
+                    });
+
+      assert(unique <= 1);
+
+      if (select != nullptr) {
+        select->action(t, {});
+        events = select->output(t);
+        _current_state = stateID;
+        compute_sigma(t);
+      } else {
+        update_sigma(t);
+      }
+    }
+    return events;
+  }
+
+  // with external event
+  Events transition(const typename Time::type &t, const ExternalEvent &event) {
+    typename std::map<int, _transitions_type>::const_iterator it = _transitions.find(_current_state);
+    Events events{};
+    uint unique = 0;
+
+    if (it != _transitions.cend()) {
+      AbstractTransition *select = nullptr;
+      int stateID{};
+
+      std::for_each(it->second.cbegin(), it->second.cend(),
+                    [t, event, &unique, &select, &stateID](
+                      const std::pair<std::unique_ptr<AbstractTransition>, int> &e) {
+                      if (e.first->guard(t) and e.first->event(t, event.id)) {
+                        select = e.first.get();
+                        stateID = e.second;
+                        ++unique;
+                      }
+                    });
+
+      assert(unique <= 1);
+
+      if (select != nullptr) {
+        select->action(t, event.data);
+        events = select->output(t);
+        _current_state = stateID;
+        compute_sigma(t);
+      } else {
+        update_sigma(t);
+      }
+    }
+    return events;
+  }
+
+  // with internal event
+  Events transition(const typename Time::type &t, const InternalEvent &event) {
+    typename std::map<int, _transitions_type>::const_iterator it = _transitions.find(_current_state);
+    Events events{};
+    uint unique = 0;
+
+    if (it != _transitions.cend()) {
+      AbstractTransition *select = nullptr;
+      int stateID{};
+
+      std::for_each(it->second.cbegin(), it->second.cend(),
+                    [t, event, &unique, &select, &stateID](
+                      const std::pair<std::unique_ptr<AbstractTransition>, int> &e) {
+                      if (e.first->guard(t) and e.first->event(t, event.id)) {
+                        select = e.first.get();
+                        stateID = e.second;
+                        ++unique;
+                      }
+                    });
+
+      assert(unique <= 1);
+
+      if (select != nullptr) {
+        select->action(t, event.data);
+        events = select->output(t);
+        _current_state = stateID;
+        compute_sigma(t);
+      } else {
+        update_sigma(t);
+      }
+    }
+    return events;
+  }
+
+  void update_sigma(const typename Time::type &t) {
+    _sigma -= t - _last_time;
+    _last_time = t;
+  }
+
+private:
+  void compute_sigma(const typename Time::type &t) {
+    _sigma = current_state()->ta(t);
+    _last_time = t;
+  }
+
+  typedef std::vector<std::pair<std::unique_ptr < AbstractTransition>, int >> _transitions_type;
+
+  std::map<int, std::unique_ptr<AbstractState>> _states;
+  std::map<int, _transitions_type> _transitions;
+  int _initial_state;
+  const typename Types::root_state_machine_type &_root;
+
+  int _current_state;
+  typename Time::type _last_time{};
+  typename Time::type _sigma{};
+};
+
+template<class Time, class Types, class StateType>
+class StateMachine : public AbstractStateMachine<Time, Types> {
+public:
+  StateMachine(const typename Types::root_state_machine_type &root, StateType state)
+    : AbstractStateMachine<Time, Types>(root), _state(state) {}
+
+  virtual ~StateMachine() = default;
+
+  const StateType &state_() const { return _state; }
+
+  StateType &state_() { return _state; }
+
+protected:
+  StateType _state;
+};
+
+}
+#endif //ARTIS_STAR_ADDONS_UTILS_STATE_MACHINE_HPP