io.hpp 16.2 KB
Newer Older
Gauthier Quesnel's avatar
Gauthier Quesnel committed
1
2
3
4
5
6
7
8
9
10
// 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>
11
12
#include <istream>
#include <ostream>
Gauthier Quesnel's avatar
Gauthier Quesnel committed
13
14
15
16
17
18

namespace irt {

class reader
{
private:
19
    std::istream& is;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
20

Gauthier Quesnel's avatar
Gauthier Quesnel committed
21
    array<model_id> map;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
22
23
24
    int model_error = 0;
    int connection_error = 0;

25
26
27
    char temp_1[32];
    char temp_2[32];

Gauthier Quesnel's avatar
Gauthier Quesnel committed
28
public:
29
30
    reader(std::istream& is_) noexcept
      : is(is_)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
31
32
    {}

33
    ~reader() noexcept = default;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
34
35
36
37
38

    status operator()(simulation& sim) noexcept
    {
        int model_number = 0;

39
        irt_return_if_fail((is >> model_number), status::io_file_format_error);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
40
41
42
43
44
        irt_return_if_fail(model_number > 0,
                           status::io_file_format_model_number_error);

        irt_return_if_bad(map.init(model_number));

Gauthier Quesnel's avatar
Gauthier Quesnel committed
45
        std::fill_n(std::begin(map), std::size(map), static_cast<model_id>(0));
Gauthier Quesnel's avatar
Gauthier Quesnel committed
46
47
48
49

        int id;

        for (int i = 0; i != model_number; ++i, ++model_error) {
50
51
            irt_return_if_fail((is >> id >> temp_1 >> temp_2),
                               status::io_file_format_model_error);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
52

Gauthier Quesnel's avatar
Gauthier Quesnel committed
53
54
55
            irt_return_if_fail(0 <= id && id < model_number,
                               status::io_file_format_model_error);

56
            irt_return_if_bad(read(sim, id, temp_1, temp_2));
Gauthier Quesnel's avatar
Gauthier Quesnel committed
57
58
        }

59
        while (is) {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
60
61
            int mdl_src_index, port_src_index, mdl_dst_index, port_dst_index;

62
63
64
65
            if (!(is >> mdl_src_index >> port_src_index >> mdl_dst_index >>
                  port_dst_index)) {
                if (is.eof())
                    break;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
66

67
68
                irt_bad_return(status::io_file_format_error);
            }
Gauthier Quesnel's avatar
Gauthier Quesnel committed
69

70
71
            auto* mdl_src = sim.models.try_to_get(mdl_src_index);
            irt_return_if_fail(mdl_src, status::io_file_format_model_unknown);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
72

73
74
            auto* mdl_dst = sim.models.try_to_get(mdl_dst_index);
            irt_return_if_fail(mdl_dst, status::io_file_format_model_unknown);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
75

76
77
            output_port_id output_port;
            input_port_id input_port;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
78

79
80
81
82
            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));
Gauthier Quesnel's avatar
Gauthier Quesnel committed
83

84
85
            irt_return_if_bad(sim.connect(output_port, input_port));
            ++connection_error;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
86
87
88
89
90
91
        }

        return status::success;
    }

private:
92
93
    bool convert(const std::string_view dynamics_name,
                 dynamics_type* type) noexcept
Gauthier Quesnel's avatar
Gauthier Quesnel committed
94
    {
95
        if (dynamics_name == "none") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
96
97
98
99
            *type = dynamics_type::none;
            return true;
        }

100
        if (dynamics_name == "integrator") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
101
102
103
104
            *type = dynamics_type::integrator;
            return true;
        }

105
        if (dynamics_name == "quantifier") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
106
107
108
109
            *type = dynamics_type::quantifier;
            return true;
        }

110
        if (dynamics_name == "adder_2") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
111
112
113
114
            *type = dynamics_type::adder_2;
            return true;
        }

115
        if (dynamics_name == "adder_3") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
116
117
118
119
            *type = dynamics_type::adder_3;
            return true;
        }

120
        if (dynamics_name == "adder_4") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
121
122
123
124
            *type = dynamics_type::adder_4;
            return true;
        }

125
        if (dynamics_name == "mult_2") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
126
127
128
129
            *type = dynamics_type::mult_2;
            return true;
        }

130
        if (dynamics_name == "mult_3") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
131
132
133
134
            *type = dynamics_type::mult_3;
            return true;
        }

135
        if (dynamics_name == "mult_4") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
136
137
138
139
            *type = dynamics_type::mult_4;
            return true;
        }

140
        if (dynamics_name == "counter") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
141
142
143
144
            *type = dynamics_type::counter;
            return true;
        }

145
        if (dynamics_name == "generator") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
146
147
148
149
            *type = dynamics_type::generator;
            return true;
        }

