Browse Source

Change QSS namespace

Eric Ramat 6 months ago
parent
commit
f89d18da30

+ 1 - 4
CMakeLists.txt

@@ -104,10 +104,7 @@ CHECK_INCLUDE_FILE_CXX(signal.h ARTIS_HAVE_SIGNAL)
 INCLUDE_DIRECTORIES(${ARTIS_STAR_BINARY_DIR})
 
 #
- # Generate the vle.pc pkg-config file.
- # Build some variable to build a correct Win32 pkg config file with:
- # prefix=/target to detect the DIRNAME
- # cflag=-Iboost_1_34_1 for the directory
+ # Generate the artis.pc pkg-config file.
 #
 
 SET(ARTIS_PKGCONFIG_PREFIXPATH "${CMAKE_INSTALL_PREFIX}")

+ 7 - 6
src/artis-star/kernel/CMakeLists.txt

@@ -1,6 +1,7 @@
-ADD_SUBDIRECTORY(devs)
-ADD_SUBDIRECTORY(dsde)
-ADD_SUBDIRECTORY(dtss)
-ADD_SUBDIRECTORY(fddevs)
-ADD_SUBDIRECTORY(pdevs)
-ADD_SUBDIRECTORY(sss)
+add_subdirectory(devs)
+add_subdirectory(dsde)
+add_subdirectory(dtss)
+add_subdirectory(fddevs)
+add_subdirectory(pdevs)
+add_subdirectory(qss)
+add_subdirectory(sss)

+ 1 - 2
src/artis-star/kernel/pdevs/CMakeLists.txt

@@ -6,10 +6,9 @@ INCLUDE_DIRECTORIES(
 LINK_DIRECTORIES(
         ${Boost_LIBRARY_DIRS})
 
-SET(PDEVS_HPP Coordinator.hpp Dynamics.hpp GraphManager.hpp Simulator.hpp)
+SET(PDEVS_HPP Context.hpp Coordinator.hpp Dynamics.hpp GraphManager.hpp Simulator.hpp)
 
 INSTALL(FILES ${PDEVS_HPP} DESTINATION ${ARTIS_INCLUDE_DIRS}/kernel/pdevs)
 
 ADD_SUBDIRECTORY(multithreading)
 ADD_SUBDIRECTORY(mpi)
-ADD_SUBDIRECTORY(qss)

+ 60 - 0
src/artis-star/kernel/pdevs/Context.hpp

@@ -0,0 +1,60 @@
+/**
+ * @file kernel/pdevs/Context.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-2019 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 PDEVS_CONTEXT
+#define PDEVS_CONTEXT
+
+namespace artis {
+    namespace pdevs {
+
+        template<class Time, class Dynamics, class Parameters>
+        class Simulator;
+
+        template<class Time, class Dynamics,
+                class Parameters = common::NoParameters>
+        class Context {
+            typedef pdevs::Simulator<Time, Dynamics, Parameters> Simulator;
+
+        public:
+            Context(const Parameters& parameters, Simulator* simulator)
+                    :
+                    _parameters(parameters), _simulator(simulator) { }
+
+            virtual ~Context() { }
+
+            const Parameters& parameters() const { return _parameters; }
+
+            Simulator* simulator() const { return _simulator; }
+
+        private:
+            const Parameters& _parameters;
+            Simulator* _simulator;
+        };
+
+    }
+} // namespace artis pdevs
+
+#endif

+ 1 - 26
src/artis-star/kernel/pdevs/Simulator.hpp

@@ -32,36 +32,11 @@
 #include <artis-star/common/Simulator.hpp>
 #include <artis-star/common/utils/String.hpp>
 #include <artis-star/common/utils/Trace.hpp>
-
-#include <cassert>
+#include <artis-star/kernel/pdevs/Context.hpp>
 
 namespace artis {
     namespace pdevs {
 
-        template<class Time, class Dynamics, class Parameters>
-        class Simulator;
-
-        template<class Time, class Dynamics,
-                class Parameters = common::NoParameters>
-        class Context {
-            typedef pdevs::Simulator<Time, Dynamics, Parameters> Simulator;
-
-        public:
-            Context(const Parameters& parameters, Simulator* simulator)
-                    :
-                    _parameters(parameters), _simulator(simulator) { }
-
-            virtual ~Context() { }
-
-            const Parameters& parameters() const { return _parameters; }
-
-            Simulator* simulator() const { return _simulator; }
-
-        private:
-            const Parameters& _parameters;
-            Simulator* _simulator;
-        };
-
         template<class Time, class Dynamics,
                 class Parameters = common::NoParameters>
         class Simulator : public common::Simulator<Time> {

+ 0 - 11
src/artis-star/kernel/pdevs/qss/CMakeLists.txt

@@ -1,11 +0,0 @@
-INCLUDE_DIRECTORIES(
-        ${ARTIS_BINARY_DIR}/src
-        ${ARTIS_SOURCE_DIR}/src
-        ${Boost_INCLUDE_DIRS})
-
-LINK_DIRECTORIES(
-        ${Boost_LIBRARY_DIRS})
-
-SET(PDEVS_QSS_HPP Data.hpp Derivative.hpp GraphManager.hpp Integrator.hpp Quantifier.hpp)
-
-INSTALL(FILES ${PDEVS_QSS_HPP} DESTINATION ${ARTIS_INCLUDE_DIRS}/kernel/pdevs/qss)

+ 0 - 215
src/artis-star/kernel/pdevs/qss/Derivative.hpp

@@ -1,215 +0,0 @@
-/**
- * @file kernel/pdevs/qss/Derivative.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-2019 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 QSS_DERIVATIVE
-#define QSS_DERIVATIVE
-
-#include <artis-star/kernel/pdevs/Dynamics.hpp>
-#include <artis-star/kernel/pdevs/qss/Data.hpp>
-
-namespace artis {
-    namespace pdevs {
-        namespace qss {
-
-            template<class Time, class Dyn, class Parameters = common::NoParameters>
-            class Derivative : public artis::pdevs::Dynamics<Time, Dyn, Parameters> {
-                typedef enum {
-                    INIT = 0, WAIT, RESPONSE
-                } State;
-
-            public:
-                enum inputs {
-                    RESET = 0, IN
-                };
-
-                enum outputs {
-                    OUT = 0
-                };
-
-                enum states {
-                    STATE = 0, INPUT_NUMBER, OUTPUT_VALUE, LAST_OUTPUT
-                };
-
-                typedef Derivative<Time, Dyn, Parameters> type;
-
-                Derivative(const std::string& name, const Context<Time, Dyn, Parameters>& context)
-                        :
-                        artis::pdevs::Dynamics<Time, Dyn, Parameters>(name, context),
-                        _external_number(0), _internal_number(0)
-                {
-                    DECLARE_STATES(int,
-                            ((STATE, &type::_state)));
-                    DECLARE_STATES(unsigned int,
-                            ((INPUT_NUMBER, &type::_input_number)));
-                    DECLARE_STATES(double,
-                            ((OUTPUT_VALUE, &type::_output_value),
-                                    (LAST_OUTPUT, &type::_output_value)));
-
-                    this->input_ports({{RESET, "reset"},
-                                       {IN,    "in"}});
-                    this->output_port({OUT, "out"});
-                }
-
-                virtual ~Derivative() { }
-
-                int external(const std::string& name, double Dyn::* var)
-                {
-                    ++_external_number;
-                    this->state_(LAST_OUTPUT + _external_number + 1, name, var);
-                    this->input_port({IN + _external_number, name});
-                    return IN + _external_number;
-                }
-
-                void internal(const std::string& name, double Dyn::* var)
-                {
-                    assert(_internal_number == 0);
-
-                    ++_internal_number;
-                    this->state_(LAST_OUTPUT + 1, name, var);
-                }
-
-                virtual double compute() const = 0;
-
-                virtual void dconf(const typename Time::type& t, typename Time::type e,
-                        const common::Bag<Time>& bag)
-                {
-                    dint(t);
-                    dext(t, e, bag);
-                }
-
-                virtual void dint(const typename Time::type& /* time */)
-                {
-                    if (_state == RESPONSE) {
-                        _last_output = _output_value;
-                    }
-                    _state = WAIT;
-                }
-
-                virtual void dext(const typename Time::type& t, typename Time::type e,
-                        const common::Bag<Time>& bag)
-                {
-                    std::for_each(bag.begin(), bag.end(),
-                            [this, t, e](const common::ExternalEvent<Time>& event) {
-                                if (event.on_port(RESET)) {
-                                    if (_input_number == 0) {
-                                        _output_value = compute();
-                                        _state = RESPONSE;
-                                    } else {
-                                        _state = INIT;
-                                    }
-                                } else {
-                                    IntegratorData data;
-
-                                    event.data()(data);
-                                    this->get((event.port_index() - 1) + LAST_OUTPUT + 1).put(
-                                            dynamic_cast<Dyn*>(this),
-                                            data.value);
-                                    switch (_state) {
-                                    case INIT:
-                                        if (_input_number
-                                                == this->state_number() - (LAST_OUTPUT + 1)) {
-                                            _output_value = compute();
-                                            _state = RESPONSE;
-                                        }
-                                        break;
-                                    case WAIT:
-                                    case RESPONSE:
-                                        double value = compute();
-
-                                        if (value != _last_output) {
-                                            _output_value = value;
-                                            _state = RESPONSE;
-                                        } else {
-                                            _state = WAIT;
-                                        }
-                                    }
-                                }
-                            });
-                }
-
-                virtual void start(const typename Time::type& /* time */)
-                {
-                    _input_number = this->input_port_number() - 1;
-                    if (_input_number == 0) {
-                        _output_value = compute();
-                        _state = RESPONSE;
-                    } else {
-                        _state = INIT;
-                    }
-                }
-
-                virtual typename Time::type ta(const typename Time::type& /* time */)
-                {
-                    switch (_state) {
-                    case INIT:
-                        return Time::infinity;
-                    case WAIT:
-                        return Time::infinity;
-                    case RESPONSE:
-                        return 0;
-                    }
-                    return Time::infinity;
-                }
-
-                virtual common::Bag<Time> lambda(const typename Time::type& /* time */) const
-                {
-                    common::Bag<Time> msgs;
-
-                    switch (_state) {
-                    case INIT:
-                        break;
-                    case WAIT:
-                        break;
-                    case RESPONSE:
-                        const DerivativeData data = {_output_value};
-
-                        msgs.push_back(common::ExternalEvent<Time>(OUT, data));
-                    }
-                    return msgs;
-                }
-
-                virtual common::Value observe(const typename Time::type& /* t */,
-                        unsigned int /* index */) const
-                {
-                    return common::Value();
-                }
-
-            private:
-                unsigned int _external_number;
-                unsigned int _internal_number;
-
-                // state
-                int _state;
-                unsigned int _input_number;
-                double _output_value;
-                double _last_output;
-            };
-
-        }
-    }
-}
-
-#endif

