• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / sdfglib / 15340968114

30 May 2025 06:47AM UTC coverage: 58.553% (+0.2%) from 58.324%
15340968114

push

github

web-flow
Add parallel Map node

* Introduce Map data structure

* Prepare infrastructure

* implement analysis support

* Add basic infrastructure

* visualizer/serializer

* include fix

* update from main

* remove default

* happens before test + fixes

* builder test

* dispatcher test

* visitor, copy and serializer tests

* for2map structures

* for2map conversion draft

* add tests

* Bug fixes

* small updates from feedback

* Visitor style pass implementation

* cleanup

* fixes linting errors

---------

Co-authored-by: Lukas Truemper <lukas.truemper@outlook.de>

258 of 381 new or added lines in 26 files covered. (67.72%)

17 existing lines in 14 files now uncovered.

8184 of 13977 relevant lines covered (58.55%)

109.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.33
/src/serializer/json_serializer.cpp
1
#include "sdfg/serializer/json_serializer.h"
2

3
#include <cassert>
4
#include <memory>
5
#include <unordered_map>
6
#include <utility>
7
#include <vector>
8

9
#include "sdfg/builder/structured_sdfg_builder.h"
10
#include "sdfg/data_flow/library_node.h"
11
#include "sdfg/element.h"
12
#include "sdfg/structured_control_flow/block.h"
13
#include "sdfg/structured_control_flow/for.h"
14
#include "sdfg/structured_control_flow/if_else.h"
15
#include "sdfg/structured_control_flow/kernel.h"
16
#include "sdfg/structured_control_flow/return.h"
17
#include "sdfg/structured_control_flow/sequence.h"
18
#include "sdfg/structured_control_flow/while.h"
19
#include "sdfg/structured_sdfg.h"
20
#include "sdfg/symbolic/symbolic.h"
21
#include "sdfg/types/function.h"
22
#include "sdfg/types/scalar.h"
23
#include "sdfg/types/type.h"
24
#include "symengine/expression.h"
25
#include "symengine/logic.h"
26
#include "symengine/symengine_rcp.h"
27