150
        if (dynamics_name == "constant") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
151
152
153
154
            *type = dynamics_type::constant;
            return true;
        }

155
        if (dynamics_name == "cross") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
156
157
158
159
            *type = dynamics_type::cross;
            return true;
        }

160
        if (dynamics_name == "time_func") {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
161
162
163
164
165
166
167
            *type = dynamics_type::time_func;
            return true;
        }

        return false;
    }

Gauthier Quesnel's avatar
Gauthier Quesnel committed
168
169
170
171
    status read(simulation& sim,
                int id,
                const char* name,
                const char* dynamics_name) noexcept
Gauthier Quesnel's avatar
Gauthier Quesnel committed
172
173
174
175
176
177
178
    {
        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);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
179
        auto ret = sim.dispatch(type, [this, &sim, name](auto& dyn_models) {
Gauthier Quesnel's avatar
Gauthier Quesnel committed
180
181
182
183
184
185
186
187
188
189
190
191
192
            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;
        });

Gauthier Quesnel's avatar
Gauthier Quesnel committed
193
194
        irt_return_if_bad(ret);

Gauthier Quesnel's avatar
Gauthier Quesnel committed
195
        map[id] = mdl;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
196
197

        return status::success;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
198
199
200
201
202
203
204
205
206
    }

    bool read(none& /*dyn*/) noexcept
    {
        return true;
    }

    bool read(integrator& dyn) noexcept
    {
207
        return !!(is >> dyn.default_current_value >> dyn.default_reset_value);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
208
209
210
211
    }

    bool read(quantifier& dyn) noexcept
    {
212
213
        if (!(is >> dyn.default_step_size >> dyn.default_past_length >>
              temp_1 >> temp_2))
Gauthier Quesnel's avatar
Gauthier Quesnel committed
214
215
            return false;

216
        if (std::strcmp(temp_1, "possible") == 0)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
217
            dyn.default_adapt_state = quantifier::adapt_state::possible;
218
        else if (std::strcmp(temp_1, "impossible") == 0)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
219
            dyn.default_adapt_state = quantifier::adapt_state::impossible;
220
        else if (std::strcmp(temp_1, "done") == 0)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
221
222
223
224
            dyn.default_adapt_state = quantifier::adapt_state::done;
        else
            return false;

225
        if (std::strcmp(temp_2, "true") == 0)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
226
            dyn.default_zero_init_offset = true;
227
        else if (std::strcmp(temp_2, "false") == 0)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
228
229
230
231
232
233
234
235
236
            dyn.default_zero_init_offset = false;
        else
            return false;

        return true;
    }

    bool read(adder_2& dyn) noexcept
    {
237
238
        return !!(is >> dyn.default_values[0] >> dyn.default_values[1] >>
                  dyn.default_input_coeffs[0] >> dyn.default_input_coeffs[1]);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
239
240
241
242
    }

    bool read(adder_3& dyn) noexcept
    {
243
244
245
        return !!(is >> 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]);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
246
247
248
249
    }

    bool read(adder_4& dyn) noexcept
    {
250
251
252
253
        return !!(is >> 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]);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
254
255
256
257
    }

    bool read(mult_2& dyn) noexcept
    {
258
259
        return !!(is >> dyn.default_values[0] >> dyn.default_values[1] >>
                  dyn.default_input_coeffs[0] >> dyn.default_input_coeffs[1]);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
260
261
262
263
    }

    bool read(mult_3& dyn) noexcept
    {
264
265
266
        return !!(is >> 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]);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
267
268
269
270
    }

    bool read(mult_4& dyn) noexcept
    {
271
272
273
274
        return !!(is >> 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]);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
275
276
277
278
279
280
281
282
283
284
285
286
287
288
    }

    bool read(counter& /*dyn*/) noexcept
    {
        return true;
    }

    bool read(generator& /*dyn*/) noexcept
    {
        return true;
    }

    bool read(constant& dyn) noexcept
    {
289
        return !!(is >> dyn.default_value);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
290
291
292
293
    }

    bool read(cross& dyn) noexcept
    {
294
        return !!(is >> dyn.default_threshold);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
295
296
297
298
    }

    bool read(time_func& dyn) noexcept
    {
299
        if (!(is >> temp_1))
Gauthier Quesnel's avatar
Gauthier Quesnel committed
300
301
            return false;

302
        if (std::strcmp(temp_1, "square") == 0)
303
            dyn.default_f = &square_time_function;
304
        else
305
            dyn.default_f = &time_function;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
306
307
308
309
310
311
312

        return true;
    }
};

struct writer
{
313
    std::ostream& os;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
314

Gauthier Quesnel's avatar
Gauthier Quesnel committed
315
316
    array<model_id> map;

317
318
    writer(std::ostream& os_) noexcept
      : os(os_)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
319
320
321
322
    {}

