Parcourir la source

Add new examples: qss/mixed and multithreading with lookahead

Eric Ramat il y a 4 ans
Parent
commit
02dab0428a

+ 1 - 0
src/tests/multithreading/CMakeLists.txt

@@ -1 +1,2 @@
 ADD_SUBDIRECTORY(lifegame)
+ADD_SUBDIRECTORY(simple)

+ 17 - 0
src/tests/multithreading/simple/CMakeLists.txt

@@ -0,0 +1,17 @@
+INCLUDE_DIRECTORIES(
+        ${CMAKE_SOURCE_DIR}/src
+        ${ARTIS_INCLUDE_DIRS}
+        ${Boost_INCLUDE_DIRS}
+        ${GLIBMM_INCLUDE_DIRS}
+        ${LIBXML_INCLUDE_DIRS})
+
+LINK_DIRECTORIES(
+        ${GLIBMM_LIBRARY_DIRS}
+        ${LIBXML_LIBRARY_DIR})
+
+ADD_EXECUTABLE(pdevs-multithreading-simple-main graph_manager.hpp main.cpp models.hpp)
+
+TARGET_LINK_LIBRARIES(pdevs-multithreading-simple-main
+        ${CMAKE_THREAD_LIBS_INIT}
+        ${Boost_SYSTEM_LIBRARY}
+        ${Boost_TIMER_LIBRARY})

+ 279 - 0
src/tests/multithreading/simple/graph_manager.hpp