+ 0 - 117
src/artis-star/kernel/pdevs/qss/GraphManager.hpp

@@ -1,117 +0,0 @@
-/**
- * @file kernel/pdevs/qss/GraphManager.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-2019 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 QSS_GRAPH_MANAGER
-#define QSS_GRAPH_MANAGER
-
-#include <artis-star/kernel/pdevs/GraphManager.hpp>
-#include <artis-star/kernel/pdevs/qss/Integrator.hpp>
-#include <artis-star/kernel/pdevs/qss/Quantifier.hpp>
-
-namespace artis {
-    namespace pdevs {
-        namespace qss {
-
-            template<class DerivativeParameters>
-            struct QSSParameters {
-                IntegratorParameters integrator;
-                QuantifierParameters quantifier;
-                DerivativeParameters derivative;
-            };
-
-            template<class Time,
-                    class Derivative,
-                    class DerivativeParameters = artis::common::NoParameters>
-            class GraphManager :
-                    public artis::pdevs::GraphManager<Time, QSSParameters<DerivativeParameters>, artis::common::NoParameters> {
-            public:
-                enum submodels {
-                    S_Derivative, S_Integrator, S_Quantifier
-                };
-
-                enum inputs {
-                    RESET
-                };
-
-                enum outputs {
-                    OUT
-                };
-
-                GraphManager(common::Coordinator<Time>* coordinator,
-                        const QSSParameters<DerivativeParameters>& parameters,
-                        const artis::common::NoParameters& graph_parameters)
-                        :
-                        artis::pdevs::GraphManager<Time, QSSParameters<DerivativeParameters>, artis::common::NoParameters>(
-                                coordinator,
-                                parameters,
-                                graph_parameters
-                        ),
-                        _derivative("d", parameters.derivative),
-                        _integrator("i", parameters.integrator),
-                        _quantifier("q", parameters.quantifier)
-                {
-                    this->add_child(S_Derivative, &_derivative);
-                    this->add_child(S_Integrator, &_integrator);
-                    this->add_child(S_Quantifier, &_quantifier);
-
-                    coordinator->input_port({RESET, "reset"});
-                    coordinator->output_port({OUT, "out"});
-
-                    this->in({coordinator, RESET})
-                            >> this->in({&_derivative, Derivative::RESET});
-                    this->in({coordinator, RESET})
-                            >> this->in({&_integrator, Integrator<Time>::RESET});
-                    this->in({coordinator, RESET})
-                            >> this->in({&_quantifier, Quantifier<Time>::RESET});
-
-                    this->out({&_derivative, Derivative::OUT})
-                            >> this->in({&_integrator, Integrator<Time>::X_DOT});
-                    this->out({&_integrator, Integrator<Time>::OUT})
-                            >> this->in({&_quantifier, Quantifier<Time>::IN});
-                    this->out({&_quantifier, Quantifier<Time>::OUT})
-                            >> this->in({&_integrator, Integrator<Time>::QUANTA});
-                    this->out({&_integrator, Integrator<Time>::OUT})
-                            >> this->out({coordinator, OUT});
-                    this->out({&_integrator, Integrator<Time>::OUT})
-                            >> this->in({&_derivative, Derivative::IN});
-                }
-
-                ~GraphManager() override = default;
-
-                artis::pdevs::Simulator<Time, Derivative, DerivativeParameters>*
-                derivative() { return &_derivative; }
-
-            private:
-                artis::pdevs::Simulator<Time, Derivative, DerivativeParameters> _derivative;
-                artis::pdevs::Simulator<Time, artis::pdevs::qss::Integrator<Time>, artis::pdevs::qss::IntegratorParameters> _integrator;
-                artis::pdevs::Simulator<Time, artis::pdevs::qss::Quantifier<Time>, artis::pdevs::qss::QuantifierParameters> _quantifier;
-            };
-
-        }
-    }
-}
-
-#endif

+ 0 - 314
src/artis-star/kernel/pdevs/qss/Integrator.hpp

@@ -1,314 +0,0 @@
-/**
- * @file kernel/pdevs/qss/Integrator.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-2019 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 QSS_INTEGRATOR
-#define QSS_INTEGRATOR
-
-#include <artis-star/kernel/pdevs/Dynamics.hpp>
-#include <artis-star/kernel/pdevs/qss/Data.hpp>
-
-namespace artis {
-    namespace pdevs {
-        namespace qss {
-
-            struct IntegratorParameters {
-                double x_0;
-            };
-
-            template<class Time>
-            class Integrator
-                    : public artis::pdevs::Dynamics<Time, Integrator<Time>, IntegratorParameters> {
-
-                typedef enum {
-                    INIT,
-                    WAIT_FOR_QUANTA,
-                    WAIT_FOR_X_DOT,
-                    WAIT_FOR_BOTH,
-                    RUNNING
-                } State;
-
-            public:
-                enum inputs {
-                    QUANTA, X_DOT, RESET
-                };
-
-                enum outputs {
-                    OUT
-                };
-
-                typedef enum vars {
-                    VALUE
-                } Observable;
-
-                enum states {
-                    STATE,
-                    LAST_OUT_DATE,
-                    UP_THRESHOLD,
-                    DOWN_THRESHOLD,
-                    LAST_OUT_VALUE,
-                    INIT_VALUE,
-                    CURRENT_VALUE,
-                    EXPECTED_VALUE,
-                    ARCHIVE_X_DOT,
-                    ARCHIVE_DATE
-                };
-
-                Integrator(const std::string& name,
-                        const Context<Time, Integrator<Time>, IntegratorParameters>& context)
-                        :
-                        artis::pdevs::Dynamics<Time, Integrator<Time>, IntegratorParameters>(name,
-                                context)
-                {
-                    DECLARE_STATES(int, ((STATE, &Integrator<Time>::_state)));
-                    DECLARE_STATES(typename Time::type,
-                            ((LAST_OUT_DATE, &Integrator<Time>::_last_output_date)));
-                    DECLARE_STATES(double, ((UP_THRESHOLD, &Integrator<Time>::_up_threshold),
-                            (DOWN_THRESHOLD, &Integrator<Time>::_down_threshold),
-                            (LAST_OUT_VALUE, &Integrator<Time>::_last_output_value),
-                            (INIT_VALUE, &Integrator<Time>::_init_value),
-                            (CURRENT_VALUE, &Integrator<Time>::_current_value),
-                            (EXPECTED_VALUE, &Integrator<Time>::_expected_value)));
-                    DECLARE_STATES(std::vector<double>,
-                            ((ARCHIVE_X_DOT, &Integrator<Time>::_archive_x_dot)));
-                    DECLARE_STATES(std::vector<typename Time::type>,
-                            ((ARCHIVE_DATE, &Integrator<Time>::_archive_date)));
-
-                    this->input_ports({
-                            {QUANTA, "quanta"},
-                            {X_DOT,  "x_dot"},
-                            {RESET,  "reset"}});
-                    this->output_port({OUT, "out"});
-                    this->observable({VALUE, "value"});
-
-                    _init_value = context.parameters().x_0;
-                }
-
-                virtual ~Integrator() { }
-
-                virtual void dconf(typename Time::type t, typename Time::type e,
-                        const common::Bag<Time>& bag)
-                {
-                    dint(t);
-                    dext(t, e, bag);
-                }
-
-                virtual void dint(const typename Time::type& time)
-                {
-                    switch (_state) {
-                    case RUNNING: {
-                        double last_derivative_value = _archive_x_dot.back();
-
-                        _last_output_value = _expected_value;
-                        _last_output_date = time;
-                        _archive_x_dot.clear();
-                        _archive_date.clear();
-                        _archive_x_dot.push_back(last_derivative_value);
-                        _archive_date.push_back(time);
-                        _current_value = _expected_value;
-                        _state = WAIT_FOR_QUANTA;
-                        break;
-                    }
-                    case INIT: {
-                        _state = WAIT_FOR_BOTH;
-                        _last_output_value = _current_value;
-                        _last_output_date = time;
-                        break;
-                    }
-                    default:
-                        assert(false);
-                    }
-                }
-
-                virtual void dext(const typename Time::type& t, const typename Time::type& e,
-                        const common::Bag<Time>& bag)
-                {
-                    bool reset = false;
-
-                    std::for_each(bag.begin(), bag.end(),
-                            [this, t, e, &reset](const common::ExternalEvent<Time>& event) {
-                                if (event.on_port(QUANTA)) {
-                                    QuantifierData data;
-
-                                    event.data()(data);
-                                    _up_threshold = data.up;
-                                    _down_threshold = data.down;
-                                    if (_state == WAIT_FOR_QUANTA) {
-                                        _state = RUNNING;
-                                    }
-                                    if (_state == WAIT_FOR_BOTH) {
-                                        _state = WAIT_FOR_X_DOT;
-                                    }
-                                } else if (event.on_port(X_DOT)) {
-                                    DerivativeData data;
-
-                                    event.data()(data);
-                                    _archive_x_dot.push_back(data.x_dot);
-                                    _archive_date.push_back(t);
-                                    if (_state == WAIT_FOR_X_DOT) {
-                                        _state = RUNNING;
-                                    }
-                                    if (_state == WAIT_FOR_BOTH) {
-                                        _state = WAIT_FOR_QUANTA;
-                                    }
-                                } else if (event.on_port(RESET)) {
-                                    IntegratorData data;
-
-                                    event.data()(data);
-                                    _current_value = data.value;
-                                    reset = true;
-                                    _archive_x_dot.clear();
-                                    _archive_date.clear();
-                                }
-                            });
-                    if (reset) {
-                        _state = INIT;
-                    } else {
-                        if (_state == RUNNING) {
-                            _current_value = current_value(t);
-                            _expected_value = expected_value(t);
-                        }
-                    }
-                }
-
-                virtual void start(const typename Time::type& /* time */)
-                {
-                    _current_value = _init_value;
-                    _state = INIT;
-                }
-
-                virtual typename Time::type ta(const typename Time::type& /* time */)
-                {
-                    double current_derivative;
-
-                    switch (_state) {
-                    case INIT:
-                        return 0;
-                    case RUNNING:
-
-                        assert(_archive_date.size() > 0);
-
-                        current_derivative = _archive_x_dot.back();
-                        if (current_derivative == 0) {
-                            return Time::infinity;
-                        }
-                        if (current_derivative > 0) {
-
-                            assert(_up_threshold - _current_value >= 0);
-
-                            return (_up_threshold - _current_value) / current_derivative;
-                        } else {
-
-                            assert(_down_threshold - _current_value <= 0);
-
-                            return (_down_threshold - _current_value) / current_derivative;
-                        }
-                    default:
-                        return Time::infinity;
-                    }
-                }
-
-                virtual common::Bag<Time> lambda(const typename Time::type& /* time */) const
-                {
-                    common::Bag<Time> msgs;
-
-                    switch (_state) {
-                    case RUNNING: {
-                        const IntegratorData data = {_expected_value};
-
-                        msgs.push_back(common::ExternalEvent<Time>(OUT, data));
-                        break;
-                    }
-                    case INIT: {
-                        const IntegratorData data = {_current_value};
-
-                        msgs.push_back(common::ExternalEvent<Time>(OUT, data));
-                        break;
-                    }
-                    default:
-                        break;
-                    }
-                    return msgs;
-                }
-
-                virtual common::Value observe(const typename Time::type& /* t */,
-                        unsigned int index) const
-                {
-                    switch (index) {
-                    case VALUE:
-                        return (double) (_current_value);
-                    default:
-                        return common::Value();
-                    }
-                }
-
-            private:
-                double current_value(const typename Time::type& time) const
-                {
-                    double val = _last_output_value;
-
-                    if (_archive_date.size() > 0) {
-                        for (size_t i = 0; i < _archive_date.size() - 1; i++) {
-                            val +=
-                                    (_archive_date[i + 1] - _archive_date[i]) * _archive_x_dot[i];
-                        }
-                        val += (time - _archive_date.back()) * _archive_x_dot.back();
-                    }
-                    return val;
-                }
-
-                double expected_value(const typename Time::type& /* time */) const
-                {
-                    double current_derivative = _archive_x_dot.back();
-
-                    if (current_derivative == 0) {
-                        return _current_value;
-                    } else if (current_derivative > 0) {
-                        return _up_threshold;
-                    }
-                    return _down_threshold;
-                }
-
-                int _state;
-
-                typename Time::type _last_output_date;
-
-                double _up_threshold;
-                double _down_threshold;
-
-                double _last_output_value;
-                double _init_value;
-                double _current_value;
-                double _expected_value;
-
-                std::vector<double> _archive_x_dot;
-                std::vector<typename Time::type> _archive_date;
-            };
-
-        }
-    }
-}
-
-#endif