    status operator()(const simulation& sim) noexcept
    {
323
        os << sim.models.size() << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
324

Gauthier Quesnel's avatar
Gauthier Quesnel committed
325
326
327
328
        irt_return_if_bad(map.init(sim.models.size()));

        std::fill_n(std::begin(map), std::size(map), static_cast<model_id>(0));

Gauthier Quesnel's avatar
Gauthier Quesnel committed
329
        model* mdl = nullptr;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
330
        int id = 0;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
331
332
333
        while (sim.models.next(mdl)) {
            const auto mdl_id = sim.models.get_id(mdl);

334
            os << id << ' ' << mdl->name.c_str() << ' ';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
335
            map[id] = mdl_id;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
336
337
338
339
340

            sim.dispatch(mdl->type, [this, mdl](auto& dyn_models) {
                write(dyn_models.get(mdl->id));
                return status::success;
            });
Gauthier Quesnel's avatar
Gauthier Quesnel committed
341
342

            ++id;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
343
        }
Gauthier Quesnel's avatar
Gauthier Quesnel committed
344

Gauthier Quesnel's avatar
Gauthier Quesnel committed
345
346
347
348
349
350
        irt::output_port* out = nullptr;
        while (sim.output_ports.next(out)) {
            for (auto dst : out->connections) {
                if (auto* in = sim.input_ports.try_to_get(dst); in) {
                    auto* mdl_src = sim.models.try_to_get(out->model);
                    auto* mdl_dst = sim.models.try_to_get(in->model);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
351

Gauthier Quesnel's avatar
Gauthier Quesnel committed
352
353
                    if (!(mdl_src && mdl_dst))
                        continue;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
354

Gauthier Quesnel's avatar
Gauthier Quesnel committed
355
356
                    int src_index = -1;
                    int dst_index = -1;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
357

Gauthier Quesnel's avatar
Gauthier Quesnel committed
358
                    irt_return_if_bad(
Gauthier Quesnel's avatar
Gauthier Quesnel committed
359
                      sim.get_input_port_index(*mdl_dst, dst, &dst_index));
Gauthier Quesnel's avatar
Gauthier Quesnel committed
360

Gauthier Quesnel's avatar
Gauthier Quesnel committed
361
                    irt_return_if_bad(sim.get_output_port_index(
Gauthier Quesnel's avatar
Gauthier Quesnel committed
362
363
364
365
366
367
368
                      *mdl_src, sim.output_ports.get_id(out), &src_index));

                    auto it_out = std::find(map.begin(), map.end(), out->model);
                    auto it_in = std::find(map.begin(), map.end(), in->model);

                    assert(it_out != map.end());
                    assert(it_in != map.end());
Gauthier Quesnel's avatar
Gauthier Quesnel committed
369

370
371
372
                    os << std::distance(map.begin(), it_out) << ' ' << src_index
                       << std::distance(map.begin(), it_in) << ' ' << dst_index
                       << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
373
374
375
376
377
378
379
380
                }
            }
        }

        return status::success;
    }

private:
Gauthier Quesnel's avatar
Gauthier Quesnel committed
381
    void write(const none& /*dyn*/) noexcept
Gauthier Quesnel's avatar
Gauthier Quesnel committed
382
    {
383
        os << "none\n";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
384
385
386
387
    }

    void write(const integrator& dyn) noexcept
    {
388
389
        os << "integrator " << dyn.default_current_value << ' '
           << dyn.default_reset_value << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
390
391
392
393
    }

    void write(const quantifier& dyn) noexcept
    {
394
395
396
397
398
399
400
401
402
        os << "quantifier " << dyn.default_step_size << ' '
           << dyn.default_past_length << ' '
           << ((dyn.default_adapt_state == quantifier::adapt_state::possible)
                 ? "possible "
                 : dyn.default_adapt_state ==
                       quantifier::adapt_state::impossible
                     ? "impossibe "
                     : "done ")
           << (dyn.default_zero_init_offset == true ? "true\n" : "false\n");
Gauthier Quesnel's avatar
Gauthier Quesnel committed
403
404
405
406
    }

    void write(const adder_2& dyn) noexcept
    {
407
408
409
        os << "adder_2 " << dyn.default_values[0] << ' '
           << dyn.default_values[1] << ' ' << dyn.default_input_coeffs[0] << ' '
           << dyn.default_input_coeffs[1] << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
410
411
412
413
    }

    void write(const adder_3& dyn) noexcept
    {
414
415
416
417
        os << "adder_3 " << 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] << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
418
419
420
421
    }

    void write(const adder_4& dyn) noexcept
    {
422
423
424
425
426
        os << "adder_4 " << 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] << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