@@ -0,0 +1,279 @@
+/**
+ * @file tests/multithreading/simple/graph_manager.cpp
+ * @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 TESTS_MULTITHREADING_SIMPLE_GRAPH_MANAGER_HPP
+#define TESTS_MULTITHREADING_SIMPLE_GRAPH_MANAGER_HPP
+
+#include <tests/multithreading/simple/models.hpp>
+
+#include <artis-star/kernel/pdevs/multithreading/Coordinator.hpp>
+#include <artis-star/kernel/pdevs/GraphManager.hpp>
+#include <artis-star/kernel/pdevs/Simulator.hpp>
+
+namespace artis {
+    namespace tests {
+        namespace multithreading {
+            namespace simple {
+
+                class LinksGraphManager :
+                        public artis::pdevs::GraphManager<artis::common::DoubleTime, GeneratorParameters> {
+                public:
+                    enum submodels {
+                        LINK_1, LINK_2
+                    };
+
+                    struct inputs {
+                        enum values {
+                            IN_1, IN_2
+                        };
+                    };
+
+                    struct outputs {
+                        enum values {
+                            OUT_1, OUT_2
+                        };
+                    };
+
+                    LinksGraphManager(
+                            artis::common::Coordinator<artis::common::DoubleTime>* coordinator,
+                            const GeneratorParameters& parameters,
+                            const artis::common::NoParameters& graph_parameters)
+                            :
+                            artis::pdevs::GraphManager<artis::common::DoubleTime, GeneratorParameters>(
+                                    coordinator, parameters, graph_parameters),
+                            _link_1("link_1", artis::common::NoParameters()),
+                            _link_2("link_2", artis::common::NoParameters())
+                    {
+                        add_child(LINK_1, &_link_1);
+                        add_child(LINK_2, &_link_2);
+
+                        coordinator->input_ports({{inputs::IN_1, "in_1"},
+                                                  {inputs::IN_2, "in_2"}});
+                        coordinator->output_ports({{outputs::OUT_1, "out_1"},
+                                                   {outputs::OUT_2, "out_2"}});
+
+                        in({coordinator, inputs::IN_1})
+                                >> out({&_link_1, Link::inputs::IN});
+                        in({coordinator, inputs::IN_2})
+                                >> out({&_link_2, Link::inputs::IN});
+
+                        out({&_link_1, Link::outputs::OUT})
+                                >> out({coordinator, outputs::OUT_1});
+                        out({&_link_2, Link::outputs::OUT})
+                                >> out({coordinator, outputs::OUT_2});
+                    }
+
+                    ~LinksGraphManager() override = default;
+
+                    common::DoubleTime::type
+                    lookahead(const common::DoubleTime::type& t) const override
+                    {
+                        std::vector<double> lookaheads = {_link_1.lookahead(t),
+                                                          _link_2.lookahead(t)};
+                        return *std::min(lookaheads.begin(), lookaheads.end());
+                    }
+
+                    void init() { }
+
+                    void start(common::DoubleTime::type /* t */) { }
+
+                    void transition(const common::Models<common::DoubleTime>& /* receivers */,
+                            artis::common::DoubleTime::type /* t */) { }
+
+                private:
+                    artis::pdevs::Simulator<artis::common::DoubleTime, Link> _link_1;
+                    artis::pdevs::Simulator<artis::common::DoubleTime, Link> _link_2;
+                };
+
+                class SimpleGraphManager :
+                        public artis::pdevs::GraphManager<artis::common::DoubleTime, GeneratorParameters> {
+                public:
+                    enum submodels {
+                        GENERATOR, LINK_1_2, LINK_3_4, LINK_5_6, LINK_7_8, COUNTER
+                    };
+
+                    SimpleGraphManager(
+                            artis::common::Coordinator<artis::common::DoubleTime>* coordinator,
+                            const GeneratorParameters& parameters,
+                            const artis::common::NoParameters& graph_parameters)
+                            :
+                            artis::pdevs::GraphManager<artis::common::DoubleTime, GeneratorParameters>(
+                                    coordinator, parameters, graph_parameters),
+                            _generator("generator", parameters),
+                            _link_1_2("link_1_2", parameters, artis::common::NoParameters()),
+                            _link_3_4("link_3_4", parameters, artis::common::NoParameters()),
+                            _link_5_6("link_5_6", parameters, artis::common::NoParameters()),
+                            _link_7_8("link_7_8", parameters, artis::common::NoParameters()),
+                            _counter("counter", artis::common::NoParameters())
+                    {
+                        add_child(GENERATOR, &_generator);
+                        add_child(LINK_1_2, &_link_1_2);
+                        add_child(LINK_3_4, &_link_3_4);
+                        add_child(LINK_5_6, &_link_5_6);
+                        add_child(LINK_7_8, &_link_7_8);
+                        add_child(COUNTER, &_counter);
+
+                        out({&_generator, Generator::outputs::OUT})
+                                >> in({&_link_1_2, LinksGraphManager::inputs::IN_1});
+                        out({&_generator, Generator::outputs::OUT + 1})
+                                >> in({&_link_1_2, LinksGraphManager::inputs::IN_2});
+                        out({&_generator, Generator::outputs::OUT + 2})
+                                >> in({&_link_3_4, LinksGraphManager::inputs::IN_1});
+                        out({&_generator, Generator::outputs::OUT + 3})
+                                >> in({&_link_3_4, LinksGraphManager::inputs::IN_2});
+                        out({&_generator, Generator::outputs::OUT + 4})
+                                >> in({&_link_5_6, LinksGraphManager::inputs::IN_1});
+                        out({&_generator, Generator::outputs::OUT + 5})
+                                >> in({&_link_5_6, LinksGraphManager::inputs::IN_2});
+                        out({&_generator, Generator::outputs::OUT + 6})
+                                >> in({&_link_7_8, LinksGraphManager::inputs::IN_1});
+                        out({&_generator, Generator::outputs::OUT + 7})
+                                >> in({&_link_7_8, LinksGraphManager::inputs::IN_2});
+
+                        out({&_link_1_2, LinksGraphManager::outputs::OUT_1})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_1_2, LinksGraphManager::outputs::OUT_2})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_3_4, LinksGraphManager::outputs::OUT_1})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_3_4, LinksGraphManager::outputs::OUT_2})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_5_6, LinksGraphManager::outputs::OUT_1})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_5_6, LinksGraphManager::outputs::OUT_2})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_7_8, LinksGraphManager::outputs::OUT_1})
+                                >> in({&_counter, Counter::inputs::IN});
+                        out({&_link_7_8, LinksGraphManager::outputs::OUT_2})
+                                >> in({&_counter, Counter::inputs::IN});
+                    }
+
+                    ~SimpleGraphManager() override = default;
+
+                    common::DoubleTime::type
+                    lookahead(const common::DoubleTime::type& t) const override
+                    {
+                        std::vector<double> lookaheads = {_generator.lookahead(t),
+                                                          _link_1_2.lookahead(t),
+                                                          _link_3_4.lookahead(t),
+                                                          _link_5_6.lookahead(t),
+                                                          _link_7_8.lookahead(t),
+                                                          _counter.lookahead(t)};
+                        return *std::min(lookaheads.begin(), lookaheads.end());
+                    }
+
+                    void init()
+                    {
+                        _link_1_2.set_sender(
+                                (dynamic_cast< artis::pdevs::multithreading::Coordinator<
+                                        artis::common::DoubleTime,
+                                        SimpleGraphManager,
+                                        GeneratorParameters,
+                                        artis::common::NoParameters>*>(this->coordinator()))->get_sender());
+                        _link_3_4.set_sender(
+                                (dynamic_cast< artis::pdevs::multithreading::Coordinator<
+                                        artis::common::DoubleTime,
+                                        SimpleGraphManager,
+                                        GeneratorParameters,
+                                        artis::common::NoParameters>*>(this->coordinator()))->get_sender());
+                        _link_5_6.set_sender(
+                                (dynamic_cast< artis::pdevs::multithreading::Coordinator<
+                                        artis::common::DoubleTime,
+                                        SimpleGraphManager,
+                                        GeneratorParameters,
+                                        artis::common::NoParameters>*>(this->coordinator()))->get_sender());
+                        _link_7_8.set_sender(
+                                (dynamic_cast< artis::pdevs::multithreading::Coordinator<
+                                        artis::common::DoubleTime,
+                                        SimpleGraphManager,
+                                        GeneratorParameters,
+                                        artis::common::NoParameters>*>(this->coordinator()))->get_sender());
+                    }
+
+                    void start(common::DoubleTime::type t)
+                    {
+                        _link_1_2.get_sender().send(
+                                artis::pdevs::multithreading::start_message<
+                                        artis::common::DoubleTime>(t));
+                        _link_3_4.get_sender().send(
+                                artis::pdevs::multithreading::start_message<
+                                        artis::common::DoubleTime>(t));
+                        _link_5_6.get_sender().send(
+                                artis::pdevs::multithreading::start_message<
+                                        artis::common::DoubleTime>(t));
+                        _link_7_8.get_sender().send(
+                                artis::pdevs::multithreading::start_message<
+                                        artis::common::DoubleTime>(t));
+                    }
+
+                    void transition(const common::Models<common::DoubleTime>& receivers,
+                            artis::common::DoubleTime::type t)
+                    {
+                        std::for_each(receivers.begin(), receivers.end(),
+                                [this, t](const common::Model<common::DoubleTime>* model) {
+                                    if (not model->is_atomic()) {
+                                        if (model == &_link_1_2) {
+                                            _link_1_2.get_sender().send(
+                                                    artis::pdevs::multithreading::transition_message<
+                                                            artis::common::DoubleTime>(t));
+                                        } else if (model == &_link_3_4) {
+                                            _link_3_4.get_sender().send(
+                                                    artis::pdevs::multithreading::transition_message<
+                                                            artis::common::DoubleTime>(t));
+                                        } else if (model == &_link_5_6) {
+                                            _link_5_6.get_sender().send(
+                                                    artis::pdevs::multithreading::transition_message<
+                                                            artis::common::DoubleTime>(t));
+                                        } else if (model == &_link_7_8) {
+                                            _link_7_8.get_sender().send(
+                                                    artis::pdevs::multithreading::transition_message<
+                                                            artis::common::DoubleTime>(t));
+                                        }
+                                    }
+                                });
+                    }
+
+                private:
+                    artis::pdevs::Simulator<artis::common::DoubleTime, Generator, GeneratorParameters> _generator;
+/*
+                    artis::pdevs::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_1_2;
+                    artis::pdevs::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_3_4;
+                    artis::pdevs::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_5_6;
+                    artis::pdevs::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_7_8;
+*/
+                    artis::pdevs::multithreading::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_1_2;
+                    artis::pdevs::multithreading::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_3_4;
+                    artis::pdevs::multithreading::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_5_6;
+                    artis::pdevs::multithreading::Coordinator<artis::common::DoubleTime, LinksGraphManager, GeneratorParameters, artis::common::NoParameters> _link_7_8;
+                    artis::pdevs::Simulator<artis::common::DoubleTime, Counter> _counter;
+                };
+
+            }
+        }
+    }
+} // namespace artis tests multithreading simple
+
+#endif

