/** * @file tests/multithreading/lifegame/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-2022 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 . */ #ifndef TESTS_MULTITHREADING_LIFEGAME_GRAPH_MANAGER_HPP #define TESTS_MULTITHREADING_LIFEGAME_GRAPH_MANAGER_HPP #include #include #include #include namespace artis { namespace tests { namespace multithreading { namespace lifegame { struct GridGraphManagerParameters { unsigned int begin_column; unsigned int end_column; unsigned int begin_line; unsigned int end_line; unsigned int min_column; unsigned int max_column; unsigned int min_line; unsigned int max_line; }; class FlatGraphManager : public artis::pdevs::GraphManager { public: enum submodels { CELL }; FlatGraphManager(common::Coordinator *coordinator, const CellParameters ¶meters, const GridGraphManagerParameters &graph_parameters) : artis::pdevs::GraphManager( coordinator, parameters, graph_parameters) { unsigned int column_number = graph_parameters.end_column - graph_parameters.begin_column + 1; unsigned int line_number = graph_parameters.end_line - graph_parameters.begin_line + 1; for (unsigned int i = graph_parameters.begin_column; i <= graph_parameters.end_column; ++i) { for (unsigned int j = graph_parameters.begin_line; j <= graph_parameters.end_line; ++j) { std::ostringstream ss; ss << "C_" << i << "_" << j; auto cell = new Simulator(ss.str(), parameters); _cells.push_back(cell); add_children(CELL, cell); } } for (int i = 0; i < (int) column_number; ++i) { for (int j = 0; j < (int) line_number; ++j) { int index = i * (int) line_number + j; // north if (j - 1 >= 0) { out({_cells[index], Cell::OUT}) >> in({_cells[i * line_number + j - 1], Cell::IN}); } // south if (j + 1 < (int) line_number) { out({_cells[index], Cell::OUT}) >> in({_cells[i * line_number + j + 1], Cell::IN}); } // west if (i - 1 >= 0) { out({_cells[index], Cell::OUT}) >> in({_cells[(i - 1) * line_number + j], Cell::IN}); } // east if (i + 1 < (int) column_number) { out({_cells[index], Cell::OUT}) >> in({_cells[(i + 1) * line_number + j], Cell::IN}); } // north west if (j - 1 >= 0 and i - 1 >= 0) { out({_cells[index], Cell::OUT}) >> in({_cells[(i - 1) * line_number + j - 1], Cell::IN}); } // south west if (j + 1 < (int) line_number and i - 1 >= 0) { out({_cells[index], Cell::OUT}) >> in({_cells[(i - 1) * line_number + j + 1], Cell::IN}); } // north east if (j - 1 >= 0 and i + 1 < (int) column_number) { out({_cells[index], Cell::OUT}) >> in({_cells[(i + 1) * line_number + j - 1], Cell::IN}); } // south east if (j + 1 < (int) line_number and i + 1 < (int) column_number) { out({_cells[index], Cell::OUT}) >> in({_cells[(i + 1) * line_number + j + 1], Cell::IN}); } } } } ~FlatGraphManager() override { std::for_each(_cells.begin(), _cells.end(), std::default_delete()); } private: typedef pdevs::Simulator Simulator; typedef std::vector Simulators; Simulators _cells; }; class ParallelBuiltFlatGraphManager : public FlatGraphManager { public: ParallelBuiltFlatGraphManager( common::Coordinator *coordinator, const CellParameters ¶meters, const GridGraphManagerParameters &graph_parameters) : FlatGraphManager(coordinator, parameters, graph_parameters) { // inputs unsigned int k = 0; // top / bottom { int j_top = (int) graph_parameters.begin_line - 1; int j_bottom = (int) graph_parameters.end_line + 1; for (int i = (int) graph_parameters.begin_column - 1; i <= (int) graph_parameters.end_column + 1; ++i) { std::ostringstream ss_out; ++k; if (i >= (int) graph_parameters.min_column and i <= (int) graph_parameters.max_column and j_top >= (int) graph_parameters.min_line) { ss_out << "in_" << i << "_" << j_top; coordinator->add_in_port({k, ss_out.str()}); } ++k; if (i >= (int) graph_parameters.min_column and i <= (int) graph_parameters.max_column and j_bottom <= (int) graph_parameters.max_line) { ss_out << "in_" << i << "_" << j_bottom; coordinator->add_in_port({k, ss_out.str()}); } } } // left / right { int i_left = (int) graph_parameters.begin_column - 1; int i_right = (int) graph_parameters.end_column + 1; for (int j = (int) graph_parameters.begin_line; j <= (int) graph_parameters.end_line; ++j) { std::ostringstream ss_out; ++k; if (j >= (int) graph_parameters.min_line and j <= (int) graph_parameters.max_line and i_left >= (int) graph_parameters.min_column) { ss_out << "out_" << i_left << "_" << j; coordinator->add_in_port({k, ss_out.str()}); } ++k; if (j >= (int) graph_parameters.min_line and j <= (int) graph_parameters.max_line and i_right >= (int) graph_parameters.max_column) { ss_out << "out_" << i_right << "_" << j; coordinator->add_in_port({k, ss_out.str()}); } } } // outputs k = 0; // top / bottom { int j_top = (int) graph_parameters.begin_line; int j_bottom = (int) graph_parameters.end_line; for (int i = (int) graph_parameters.begin_column; i <= (int) graph_parameters.end_column; ++i) { std::ostringstream ss_out; ++k; ss_out << "out_" << i << "_" << j_top; coordinator->add_out_port({k, ss_out.str()}); ++k; ss_out << "out_" << i << "_" << j_bottom; coordinator->add_out_port({k, ss_out.str()}); } } // left / right { int i_left = (int) graph_parameters.begin_column; int i_right = (int) graph_parameters.end_column; for (int j = (int) graph_parameters.begin_line + 1; j <= (int) graph_parameters.end_line - 1; ++j) { std::ostringstream ss_out; ++k; ss_out << "out_" << i_left << "_" << j; coordinator->add_out_port({k, ss_out.str()}); ++k; ss_out << "out_" << i_right << "_" << j; coordinator->add_out_port({k, ss_out.str()}); } } // for (Edges::const_iterator it = parameters._output_edges.begin(); // it != parameters._output_edges.end(); ++it) { // std::ostringstream ss_out; // // ss_out << "out_" << it->first; // if (not coordinator->exist_out_port(ss_out.str())) { // coordinator->add_out_port(ss_out.str()); // } // if (not ParallelBuiltFlatGraphManager::exist_link( // ParallelBuiltFlatGraphManager::_simulators[it->first], // "out", coordinator, ss_out.str())) { // ParallelBuiltFlatGraphManager::add_link( // ParallelBuiltFlatGraphManager::_simulators[it->first], // "out", coordinator, ss_out.str()); // } // } } void init() {} void start(common::DoubleTime::type /* t */) {} void transition( const common::Models & /* receivers */, common::DoubleTime::type /* t */) {} ~ParallelBuiltFlatGraphManager() override = default; }; class ParallelHierarchicalGraphManager : public artis::pdevs::GraphManager { typedef artis::pdevs::multithreading::Coordinator< common::DoubleTime, ParallelHierarchicalGraphManager, CellParameters, GridGraphManagerParameters> parent_coordinator_type; public: enum submodels { S1_1 = 0, S1_2, S2_1, S2_2 }; ParallelHierarchicalGraphManager( common::Coordinator *coordinator, const CellParameters ¶meters, const GridGraphManagerParameters &graph_parameters) : artis::pdevs::GraphManager( coordinator, parameters, graph_parameters) { // build coordinators (graphs) for (unsigned int i = 0; i < 2; ++i) { for (unsigned int j = 0; j < 2; ++j) { ParallelCoordinator *sub_coordinator = nullptr; std::ostringstream ss; ss << "S_" << (i + 1) << "_" << (j + 1); sub_coordinator = new ParallelCoordinator(ss.str(), parameters, {i * 5 + 1, (i + 1) * 5, j * 5 + 1, (j + 1) * 5, 1, 10, 1, 10}); _coordinators.push_back(sub_coordinator); add_child(i, sub_coordinator); } } // builds internal connections (edges) // for (Connections::const_iterator it = parent_connections.begin(); // it != parent_connections.end(); ++it) { // const Connection& connection = *it; // std::ostringstream ss_out; // std::ostringstream ss_in; // // ss_out << "out_" << connection.first.second; // ss_in << "in_" << connection.first.second; // // if (not exist_link( // _coordinators[connection.first.first - 1], // ss_out.str(), // _coordinators[connection.second.first - 1], // ss_in.str())) { // add_link( // _coordinators[connection.first.first - 1], // ss_out.str(), // _coordinators[connection.second.first - 1], // ss_in.str()); // } // } } ~ParallelHierarchicalGraphManager() override { for (typename Coordinators::const_iterator it = _coordinators.begin(); it != _coordinators.end(); ++it) { delete *it; } } void init() { std::for_each(_coordinators.begin(), _coordinators.end(), [this](ParallelCoordinator *coordinator) { dynamic_cast< parent_coordinator_type *>(this->coordinator()) ->attach_child(coordinator, coordinator->get_queue()); coordinator->attach_parent(dynamic_cast< parent_coordinator_type *>(this->coordinator())->get_queue()); }); } private: typedef artis::pdevs::multithreading::Coordinator< common::DoubleTime, ParallelBuiltFlatGraphManager, CellParameters, GridGraphManagerParameters > ParallelCoordinator; typedef std::vector Coordinators; Coordinators _coordinators; }; } } } } // namespace artis tests multithreading lifegame #endif