427
428
429
430
    }

    void write(const mult_2& dyn) noexcept
    {
431
432
433
        os << "mult_2 " << dyn.default_values[0] << ' ' << dyn.default_values[1]
           << ' ' << dyn.default_input_coeffs[0] << ' '
           << dyn.default_input_coeffs[1] << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
434
435
436
437
    }

    void write(const mult_3& dyn) noexcept
    {
438
439
440
441
        os << "mult_3 " << 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] << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
442
443
444
445
    }

    void write(const mult_4& dyn) noexcept
    {
446
447
448
449
450
        os << "mult_4 " << 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] << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
451
452
453
454
    }

    void write(const counter& /*dyn*/) noexcept
    {
455
        os << "counter\n";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
456
457
458
459
    }

    void write(const generator& /*dyn*/) noexcept
    {
460
        os << "generator\n";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
461
462
463
464
    }

    void write(const constant& dyn) noexcept
    {
465
        os << "constant " << dyn.default_value << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
466
467
468
469
    }

    void write(const cross& dyn) noexcept
    {
470
        os << "cross " << dyn.default_threshold << '\n';
Gauthier Quesnel's avatar
Gauthier Quesnel committed
471
472
473
474
    }

    void write(const time_func& dyn) noexcept
    {
475
476
        os << "time_func "
           << (dyn.default_f == &time_function ? "time\n" : "square\n");
Gauthier Quesnel's avatar
Gauthier Quesnel committed
477
478
479
480
481
482
    }
};

class dot_writer
{
private:
483
    std::ostream& os;
Gauthier Quesnel's avatar
Gauthier Quesnel committed
484
485

public:
486
487
    dot_writer(std::ostream& os_)
      : os(os_)
Gauthier Quesnel's avatar
Gauthier Quesnel committed
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
    {}

    /* With input and output port.

    digraph graphname{
        graph[rankdir = "LR"];
        node[shape = "record"];
        edge[];

        "sum_a"[label = "sum-a | <f0> | <f1>"];

        "sum_a":f0->int_a[id = 1];
        sum_b->int_b[label = "2-10"];
        prod->sum_b[label = "3-4"];
        prod -> "sum_a":f0[label = "3-2"];
        int_a->qua_a[label = "4-11"];
        int_a->prod[label = "4-5"];
        int_a -> "sum_a":f1[label = "4-1"];
        int_b->qua_b[label = "5-12"];
        int_b->prod[label = "5-6"];
        int_b->sum_b[label = "5-3"];
        qua_a->int_a[label = "6-7"];
        qua_b->int_b[label = "7-9"];
    }
    */

    void operator()(const simulation& sim) noexcept
    {
516
        os << "digraph graphname {\n";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
517
518
519
520
521
522
523
524
525
526
527
528
529

        irt::output_port* output_port = nullptr;
        while (sim.output_ports.next(output_port)) {
            for (const irt::input_port_id dst : output_port->connections) {
                if (auto* input_port = sim.input_ports.try_to_get(dst);
                    input_port) {
                    auto* mdl_src = sim.models.try_to_get(output_port->model);
                    auto* mdl_dst = sim.models.try_to_get(input_port->model);

                    if (!(mdl_src && mdl_dst))
                        continue;

                    if (mdl_src->name.empty())
530
                        os << irt::get_key(output_port->model);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
531
                    else
532
533
534
                        os << mdl_src->name.c_str();

                    os << " -> ";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
535
536

                    if (mdl_dst->name.empty())
537
                        os << irt::get_key(input_port->model);
Gauthier Quesnel's avatar
Gauthier Quesnel committed
538
                    else
539
                        os << mdl_dst->name.c_str();
Gauthier Quesnel's avatar
Gauthier Quesnel committed
540

541
                    os << " [label=\"";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
542
543

                    if (output_port->name.empty())
544
545
                        os << irt::get_key(
                          sim.output_ports.get_id(*output_port));
Gauthier Quesnel's avatar
Gauthier Quesnel committed
546
                    else
547
                        os << output_port->name.c_str();
Gauthier Quesnel's avatar
Gauthier Quesnel committed
548

549
                    os << " - ";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
550
551

                    if (input_port->name.empty())
552
                        os << irt::get_key(sim.input_ports.get_id(*input_port));
Gauthier Quesnel's avatar
Gauthier Quesnel committed
553
                    else
554
                        os << input_port->name.c_str();
Gauthier Quesnel's avatar
Gauthier Quesnel committed
555

556
                    os << "\"];\n";
Gauthier Quesnel's avatar
Gauthier Quesnel committed
557
558
559
560
561
562
563
564
565
                }
            }
        }
    }
};

} // namespace irt

#endif