+ 90 - 0
src/tests/multithreading/simple/main.cpp

@@ -0,0 +1,90 @@
+/**
+ * @file tests/multithreading/simple/main.cpp
+ * @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/>.
+ */
+
+#include <artis-star/common/RootCoordinator.hpp>
+
+#include <tests/multithreading/simple/graph_manager.hpp>
+#include <tests/multithreading/simple/models.hpp>
+
+#include <chrono>
+#include <iostream>
+
+using namespace artis::common;
+using namespace std::chrono;
+using namespace artis::tests::multithreading::simple;
+
+void simple_monothreading()
+{
+    GeneratorParameters parameters = {10, 2, 5, 763752};
+    artis::common::context::Context<artis::common::DoubleTime> context(0, 1000);
+    artis::common::RootCoordinator<
+            DoubleTime, artis::pdevs::Coordinator<
+                    DoubleTime,
+                    SimpleGraphManager,
+                    GeneratorParameters,
+                    NoParameters>
+    > rc(context, "root", parameters, NoParameters());
+
+    steady_clock::time_point t1 = steady_clock::now();
+
+    rc.run(context);
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration<double> time_span = duration_cast<duration<double> >(t2 - t1);
+
+    std::cout << "Time = " << time_span.count() << std::endl;
+}
+
+void simple_multithreading()
+{
+    GeneratorParameters parameters = {10, 2, 5, 763752};
+    artis::common::context::Context<artis::common::DoubleTime> context(0, 1000);
+    artis::common::RootCoordinator<
+            DoubleTime, artis::pdevs::multithreading::Coordinator<
+                    DoubleTime,
+                    SimpleGraphManager,
+                    GeneratorParameters,
+                    NoParameters>
+    > rc(context, "root", parameters, NoParameters());
+
+    steady_clock::time_point t1 = steady_clock::now();
+
+    rc.run(context);
+
+    steady_clock::time_point t2 = steady_clock::now();
+
+    duration<double> time_span = duration_cast<duration<double> >(t2 - t1);
+
+    std::cout << "Time = " << time_span.count() << std::endl;
+}
+
+int main()
+{
+//    simple_monothreading();
+    simple_multithreading();
+    return 0;
+}