+ 0 - 390
src/artis-star/kernel/pdevs/qss/Quantifier.hpp

@@ -1,390 +0,0 @@
-/**
- * @file kernel/pdevs/qss/Quantifier.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-2019 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 QSS_QUANTIFIER
-#define QSS_QUANTIFIER
-
-#include <artis-star/kernel/pdevs/Dynamics.hpp>
-#include <artis-star/kernel/pdevs/qss/Data.hpp>
-
-#include <cmath>
-
-namespace artis {
-    namespace pdevs {
-        namespace qss {
-
-            struct QuantifierParameters {
-                bool allow_offsets;
-                bool zero_init_offset;
-                double quantum;
-                unsigned int archive_length;
-            };
-
-            template<class Time>
-            class Quantifier
-                    : public artis::pdevs::Dynamics<Time, Quantifier<Time>, QuantifierParameters> {
-            public:
-                enum inputs {
-                    IN, RESET
-                };
-
-                enum outputs {
-                    OUT
-                };
-
-                enum states {
-                    STATE, ADAPTIVE_STATE, STEP_NUMBER, OFFSET, UP_THRESHOLD, DOWN_THRESHOLD
-                };
-
-                Quantifier(const std::string& name,
-                        const Context<Time, Quantifier<Time>, QuantifierParameters>& context)
-                        :
-                        artis::pdevs::Dynamics<Time, Quantifier<Time>, QuantifierParameters>(name,
-                                context)
-                {
-                    DECLARE_STATES(int,
-                            ((STATE, &Quantifier<Time>::_state), (ADAPTIVE_STATE, &Quantifier<Time>::_adaptive_state)));
-                    DECLARE_STATES(unsigned int,
-                            ((STEP_NUMBER, &Quantifier<Time>::_step_number)));
-                    DECLARE_STATES(double,
-                            ((OFFSET, &Quantifier<Time>::_offset), (UP_THRESHOLD, &Quantifier<Time>::_up_threshold), (DOWN_THRESHOLD, &Quantifier<Time>::_down_threshold)));
-
-                    this->input_ports({{IN,    "in"},
-                                       {RESET, "reset"}});
-                    this->output_port({OUT, "out"});
-                    this->observables({{UP,    "up"},
-                                       {DOWN,  "down"},
-                                       {VALUE, "value"}});
-
-                    _adaptive = context.parameters().allow_offsets;
-                    _adaptive_state = _adaptive ? POSSIBLE : IMPOSSIBLE;
-                    _zero_init_offset = context.parameters().zero_init_offset;
-                    _step_size = context.parameters().quantum;
-
-                    assert(_step_size > 0);
-
-                    _past_length = context.parameters().archive_length;
-
-                    assert(_past_length > 2);
-                }
-
-                virtual ~Quantifier() { }
-
-                virtual void dconf(const typename Time::type& t, const typename Time::type& e,
-                        const common::Bag<Time>& bag)
-                {
-                    dint(t);
-                    dext(t, e, bag);
-                }
-
-                virtual void dint(const typename Time::type& /* t */)
-                {
-                    switch (_state) {
-                    case INIT:
-                        break;
-                    case IDLE:
-                        break;
-                    case RESPONSE:
-                        _state = IDLE;
-                        break;
-                    }
-                }
-
-                virtual void dext(const typename Time::type& t, const typename Time::type& e,
-                        const common::Bag<Time>& bag)
-                {
-                    bool reset = false;
-
-                    std::for_each(bag.begin(), bag.end(),
-                            [this, t, e, &reset](const common::ExternalEvent<Time>& event) {
-                                if (event.on_port(IN)) {
-                                    IntegratorData data;
-                                    double shifting_factor;
-                                    double value;
-                                    int cnt;
-
-                                    event.data()(data);
-                                    value = data.value;
-                                    if (_state == INIT) {
-                                        init_step_number_and_offset(value);
-                                        update_thresholds();
-                                        _state = RESPONSE;
-                                    } else {
-                                        cnt = 0;
-                                        while (value >= _up_threshold or value <= _down_threshold) {
-                                            cnt++;
-                                            if (value >= _up_threshold) {
-                                                _step_number++;
-                                            } else {
-                                                _step_number--;
-                                            }
-                                            switch (_adaptive_state) {
-                                            case IMPOSSIBLE:
-                                                update_thresholds();
-                                                break;
-                                            case POSSIBLE:
-                                                if (value >= _up_threshold) {
-                                                    store_change(_step_size, t);
-                                                } else {
-                                                    store_change(-_step_size, t);
-                                                }
-                                                shifting_factor = shift_quanta();
-
-                                                assert(shifting_factor >= 0
-                                                        and shifting_factor <= 1);
-
-                                                if (shifting_factor != 0 and shifting_factor != 1) {
-                                                    if (value >= _up_threshold) {
-                                                        update_thresholds(shifting_factor,
-                                                                DIRECTION_DOWN);
-                                                    } else {
-                                                        update_thresholds(shifting_factor,
-                                                                DIRECTION_UP);
-                                                    }
-                                                    _adaptive_state = DONE;
-                                                } else {
-                                                    update_thresholds();
-                                                }
-                                                break;
-                                            case DONE:
-                                                init_step_number_and_offset(value);
-                                                _adaptive_state = POSSIBLE;
-                                                update_thresholds();
-                                                break;
-                                            }
-                                        }
-                                    }
-                                } else if (event.on_port(RESET)) {
-                                    _offset = 0;
-                                    reset = true;
-                                    _archive.clear();
-                                }
-                            });
-                    if (reset) {
-                        _state = INIT;
-                    } else {
-                        _state = RESPONSE;
-                    }
-                }
-
-                virtual void start(const typename Time::type& /* time */)
-                {
-                    _offset = 0;
-                    _state = INIT;
-                }
-
-                virtual typename Time::type ta(const typename Time::type& /* time */)
-                {
-                    switch (_state) {
-                    case INIT:
-                    case IDLE:
-                        return Time::infinity;
-                    case RESPONSE:
-                        return 0.0;
-                    }
-                    return Time::infinity;
-                }
-
-                virtual common::Bag<Time> lambda(const typename Time::type& /* time */) const
-                {
-                    common::Bag<Time> msgs;
-                    const QuantifierData data = {_up_threshold, _down_threshold};
-
-                    msgs.push_back(common::ExternalEvent<Time>(OUT, data));
-                    return msgs;
-                }
-
-                virtual common::Value observe(const typename Time::type& /* t */,
-                        unsigned int index) const
-                {
-                    switch (index) {
-                    case UP:
-                        return (double) _up_threshold;
-                    case DOWN:
-                        return (double) _down_threshold;
-                    case VALUE:
-                        return (double) (_up_threshold - _down_threshold);
-                    default:
-                        return common::Value();
-                    }
-                }
-
-            private:
-                typedef enum {
-                    DIRECTION_UP, DIRECTION_DOWN
-                } Direction;
-
-                void init_step_number_and_offset(double value)
-                {
-                    _step_number = static_cast<long int>(std::floor(value / _step_size));
-                    if (_zero_init_offset) {
-                        _offset = 0;
-                    } else {
-                        _offset = value - static_cast<double>(_step_number) * _step_size;
-                    }
-                }
-
-                bool monotonous(unsigned int range)
-                {
-                    if ((range + 1) > _archive.size()) {
-                        return false;
-                    }
-                    for (size_t i = 0; i < range; i++) {
-                        if (_archive[i].value * _archive[i + 1].value < 0) {
-                            return false;
-                        }
-                    }
-                    return true;
-                }
-
-                bool oscillating(unsigned int range)
-                {
-                    if ((range + 1) > _archive.size()) {
-                        return false;
-                    }
-                    for (size_t i = _archive.size() - range; i < _archive.size() - 1; i++) {
-                        if (_archive[i].value * _archive[i + 1].value > 0) {
-                            return false;
-                        }
-                    }
-                    return true;
-                }
-
-                double shift_quanta()
-                {
-                    double factor = 0;
-
-                    if (oscillating(_past_length - 1) and
-                            _archive.back().date - _archive.front().date != 0) {
-                        double acc;
-                        double local_estim;
-                        int cnt;
-
-                        acc = 0;
-                        cnt = 0;
-                        for (size_t i = 0; i < _archive.size() - 2; ++i) {
-                            if (0 != (_archive[i + 2].date - _archive[i].date)) {
-                                if ((_archive.back().value * _archive[i + 1].value) > 0) {
-                                    local_estim =
-                                            1 - (_archive[i + 1].date - _archive[i].date) /
-                                                    (_archive[i + 2].date - _archive[i].date);
-                                } else {
-                                    local_estim = (_archive[i + 1].date - _archive[i].date) /
-                                            (_archive[i + 2].date - _archive[i].date);
-                                }
-                                acc += local_estim;
-                                cnt++;
-                            }
-                        }
-                        acc = acc / cnt;
-                        factor = acc;
-                        _archive.resize(0);
-                    }
-                    return factor;
-                }
-
-                void store_change(double val, const typename Time::type& time)
-                {
-                    record_t record;
-
-                    record.date = time;
-                    record.value = val;
-                    _archive.push_back(record);
-                    while (_archive.size() > _past_length) {
-                        _archive.pop_front();
-                    }
-                }
-
-                void update_thresholds()
-                {
-                    auto step_number = static_cast<double>(_step_number);
-
-                    _up_threshold = _offset + _step_size * (step_number + 1);
-                    _down_threshold = _offset + _step_size * (step_number - 1);
-                }
-
-                void update_thresholds(double factor)
-                {
-                    auto step_number = static_cast<double>(_step_number);
-
-                    _up_threshold = _offset + _step_size * (step_number + (1 - factor));
-                    _down_threshold = _offset + _step_size * (step_number - (1 - factor));
-                }
-
-                void update_thresholds(double factor, Direction d)
-                {
-                    auto step_number = static_cast<double>(_step_number);
-
-                    if (d == DIRECTION_UP) {
-                        _up_threshold = _offset + _step_size * (step_number + (1 - factor));
-                        _down_threshold = _offset + _step_size * (step_number - 1);
-                    } else {
-                        _up_threshold = _offset + _step_size * (step_number + 1);
-                        _down_threshold = _offset + _step_size * (step_number - (1 - factor));
-                    }
-                }
-
-                typedef enum vars {
-                    UP, DOWN, VALUE
-                } Observable;
-
-                typedef enum {
-                    INIT, IDLE, RESPONSE
-                } State;
-
-                typedef enum {
-                    IMPOSSIBLE, POSSIBLE, DONE
-                } AdaptiveState;
-
-                struct record_t {
-                    double value;
-                    typename Time::type date;
-                };
-
-                // parameters
-                bool _adaptive;
-                bool _zero_init_offset;
-                unsigned int _past_length;
-                double _step_size;
-
-                // state
-                int _state;
-                int _adaptive_state;
-
-                unsigned int _step_number; // long int
-
-                double _offset;
-                double _up_threshold;
-                double _down_threshold;
-
-                std::deque<record_t> _archive;
-            };
-
-        }
-    }
-}
-
-#endif

