/**
* @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