+ 403 - 0
src/tests/multithreading/simple/models.hpp

@@ -0,0 +1,403 @@
+/**
+ * @file tests/multithreading/simple/models.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 TESTS_MULTITHREADING_SIMPLE_MODELS_HPP
+#define TESTS_MULTITHREADING_SIMPLE_MODELS_HPP
+
+#include <artis-star/common/time/DoubleTime.hpp>
+#include <artis-star/kernel/pdevs/Dynamics.hpp>
+#include <random>
+#include <iostream>
+
+namespace artis {
+    namespace tests {
+        namespace multithreading {
+            namespace simple {
+
+                void delay()
+                {
+                    for (unsigned int i = 0; i < 1000; ++i) {
+                        std::vector < int > v;
+
+                        for (unsigned int j = 1000; j > 0; --j) {
+                            v.push_back(j);
+                        }
+                        std::sort(v.begin(), v.end());
+                    }
+                }
+
+                struct State {
+                    enum values {
+                        STOP, UP, MAX, DOWN
+                    };
+                };
+
+                struct Vehicle {
+                    unsigned int index;
+                    double v_max;
+                    double acceleration;
+                    State::values state;
+                    artis::common::DoubleTime::type next_time;
+                };
+
+                struct GeneratorParameters {
+                    double v_max;
+                    double mean;
+                    double stddev;
+                    unsigned long seed;
+                };
+
+                class Generator
+                        : public artis::pdevs::Dynamics<artis::common::DoubleTime, Generator, GeneratorParameters> {
+                public:
+                    struct outputs {
+                        enum values {
+                            OUT
+                        };
+                    };
+
+                    Generator(const std::string& name,
+                            const artis::pdevs::Context<artis::common::DoubleTime, Generator, GeneratorParameters>& context)
+                            :
+                            artis::pdevs::Dynamics<artis::common::DoubleTime, Generator, GeneratorParameters>(
+                                    name, context),
+                            _v_max(context.parameters().v_max),
+                            _distribution(context.parameters().mean, context.parameters().stddev),
+                            _v_max_distribution(0.5, 1.),
+                            _port_distribution(0, 7)
+                    {
+                        _generator.seed(context.parameters().seed);
+
+                        output_ports({{outputs::OUT, "out_1"}});
+                        output_ports({{outputs::OUT + 1, "out_2"}});
+                        output_ports({{outputs::OUT + 2, "out_3"}});
+                        output_ports({{outputs::OUT + 3, "out_4"}});
+                        output_ports({{outputs::OUT + 4, "out_5"}});
+                        output_ports({{outputs::OUT + 5, "out_6"}});
+                        output_ports({{outputs::OUT + 6, "out_7"}});
+                        output_ports({{outputs::OUT + 7, "out_8"}});
+                    }
+
+                    ~Generator() override = default;
+
+                    void dint(const artis::common::DoubleTime::type& t) override
+                    {
+                        _last_time = t;
+                        _sigma = _distribution(_generator);
+                        _sigma = _sigma <= 0 ? 0.1 : _sigma;
+
+                        _next_v_max = _v_max * _v_max_distribution(_generator);
+                        _next_port = _port_distribution(_generator);
+                        ++_index;
+                    }
+
+                    void start(const artis::common::DoubleTime::type& t) override
+                    {
+                        _last_time = t;
+                        _sigma = _distribution(_generator);
+                        _sigma = _sigma <= 0 ? 0.1 : _sigma;
+                        _next_v_max = _v_max * _v_max_distribution(_generator);
+                        _next_port = _port_distribution(_generator);
+                        _index = 1;
+                    }
+
+                    artis::common::DoubleTime::type
+                    ta(const artis::common::DoubleTime::type& /* t */) const override { return _sigma; }
+
+                    artis::common::Bag<artis::common::DoubleTime>
+                    lambda(const artis::common::DoubleTime::type& t) const override
+                    {
+                        artis::common::Bag<artis::common::DoubleTime> bag;
+
+                        if (t > 0) {
+                            Vehicle vehicle = {_index, _next_v_max, 0.5, State::STOP, t};
+
+                            bag.push_back(
+                                    artis::common::ExternalEvent<artis::common::DoubleTime>(
+                                            outputs::OUT + _next_port, vehicle));
+                        }
+                        return bag;
+                    }
+
+                    common::DoubleTime::type
+                    lookahead(const common::DoubleTime::type& /* t */) const override
+                    {
+                        return _last_time + _sigma;
+                    }
+
+                private:
+                    // parameters
+                    double _v_max;
+
+                    // state
+                    artis::common::DoubleTime::type _sigma;
+                    artis::common::DoubleTime::type _last_time;
+                    std::default_random_engine _generator;
+                    std::normal_distribution<double> _distribution;
+                    std::uniform_real_distribution<double> _v_max_distribution;
+                    std::uniform_int_distribution<int> _port_distribution;
+                    double _next_v_max;
+                    int _next_port;
+                    unsigned int _index;
+                };
+
+                class Counter
+                        : public artis::pdevs::Dynamics<artis::common::DoubleTime, Counter> {
+                public:
+                    struct inputs {
+                        enum values {
+                            IN
+                        };
+                    };
+
+                    struct vars {
+                        enum values {
+                            COUNTER
+                        };
+                    };
+
+                    Counter(const std::string& name,
+                            const artis::pdevs::Context<artis::common::DoubleTime, Counter>& context)
+                            :
+                            artis::pdevs::Dynamics<artis::common::DoubleTime, Counter>(name,
+                                    context)
+                    {
+                        input_port({inputs::IN, "in"});
+                        observable({vars::COUNTER, "counter"});
+                    }
+
+                    ~Counter() override = default;
+
+                    void
+                    dext(const artis::common::DoubleTime::type& /* t */,
+                            const artis::common::DoubleTime::type& /* e */,
+                            const artis::common::Bag<artis::common::DoubleTime>& bag) override
+                    {
+
+//                        std::cout << t << ": " << _counter << std::endl;
+
+                        _counter += bag.size();
+                    }
+
+                    void start(const artis::common::DoubleTime::type& /* t */) override
+                    {
+                        _counter = 0;
+                    }
+
+                    artis::common::DoubleTime::type
+                    ta(const artis::common::DoubleTime::type& /* t */) const override
+                    {
+                        return artis::common::DoubleTime::infinity;
+                    }
+
+                    artis::common::Value
+                    observe(const artis::common::DoubleTime::type& /* t */,
+                            unsigned int index) const override
+                    {
+                        if (index == vars::COUNTER) {
+                            return _counter;
+                        } else {
+                            return artis::common::Value();
+                        }
+                    }
+
+                    common::DoubleTime::type
+                    lookahead(const common::DoubleTime::type& /* t */) const override
+                    {
+                        return common::DoubleTime::infinity;
+                    }
+
+                private:
+                    unsigned int _counter;
+                };
+
+                class Link :
+                        public artis::pdevs::Dynamics<common::DoubleTime, Link> {
+                public :
+                    struct inputs {
+                        enum values {
+                            IN
+                        };
+                    };
+
+                    struct outputs {
+                        enum values {
+                            OUT
+                        };
+                    };
+
+                    Link(const std::string& name,
+                            const artis::pdevs::Context<common::DoubleTime, Link>& context)
+                            :artis::pdevs::Dynamics<common::DoubleTime, Link>(name, context)
+                    {
+                        input_port({inputs::IN, "in"});
+                        output_port({outputs::OUT, "out"});
+                    }
+
+                    ~ Link() override = default;
+
+                    void dint(const artis::common::DoubleTime::type& t) override
+                    {
+                        delay();
+
+                        auto it = _vehicles.begin();
+
+                        while (it != _vehicles.end()) {
+                            if (it->next_time == t and it->state == State::STOP) {
+                                _vehicles.erase(it);
+                                it = _vehicles.begin();
+                            } else {
+                                ++it;
+                            }
+                        }
+                        for (auto& vehicle: _vehicles) {
+                            if (vehicle.next_time == t) {
+                                switch (vehicle.state) {
+                                case State::UP: {
+                                    double duration = vehicle.v_max / vehicle.acceleration;
+                                    double acceleration_distance =
+                                            0.5 * vehicle.acceleration * duration * duration;
+
+                                    vehicle.state = State::MAX;
+                                    vehicle.next_time = t +
+                                            (_length - 2 * acceleration_distance) / vehicle.v_max;
+                                    break;
+                                }
+                                case State::MAX: {
+                                    vehicle.state = State::DOWN;
+                                    vehicle.next_time = t + vehicle.v_max / vehicle.acceleration;
+                                    break;
+                                }
+                                case State::DOWN: {
+                                    vehicle.state = State::STOP;
+                                    vehicle.next_time = t;
+                                    break;
+                                }
+                                case State::STOP: {
+                                    assert(false);
+                                    break;
+                                }
+                                }
+                            }
+                        }
+                        update_sigma(t);
+                    }
+
+                    void dext(const artis::common::DoubleTime::type& t,
+                            const artis::common::DoubleTime::type& /* e */,
+                            const artis::common::Bag<artis::common::DoubleTime>& bag) override
+                    {
+                        std::for_each(bag.begin(), bag.end(),
+                                [this, t](const common::ExternalEvent<common::DoubleTime>& event) {
+                                    if (event.on_port(inputs::IN)) {
+                                        Vehicle vehicle;
+
+                                        event.data()(vehicle);
+                                        vehicle.next_time =
+                                                t + vehicle.v_max / vehicle.acceleration;
+                                        vehicle.state = State::UP;
+                                        _vehicles.push_back(vehicle);
+                                    }
+                                });
+                        update_sigma(t);
+                    }
+
+                    artis::common::DoubleTime::type
+                    ta(const artis::common::DoubleTime::type& /* t */) const override { return _sigma; }
+
+                    artis::common::Bag<artis::common::DoubleTime>
+                    lambda(const artis::common::DoubleTime::type& t) const override
+                    {
+                        artis::common::Bag<artis::common::DoubleTime> bag;
+
+                        for (auto vehicle: _vehicles) {
+                            if (vehicle.next_time == t and vehicle.state == State::STOP) {
+                                bag.push_back(
+                                        artis::common::ExternalEvent<artis::common::DoubleTime>(
+                                                outputs::OUT, vehicle));
+                            }
+                        }
+                        return bag;
+                    }
+
+                    void
+                    start(const artis::common::DoubleTime::type& /* t */) override { }
+
+                    common::DoubleTime::type
+                    lookahead(const common::DoubleTime::type& t) const override
+                    {
+                        double eot = artis::common::DoubleTime::infinity;
+
+                        for (auto vehicle: _vehicles) {
+                            double eot_i = artis::common::DoubleTime::infinity;
+
+                            if (vehicle.next_time == t and vehicle.state == State::STOP) {
+                                eot_i = t;
+                            } else if (vehicle.state == State::DOWN) {
+                                eot_i = vehicle.next_time;
+                            } else if (vehicle.state == State::MAX) {
+                                eot_i = vehicle.next_time + vehicle.v_max / vehicle.acceleration;
+                            } else if (vehicle.state == State::UP) {
+                                double duration = vehicle.v_max / vehicle.acceleration;
+                                double acceleration_distance =
+                                        0.5 * vehicle.acceleration * duration * duration;
+
+                                eot_i = vehicle.next_time
+                                        + (_length - 2 * acceleration_distance) / vehicle.v_max
+                                        + vehicle.v_max / vehicle.acceleration;
+                            }
+                            if (eot_i < eot) {
+                                eot = eot_i;
+                            }
+                        }
+                        return eot;
+                    }
+
+                private:
+                    void update_sigma(const artis::common::DoubleTime::type& t)
+                    {
+                        if (_vehicles.empty()) {
+                            _sigma = artis::common::DoubleTime::infinity;
+                        } else {
+                            _sigma = std::min_element(_vehicles.begin(), _vehicles.end(),
+                                    [](const Vehicle& e1, const Vehicle& e2) {
+                                        return e1.next_time < e2.next_time;
+                                    })->next_time - t;
+                        }
+                    }
+
+                    const double _length = 500;
+
+                    std::deque<Vehicle> _vehicles;
+                    artis::common::DoubleTime::type _sigma;
+                };
+
+            }
+        }
+    }
+} // namespace artis tests multithreading simple
+
+#endif

+ 106 - 2
src/tests/qss/graph_manager.hpp

@@ -31,6 +31,9 @@
 
 #include <artis-star/kernel/pdevs/Coordinator.hpp>
 #include <artis-star/kernel/pdevs/qss/GraphManager.hpp>
+#include <artis-star/kernel/dtss/Coordinator.hpp>
+#include <artis-star/kernel/dtss/GraphManager.hpp>
+#include <artis-star/kernel/dtss/Policy.hpp>
 
 namespace artis {
     namespace tests {
@@ -114,7 +117,9 @@ namespace artis {
                     public artis::pdevs::qss::GraphManager<common::DoubleTime, Predator, PreyPredatorParameters> {
             public:
                 enum inputs {
-                    IN_X = artis::pdevs::qss::GraphManager<common::DoubleTime, Predator, PreyPredatorParameters>::RESET + 1
+                    IN_X =
+                    artis::pdevs::qss::GraphManager<common::DoubleTime, Predator, PreyPredatorParameters>::RESET
+                            + 1
                 };
 
                 PredatorGraphManager(common::Coordinator<common::DoubleTime>* coordinator,
@@ -135,7 +140,9 @@ namespace artis {
                     public artis::pdevs::qss::GraphManager<common::DoubleTime, Prey, PreyPredatorParameters> {
             public:
                 enum inputs {
-                    IN_Y = artis::pdevs::qss::GraphManager<common::DoubleTime, Prey, PreyPredatorParameters>::RESET + 1
+                    IN_Y =
+                    artis::pdevs::qss::GraphManager<common::DoubleTime, Prey, PreyPredatorParameters>::RESET
+                            + 1
                 };
 
                 PreyGraphManager(common::Coordinator<common::DoubleTime>* coordinator,
@@ -255,6 +262,103 @@ namespace artis {
                 artis::pdevs::Simulator<common::DoubleTime, SmartGardener, SmartGardenerParameters> _smart_gardener;
             };
 
+            class DiscretePredatorGraphManager :
+                    public artis::dtss::GraphManager<artis::common::DoubleTime, DiscretePreyPredatorParameters> {
+            public:
+                enum submodels {
+                    PREDATOR
+                };
+                enum inputs {
+                    RESET, IN_X
+                };
+                enum outputs {
+                    OUT
+                };
+
+                DiscretePredatorGraphManager(
+                        artis::common::Coordinator<artis::common::DoubleTime>* coordinator,
+                        const DiscretePreyPredatorParameters& parameters,
+                        const artis::common::NoParameters& graph_parameters)
+                        :
+                        artis::dtss::GraphManager<artis::common::DoubleTime, DiscretePreyPredatorParameters>(
+                                coordinator, parameters, graph_parameters
+                        ),
+                        _predator("predator", parameters)
+                {
+                    add_child(PREDATOR, &_predator);
+
+                    coordinator->input_ports({{RESET, "reset"},
+                                              {IN_X,  "in_x"}});
+                    coordinator->output_port({OUT, "out"});
+
+                    out({&_predator, DiscretePredator::OUT}) >> out({coordinator, OUT});
+                    in({coordinator, RESET}) >> in({&_predator, DiscretePredator::RESET});
+                    in({coordinator, IN_X}) >> in({&_predator, DiscretePredator::IN_X});
+                }
+
+                ~DiscretePredatorGraphManager() override = default;
+
+            private:
+                artis::dtss::Simulator<artis::common::DoubleTime, DiscretePredator, DiscretePreyPredatorParameters> _predator;
+            };
+
+            struct MixedPreyPredatorGraphManagerParameters {
+                DiscretePreyPredatorParameters _predator;
+                artis::pdevs::qss::QSSParameters<PreyPredatorParameters> _prey;
+            };
+
+            class MixedPreyPredatorGraphManager :
+                    public artis::pdevs::GraphManager<artis::common::DoubleTime, MixedPreyPredatorGraphManagerParameters> {
+            public:
+                enum submodels {
+                    PREDATOR, PREY
+                };
+
+                enum inputs {
+                    RESET_X, RESET_Y
+                };
+
+                enum outputs {
+                    OUT_X, OUT_Y
+                };
+
+                MixedPreyPredatorGraphManager(
+                        artis::common::Coordinator<artis::common::DoubleTime>* coordinator,
+                        const MixedPreyPredatorGraphManagerParameters& parameters,
+                        const artis::common::NoParameters& graph_parameters)
+                        :
+                        artis::pdevs::GraphManager<artis::common::DoubleTime, MixedPreyPredatorGraphManagerParameters>(
+                                coordinator, parameters, graph_parameters),
+                        _predator("predator", parameters._predator, graph_parameters),
+                        _prey("prey", parameters._prey, graph_parameters)
+                {
+                    add_child(PREDATOR, &_predator);
+                    add_child(PREY, &_prey);
+
+                    coordinator->input_ports({{RESET_X, "reset_x"},
+                                              {RESET_Y, "reset_y"}});
+                    coordinator->output_ports({{OUT_X, "out_x"},
+                                               {OUT_Y, "out_y"}});
+
+                    in({coordinator, RESET_X}) >> in({&_prey, PreyGraphManager::RESET});
+                    in({coordinator, RESET_Y}) >> in({&_predator, PredatorGraphManager::RESET});
+
+                    out({&_prey, PreyGraphManager::OUT}) >> out({coordinator, OUT_X});
+                    out({&_predator, PredatorGraphManager::OUT}) >> out({coordinator, OUT_Y});
+
+                    out({&_predator, PredatorGraphManager::OUT})
+                            >> in({&_prey, PreyGraphManager::IN_Y});
+                    out({&_prey, PreyGraphManager::OUT})
+                            >> in({&_predator, PredatorGraphManager::IN_X});
+                }
+
+                ~MixedPreyPredatorGraphManager() override = default;
+
+            private:
+                artis::dtss::Coordinator<artis::common::DoubleTime, artis::dtss::LastBagPolicy, DiscretePredatorGraphManager, DiscretePreyPredatorParameters> _predator;
+                artis::pdevs::Coordinator<artis::common::DoubleTime, PreyGraphManager, artis::pdevs::qss::QSSParameters<PreyPredatorParameters>> _prey;
+            };
+
         }
     }
 } // namespace artis tests qss

+ 41 - 4
src/tests/qss/main.cpp

@@ -96,7 +96,7 @@ void run_predator_prey(artis::common::context::Context<artis::common::DoubleTime
                     PreyPredatorGraphManagerParameters>
     > rc(context, "root", parameters, artis::common::NoParameters());
 
-    rc.attachView("Value", new PredatorPreyView());
+    rc.attachView("Value1", new PredatorPreyView());
 
     rc.run(context);
 
@@ -185,7 +185,43 @@ void test_predator_prey_smart_gardener()
                     PreyPredatorSmartGardenerGraphManagerParameters>
     > rc(context, "root", parameters, artis::common::NoParameters());
 
-    rc.attachView("Value", new PredatorPreySmartGardenerView());
+    rc.attachView("Value2", new PredatorPreySmartGardenerView());
+
+    rc.run(context);
+
+    artis::observer::Output<artis::common::DoubleTime> output(rc.observer());
+
+    output(0, 100, 0.1);
+}
+
+class MixedPredatorPreyView : public artis::observer::View<artis::common::DoubleTime> {
+public:
+    MixedPredatorPreyView()
+    {
+        selector("PredatorView",
+                {MixedPreyPredatorGraphManager::PREDATOR, DiscretePredatorGraphManager::PREDATOR,
+                 DiscretePredator::VALUE});
+        selector("PreyView",
+                {MixedPreyPredatorGraphManager::PREY, PreyGraphManager::S_Integrator,
+                 artis::pdevs::qss::Integrator<artis::common::DoubleTime>::VALUE});
+    }
+};
+
+void test_mixed_predator_prey()
+{
+    MixedPreyPredatorGraphManagerParameters parameters = {{0.0001, 45., 0.5, 0.01, 0.01, 0.2},
+                                                          {{5000.},
+                                                                   {true, true, 1, 3},
+                                                                        {0.5, 0.01, 0.01, 0.2}}};
+    artis::common::context::Context<artis::common::DoubleTime> context(0, 100);
+    artis::common::RootCoordinator<
+            artis::common::DoubleTime, artis::pdevs::Coordinator<
+                    artis::common::DoubleTime,
+                    MixedPreyPredatorGraphManager,
+                    MixedPreyPredatorGraphManagerParameters>
+    > rc(context, "root", parameters, artis::common::NoParameters());
+
+    rc.attachView("Value3", new MixedPredatorPreyView());
 
     rc.run(context);
 
@@ -196,7 +232,8 @@ void test_predator_prey_smart_gardener()
 
 int main()
 {
-//    test_parabola();
-//    test_predator_prey();
+    test_parabola();
+    test_predator_prey();
     test_predator_prey_smart_gardener();
+    test_mixed_predator_prey();
 }

+ 93 - 0
src/tests/qss/models.hpp

@@ -31,6 +31,7 @@
 #include <artis-star/common/utils/Trace.hpp>
 
 #include <artis-star/kernel/pdevs/qss/Derivative.hpp>
+#include <artis-star/kernel/dtss/Dynamics.hpp>
 
 namespace artis {
     namespace tests {
@@ -271,6 +272,98 @@ namespace artis {
                 double _predator_amount;
             };
 
+            struct DiscretePreyPredatorParameters {
+                artis::common::DoubleTime::type time_step;
+                double init_value;
+                double a;
+                double b;
+                double d;
+                double e;
+            };
+
+            class DiscretePredator
+                    : public artis::dtss::Dynamics<artis::common::DoubleTime, DiscretePredator, DiscretePreyPredatorParameters> {
+            public:
+                enum inputs {
+                    RESET, IN_X, IN_Y
+                };
+                enum outputs {
+                    OUT
+                };
+                enum vars {
+                    VALUE
+                };
+
+                DiscretePredator(const std::string& name,
+                        const artis::dtss::Context<artis::common::DoubleTime, DiscretePredator, DiscretePreyPredatorParameters>& context)
+                        :
+                        artis::dtss::Dynamics<artis::common::DoubleTime, DiscretePredator, DiscretePreyPredatorParameters>(
+                                name, context), _init_value(context.parameters().init_value),
+                        _b(context.parameters().b), _d(context.parameters().d),
+                        _e(context.parameters().e)
+                {
+                    input_ports({{RESET, "reset"},
+                                 {IN_X,  "in_x"},
+                                 {IN_Y,  "in_y"}});
+                    output_ports({{OUT, "out"}});
+                    observables({{VALUE, "value"}});
+                }
+
+                ~DiscretePredator() override = default;
+
+                void transition(const artis::common::Bag<artis::common::DoubleTime>& bag,
+                        const artis::common::DoubleTime::type& /* t */) override
+                {
+                    std::for_each(bag.begin(), bag.end(),
+                            [this](const artis::common::ExternalEvent<artis::common::DoubleTime>& event) {
+                                if (event.on_port(IN_X)) {
+                                    artis::pdevs::qss::IntegratorData data;
+
+                                    event.data()(data);
+                                    _x = data.value;
+                                } else if (event.on_port(RESET)) {
+                                    // TODO
+                                }
+                            });
+                    _y += (_b * _d * _x * _y - _e * _y) * time_step();
+                }
+
+                void start(const artis::common::DoubleTime::type& /* t */) override
+                {
+                    _y = _init_value;
+                }
+
+                artis::common::Bag<artis::common::DoubleTime>
+                lambda(const artis::common::DoubleTime::type& /* t */) const override
+                {
+                    artis::common::Bag<artis::common::DoubleTime> msgs;
+                    artis::pdevs::qss::IntegratorData data = {_y};
+
+                    msgs.push_back(artis::common::ExternalEvent<artis::common::DoubleTime>(OUT, data));
+                    return msgs;
+                }
+
+                artis::common::Value observe(const artis::common::DoubleTime::type& /* t */,
+                        unsigned int index) const override
+                {
+                    if (index == VALUE) {
+                        return (double) _y;
+                    }
+                    return artis::common::Value();
+                }
+
+            private:
+                // parameters
+                double _init_value;
+                double _b;
+                double _d;
+                double _e;
+
+                // state
+                double _x;
+                double _y;
+            };
+
         }
     }
 } // namespace artis tests qss