+ 11 - 0
src/artis-star/kernel/qss/CMakeLists.txt

@@ -0,0 +1,11 @@
+INCLUDE_DIRECTORIES(
+        ${ARTIS_BINARY_DIR}/src
+        ${ARTIS_SOURCE_DIR}/src
+        ${Boost_INCLUDE_DIRS})
+
+LINK_DIRECTORIES(
+        ${Boost_LIBRARY_DIRS})
+
+SET(QSS_HPP Data.hpp Derivative.hpp Integrator.hpp Quantifier.hpp)
+
+INSTALL(FILES ${QSS_HPP} DESTINATION ${ARTIS_INCLUDE_DIRS}/kernel/qss)

+ 12 - 15
src/artis-star/kernel/pdevs/qss/Data.hpp

@@ -1,5 +1,5 @@
 /**
- * @file kernel/pdevs/qss/Data.hpp
+ * @file kernel/qss/Data.hpp
  * @author The ARTIS Development Team
  * See the AUTHORS or Authors.txt file
  */
@@ -28,24 +28,21 @@
 #define QSS_DATA
 
 namespace artis {
-    namespace pdevs {
-        namespace qss {
+    namespace qss {
 
-            struct IntegratorData {
-                double value;
-            };
+        struct IntegratorData {
+            double value;
+        };
 
-            struct DerivativeData {
-                double x_dot;
-            };
+        struct DerivativeData {
+            double x_dot;
+        };
 
-            struct QuantifierData {
-                double up;
-                double down;
-            };
+        struct QuantifierData {
+            double up;
+            double down;
+        };
 
-
-        }
     }
 }
 

+ 213 - 0
src/artis-star/kernel/qss/Derivative.hpp

@@ -0,0 +1,213 @@
+/**
+ * @file kernel/qss/Derivative.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-2019 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 QSS_DERIVATIVE
+#define QSS_DERIVATIVE
+
+#include <artis-star/kernel/pdevs/Dynamics.hpp>
+#include <artis-star/kernel/qss/Data.hpp>
+
+namespace artis {
+    namespace qss {
+
+        template<class Time, class Dyn, class Parameters = common::NoParameters>
+        class Derivative : public artis::pdevs::Dynamics<Time, Dyn, Parameters> {
+            typedef enum {
+                INIT = 0, WAIT, RESPONSE
+            } State;
+
+        public:
+            enum inputs {
+                RESET = 0, IN
+            };
+
+            enum outputs {
+                OUT = 0
+            };
+
+            enum states {
+                STATE = 0, INPUT_NUMBER, OUTPUT_VALUE, LAST_OUTPUT
+            };
+
+            typedef Derivative<Time, Dyn, Parameters> type;
+
+            Derivative(const std::string& name, const artis::pdevs::Context<Time, Dyn, Parameters>& context)
+                    :
+                    artis::pdevs::Dynamics<Time, Dyn, Parameters>(name, context),
+                    _external_number(0), _internal_number(0)
+            {
+                DECLARE_STATES(int,
+                        ((STATE, &type::_state)));
+                DECLARE_STATES(unsigned int,
+                        ((INPUT_NUMBER, &type::_input_number)));
+                DECLARE_STATES(double,
+                        ((OUTPUT_VALUE, &type::_output_value),
+                                (LAST_OUTPUT, &type::_output_value)));
+
+                this->input_ports({{RESET, "reset"},
+                                   {IN,    "in"}});
+                this->output_port({OUT, "out"});
+            }
+
+            virtual ~Derivative() { }
+
+            int external(const std::string& name, double Dyn::* var)
+            {
+                ++_external_number;
+                this->state_(LAST_OUTPUT + _external_number + 1, name, var);
+                this->input_port({IN + _external_number, name});
+                return IN + _external_number;
+            }
+
+            void internal(const std::string& name, double Dyn::* var)
+            {
+                assert(_internal_number == 0);
+
+                ++_internal_number;
+                this->state_(LAST_OUTPUT + 1, name, var);
+            }
+
+            virtual double compute() const = 0;
+
+            virtual void dconf(const typename Time::type& t, typename Time::type e,
+                    const common::Bag<Time>& bag)
+            {
+                dint(t);
+                dext(t, e, bag);
+            }
+
+            virtual void dint(const typename Time::type& /* time */)
+            {
+                if (_state == RESPONSE) {
+                    _last_output = _output_value;
+                }
+                _state = WAIT;
+            }
+
+            virtual void dext(const typename Time::type& t, typename Time::type e,
+                    const common::Bag<Time>& bag)
+            {
+                std::for_each(bag.begin(), bag.end(),
+                        [this, t, e](const common::ExternalEvent<Time>& event) {
+                            if (event.on_port(RESET)) {
+                                if (_input_number == 0) {
+                                    _output_value = compute();
+                                    _state = RESPONSE;
+                                } else {
+                                    _state = INIT;
+                                }
+                            } else {
+                                IntegratorData data;
+
+                                event.data()(data);
+                                this->get((event.port_index() - 1) + LAST_OUTPUT + 1).put(
+                                        dynamic_cast<Dyn*>(this),
+                                        data.value);
+                                switch (_state) {
+                                case INIT:
+                                    if (_input_number
+                                            == this->state_number() - (LAST_OUTPUT + 1)) {
+                                        _output_value = compute();
+                                        _state = RESPONSE;
+                                    }
+                                    break;
+                                case WAIT:
+                                case RESPONSE:
+                                    double value = compute();
+
+                                    if (value != _last_output) {
+                                        _output_value = value;
+                                        _state = RESPONSE;
+                                    } else {
+                                        _state = WAIT;
+                                    }
+                                }
+                            }
+                        });
+            }
+
+            virtual void start(const typename Time::type& /* time */)
+            {
+                _input_number = this->input_port_number() - 1;
+                if (_input_number == 0) {
+                    _output_value = compute();
+                    _state = RESPONSE;
+                } else {
+                    _state = INIT;
+                }
+            }
+
+            virtual typename Time::type ta(const typename Time::type& /* time */)
+            {
+                switch (_state) {
+                case INIT:
+                    return Time::infinity;
+                case WAIT:
+                    return Time::infinity;
+                case RESPONSE:
+                    return 0;
+                }
+                return Time::infinity;
+            }
+
+            virtual common::Bag<Time> lambda(const typename Time::type& /* time */) const
+            {
+                common::Bag<Time> msgs;
+
+                switch (_state) {
+                case INIT:
+                    break;
+                case WAIT:
+                    break;
+                case RESPONSE:
+                    const DerivativeData data = {_output_value};
+
+                    msgs.push_back(common::ExternalEvent<Time>(OUT, data));
+                }
+                return msgs;
+            }
+
+            virtual common::Value observe(const typename Time::type& /* t */,
+                    unsigned int /* index */) const
+            {
+                return common::Value();
+            }
+
+        private:
+            unsigned int _external_number;
+            unsigned int _internal_number;
+
+            // state
+            int _state;
+            unsigned int _input_number;
+            double _output_value;
+            double _last_output;
+        };
+
+    }
+}
+
+#endif