28
namespace sdfg {
29
namespace serializer {
30

31
/*
32
 * * JSONSerializer class
33
 * * Serialization logic
34
 */
35

36
nlohmann::json JSONSerializer::serialize(std::unique_ptr<sdfg::StructuredSDFG>& sdfg) {
4✔
37
    nlohmann::json j;
4✔
38

39
    j["name"] = sdfg->name();
4✔
40

41
    j["structures"] = nlohmann::json::array();
4✔
42
    for (const auto& structure_name : sdfg->structures()) {
4✔
43
        const auto& structure = sdfg->structure(structure_name);
×
44
        nlohmann::json structure_json;
×
45
        structure_definition_to_json(structure_json, structure);
×
46
        j["structures"].push_back(structure_json);
×
47
    }
×
48
    j["containers"] = nlohmann::json::array();
4✔
49
    for (const auto& container : sdfg->containers()) {
13✔
50
        if (sdfg->is_argument(container)) {
9✔
51
            continue;
4✔
52
        }
53
        nlohmann::json container_json;
5✔
54
        container_json["name"] = container;
5✔
55

56
        if (sdfg->is_external(container)) {
5✔
57
            container_json["external"] = true;
1✔
58
        } else {
1✔
59
            container_json["external"] = false;
4✔
60
        }
61

62
        nlohmann::json container_type_json;
5✔
63
        type_to_json(container_type_json, sdfg->type(container));
5✔
64
        container_json["type"] = container_type_json;
5✔
65
        j["containers"].push_back(container_json);
5✔
66
    }
5✔
67

68
    j["arguments"] = nlohmann::json::array();
4✔
69
    for (const auto& argument : sdfg->arguments()) {
8✔
70
        nlohmann::json argument_json;
4✔
71
        argument_json["name"] = argument;
4✔
72
        nlohmann::json argument_type_json;
4✔
73
        type_to_json(argument_type_json, sdfg->type(argument));
4✔
74
        argument_json["type"] = argument_type_json;
4✔
75
        j["arguments"].push_back(argument_json);
4✔
76
    }
4✔
77

78
    // dump the root node
79
    nlohmann::json root_json;
4✔
80
    sequence_to_json(root_json, sdfg->root());
4✔
81
    j["root"] = root_json;
4✔
82

83
    j["metadata"] = nlohmann::json::object();
4✔
84
    for (const auto& entry : sdfg->metadata()) {
5✔
85
        j["metadata"][entry.first] = entry.second;
1✔
86
    }
87

88
    return j;
4✔
89
}
4✔
90

91
void JSONSerializer::dataflow_to_json(nlohmann::json& j, const data_flow::DataFlowGraph& dataflow) {
22✔
92
    j["type"] = "dataflow";
22✔
93
    j["nodes"] = nlohmann::json::array();
22✔
94
    j["edges"] = nlohmann::json::array();
22✔
95

96
    for (auto& node : dataflow.nodes()) {
42✔
97
        nlohmann::json node_json;
20✔
98
        if (auto code_node = dynamic_cast<const data_flow::Tasklet*>(&node)) {
20✔
99
            node_json["type"] = "tasklet";
5✔
100
            node_json["code"] = code_node->code();
5✔
101
            node_json["inputs"] = nlohmann::json::array();
5✔
102
            for (auto& input : code_node->inputs()) {
15✔
103
                nlohmann::json input_json;
10✔
104
                nlohmann::json type_json;
10✔
105
                type_to_json(type_json, input.second);
10✔
106
                input_json["type"] = type_json;
10✔
107
                input_json["name"] = input.first;
10✔
108
                node_json["inputs"].push_back(input_json);
10✔
109
            }
10✔
110
            node_json["outputs"] = nlohmann::json::array();
5✔
111
            for (auto& output : code_node->outputs()) {
10✔
112
                nlohmann::json output_json;
5✔
113
                nlohmann::json type_json;
5✔
114
                type_to_json(type_json, output.second);
5✔
115
                output_json["type"] = type_json;
5✔
116
                output_json["name"] = output.first;
5✔
117
                node_json["outputs"].push_back(output_json);
5✔
118
            }
5✔
119
            // node_json["conditional"] = code_node->is_conditional();
120
            // if (code_node->is_conditional()) {
121
            //     node_json["condition"] = dumps_expression(code_node->condition());
122
            // }
123
        } else if (auto lib_node = dynamic_cast<const data_flow::LibraryNode*>(&node)) {
20✔
124
            node_json["type"] = "library_node";
×
125
            node_json["call"] = lib_node->call();
×
126
            node_json["side_effect"] = lib_node->has_side_effect();
×
127
            node_json["inputs"] = nlohmann::json::array();
×
128
            for (auto& input : lib_node->inputs()) {
×
129
                nlohmann::json input_json;
×
130
                nlohmann::json type_json;
×
131
                type_to_json(type_json, input.second);
×
132
                input_json["type"] = type_json;
×
133
                input_json["name"] = input.first;
×
134
                node_json["inputs"].push_back(input_json);
×
135
            }
×
136
            node_json["outputs"] = nlohmann::json::array();
×
137
            for (auto& output : lib_node->outputs()) {
×
138
                nlohmann::json output_json;
×
139
                nlohmann::json type_json;
×
140
                type_to_json(type_json, output.second);
×
141
                output_json["type"] = type_json;
×
142
                output_json["name"] = output.first;
×
143
                node_json["outputs"].push_back(output_json);
×
144
            }
×
145
        } else if (auto code_node = dynamic_cast<const data_flow::AccessNode*>(&node)) {
15✔
146
            node_json["type"] = "access_node";
15✔
147
            node_json["container"] = code_node->data();
15✔
148
        } else {
15✔
149
            throw std::runtime_error("Unknown node type");
×
150
        }
151
        node_json["element_id"] = node.element_id();
20✔
152
        j["nodes"].push_back(node_json);
20✔
153
    }
20✔
154

155
    for (auto& edge : dataflow.edges()) {
37✔
156
        nlohmann::json edge_json;
15✔
157
        edge_json["source"] = edge.src().element_id();
15✔
158
        edge_json["target"] = edge.dst().element_id();
15✔
159

160
        edge_json["source_connector"] = edge.src_conn();
15✔
161
        edge_json["target_connector"] = edge.dst_conn();
15✔
162

163
        // add subset
164
        edge_json["subset"] = nlohmann::json::array();
15✔
165
        for (auto& subset : edge.subset()) {
21✔
166
            edge_json["subset"].push_back(expression(subset));
6✔
167
        }
168

169
        j["edges"].push_back(edge_json);
15✔
170
    }
15✔
171
}
22✔
172

173
void JSONSerializer::block_to_json(nlohmann::json& j, const structured_control_flow::Block& block) {
20✔
174
    j["type"] = "block";
20✔
175
    nlohmann::json dataflow_json;
20✔
176
    dataflow_to_json(dataflow_json, block.dataflow());
20✔
177
    j["dataflow"] = dataflow_json;
20✔
178
}
20✔
179

180
void JSONSerializer::for_to_json(nlohmann::json& j, const structured_control_flow::For& for_node) {
2✔
181
    j["type"] = "for";
2✔
182
    j["indvar"] = expression(for_node.indvar());
2✔
183
    j["init"] = expression(for_node.init());
2✔
184
    j["condition"] = expression(for_node.condition());
2✔
185
    j["update"] = expression(for_node.update());
2✔
186

187
    nlohmann::json body_json;
2✔
188
    sequence_to_json(body_json, for_node.root());
2✔
189
    j["children"] = body_json;
2✔
190
}
2✔
191

192
void JSONSerializer::if_else_to_json(nlohmann::json& j,
2✔
193
                                     const structured_control_flow::IfElse& if_else_node) {
194
    j["type"] = "if_else";
2✔
195
    j["branches"] = nlohmann::json::array();
2✔
196
    for (size_t i = 0; i < if_else_node.size(); i++) {
6✔
197
        nlohmann::json branch_json;
4✔
198
        branch_json["condition"] = expression(if_else_node.at(i).second);
4✔
199
        nlohmann::json body_json;
4✔
200
        sequence_to_json(body_json, if_else_node.at(i).first);
4✔
201
        branch_json["children"] = body_json;
4✔
202
        j["branches"].push_back(branch_json);
4✔
203
    }
4✔
204
}
2✔
205

206
void JSONSerializer::while_node_to_json(nlohmann::json& j,
5✔
207
                                        const structured_control_flow::While& while_node) {
208
    j["type"] = "while";
5✔
209

210
    nlohmann::json body_json;
5✔
211
    sequence_to_json(body_json, while_node.root());
5✔
212
    j["children"] = body_json;
5✔
213
}
5✔
214

215
void JSONSerializer::break_node_to_json(nlohmann::json& j,
2✔
216
                                        const structured_control_flow::Break& break_node) {
217
    j["type"] = "break";
2✔
218
}
2✔
219
void JSONSerializer::continue_node_to_json(nlohmann::json& j,
2✔
220
                                           const structured_control_flow::Continue& continue_node) {
221
    j["type"] = "continue";
2✔
222
}
2✔
223

224
void JSONSerializer::kernel_to_json(nlohmann::json& j,
2✔
225
                                    const structured_control_flow::Kernel& kernel_node) {
226
    j["type"] = "kernel";
2✔
227
    j["suffix"] = kernel_node.suffix();
2✔
228

229
    nlohmann::json body_json;
2✔
230
    sequence_to_json(body_json, kernel_node.root());
2✔
231
    j["children"] = body_json;
2✔
232
}
2✔
233

234
void JSONSerializer::map_to_json(nlohmann::json& j, const structured_control_flow::Map& map_node) {
2✔
235
    j["type"] = "map";
2✔
236
    j["indvar"] = expression(map_node.indvar());
2✔
237
    j["num_iterations"] = expression(map_node.num_iterations());
2✔
238
    nlohmann::json body_json;
2✔
239
    sequence_to_json(body_json, map_node.root());
2✔
240
    j["children"] = body_json;
2✔
241
}
2✔
242

243
void JSONSerializer::return_node_to_json(nlohmann::json& j,
2✔
244
                                         const structured_control_flow::Return& return_node) {
245
    j["type"] = "return";
2✔
246
}
2✔
247

248
void JSONSerializer::sequence_to_json(nlohmann::json& j,
22✔
249
                                      const structured_control_flow::Sequence& sequence) {
250
    j["type"] = "sequence";
22✔
251
    j["children"] = nlohmann::json::array();
22✔
252
    j["transitions"] = nlohmann::json::array();
22✔
253

254
    for (size_t i = 0; i < sequence.size(); i++) {
44✔
255
        nlohmann::json child_json;
22✔
256
        auto& child = sequence.at(i).first;
22✔
257
        auto& transition = sequence.at(i).second;
22✔
258

259
        if (auto block = dynamic_cast<const structured_control_flow::Block*>(&child)) {
22✔
260
            block_to_json(child_json, *block);
18✔
261
        } else if (auto for_node = dynamic_cast<const structured_control_flow::For*>(&child)) {
22✔
262
            for_to_json(child_json, *for_node);
×
263
        } else if (auto sequence_node =
4✔
264
                       dynamic_cast<const structured_control_flow::Sequence*>(&child)) {
4✔
265
            sequence_to_json(child_json, *sequence_node);
×
266
        } else if (auto condition_node =
4✔
267
                       dynamic_cast<const structured_control_flow::IfElse*>(&child)) {
4✔
268
            if_else_to_json(child_json, *condition_node);
×
269
        } else if (auto while_node = dynamic_cast<const structured_control_flow::While*>(&child)) {
4✔
270
            while_node_to_json(child_json, *while_node);
×
271
        } else if (auto kernel_node =
4✔
272
                       dynamic_cast<const structured_control_flow::Kernel*>(&child)) {
4✔
273
            kernel_to_json(child_json, *kernel_node);
×
274
        } else if (auto return_node =
4✔
275
                       dynamic_cast<const structured_control_flow::Return*>(&child)) {
4✔
276
            return_node_to_json(child_json, *return_node);
×
277
        } else if (auto break_node = dynamic_cast<const structured_control_flow::Break*>(&child)) {
4✔
278
            break_node_to_json(child_json, *break_node);
2✔
279
        } else if (auto continue_node =
4✔
280
                       dynamic_cast<const structured_control_flow::Continue*>(&child)) {
2✔
281
            continue_node_to_json(child_json, *continue_node);
2✔
282
        } else if (auto map_node = dynamic_cast<const structured_control_flow::Map*>(&child)) {
2✔
NEW
283
            map_to_json(child_json, *map_node);
×
284
        } else {
×
285
            throw std::runtime_error("Unknown child type");
×
286
        }
287

288
        j["children"].push_back(child_json);
22✔
289

290
        // Add transition information
291
        nlohmann::json transition_json;
22✔
292
        transition_json["type"] = "transition";
22✔
293
        transition_json["assignments"] = nlohmann::json::array();
22✔
294
        for (const auto& assignment : transition.assignments()) {
24✔
295
            nlohmann::json assignment_json;
2✔
296
            assignment_json["symbol"] = expression(assignment.first);
2✔
297
            assignment_json["expression"] = expression(assignment.second);
2✔
298
            transition_json["assignments"].push_back(assignment_json);
2✔
299
        }
2✔
300

301
        j["transitions"].push_back(transition_json);
22✔
302
    }
22✔
303
}
22✔
304

305
void JSONSerializer::type_to_json(nlohmann::json& j, const types::IType& type) {
48✔
306
    if (auto scalar_type = dynamic_cast<const types::Scalar*>(&type)) {
48✔
307
        j["type"] = "scalar";
37✔
308
        j["primitive_type"] = scalar_type->primitive_type();
37✔
309
        j["address_space"] = scalar_type->address_space();
37✔
310
        j["initializer"] = scalar_type->initializer();
37✔
311
        j["device_location"] = scalar_type->device_location();
37✔
312
    } else if (auto array_type = dynamic_cast<const types::Array*>(&type)) {
48✔
313
        j["type"] = "array";
3✔
314
        nlohmann::json element_type_json;
3✔
315
        type_to_json(element_type_json, array_type->element_type());
3✔
316
        j["element_type"] = element_type_json;
3✔
317
        j["num_elements"] = expression(array_type->num_elements());
3✔
318
        j["address_space"] = array_type->address_space();
3✔
319
        j["initializer"] = array_type->initializer();
3✔
320
        j["device_location"] = array_type->device_location();
3✔
321
        j["alignment"] = array_type->alignment();
3✔
322
    } else if (auto pointer_type = dynamic_cast<const types::Pointer*>(&type)) {
11✔
323
        j["type"] = "pointer";
4✔
324
        nlohmann::json pointee_type_json;
4✔
325
        type_to_json(pointee_type_json, pointer_type->pointee_type());
4✔
326
        j["pointee_type"] = pointee_type_json;
4✔
327
        j["address_space"] = pointer_type->address_space();
4✔
328
        j["initializer"] = pointer_type->initializer();
4✔
329
        j["device_location"] = pointer_type->device_location();
4✔
330
    } else if (auto structure_type = dynamic_cast<const types::Structure*>(&type)) {
8✔
331
        j["type"] = "structure";
2✔
332
        j["name"] = structure_type->name();
2✔
333
        j["address_space"] = structure_type->address_space();
2✔
334
        j["initializer"] = structure_type->initializer();
2✔
335
        j["device_location"] = structure_type->device_location();
2✔
336
    } else if (auto function_type = dynamic_cast<const types::Function*>(&type)) {
4✔
337
        j["type"] = "function";
2✔
338
        nlohmann::json return_type_json;
2✔
339
        type_to_json(return_type_json, function_type->return_type());
2✔
340
        j["return_type"] = return_type_json;
2✔
341
        j["argument_types"] = nlohmann::json::array();
2✔
342
        for (size_t i = 0; i < function_type->num_params(); i++) {
5✔
343
            nlohmann::json param_json;
3✔
344
            type_to_json(param_json, function_type->param_type(symbolic::integer(i)));
3✔
345
            j["argument_types"].push_back(param_json);
3✔
346
        }
3✔
347
        j["is_var_arg"] = function_type->is_var_arg();
2✔
348
        j["address_space"] = function_type->address_space();
2✔
349
        j["initializer"] = function_type->initializer();
2✔
350
        j["device_location"] = function_type->device_location();
2✔
351
    } else {
2✔
352
        throw std::runtime_error("Unknown type");
×
353
    }
354
}
48✔
355

356
void JSONSerializer::structure_definition_to_json(nlohmann::json& j,
1✔
357
                                                  const types::StructureDefinition& definition) {
358
    j["name"] = definition.name();
1✔
359
    j["members"] = nlohmann::json::array();
1✔
360
    for (size_t i = 0; i < definition.num_members(); i++) {
3✔
361
        nlohmann::json member_json;
2✔
362
        type_to_json(member_json, definition.member_type(symbolic::integer(i)));
2✔
363
        j["members"].push_back(member_json);
2✔
364
    }
2✔
365
    j["is_packed"] = definition.is_packed();
1✔
366
}
1✔
367

368
/*
369
 * * Deserialization logic
370
 */
371

372
std::unique_ptr<StructuredSDFG> JSONSerializer::deserialize(nlohmann::json& j) {
3✔
373
    assert(j.contains("name"));
3✔
374
    assert(j["name"].is_string());
3✔
375

376
    builder::StructuredSDFGBuilder builder(j["name"]);
3✔
377

378
    // deserialize structures
379
    assert(j.contains("structures"));
3✔
380
    assert(j["structures"].is_array());
3✔
381
    for (const auto& structure : j["structures"]) {
3✔
382
        assert(structure.contains("name"));
×
383
        assert(structure["name"].is_string());
×
384
        json_to_structure_definition(structure, builder);
×
385
    }
386

387
    // deserialize arguments
388
    assert(j.contains("arguments"));
3✔
389
    assert(j["arguments"].is_array());
3✔
390
    for (const auto& argument : j["arguments"]) {
5✔
391
        assert(argument.contains("name"));
2✔
392
        assert(argument["name"].is_string());
2✔
393
        assert(argument.contains("type"));
2✔
394
        assert(argument["type"].is_object());
2✔
395
        std::string name = argument["name"];
2✔
396
        auto type = json_to_type(argument["type"]);
2✔
397
        builder.add_container(name, *type, true, false);
2✔
398
    }
2✔
399

400
    // deserialize containers
401
    json_to_containers(j, builder);
3✔
402

403
    // deserialize root node
404
    assert(j.contains("root"));
3✔
405
    auto& root = builder.subject().root();
3✔
406
    json_to_sequence(j["root"], builder, root);
3✔
407

408
    // deserialize metadata
409
    assert(j.contains("metadata"));
3✔
410
    assert(j["metadata"].is_object());
3✔
411
    for (const auto& entry : j["metadata"].items()) {
4✔
412
        builder.subject().add_metadata(entry.key(), entry.value());
1✔
413
    }
414

415
    return builder.move();
3✔
416
}
3✔
417

418
void JSONSerializer::json_to_structure_definition(const nlohmann::json& j,
1✔
419
                                                  builder::StructuredSDFGBuilder& builder) {
420
    assert(j.contains("name"));
1✔
421
    assert(j["name"].is_string());
1✔
422
    assert(j.contains("members"));
1✔
423
    assert(j["members"].is_array());
1✔
424
    assert(j.contains("is_packed"));
1✔
425
    assert(j["is_packed"].is_boolean());
1✔
426
    auto is_packed = j["is_packed"];
1✔
427
    auto& definition = builder.add_structure(j["name"], is_packed);
1✔
428
    for (const auto& member : j["members"]) {
3✔
429
        nlohmann::json member_json;
2✔
430
        auto member_type = json_to_type(member);
2✔
431
        definition.add_member(*member_type);
2✔
432
    }
2✔
433
}
1✔
434

435
void JSONSerializer::json_to_containers(const nlohmann::json& j,
4✔
436
                                        builder::StructuredSDFGBuilder& builder) {
437
    assert(j.contains("containers"));
4✔
438
    assert(j["containers"].is_array());
4✔
439
    for (const auto& container : j["containers"]) {
9✔
440
        assert(container.contains("name"));
5✔
441
        assert(container["name"].is_string());
5✔
442
        assert(container.contains("external"));
5✔
443
        assert(container["external"].is_boolean());
5✔
444
        assert(container.contains("type"));
5✔
445
        assert(container["type"].is_object());
5✔
446
        std::string name = container["name"];
5✔
447
        bool external = container["external"];
5✔
448
        auto container_type = json_to_type(container["type"]);
5✔
449
        builder.add_container(name, *container_type, false, external);
5✔
450
    }
5✔
451
}
4✔
452

453
std::vector<std::pair<std::string, types::Scalar>> JSONSerializer::json_to_arguments(
8✔
454
    const nlohmann::json& j) {
455
    std::vector<std::pair<std::string, types::Scalar>> arguments;
8✔
456
    for (const auto& argument : j) {
20✔
457
        assert(argument.contains("name"));
12✔
458
        assert(argument["name"].is_string());
12✔
459
        assert(argument.contains("type"));
12✔
460
        assert(argument["type"].is_object());
12✔
461
        std::string name = argument["name"];
12✔
462
        auto type = json_to_type(argument["type"]);
12✔
463
        arguments.emplace_back(name, *dynamic_cast<types::Scalar*>(type.get()));
12✔
464
    }
12✔
465
    return arguments;
8✔
466
}
8✔
467

468
void JSONSerializer::json_to_dataflow(const nlohmann::json& j,
11✔
469
                                      builder::StructuredSDFGBuilder& builder,
470
                                      structured_control_flow::Block& parent) {
471
    std::unordered_map<long, data_flow::DataFlowNode&> nodes_map;
11✔
472

473
    assert(j.contains("nodes"));
11✔
474
    assert(j["nodes"].is_array());
11✔
475
    for (const auto& node : j["nodes"]) {
27✔
476
        assert(node.contains("type"));
16✔
477
        assert(node["type"].is_string());
16✔
478
        assert(node.contains("element_id"));
16✔
479
        assert(node["element_id"].is_number_integer());
16✔
480
        std::string type = node["type"];
16✔
481
        if (type == "tasklet") {
16✔
482
            assert(node.contains("code"));
4✔
483
            assert(node["code"].is_number_integer());
4✔
484
            assert(node.contains("inputs"));
4✔
485
            assert(node["inputs"].is_array());
4✔
486
            assert(node.contains("outputs"));
4✔
487
            assert(node["outputs"].is_array());
4✔
488
            auto outputs = json_to_arguments(node["outputs"]);
4✔
489
            assert(outputs.size() == 1);
4✔
490
            auto inputs = json_to_arguments(node["inputs"]);
4✔
491
            auto& tasklet = builder.add_tasklet(parent, node["code"], outputs.at(0), inputs);
4✔
492

493
            nodes_map.insert({node["element_id"], tasklet});
4✔
494
        } else if (type == "library_node") {
16✔
495
            assert(node.contains("call"));
×
496
            assert(node.contains("inputs"));
×
497
            assert(node["inputs"].is_array());
×
498
            assert(node.contains("outputs"));
×
499
            assert(node["outputs"].is_array());
×
500
            auto outputs = json_to_arguments(node["outputs"]);
×
501
            auto inputs = json_to_arguments(node["inputs"]);
×
502
            auto& lib_node = builder.add_library_node(parent, node["call"], outputs, inputs);
×
503

504
            nodes_map.insert({node["element_id"], lib_node});
×
505
        } else if (type == "access_node") {
12✔
506
            assert(node.contains("container"));
12✔
507
            auto& access_node = builder.add_access(parent, node["container"]);
12✔
508

509
            nodes_map.insert({node["element_id"], access_node});
12✔
510
        } else {
12✔
511
            throw std::runtime_error("Unknown node type");
×
512
        }
513
    }
16✔
514

515
    assert(j.contains("edges"));
11✔
516
    assert(j["edges"].is_array());
11✔
517
    for (const auto& edge : j["edges"]) {
23✔
518
        assert(edge.contains("source"));
12✔
519
        assert(edge["source"].is_number_integer());
12✔
520
        assert(edge.contains("target"));
12✔
521
        assert(edge["target"].is_number_integer());
12✔
522
        assert(edge.contains("source_connector"));
12✔
523
        assert(edge["source_connector"].is_string());
12✔
524
        assert(edge.contains("target_connector"));
12✔
525
        assert(edge["target_connector"].is_string());
12✔
526
        assert(edge.contains("subset"));
12✔
527
        assert(edge["subset"].is_array());
12✔
528

529
        assert(nodes_map.contains(edge["source"]));
12✔
530
        assert(nodes_map.contains(edge["target"]));
12✔
531
        auto& source = nodes_map.at(edge["source"]);
12✔
532
        auto& target = nodes_map.at(edge["target"]);
12✔
533

534
        assert(edge.contains("subset"));
12✔
535
        assert(edge["subset"].is_array());
12✔
536
        std::vector<symbolic::Expression> subset;
12✔
537
        for (const auto& subset_str : edge["subset"]) {
16✔
538
            assert(subset_str.is_string());
4✔
539
            SymEngine::Expression subset_expr(subset_str);
4✔
540
            subset.push_back(subset_expr);
4✔
541
        }
4✔
542
        builder.add_memlet(parent, source, edge["source_connector"], target,
24✔
543
                           edge["target_connector"], subset);
12✔
544
    }
12✔
545
}
11✔
546

547
void JSONSerializer::json_to_sequence(const nlohmann::json& j,
13✔
548
                                      builder::StructuredSDFGBuilder& builder,
549
                                      structured_control_flow::Sequence& sequence) {
550
    assert(j.contains("type"));
13✔
551
    assert(j["type"].is_string());
13✔
552
    assert(j.contains("children"));
13✔
553
    assert(j["children"].is_array());
13✔
554
    assert(j.contains("transitions"));
13✔
555
    assert(j["transitions"].is_array());
13✔
556
    assert(j["transitions"].size() == j["children"].size());
13✔
557
    std::string type = j["type"];
13✔
558
    if (type == "sequence") {
13✔
559
        for (size_t i = 0; i < j["children"].size(); i++) {
24✔
560
            auto& child = j["children"][i];
11✔
561
            auto& transition = j["transitions"][i];
11✔
562
            assert(child.contains("type"));
11✔
563
            assert(child["type"].is_string());
11✔
564

565
            assert(transition.contains("type"));
11✔
566
            assert(transition["type"].is_string());
11✔
567
            assert(transition.contains("assignments"));
11✔
568
            assert(transition["assignments"].is_array());
11✔
569
            symbolic::Assignments assignments;
11✔
570
            for (const auto& assignment : transition["assignments"]) {
12✔
571
                assert(assignment.contains("symbol"));
1✔
572
                assert(assignment["symbol"].is_string());
1✔
573
                assert(assignment.contains("expression"));
1✔
574
                assert(assignment["expression"].is_string());
1✔
575
                SymEngine::Expression expr(assignment["expression"]);
1✔
576
                assignments.insert({symbolic::symbol(assignment["symbol"]), expr});
1✔
577
            }
1✔
578

579
            if (child["type"] == "block") {
11✔
580
                json_to_block_node(child, builder, sequence, assignments);
9✔
581
            } else if (child["type"] == "for") {
11✔
582
                json_to_for_node(child, builder, sequence, assignments);
×
583
            } else if (child["type"] == "if_else") {
2✔
584
                json_to_if_else_node(child, builder, sequence);
×
585
            } else if (child["type"] == "while") {
2✔
586
                json_to_while_node(child, builder, sequence, assignments);
×
587
            } else if (child["type"] == "break") {
2✔
588
                json_to_break_node(child, builder, sequence);
1✔
589
            } else if (child["type"] == "continue") {
2✔
590
                json_to_continue_node(child, builder, sequence);
1✔
591
            } else if (child["type"] == "kernel") {
1✔
592
                json_to_kernel_node(child, builder, sequence);
×
593
            } else if (child["type"] == "return") {
×
594
                json_to_return_node(child, builder, sequence, assignments);
×
595
            } else {
×
596
                throw std::runtime_error("Unknown child type");
×
597
            }
598
        }
11✔
599
    } else {
13✔
600
        throw std::runtime_error("expected sequence type");
×
601
    }
602
}
13✔
603

604
void JSONSerializer::json_to_block_node(const nlohmann::json& j,
10✔
605
                                        builder::StructuredSDFGBuilder& builder,
606
                                        structured_control_flow::Sequence& parent,
607
                                        symbolic::Assignments& assignments) {
608
    assert(j.contains("type"));
10✔
609
    assert(j["type"].is_string());
10✔
610
    assert(j.contains("dataflow"));
10✔
611
    assert(j["dataflow"].is_object());
10✔
612
    auto& block = builder.add_block(parent, assignments);
10✔
613
    assert(j["dataflow"].contains("type"));
10✔
614
    assert(j["dataflow"]["type"].is_string());
10✔
615
    std::string type = j["dataflow"]["type"];
10✔
616
    if (type == "dataflow") {
10✔
617
        json_to_dataflow(j["dataflow"], builder, block);
10✔
618
    } else {
10✔
619
        throw std::runtime_error("Unknown dataflow type");
×
620
    }
621
}
10✔
622

623
void JSONSerializer::json_to_for_node(const nlohmann::json& j,
1✔
624
                                      builder::StructuredSDFGBuilder& builder,
625
                                      structured_control_flow::Sequence& parent,
626
                                      symbolic::Assignments& assignments) {
627
    assert(j.contains("type"));
1✔
628
    assert(j["type"].is_string());
1✔
629
    assert(j.contains("indvar"));
1✔
630
    assert(j["indvar"].is_string());
1✔
631
    assert(j.contains("init"));
1✔
632
    assert(j["init"].is_string());
1✔
633
    assert(j.contains("condition"));
1✔
634
    assert(j["condition"].is_string());
1✔
635
    assert(j.contains("update"));
1✔
636
    assert(j["update"].is_string());
1✔
637
    assert(j.contains("children"));
1✔
638
    assert(j["children"].is_object());
1✔
639

640
    symbolic::Symbol indvar = symbolic::symbol(j["indvar"]);
1✔
641
    SymEngine::Expression init(j["init"]);
1✔
642
    SymEngine::Expression condition_expr(j["condition"]);
1✔
643
    assert(!SymEngine::rcp_static_cast<const SymEngine::Boolean>(condition_expr.get_basic())
1✔
644
                .is_null());
645
    symbolic::Condition condition =
646
        SymEngine::rcp_static_cast<const SymEngine::Boolean>(condition_expr.get_basic());
1✔
647
    SymEngine::Expression update(j["update"]);
1✔
648
    auto& for_node = builder.add_for(parent, indvar, condition, init, update, assignments);
1✔
649

650
    assert(j["children"].contains("type"));
1✔
651
    assert(j["children"]["type"].is_string());
1✔
652
    std::string type = j["children"]["type"];
1✔
653
    if (type == "sequence") {
1✔
654
        json_to_sequence(j["children"], builder, for_node.root());
1✔
655
    } else {
1✔
656
        throw std::runtime_error("Unknown child type");
×
657
    }
658
}
1✔
659

660
void JSONSerializer::json_to_if_else_node(const nlohmann::json& j,
1✔
661
                                          builder::StructuredSDFGBuilder& builder,
662
                                          structured_control_flow::Sequence& parent) {
663
    assert(j.contains("type"));
1✔
664
    assert(j["type"].is_string());
1✔
665
    assert(j["type"] == "if_else");
1✔
666
    assert(j.contains("branches"));
1✔
667
    assert(j["branches"].is_array());
1✔
668
    auto& if_else_node = builder.add_if_else(parent);
1✔
669
    for (const auto& branch : j["branches"]) {
3✔
670
        assert(branch.contains("condition"));
2✔
671
        assert(branch["condition"].is_string());
2✔
672
        assert(branch.contains("children"));
2✔
673
        assert(branch["children"].is_object());
2✔
674
        SymEngine::Expression condition_expr(branch["condition"]);
2✔
675
        assert(!SymEngine::rcp_static_cast<const SymEngine::Boolean>(condition_expr.get_basic())
2✔
676
                    .is_null());
677
        symbolic::Condition condition =
678
            SymEngine::rcp_static_cast<const SymEngine::Boolean>(condition_expr.get_basic());
2✔
679
        auto& true_case = builder.add_case(if_else_node, condition);
2✔
680
        assert(branch["children"].contains("type"));
2✔
681
        assert(branch["children"]["type"].is_string());
2✔
682
        std::string type = branch["children"]["type"];
2✔
683
        if (type == "sequence") {
2✔
684
            json_to_sequence(branch["children"], builder, true_case);
2✔
685
        } else {
2✔
686
            throw std::runtime_error("Unknown child type");
×
687
        }
688
    }
2✔
689
}
1✔
690

691
void JSONSerializer::json_to_while_node(const nlohmann::json& j,
3✔
692
                                        builder::StructuredSDFGBuilder& builder,
693
                                        structured_control_flow::Sequence& parent,
694
                                        symbolic::Assignments& assignments) {
695
    assert(j.contains("type"));
3✔
696
    assert(j["type"].is_string());
3✔
697
    assert(j["type"] == "while");
3✔
698
    assert(j.contains("children"));
3✔
699
    assert(j["children"].is_object());
3✔
700

701
    auto& while_node = builder.add_while(parent, assignments);
3✔
702

703
    assert(j["children"].contains("type"));
3✔
704
    assert(j["children"]["type"].is_string());
3✔
705
    std::string type = j["children"]["type"];
3✔
706
    if (type == "sequence") {
3✔
707
        json_to_sequence(j["children"], builder, while_node.root());
3✔
708
    } else {
3✔
709
        throw std::runtime_error("Unknown child type");
×
710
    }
711
}
3✔
712

713
void JSONSerializer::json_to_break_node(const nlohmann::json& j,
1✔
714
                                        builder::StructuredSDFGBuilder& builder,
715
                                        structured_control_flow::Sequence& parent) {
716
    assert(j.contains("type"));
1✔
717
    assert(j["type"].is_string());
1✔
718
    assert(j["type"] == "break");
1✔
719
    builder.add_break(parent);
1✔
720
}
1✔
721

722
void JSONSerializer::json_to_continue_node(const nlohmann::json& j,
1✔
723
                                           builder::StructuredSDFGBuilder& builder,
724
                                           structured_control_flow::Sequence& parent) {
725
    assert(j.contains("type"));
1✔
726
    assert(j["type"].is_string());
1✔
727
    assert(j["type"] == "continue");
1✔
728
    builder.add_continue(parent);
1✔
729
}
1✔
730

731
void JSONSerializer::json_to_kernel_node(const nlohmann::json& j,
1✔
732
                                         builder::StructuredSDFGBuilder& builder,
733
                                         structured_control_flow::Sequence& parent) {
734
    assert(j.contains("type"));
1✔
735
    assert(j["type"].is_string());
1✔
736
    assert(j["type"] == "kernel");
1✔
737
    assert(j.contains("suffix"));
1✔
738
    assert(j["suffix"].is_string());
1✔
739
    assert(j.contains("children"));
1✔
740
    assert(j["children"].is_object());
1✔
741
    auto& kernel_node = builder.add_kernel(parent, j["suffix"]);
1✔
742

743
    assert(j["children"].contains("type"));
1✔
744
    assert(j["children"]["type"].is_string());
1✔
745
    std::string type = j["children"]["type"];
1✔
746
    if (type == "sequence") {
1✔
747
        json_to_sequence(j["children"], builder, kernel_node.root());
1✔
748
    } else {
1✔
749
        throw std::runtime_error("Unknown child type");
×
750
    }
751
}
1✔
752

753
void JSONSerializer::json_to_map_node(const nlohmann::json& j,
1✔
754
                                      builder::StructuredSDFGBuilder& builder,
755
                                      structured_control_flow::Sequence& parent,
756
                                      symbolic::Assignments& assignments) {
757
    assert(j.contains("type"));
1✔
758
    assert(j["type"].is_string());
1✔
759
    assert(j["type"] == "map");
1✔
760
    assert(j.contains("indvar"));
1✔
761
    assert(j["indvar"].is_string());
1✔
762
    assert(j.contains("num_iterations"));
1✔
763
    assert(j["num_iterations"].is_string());
1✔
764
    assert(j.contains("children"));
1✔
765
    assert(j["children"].is_object());
1✔
766
    symbolic::Symbol indvar = symbolic::symbol(j["indvar"]);
1✔
767
    SymEngine::Expression num_iterations(j["num_iterations"]);
1✔
768

769
    auto& map_node = builder.add_map(parent, indvar, num_iterations, assignments);
1✔
770
    assert(j["children"].contains("type"));
1✔
771
    assert(j["children"]["type"].is_string());
1✔
772
    std::string type = j["children"]["type"];
1✔
773
    if (type == "sequence") {
1✔
774
        json_to_sequence(j["children"], builder, map_node.root());
1✔
775
    } else {
1✔
NEW
776
        throw std::runtime_error("Unknown child type");
×
777
    }
778
}
1✔
779

780
void JSONSerializer::json_to_return_node(const nlohmann::json& j,
1✔
781
                                         builder::StructuredSDFGBuilder& builder,
782
                                         structured_control_flow::Sequence& parent,
783
                                         symbolic::Assignments& assignments) {
784
    assert(j.contains("type"));
1✔
785
    assert(j["type"].is_string());
1✔
786
    assert(j["type"] == "return");
1✔
787

788
    builder.add_return(parent, assignments);
1✔
789
}
1✔
790

791
std::unique_ptr<types::IType> JSONSerializer::json_to_type(const nlohmann::json& j) {
33✔
792
    if (j.contains("type")) {
33✔
793
        if (j["type"] == "scalar") {
33✔
794
            // Deserialize scalar type
795
            assert(j.contains("primitive_type"));
27✔
796
            types::PrimitiveType primitive_type = j["primitive_type"];
27✔
797
            assert(j.contains("device_location"));
27✔
798
            types::DeviceLocation device_location = j["device_location"];
27✔
799
            assert(j.contains("address_space"));
27✔
800
            uint address_space = j["address_space"];
27✔
801
            assert(j.contains("initializer"));
27✔
802
            std::string initializer = j["initializer"];
27✔
803
            return std::make_unique<types::Scalar>(primitive_type, device_location, address_space,
27✔
804
                                                   initializer);
805
        } else if (j["type"] == "array") {
33✔
806
            // Deserialize array type
807
            assert(j.contains("element_type"));
2✔
808
            std::unique_ptr<types::IType> member_type = json_to_type(j["element_type"]);
2✔
809
            assert(j.contains("num_elements"));
2✔
810
            std::string num_elements_str = j["num_elements"];
2✔
811
            // Convert num_elements_str to symbolic::Expression
812
            SymEngine::Expression num_elements(num_elements_str);
2✔
813
            assert(j.contains("address_space"));
2✔
814
            uint address_space = j["address_space"];
2✔
815
            assert(j.contains("initializer"));
2✔
816
            std::string initializer = j["initializer"];
2✔
817
            assert(j.contains("device_location"));
2✔
818
            types::DeviceLocation device_location = j["device_location"];
2✔
819
            assert(j.contains("alignment"));
2✔
820
            size_t alignment = j["alignment"];
2✔
821
            return std::make_unique<types::Array>(*member_type, num_elements, device_location,
2✔
822
                                                  address_space, initializer, alignment);
823
        } else if (j["type"] == "pointer") {
6✔
824
            // Deserialize pointer type
825
            assert(j.contains("pointee_type"));
2✔
826
            std::unique_ptr<types::IType> pointee_type = json_to_type(j["pointee_type"]);
2✔
827
            assert(j.contains("address_space"));
2✔
828
            uint address_space = j["address_space"];
2✔
829
            assert(j.contains("initializer"));
2✔
830
            std::string initializer = j["initializer"];
2✔
831
            assert(j.contains("device_location"));
2✔
832
            types::DeviceLocation device_location = j["device_location"];
2✔
833
            return std::make_unique<types::Pointer>(*pointee_type, device_location, address_space,
2✔
834
                                                    initializer);
835
        } else if (j["type"] == "structure") {
4✔
836
            // Deserialize structure type
837
            assert(j.contains("name"));
1✔
838
            std::string name = j["name"];
1✔
839
            assert(j.contains("address_space"));
1✔
840
            uint address_space = j["address_space"];
1✔
841
            assert(j.contains("initializer"));
1✔
842
            std::string initializer = j["initializer"];
1✔
843
            assert(j.contains("device_location"));
1✔
844
            types::DeviceLocation device_location = j["device_location"];
1✔
845
            return std::make_unique<types::Structure>(name, device_location, address_space,
1✔
846
                                                      initializer);
847
        } else if (j["type"] == "function") {
2✔
848
            // Deserialize function type
849
            assert(j.contains("return_type"));
1✔
850
            std::unique_ptr<types::IType> return_type = json_to_type(j["return_type"]);
1✔
851
            assert(j.contains("argument_types"));
1✔
852
            std::vector<std::unique_ptr<types::IType>> argument_types;
1✔
853
            for (const auto& arg : j["argument_types"]) {
3✔
854
                argument_types.push_back(json_to_type(arg));
2✔
855
            }
856
            assert(j.contains("is_var_arg"));
1✔
857
            bool is_var_arg = j["is_var_arg"];
1✔
858
            assert(j.contains("address_space"));
1✔
859
            uint address_space = j["address_space"];
1✔
860
            assert(j.contains("initializer"));
1✔
861
            std::string initializer = j["initializer"];
1✔
862
            assert(j.contains("device_location"));
1✔
863
            types::DeviceLocation device_location = j["device_location"];
1✔
864
            auto function = std::make_unique<types::Function>(
1✔
865
                *return_type, is_var_arg, device_location, address_space, initializer);
1✔
866
            for (const auto& arg : argument_types) {
3✔
867
                function->add_param(*arg);
2✔
868
            }
869
            return function->clone();
1✔
870

871
        } else {
1✔
872
            throw std::runtime_error("Unknown type");
×
873
        }
874
    } else {
875
        throw std::runtime_error("Type not found");
×
876
    }
877
}
33✔
878

879
std::string JSONSerializer::expression(const symbolic::Expression& expr) {
29✔
880
    JSONSymbolicPrinter printer;
29✔
881
    return printer.apply(expr);
29✔
882
};
29✔
883

884
void JSONSymbolicPrinter::bvisit(const SymEngine::Equality& x) {
×
885
    str_ = apply(x.get_args()[0]) + " == " + apply(x.get_args()[1]);
×
886
    str_ = parenthesize(str_);
×
887
};
×
888

889
void JSONSymbolicPrinter::bvisit(const SymEngine::Unequality& x) {
×
890
    str_ = apply(x.get_args()[0]) + " != " + apply(x.get_args()[1]);
×
891
    str_ = parenthesize(str_);
×
892
};
×
893

894
void JSONSymbolicPrinter::bvisit(const SymEngine::LessThan& x) {
×
895
    str_ = apply(x.get_args()[0]) + " <= " + apply(x.get_args()[1]);
×
896
    str_ = parenthesize(str_);
×
897
};
×
898

899
void JSONSymbolicPrinter::bvisit(const SymEngine::StrictLessThan& x) {
2✔
900
    str_ = apply(x.get_args()[0]) + " < " + apply(x.get_args()[1]);
2✔
901
    str_ = parenthesize(str_);
2✔
902
};
2✔
903

904
void JSONSymbolicPrinter::bvisit(const SymEngine::Min& x) {
×
905
    std::ostringstream s;
×
906
    auto container = x.get_args();
×
907
    if (container.size() == 1) {
×
908
        s << apply(*container.begin());
×
909
    } else {
×
910
        s << "min(";
×
911
        s << apply(*container.begin());
×
912

913
        // Recursively apply __daisy_min to the arguments
914
        SymEngine::vec_basic subargs;
×
915
        for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
916
            subargs.push_back(*it);
×
917
        }
×
918
        auto submin = SymEngine::min(subargs);
×
919
        s << ", " << apply(submin);
×
920

921
        s << ")";
×
922
    }
×
923

924
    str_ = s.str();
×
925
};
×
926

927
void JSONSymbolicPrinter::bvisit(const SymEngine::Max& x) {
×
928
    std::ostringstream s;
×
929
    auto container = x.get_args();
×
930
    if (container.size() == 1) {
×
931
        s << apply(*container.begin());
×
932
    } else {
×
933
        s << "max(";
×
934
        s << apply(*container.begin());
×
935

936
        // Recursively apply __daisy_max to the arguments
937
        SymEngine::vec_basic subargs;
×
938
        for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
939
            subargs.push_back(*it);
×
940
        }
×
941
        auto submax = SymEngine::max(subargs);
×
942
        s << ", " << apply(submax);
×
943

944
        s << ")";
×
945
    }
×
946

947
    str_ = s.str();
×
948
};
×
949

950
}  // namespace serializer
951
}  // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc