Commit 232e49e3 authored by Gauthier Quesnel's avatar Gauthier Quesnel
Browse files

core: add grah i/o

parent a62376e9
Pipeline #10984 failed with stage
in 57 seconds
......@@ -56,16 +56,15 @@ Simple file
[source]
''''
# '#' means comment until end of line
4 # 4 models will be allocated
A generator 2 0.0 100.0 0 # Model 'A' is a generator with one double real message
B generator 2 0.0 100.0 0 # Model 'B' is a generator with one double real message
Add adder_2 2 1.0 1.0 0 # Model 'Add' is a adder_2 with one double real message
C counter 1 0.0 0 # Model 'C' is a counter with one real message
0 A generator 2 0.0 100.0 0 # Model 'A' is a generator with one double real message
1 B generator 2 0.0 100.0 0 # Model 'B' is a generator with one double real message
2 Add adder_2 2 1.0 1.0 0 # Model 'Add' is a adder_2 with one double real message
3 C counter 1 0.0 0 # Model 'C' is a counter with one real message
3 # 3 internal connections
A 0 Add 0 # Model 'A' output port '0' connected to model 'Add' input port '0'
B 0 Add 1 # Model 'A' output port '0' connected to model 'Add' input port '0'
Add 0 C 0 # Model 'Add' output port '0' connected to model 'C' input port '0'
0 0 2 0 # Model 'A' output port '0' connected to model 'Add' input port '0'
1 0 2 1 # Model 'A' output port '0' connected to model 'Add' input port '0'
2 0 3 0 # Model 'Add' output port '0' connected to model 'C' input port '0'
0 # 0 input connection
1 # 1 output connection
C 0 0 # Model 'C' output port '0' connected to coupled model port '0'
......
......@@ -1111,9 +1111,10 @@ show_editor(const char* editor_name, editor& ed)
}
{
const int num_selected = imnodes::NumSelectedLinks();
if (num_selected > 0 && ImGui::IsKeyReleased('D')) {
static array<int> selected_links;
const int num_selected = imnodes::NumSelectedLinks();
if (num_selected > 0 && ImGui::IsKeyReleased('X')) {
if (selected_links.capacity() < static_cast<size_t>(num_selected))
selected_links.init(num_selected);
......@@ -1131,10 +1132,13 @@ show_editor(const char* editor_name, editor& ed)
}
{
const int num_selected = imnodes::NumSelectedNodes();
if (num_selected > 0 && ImGui::IsKeyReleased('D')) {
static array<int> selected_nodes;
if (selected_nodes.capacity() < static_cast<size_t>(num_selected))
const int num_selected = imnodes::NumSelectedNodes();
if (num_selected > 0) {
if (ImGui::IsKeyReleased('X')) {
if (selected_nodes.capacity() <
static_cast<size_t>(num_selected))
selected_nodes.init(num_selected);
std::fill_n(selected_nodes.data(), selected_nodes.size(), -1);
......@@ -1144,6 +1148,14 @@ show_editor(const char* editor_name, editor& ed)
ed.free(node_id);
selected_nodes.clear();
} else if (ImGui::IsKeyReleased('D')) {
if (selected_nodes.capacity() <
static_cast<size_t>(num_selected))
selected_nodes.init(num_selected);
std::fill_n(selected_nodes.data(), selected_nodes.size(), -1);
imnodes::GetSelectedNodes(selected_nodes.data());
}
}
}
......
......@@ -117,7 +117,15 @@ enum class status
gui_not_enough_memory,
gui_too_many_model,
gui_too_many_connection
gui_too_many_connection,
io_file_format_error,
io_file_format_model_error,
io_file_format_model_number_error,
io_file_format_model_unknown,
io_file_format_dynamics_unknown,
io_file_format_dynamics_limit_reach,
io_file_format_dynamics_init_error
};
constexpr bool
......@@ -4157,7 +4165,6 @@ struct simulation
time begin = time_domain<time>::zero;
time end = time_domain<time>::infinity;
private:
template<typename Function>
status dispatch(const dynamics_type type, Function f) noexcept
{
......@@ -4195,35 +4202,72 @@ private:
irt_bad_return(status::unknown_dynamics);
}
template<typename Dynamics>
int get_input_port_index(const Dynamics& dynamics,
const input_port_id id) const noexcept
template<typename Function>
status dispatch(const dynamics_type type, Function f) const noexcept
{
static_assert(is_detected_v<has_input_port_t, Dynamics>);
auto it = std::find(std::begin(dynamics.x), std::end(dynamics.x), id);
if (it == std::end(dynamics.x))
return -1;
switch (type) {
case dynamics_type::none:
return f(none_models);
case dynamics_type::integrator:
return f(integrator_models);
case dynamics_type::quantifier:
return f(quantifier_models);
case dynamics_type::adder_2:
return f(adder_2_models);
case dynamics_type::adder_3:
return f(adder_3_models);
case dynamics_type::adder_4:
return f(adder_4_models);
case dynamics_type::mult_2:
return f(mult_2_models);
case dynamics_type::mult_3:
return f(mult_3_models);
case dynamics_type::mult_4:
return f(mult_4_models);
case dynamics_type::counter:
return f(counter_models);
case dynamics_type::generator:
return f(generator_models);
case dynamics_type::constant:
return f(constant_models);
case dynamics_type::cross:
return f(cross_models);
case dynamics_type::time_func:
return f(time_func_models);
}
return static_cast<int>(std::distance(std::begin(dynamics.x), it));
irt_bad_return(status::unknown_dynamics);
}
template<typename Dynamics>
int get_output_port_index(const Dynamics& dynamics,
const output_port_id id) const noexcept
{
static_assert(is_detected_v<has_output_port_t, Dynamics>);
//template<typename Dynamics>
//int get_input_port_index(const Dynamics& dynamics,
// const input_port_id id) const noexcept
//{
// static_assert(is_detected_v<has_input_port_t, Dynamics>);
auto it = std::find(std::begin(dynamics.y), std::end(dynamics.y), id);
if (it == std::end(dynamics.y))
return -1;
// auto it = std::find(std::begin(dynamics.x), std::end(dynamics.x), id);
// if (it == std::end(dynamics.x))
// return -1;
return static_cast<int>(std::distance(std::begin(dynamics.y), it));
}
// return static_cast<int>(std::distance(std::begin(dynamics.x), it));
//}
//template<typename Dynamics>
//int get_output_port_index(const Dynamics& dynamics,
// const output_port_id id) const noexcept
//{
// static_assert(is_detected_v<has_output_port_t, Dynamics>);
// auto it = std::find(std::begin(dynamics.y), std::end(dynamics.y), id);
// if (it == std::end(dynamics.y))
// return -1;
// return static_cast<int>(std::distance(std::begin(dynamics.y), it));
//}
status get_output_port_index(const model& mdl,
const output_port_id port,
int* index) noexcept
int* index) const noexcept
{
return dispatch(
mdl.type,
......@@ -4250,7 +4294,7 @@ private:
status get_input_port_index(const model& mdl,
const input_port_id port,
int* index) noexcept
int* index) const noexcept
{
return dispatch(
mdl.type,
......@@ -4277,7 +4321,7 @@ private:
status get_output_port_id(const model& mdl,
int index,
output_port_id* port) noexcept
output_port_id* port) const noexcept
{
return dispatch(
mdl.type,
......@@ -4305,7 +4349,7 @@ private:
status get_input_port_id(const model& mdl,
int index,
input_port_id* port) noexcept
input_port_id* port) const noexcept
{
return dispatch(
mdl.type,
......
// Copyright (c) 2020 INRA Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef ORG_VLEPROJECT_IRRITATOR_IO_2020
#define ORG_VLEPROJECT_IRRITATOR_IO_2020
#include <irritator/core.hpp>
#include <algorithm>
#include <cstdio>
namespace irt {
class reader
{
private:
::std::FILE* file = stdin;
struct map_value
{
map_value() noexcept = default;
map_value(int first_, model_id second_) noexcept
: first(first_)
, second(second_)
{}
int first = 0;
model_id second = static_cast<model_id>(0);
};
vector<map_value> map;
int model_error = 0;
int connection_error = 0;
public:
reader(::std::FILE* file_ = stdin) noexcept
: file(file_ == nullptr ? stdin : file_)
{}
~reader() noexcept
{
if (file && file != stdin)
::std::fclose(file);
}
status operator()(simulation& sim) noexcept
{
int model_number = 0;
irt_return_if_fail(std::fscanf(file, "%d", &model_number) == 1,
status::io_file_format_error);
irt_return_if_fail(model_number > 0,
status::io_file_format_model_number_error);
irt_return_if_bad(map.init(model_number));
std::fill_n(std::begin(map),
std::size(map),
map_value(-1, static_cast<model_id>(0)));
int id;
char name[8];
char dynamics[11];
for (int i = 0; i != model_number; ++i, ++model_error) {
irt_return_if_fail(
3 == std::fscanf(file, "%d %7s %10s", &id, name, dynamics),
status::io_file_format_model_error);
irt_return_if_bad(read(sim, id, name, dynamics));
}
std::sort(
std::begin(map), std::end(map), [](const auto& rhs, const auto& lhs) {
return rhs.first < lhs.first;
});
while (!std::feof(file)) {
int mdl_src_index, port_src_index, mdl_dst_index, port_dst_index;
int read = std::fscanf(file,
"%d %d %d %d",
&mdl_src_index,
&port_src_index,
&mdl_dst_index,
&port_dst_index);
irt_return_if_fail(read == 0 || read == 4,
status::io_file_format_error);
if (read == 4) {
auto* mdl_src = get_model(sim, mdl_src_index);
irt_return_if_fail(mdl_src,
status::io_file_format_model_unknown);
auto* mdl_dst = get_model(sim, mdl_dst_index);
irt_return_if_fail(mdl_dst,
status::io_file_format_model_unknown);
output_port_id output_port;
input_port_id input_port;
irt_return_if_bad(sim.get_output_port_id(
*mdl_src, port_src_index, &output_port));
irt_return_if_bad(
sim.get_input_port_id(*mdl_dst, port_dst_index, &input_port));
irt_return_if_bad(sim.connect(output_port, input_port));
++connection_error;
}
}
return status::success;
}
private:
bool convert(const char* dynamics_name, dynamics_type* type) noexcept
{
if (std::strcmp(dynamics_name, "none") == 0) {
*type = dynamics_type::none;
return true;
}
if (std::strcmp(dynamics_name, "integrator") == 0) {
*type = dynamics_type::integrator;
return true;
}
if (std::strcmp(dynamics_name, "quantifier") == 0) {
*type = dynamics_type::quantifier;
return true;
}
if (std::strcmp(dynamics_name, "adder_2") == 0) {
*type = dynamics_type::adder_2;
return true;
}
if (std::strcmp(dynamics_name, "adder_3") == 0) {
*type = dynamics_type::adder_3;
return true;
}
if (std::strcmp(dynamics_name, "adder_4") == 0) {
*type = dynamics_type::adder_4;
return true;
}
if (std::strcmp(dynamics_name, "mult_2") == 0) {
*type = dynamics_type::mult_2;
return true;
}
if (std::strcmp(dynamics_name, "mult_3") == 0) {
*type = dynamics_type::mult_3;
return true;
}
if (std::strcmp(dynamics_name, "mult_4") == 0) {
*type = dynamics_type::mult_4;
return true;
}
if (std::strcmp(dynamics_name, "counter") == 0) {
*type = dynamics_type::counter;
return true;
}
if (std::strcmp(dynamics_name, "generator") == 0) {
*type = dynamics_type::generator;
return true;
}
if (std::strcmp(dynamics_name, "constant") == 0) {
*type = dynamics_type::constant;
return true;
}
if (std::strcmp(dynamics_name, "cross") == 0) {
*type = dynamics_type::cross;
return true;
}
if (std::strcmp(dynamics_name, "time_func") == 0) {
*type = dynamics_type::time_func;
return true;
}
return false;
}
model* get_model(simulation& sim, int index) noexcept
{
const map_value value(index, static_cast<model_id>(0));
const auto it = std::lower_bound(std::begin(map),
std::end(map),
value,
[](const auto& lhs, const auto& rhs) {
return lhs.first < rhs.first;
});
if (it == std::end(map) && value.first < it->first)
return nullptr;
return sim.models.try_to_get(it->second);
}
status read(simulation& sim, int id, const char* name, const char* dynamics_name) noexcept
{
dynamics_type type;
irt_return_if_fail(convert(dynamics_name, &type),
status::io_file_format_dynamics_unknown);
model_id mdl = static_cast<model_id>(0);
auto ret = sim.dispatch(
type, [ this, &sim, name ](auto& dyn_models) {
irt_return_if_fail(dyn_models.can_alloc(1),
status::io_file_format_dynamics_limit_reach);
auto& dyn = dyn_models.alloc();
auto dyn_id = dyn_models.get_id(dyn);
sim.alloc(dyn, dyn_id, name);
irt_return_if_fail(read(dyn),
status::io_file_format_dynamics_init_error);
return status::success;
});
map.emplace_back(id, mdl);
}
bool read(none& /*dyn*/) noexcept
{
return true;
}
bool read(integrator& dyn) noexcept
{
return 2 == std::fscanf(file,
"%lf %lf",
&dyn.default_current_value,
&dyn.default_reset_value);
}
bool read(quantifier& dyn) noexcept
{
char state[16];
char init[8];
int ret = std::fscanf(file,
"%lf %d %15s %7s",
&dyn.default_step_size,
&dyn.default_past_length,
state,
init);
if (ret != 4)
return false;
if (std::strcmp(state, "possible") == 0)
dyn.default_adapt_state = quantifier::adapt_state::possible;
else if (std::strcmp(state, "impossible") == 0)
dyn.default_adapt_state = quantifier::adapt_state::impossible;
else if (std::strcmp(state, "done") == 0)
dyn.default_adapt_state = quantifier::adapt_state::done;
else
return false;
if (std::strcmp(init, "true") == 0)
dyn.default_zero_init_offset = true;
else if (std::strcmp(init, "false") == 0)
dyn.default_zero_init_offset = false;
else
return false;
return true;
}
bool read(adder_2& dyn) noexcept
{
return 4 == std::fscanf(file,
"%lf %lf %lf %lf",
&dyn.default_values[0],
&dyn.default_values[1],
&dyn.default_input_coeffs[0],
&dyn.default_input_coeffs[1]);
}
bool read(adder_3& dyn) noexcept
{
return 6 == std::fscanf(file,
"%lf %lf %lf %lf %lf %lf",
&dyn.default_values[0],
&dyn.default_values[1],
&dyn.default_values[2],
&dyn.default_input_coeffs[0],
&dyn.default_input_coeffs[1],
&dyn.default_input_coeffs[2]);
}
bool read(adder_4& dyn) noexcept
{
return 8 == std::fscanf(file,
"%lf %lf %lf %lf %lf %lf %lf %lf",
&dyn.default_values[0],
&dyn.default_values[1],
&dyn.default_values[2],
&dyn.default_values[3],
&dyn.default_input_coeffs[0],
&dyn.default_input_coeffs[1],
&dyn.default_input_coeffs[2],
&dyn.default_input_coeffs[3]);
}
bool read(mult_2& dyn) noexcept
{
return 4 == std::fscanf(file,
"%lf %lf %lf %lf",
&dyn.default_values[0],
&dyn.default_values[1],
&dyn.default_input_coeffs[0],
&dyn.default_input_coeffs[1]);
}
bool read(mult_3& dyn) noexcept
{
return 6 == std::fscanf(file,
"%lf %lf %lf %lf %lf %lf",
&dyn.default_values[0],
&dyn.default_values[1],
&dyn.default_values[2],
&dyn.default_input_coeffs[0],
&dyn.default_input_coeffs[1],
&dyn.default_input_coeffs[2]);
}
bool read(mult_4& dyn) noexcept
{
return 8 == std::fscanf(file,
"%lf %lf %lf %lf %lf %lf %lf %lf",
&dyn.default_values[0],
&dyn.default_values[1],
&dyn.default_values[2],
&dyn.default_values[3],
&dyn.default_input_coeffs[0],
&dyn.default_input_coeffs[1],
&dyn.default_input_coeffs[2],
&dyn.default_input_coeffs[3]);
}
bool read(counter& /*dyn*/) noexcept
{
return true;
}
bool read(generator& /*dyn*/) noexcept
{
return true;
}
bool read(constant& dyn) noexcept
{
return 1 == std::fscanf(file, "%lf", &dyn.default_value);
}
bool read(cross& dyn) noexcept
{
return 1 == std::fscanf(file, "%lf", &dyn.default_threshold);
}
bool read(time_func& dyn) noexcept
{
char fn[10];
if (1 != std::fscanf(file, "%9s", fn))
return false;
if (std::strcmp(fn, "square") == 0)
dyn.default_f = nullptr;
else if (std::strcmp(fn, "nullptr") == 0)
dyn.default_f = nullptr;
else
return false;
return true;
}
};
struct writer
{