123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384 |
- /**
- * @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 artis::common::event::Value & /* value */) 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 artis::common::event::Value & /* value */) 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> ¤t_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, event.data) 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, event.data) 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;
- };
- }
- #define DECLARE_STATE_TRANSITION_TYPES(StateMachineClassName) \
- typedef typename StateMachineClassName<Types, Parameters, StateType>::template State<StateMachineClassName<Types, Parameters, StateType>> State_t; \
- typedef typename StateMachineClassName<Types, Parameters, StateType>::template Transition<StateMachineClassName<Types, Parameters, StateType>> Transition_t;
- #define DEFINE_STATE_MACHINE_STATE(StateClassName, StateID, StateMachineClassName) \
- template<class Types, class Parameters, class StateType> \
- struct StateClassName : StateMachineClassName<Types, Parameters, StateType>::State_t { \
- StateClassName(const std::shared_ptr<StateMachineClassName<Types, Parameters, StateType>> &machine) : \
- StateMachineClassName<Types, Parameters, StateType>::State_t(StateID, machine) {} \
- };
- #define DEFINE_STATE_MACHINE_STATE_WITH_NULL_TA(StateClassName, StateID, StateMachineClassName) \
- template<class Types, class Parameters, class StateType> \
- struct StateClassName : StateMachineClassName<Types, Parameters, StateType>::State_t { \
- StateClassName(const std::shared_ptr<StateMachineClassName<Types, Parameters, StateType>> &machine) : \
- StateMachineClassName<Types, Parameters, StateType>::State_t(StateID, machine) {} \
- artis::traffic::core::Time ta(const artis::traffic::core::Time & /* t */) const override { return 0; }\
- };
- #define DEFINE_STATE_MACHINE_STATE_WITH_TA(StateClassName, StateID, StateMachineClassName) \
- template<class Types, class Parameters, class StateType> \
- struct StateClassName : StateMachineClassName<Types, Parameters, StateType>::State_t { \
- StateClassName(const std::shared_ptr<StateMachineClassName<Types, Parameters, StateType>> &machine) : \
- StateMachineClassName<Types, Parameters, StateType>::State_t(StateID, machine) {} \
- artis::traffic::core::Time ta(const artis::traffic::core::Time & /* t */) const override; \
- };
- #define DEFINE_STATE_MACHINE_TRANSITION_HEADER(TransitionClassName, StateMachineClassName) \
- template<class Types, class Parameters, class StateType> \
- struct TransitionClassName : StateMachineClassName<Types, Parameters, StateType>::Transition_t { \
- TransitionClassName( \
- const std::shared_ptr<StateMachineClassName<Types, Parameters, StateType>> &machine) : \
- StateMachineClassName<Types, Parameters, StateType>::Transition_t(machine) {}
- #define ATTRIBUTE(Type, Var) Type Var;
- #define NO_ATTRIBUTE
- #define DEFINE_STATE_MACHINE_TRANSITION_FOOTER(Attribute) \
- Attribute \
- };
- #define DEFINE_STATE_MACHINE_TRANSITION_ACTION_true void action(const artis::traffic::core::Time & /* t */, const artis::common::event::Value & /* value */) override;
- #define DEFINE_STATE_MACHINE_TRANSITION_ACTION_false
- #define DEFINE_STATE_MACHINE_TRANSITION_EVENT_true bool event(const artis::traffic::core::Time & /* t */, int event) override;
- #define DEFINE_STATE_MACHINE_TRANSITION_EVENT_false
- #define DEFINE_STATE_MACHINE_TRANSITION_GUARD_true bool guard(const artis::traffic::core::Time & /* t */) const override;
- #define DEFINE_STATE_MACHINE_TRANSITION_GUARD_false
- #define DEFINE_STATE_MACHINE_TRANSITION_NO_EVENT_true bool no_event() const override { return true; }
- #define DEFINE_STATE_MACHINE_TRANSITION_NO_EVENT_false
- #define DEFINE_STATE_MACHINE_TRANSITION_OUTPUT_true(StateMachineClassName) typename StateMachineClassName<Types, Parameters, StateType>::Events output(const artis::traffic::core::Time & /* t */) const override;
- #define DEFINE_STATE_MACHINE_TRANSITION_OUTPUT_false(StateMachineClassName)
- #define DEFINE_STATE_MACHINE_TRANSITION(TransitionClassName, StateMachineClassName, Attribute, ActionMethod, EventMethod, GuardMethod, NoEventMethod, OutputMethod) \
- DEFINE_STATE_MACHINE_TRANSITION_HEADER(TransitionClassName, StateMachineClassName) \
- DEFINE_STATE_MACHINE_TRANSITION_ACTION_##ActionMethod \
- DEFINE_STATE_MACHINE_TRANSITION_EVENT_##EventMethod \
- DEFINE_STATE_MACHINE_TRANSITION_GUARD_##GuardMethod \
- DEFINE_STATE_MACHINE_TRANSITION_NO_EVENT_##NoEventMethod \
- DEFINE_STATE_MACHINE_TRANSITION_OUTPUT_##OutputMethod(StateMachineClassName) \
- DEFINE_STATE_MACHINE_TRANSITION_FOOTER(Attribute)
- #endif //ARTIS_STAR_ADDONS_UTILS_STATE_MACHINE_HPP
|