+ 312 - 0
src/artis-star/kernel/qss/Integrator.hpp

@@ -0,0 +1,312 @@
+/**
+ * @file kernel/qss/Integrator.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-2019 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 QSS_INTEGRATOR
+#define QSS_INTEGRATOR
+
+#include <artis-star/kernel/pdevs/Dynamics.hpp>
+#include <artis-star/kernel/qss/Data.hpp>
+
+namespace artis {
+    namespace qss {
+
+        struct IntegratorParameters {
+            double x_0;
+        };
+
+        template<class Time>
+        class Integrator
+                : public artis::pdevs::Dynamics<Time, Integrator<Time>, IntegratorParameters> {
+
+            typedef enum {
+                INIT,
+                WAIT_FOR_QUANTA,
+                WAIT_FOR_X_DOT,
+                WAIT_FOR_BOTH,
+                RUNNING
+            } State;
+
+        public:
+            enum inputs {
+                QUANTA, X_DOT, RESET
+            };
+
+            enum outputs {
+                OUT
+            };
+
+            typedef enum vars {
+                VALUE
+            } Observable;
+
+            enum states {
+                STATE,
+                LAST_OUT_DATE,
+                UP_THRESHOLD,
+                DOWN_THRESHOLD,
+                LAST_OUT_VALUE,
+                INIT_VALUE,
+                CURRENT_VALUE,
+                EXPECTED_VALUE,
+                ARCHIVE_X_DOT,
+                ARCHIVE_DATE
+            };
+
+            Integrator(const std::string& name,
+                    const artis::pdevs::Context<Time, Integrator<Time>, IntegratorParameters>& context)
+                    :
+                    artis::pdevs::Dynamics<Time, Integrator<Time>, IntegratorParameters>(name,
+                            context)
+            {
+                DECLARE_STATES(int, ((STATE, &Integrator<Time>::_state)));
+                DECLARE_STATES(typename Time::type,
+                        ((LAST_OUT_DATE, &Integrator<Time>::_last_output_date)));
+                DECLARE_STATES(double, ((UP_THRESHOLD, &Integrator<Time>::_up_threshold),
+                        (DOWN_THRESHOLD, &Integrator<Time>::_down_threshold),
+                        (LAST_OUT_VALUE, &Integrator<Time>::_last_output_value),
+                        (INIT_VALUE, &Integrator<Time>::_init_value),
+                        (CURRENT_VALUE, &Integrator<Time>::_current_value),
+                        (EXPECTED_VALUE, &Integrator<Time>::_expected_value)));
+                DECLARE_STATES(std::vector<double>,
+                        ((ARCHIVE_X_DOT, &Integrator<Time>::_archive_x_dot)));
+                DECLARE_STATES(std::vector<typename Time::type>,
+                        ((ARCHIVE_DATE, &Integrator<Time>::_archive_date)));
+
+                this->input_ports({
+                        {QUANTA, "quanta"},
+                        {X_DOT,  "x_dot"},
+                        {RESET,  "reset"}});
+                this->output_port({OUT, "out"});
+                this->observable({VALUE, "value"});
+
+                _init_value = context.parameters().x_0;
+            }
+
+            virtual ~Integrator() { }
+
+            virtual void dconf(typename Time::type t, typename Time::type e,
+                    const common::Bag<Time>& bag)
+            {
+                dint(t);
+                dext(t, e, bag);
+            }
+
+            virtual void dint(const typename Time::type& time)
+            {
+                switch (_state) {
+                case RUNNING: {
+                    double last_derivative_value = _archive_x_dot.back();
+
+                    _last_output_value = _expected_value;
+                    _last_output_date = time;
+                    _archive_x_dot.clear();
+                    _archive_date.clear();
+                    _archive_x_dot.push_back(last_derivative_value);
+                    _archive_date.push_back(time);
+                    _current_value = _expected_value;
+                    _state = WAIT_FOR_QUANTA;
+                    break;
+                }
+                case INIT: {
+                    _state = WAIT_FOR_BOTH;
+                    _last_output_value = _current_value;
+                    _last_output_date = time;
+                    break;
+                }
+                default:
+                    assert(false);
+                }
+            }
+
+            virtual void dext(const typename Time::type& t, const typename Time::type& e,
+                    const common::Bag<Time>& bag)
+            {
+                bool reset = false;
+
+                std::for_each(bag.begin(), bag.end(),
+                        [this, t, e, &reset](const common::ExternalEvent<Time>& event) {
+                            if (event.on_port(QUANTA)) {
+                                QuantifierData data;
+
+                                event.data()(data);
+                                _up_threshold = data.up;
+                                _down_threshold = data.down;
+                                if (_state == WAIT_FOR_QUANTA) {
+                                    _state = RUNNING;
+                                }
+                                if (_state == WAIT_FOR_BOTH) {
+                                    _state = WAIT_FOR_X_DOT;
+                                }
+                            } else if (event.on_port(X_DOT)) {
+                                DerivativeData data;
+
+                                event.data()(data);
+                                _archive_x_dot.push_back(data.x_dot);
+                                _archive_date.push_back(t);
+                                if (_state == WAIT_FOR_X_DOT) {
+                                    _state = RUNNING;
+                                }
+                                if (_state == WAIT_FOR_BOTH) {
+                                    _state = WAIT_FOR_QUANTA;
+                                }
+                            } else if (event.on_port(RESET)) {
+                                IntegratorData data;
+
+                                event.data()(data);
+                                _current_value = data.value;
+                                reset = true;
+                                _archive_x_dot.clear();
+                                _archive_date.clear();
+                            }
+                        });
+                if (reset) {
+                    _state = INIT;
+                } else {
+                    if (_state == RUNNING) {
+                        _current_value = current_value(t);
+                        _expected_value = expected_value(t);
+                    }
+                }
+            }
+
+            virtual void start(const typename Time::type& /* time */)
+            {
+                _current_value = _init_value;
+                _state = INIT;
+            }
+
+            virtual typename Time::type ta(const typename Time::type& /* time */)
+            {
+                double current_derivative;
+
+                switch (_state) {
+                case INIT:
+                    return 0;
+                case RUNNING:
+
+                    assert(_archive_date.size() > 0);
+
+                    current_derivative = _archive_x_dot.back();
+                    if (current_derivative == 0) {
+                        return Time::infinity;
+                    }
+                    if (current_derivative > 0) {
+
+                        assert(_up_threshold - _current_value >= 0);
+
+                        return (_up_threshold - _current_value) / current_derivative;
+                    } else {
+
+                        assert(_down_threshold - _current_value <= 0);
+
+                        return (_down_threshold - _current_value) / current_derivative;
+                    }
+                default:
+                    return Time::infinity;
+                }
+            }
+
+            virtual common::Bag<Time> lambda(const typename Time::type& /* time */) const
+            {
+                common::Bag<Time> msgs;
+
+                switch (_state) {
+                case RUNNING: {
+                    const IntegratorData data = {_expected_value};
+
+                    msgs.push_back(common::ExternalEvent<Time>(OUT, data));
+                    break;
+                }
+                case INIT: {
+                    const IntegratorData data = {_current_value};
+
+                    msgs.push_back(common::ExternalEvent<Time>(OUT, data));
+                    break;
+                }
+                default:
+                    break;
+                }
+                return msgs;
+            }
+
+            virtual common::Value observe(const typename Time::type& /* t */,
+                    unsigned int index) const
+            {
+                switch (index) {
+                case VALUE:
+                    return (double) (_current_value);
+                default:
+                    return common::Value();
+                }
+            }
+
+        private:
+            double current_value(const typename Time::type& time) const
+            {
+                double val = _last_output_value;
+
+                if (_archive_date.size() > 0) {
+                    for (size_t i = 0; i < _archive_date.size() - 1; i++) {
+                        val +=
+                                (_archive_date[i + 1] - _archive_date[i]) * _archive_x_dot[i];
+                    }
+                    val += (time - _archive_date.back()) * _archive_x_dot.back();
+                }
+                return val;
+            }
+
+            double expected_value(const typename Time::type& /* time */) const
+            {
+                double current_derivative = _archive_x_dot.back();
+
+                if (current_derivative == 0) {
+                    return _current_value;
+                } else if (current_derivative > 0) {
+                    return _up_threshold;
+                }
+                return _down_threshold;
+            }
+
+            int _state;
+
+            typename Time::type _last_output_date;
+
+            double _up_threshold;
+            double _down_threshold;
+
+            double _last_output_value;
+            double _init_value;
+            double _current_value;
+            double _expected_value;
+
+            std::vector<double> _archive_x_dot;
+            std::vector<typename Time::type> _archive_date;
+        };
+
+    }
+}
+
+#endif

+ 388 - 0
src/artis-star/kernel/qss/Quantifier.hpp

@@ -0,0 +1,388 @@
+/**
+ * @file kernel/qss/Quantifier.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-2019 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 QSS_QUANTIFIER
+#define QSS_QUANTIFIER
+
+#include <artis-star/kernel/pdevs/Dynamics.hpp>
+#include <artis-star/kernel/qss/Data.hpp>
+
+#include <cmath>
+
+namespace artis {
+    namespace qss {
+
+        struct QuantifierParameters {
+            bool allow_offsets;
+            bool zero_init_offset;
+            double quantum;
+            unsigned int archive_length;
+        };
+
+        template<class Time>
+        class Quantifier
+                : public artis::pdevs::Dynamics<Time, Quantifier<Time>, QuantifierParameters> {
+        public:
+            enum inputs {
+                IN, RESET
+            };
+
+            enum outputs {
+                OUT
+            };
+
+            enum states {
+                STATE, ADAPTIVE_STATE, STEP_NUMBER, OFFSET, UP_THRESHOLD, DOWN_THRESHOLD
+            };
+
+            Quantifier(const std::string& name,
+                    const artis::pdevs::Context<Time, Quantifier<Time>, QuantifierParameters>& context)
+                    :
+                    artis::pdevs::Dynamics<Time, Quantifier<Time>, QuantifierParameters>(name,
+                            context)
+            {
+                DECLARE_STATES(int,
+                        ((STATE, &Quantifier<Time>::_state), (ADAPTIVE_STATE, &Quantifier<Time>::_adaptive_state)));
+                DECLARE_STATES(unsigned int,
+                        ((STEP_NUMBER, &Quantifier<Time>::_step_number)));
+                DECLARE_STATES(double,
+                        ((OFFSET, &Quantifier<Time>::_offset), (UP_THRESHOLD, &Quantifier<Time>::_up_threshold), (DOWN_THRESHOLD, &Quantifier<Time>::_down_threshold)));
+
+                this->input_ports({{IN,    "in"},
+                                   {RESET, "reset"}});
+                this->output_port({OUT, "out"});
+                this->observables({{UP,    "up"},
+                                   {DOWN,  "down"},
+                                   {VALUE, "value"}});
+
+                _adaptive = context.parameters().allow_offsets;
+                _adaptive_state = _adaptive ? POSSIBLE : IMPOSSIBLE;
+                _zero_init_offset = context.parameters().zero_init_offset;
+                _step_size = context.parameters().quantum;
+
+                assert(_step_size > 0);
+
+                _past_length = context.parameters().archive_length;
+
+                assert(_past_length > 2);
+            }
+
+            virtual ~Quantifier() { }
+
+            virtual void dconf(const typename Time::type& t, const typename Time::type& e,
+                    const common::Bag<Time>& bag)
+            {
+                dint(t);
+                dext(t, e, bag);
+            }
+
+            virtual void dint(const typename Time::type& /* t */)
+            {
+                switch (_state) {
+                case INIT:
+                    break;
+                case IDLE:
+                    break;
+                case RESPONSE:
+                    _state = IDLE;
+                    break;
+                }
+            }
+
+            virtual void dext(const typename Time::type& t, const typename Time::type& e,
+                    const common::Bag<Time>& bag)
+            {
+                bool reset = false;
+
+                std::for_each(bag.begin(), bag.end(),
+                        [this, t, e, &reset](const common::ExternalEvent<Time>& event) {
+                            if (event.on_port(IN)) {
+                                IntegratorData data;
+                                double shifting_factor;
+                                double value;
+                                int cnt;
+
+                                event.data()(data);
+                                value = data.value;
+                                if (_state == INIT) {
+                                    init_step_number_and_offset(value);
+                                    update_thresholds();
+                                    _state = RESPONSE;
+                                } else {
+                                    cnt = 0;
+                                    while (value >= _up_threshold or value <= _down_threshold) {
+                                        cnt++;
+                                        if (value >= _up_threshold) {
+                                            _step_number++;
+                                        } else {
+                                            _step_number--;
+                                        }
+                                        switch (_adaptive_state) {
+                                        case IMPOSSIBLE:
+                                            update_thresholds();
+                                            break;
+                                        case POSSIBLE:
+                                            if (value >= _up_threshold) {
+                                                store_change(_step_size, t);
+                                            } else {
+                                                store_change(-_step_size, t);
+                                            }
+                                            shifting_factor = shift_quanta();
+
+                                            assert(shifting_factor >= 0
+                                                    and shifting_factor <= 1);
+
+                                            if (shifting_factor != 0 and shifting_factor != 1) {
+                                                if (value >= _up_threshold) {
+                                                    update_thresholds(shifting_factor,
+                                                            DIRECTION_DOWN);
+                                                } else {
+                                                    update_thresholds(shifting_factor,
+                                                            DIRECTION_UP);
+                                                }
+                                                _adaptive_state = DONE;
+                                            } else {
+                                                update_thresholds();
+                                            }
+                                            break;
+                                        case DONE:
+                                            init_step_number_and_offset(value);
+                                            _adaptive_state = POSSIBLE;
+                                            update_thresholds();
+                                            break;
+                                        }
+                                    }
+                                }
+                            } else if (event.on_port(RESET)) {
+                                _offset = 0;
+                                reset = true;
+                                _archive.clear();
+                            }
+                        });
+                if (reset) {
+                    _state = INIT;
+                } else {
+                    _state = RESPONSE;
+                }
+            }
+
+            virtual void start(const typename Time::type& /* time */)
+            {
+                _offset = 0;
+                _state = INIT;
+            }
+
+            virtual typename Time::type ta(const typename Time::type& /* time */)
+            {
+                switch (_state) {
+                case INIT:
+                case IDLE:
+                    return Time::infinity;
+                case RESPONSE:
+                    return 0.0;
+                }
+                return Time::infinity;
+            }
+
+            virtual common::Bag<Time> lambda(const typename Time::type& /* time */) const
+            {
+                common::Bag<Time> msgs;
+                const QuantifierData data = {_up_threshold, _down_threshold};
+
+                msgs.push_back(common::ExternalEvent<Time>(OUT, data));
+                return msgs;
+            }
+
+            virtual common::Value observe(const typename Time::type& /* t */,
+                    unsigned int index) const
+            {
+                switch (index) {
+                case UP:
+                    return (double) _up_threshold;
+                case DOWN:
+                    return (double) _down_threshold;
+                case VALUE:
+                    return (double) (_up_threshold - _down_threshold);
+                default:
+                    return common::Value();
+                }
+            }
+
+        private:
+            typedef enum {
+                DIRECTION_UP, DIRECTION_DOWN
+            } Direction;
+
+            void init_step_number_and_offset(double value)
+            {
+                _step_number = static_cast<long int>(std::floor(value / _step_size));
+                if (_zero_init_offset) {
+                    _offset = 0;
+                } else {
+                    _offset = value - static_cast<double>(_step_number) * _step_size;
+                }
+            }
+
+            bool monotonous(unsigned int range)
+            {
+                if ((range + 1) > _archive.size()) {
+                    return false;
+                }
+                for (size_t i = 0; i < range; i++) {
+                    if (_archive[i].value * _archive[i + 1].value < 0) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            bool oscillating(unsigned int range)
+            {
+                if ((range + 1) > _archive.size()) {
+                    return false;
+                }
+                for (size_t i = _archive.size() - range; i < _archive.size() - 1; i++) {
+                    if (_archive[i].value * _archive[i + 1].value > 0) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+            double shift_quanta()
+            {
+                double factor = 0;
+
+                if (oscillating(_past_length - 1) and
+                        _archive.back().date - _archive.front().date != 0) {
+                    double acc;
+                    double local_estim;
+                    int cnt;
+
+                    acc = 0;
+                    cnt = 0;
+                    for (size_t i = 0; i < _archive.size() - 2; ++i) {
+                        if (0 != (_archive[i + 2].date - _archive[i].date)) {
+                            if ((_archive.back().value * _archive[i + 1].value) > 0) {
+                                local_estim =
+                                        1 - (_archive[i + 1].date - _archive[i].date) /
+                                                (_archive[i + 2].date - _archive[i].date);
+                            } else {
+                                local_estim = (_archive[i + 1].date - _archive[i].date) /
+                                        (_archive[i + 2].date - _archive[i].date);
+                            }
+                            acc += local_estim;
+                            cnt++;
+                        }
+                    }
+                    acc = acc / cnt;
+                    factor = acc;
+                    _archive.resize(0);
+                }
+                return factor;
+            }
+
+            void store_change(double val, const typename Time::type& time)
+            {
+                record_t record;
+
+                record.date = time;
+                record.value = val;
+                _archive.push_back(record);
+                while (_archive.size() > _past_length) {
+                    _archive.pop_front();
+                }
+            }
+
+            void update_thresholds()
+            {
+                auto step_number = static_cast<double>(_step_number);
+
+                _up_threshold = _offset + _step_size * (step_number + 1);
+                _down_threshold = _offset + _step_size * (step_number - 1);
+            }
+
+            void update_thresholds(double factor)
+            {
+                auto step_number = static_cast<double>(_step_number);
+
+                _up_threshold = _offset + _step_size * (step_number + (1 - factor));
+                _down_threshold = _offset + _step_size * (step_number - (1 - factor));
+            }
+
+            void update_thresholds(double factor, Direction d)
+            {
+                auto step_number = static_cast<double>(_step_number);
+
+                if (d == DIRECTION_UP) {
+                    _up_threshold = _offset + _step_size * (step_number + (1 - factor));
+                    _down_threshold = _offset + _step_size * (step_number - 1);
+                } else {
+                    _up_threshold = _offset + _step_size * (step_number + 1);
+                    _down_threshold = _offset + _step_size * (step_number - (1 - factor));
+                }
+            }
+
+            typedef enum vars {
+                UP, DOWN, VALUE
+            } Observable;
+
+            typedef enum {
+                INIT, IDLE, RESPONSE
+            } State;
+
+            typedef enum {
+                IMPOSSIBLE, POSSIBLE, DONE
+            } AdaptiveState;
+
+            struct record_t {
+                double value;
+                typename Time::type date;
+            };
+
+            // parameters
+            bool _adaptive;
+            bool _zero_init_offset;
+            unsigned int _past_length;
+            double _step_size;
+
+            // state
+            int _state;
+            int _adaptive_state;
+
+            unsigned int _step_number; // long int
+
+            double _offset;
+            double _up_threshold;
+            double _down_threshold;
+
+            std::deque<record_t> _archive;
+        };
+
+    }
+}
+
+#endif