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

daisytuner / docc / 29726336600

20 Jul 2026 07:59AM UTC coverage: 63.433% (+0.3%) from 63.18%
29726336600

Pull #857

github

web-flow
Merge 129cc05f2 into b57f184e7
Pull Request #857: Added PyTorch frontend

419 of 544 new or added lines in 14 files covered. (77.02%)

1 existing line in 1 file now uncovered.

41004 of 64641 relevant lines covered (63.43%)

977.49 hits per line

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

76.63
/sdfg/src/data_flow/library_nodes/math/tensor/copy_node.cpp
1
#include "sdfg/data_flow/library_nodes/math/tensor/copy_node.h"
2
#include <cstddef>
3
#include <list>
4
#include <memory>
5
#include <nlohmann/json_fwd.hpp>
6
#include <string>
7
#include <unordered_set>
8
#include <vector>
9
#include "sdfg/builder/structured_sdfg_builder.h"
10
#include "sdfg/data_flow/data_flow_graph.h"
11
#include "sdfg/data_flow/data_flow_node.h"
12
#include "sdfg/data_flow/library_node.h"
13
#include "sdfg/data_flow/library_nodes/math/tensor/tensor_layout.h"
14
#include "sdfg/data_flow/library_nodes/math/tensor/tensor_node.h"
15
#include "sdfg/data_flow/memlet.h"
16
#include "sdfg/data_flow/tasklet.h"
17
#include "sdfg/element.h"
18
#include "sdfg/exceptions.h"
19
#include "sdfg/function.h"
20
#include "sdfg/graph/graph.h"
21
#include "sdfg/passes/expansion/lib_node_expander.h"
22
#include "sdfg/serializer/json_serializer.h"
23
#include "sdfg/structured_control_flow/block.h"
24
#include "sdfg/structured_control_flow/sequence.h"
25
#include "sdfg/structured_control_flow/structured_loop.h"
26
#include "sdfg/symbolic/symbolic.h"
27
#include "sdfg/types/scalar.h"
28
#include "sdfg/types/type.h"
29
#include "symengine/symengine_rcp.h"
30

31
namespace sdfg {
32
namespace math {
33
namespace tensor {
34

35
void TensorCopyNode::expand_identity_mode(
36
    passes::LibNodeExpander::AccessNodeExpand& standalone,
37
    builder::StructuredSDFGBuilder& builder,
38
    structured_control_flow::Sequence& sequence
39
) {
2✔
40
    auto& dfg = this->get_parent();
2✔
41
    structured_control_flow::Sequence* current_seq = &sequence;
2✔
42
    int dims = this->layout_x_.dims();
2✔
43
    types::Scalar indvar_type(types::PrimitiveType::UInt64);
2✔
44

45
    data_flow::Subset indvars;
2✔
46
    indvars.reserve(dims);
2✔
47
    for (int i = 0; i < dims; i++) {
4✔
48
        auto indvar_container = builder.find_new_name("_i");
2✔
49
        builder.add_container(indvar_container, indvar_type);
2✔
50
        auto indvar = symbolic::symbol(indvar_container);
2✔
51
        indvars.push_back(indvar);
2✔
52
        auto& map = builder.add_map(
2✔
53
            *current_seq,
2✔
54
            indvar,
2✔
55
            symbolic::Lt(indvar, this->layout_x_.get_dim(i)),
2✔
56
            symbolic::zero(),
2✔
57
            symbolic::add(indvar, symbolic::one()),
2✔
58
            structured_control_flow::ScheduleType_Sequential::create(),
2✔
59
            {},
2✔
60
            this->debug_info_
2✔
61
        );
2✔
62
        current_seq = &map.root();
2✔
63
    }
2✔
64

65
    auto& block = builder.add_block(*current_seq, {}, this->debug_info_);
2✔
66
    auto& x_access = standalone.add_scalar_input_access(block, X_INPUT_IDX);
2✔
67
    auto& y_access = standalone.add_scalar_input_access(block, Y_INPUT_IDX);
2✔
68

69
    auto& tasklet = builder.add_tasklet(block, data_flow::TaskletCode::assign, "_out", {"_in"}, this->debug_info_);
2✔
70

71
    auto* iedge_X = dfg.in_edge_for_connector(*this, "X");
2✔
72
    if (!iedge_X) {
2✔
NEW
73
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector X");
×
NEW
74
    }
×
75
    builder
2✔
76
        .add_computational_memlet(block, x_access, tasklet, "_in", indvars, iedge_X->base_type(), iedge_X->debug_info());
2✔
77

78
    auto* iedge_Y = dfg.in_edge_for_connector(*this, "Y");
2✔
79
    if (!iedge_Y) {
2✔
NEW
80
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector Y");
×
NEW
81
    }
×
82
    builder
2✔
83
        .add_computational_memlet(block, tasklet, "_out", y_access, indvars, iedge_Y->base_type(), iedge_Y->debug_info());
2✔
84
}
2✔
85

86
void TensorCopyNode::expand_permutation_mode(
87
    passes::LibNodeExpander::AccessNodeExpand& standalone,
88
    builder::StructuredSDFGBuilder& builder,
89
    structured_control_flow::Sequence& sequence
90
) {
3✔
91
    int dims = this->layout_x_.dims();
3✔
92
    std::vector<int> mask;
3✔
93
    std::unordered_set<int> used;
3✔
94
    mask.reserve(dims);
3✔
95
    for (int i = 0; i < dims; i++) {
11✔
96
        bool found = false;
8✔
97
        for (int j = 0; j < dims; j++) {
15✔
98
            if (!used.contains(j) && symbolic::eq(this->layout_y_.get_dim(i), this->layout_x_.get_dim(j))) {
15✔
99
                mask.push_back(j);
8✔
100
                used.insert(j);
8✔
101
                found = true;
8✔
102
                break;
8✔
103
            }
8✔
104
        }
15✔
105
        if (!found) {
8✔
NEW
106
            throw InvalidSDFGException(
×
NEW
107
                "TensorCopyNode: Could not find dimension in layout x matching to: " +
×
NEW
108
                this->layout_y_.get_dim(i)->__str__()
×
NEW
109
            );
×
NEW
110
        }
×
111
    }
8✔
112

113
    auto& dfg = this->get_parent();
3✔
114
    structured_control_flow::Sequence* current_seq = &sequence;
3✔
115
    types::Scalar indvar_type(types::PrimitiveType::UInt64);
3✔
116

117
    data_flow::Subset indvars_y;
3✔
118
    indvars_y.reserve(dims);
3✔
119
    for (int i = 0; i < dims; i++) {
11✔
120
        auto indvar_container = builder.find_new_name("_i");
8✔
121
        builder.add_container(indvar_container, indvar_type);
8✔
122
        auto indvar = symbolic::symbol(indvar_container);
8✔
123
        indvars_y.push_back(indvar);
8✔
124
        auto& map = builder.add_map(
8✔
125
            *current_seq,
8✔
126
            indvar,
8✔
127
            symbolic::Lt(indvar, this->layout_y_.get_dim(i)),
8✔
128
            symbolic::zero(),
8✔
129
            symbolic::add(indvar, symbolic::one()),
8✔
130
            structured_control_flow::ScheduleType_Sequential::create(),
8✔
131
            {},
8✔
132
            this->debug_info_
8✔
133
        );
8✔
134
        current_seq = &map.root();
8✔
135
    }
8✔
136

137
    data_flow::Subset indvars_x(dims, SymEngine::null);
3✔
138
    for (int i = 0; i < dims; i++) {
11✔
139
        indvars_x[mask[i]] = indvars_y[i];
8✔
140
    }
8✔
141

142
    auto& block = builder.add_block(*current_seq, {}, this->debug_info_);
3✔
143
    auto& x_access = standalone.add_scalar_input_access(block, X_INPUT_IDX);
3✔
144
    auto& y_access = standalone.add_scalar_input_access(block, Y_INPUT_IDX);
3✔
145

146
    auto& tasklet = builder.add_tasklet(block, data_flow::TaskletCode::assign, "_out", {"_in"}, this->debug_info_);
3✔
147

148
    auto* iedge_X = dfg.in_edge_for_connector(*this, "X");
3✔
149
    if (!iedge_X) {
3✔
NEW
150
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector X");
×
NEW
151
    }
×
152
    builder
3✔
153
        .add_computational_memlet(block, x_access, tasklet, "_in", indvars_x, iedge_X->base_type(), iedge_X->debug_info());
3✔
154

155
    auto* iedge_Y = dfg.in_edge_for_connector(*this, "Y");
3✔
156
    if (!iedge_Y) {
3✔
NEW
157
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector Y");
×
NEW
158
    }
×
159
    builder.add_computational_memlet(
3✔
160
        block, tasklet, "_out", y_access, indvars_y, iedge_Y->base_type(), iedge_Y->debug_info()
3✔
161
    );
3✔
162
}
3✔
163

164
void TensorCopyNode::expand_squeeze_mode(
165
    passes::LibNodeExpander::AccessNodeExpand& standalone,
166
    builder::StructuredSDFGBuilder& builder,
167
    structured_control_flow::Sequence& sequence
168
) {
4✔
169
    bool x_bigger = this->layout_x_.dims() > this->layout_y_.dims();
4✔
170
    TensorLayout& bigger = x_bigger ? this->layout_x_ : this->layout_y_;
4✔
171
    TensorLayout& smaller = x_bigger ? this->layout_y_ : this->layout_x_;
4✔
172

173
    auto& dfg = this->get_parent();
4✔
174
    structured_control_flow::Sequence* current_seq = &sequence;
4✔
175
    int smaller_dims = smaller.dims();
4✔
176
    types::Scalar indvar_type(types::PrimitiveType::UInt64);
4✔
177

178
    data_flow::Subset indvars_smaller;
4✔
179
    indvars_smaller.reserve(smaller_dims);
4✔
180
    for (int i = 0; i < smaller_dims; i++) {
12✔
181
        auto indvar_container = builder.find_new_name("_i");
8✔
182
        builder.add_container(indvar_container, indvar_type);
8✔
183
        auto indvar = symbolic::symbol(indvar_container);
8✔
184
        indvars_smaller.push_back(indvar);
8✔
185
        auto& map = builder.add_map(
8✔
186
            *current_seq,
8✔
187
            indvar,
8✔
188
            symbolic::Lt(indvar, smaller.get_dim(i)),
8✔
189
            symbolic::zero(),
8✔
190
            symbolic::add(indvar, symbolic::one()),
8✔
191
            structured_control_flow::ScheduleType_Sequential::create(),
8✔
192
            {},
8✔
193
            this->debug_info_
8✔
194
        );
8✔
195
        current_seq = &map.root();
8✔
196
    }
8✔
197

198
    int bigger_dims = bigger.dims();
4✔
199
    data_flow::Subset indvars_bigger;
4✔
200
    indvars_bigger.reserve(bigger_dims);
4✔
201
    for (int i = 0, j = 0; i < bigger_dims; i++) {
20✔
202
        if (j >= smaller_dims || !symbolic::eq(bigger.get_dim(i), smaller.get_dim(j))) {
16✔
203
            if (symbolic::eq(bigger.get_dim(i), symbolic::one())) {
8✔
204
                indvars_bigger.push_back(symbolic::zero());
8✔
205
            } else {
8✔
NEW
206
                throw InvalidSDFGException(
×
NEW
207
                    "TensorCopyNode: Got not matching dimension that is not one: " + std::to_string(i) + " in " +
×
NEW
208
                    bigger.toStr()
×
NEW
209
                );
×
NEW
210
            }
×
211
        } else {
8✔
212
            indvars_bigger.push_back(indvars_smaller[j]);
8✔
213
            j++;
8✔
214
        }
8✔
215
    }
16✔
216

217
    auto& block = builder.add_block(*current_seq, {}, this->debug_info_);
4✔
218
    auto& x_access = standalone.add_scalar_input_access(block, X_INPUT_IDX);
4✔
219
    auto& y_access = standalone.add_scalar_input_access(block, Y_INPUT_IDX);
4✔
220

221
    auto& tasklet = builder.add_tasklet(block, data_flow::TaskletCode::assign, "_out", {"_in"}, this->debug_info_);
4✔
222

223
    auto* iedge_X = dfg.in_edge_for_connector(*this, "X");
4✔
224
    if (!iedge_X) {
4✔
NEW
225
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector X");
×
NEW
226
    }
×
227
    builder.add_computational_memlet(
4✔
228
        block,
4✔
229
        x_access,
4✔
230
        tasklet,
4✔
231
        "_in",
4✔
232
        (x_bigger ? indvars_bigger : indvars_smaller),
4✔
233
        iedge_X->base_type(),
4✔
234
        iedge_X->debug_info()
4✔
235
    );
4✔
236

237
    auto* iedge_Y = dfg.in_edge_for_connector(*this, "Y");
4✔
238
    if (!iedge_Y) {
4✔
NEW
239
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector Y");
×
NEW
240
    }
×
241
    builder.add_computational_memlet(
4✔
242
        block,
4✔
243
        tasklet,
4✔
244
        "_out",
4✔
245
        y_access,
4✔
246
        (x_bigger ? indvars_smaller : indvars_bigger),
4✔
247
        iedge_Y->base_type(),
4✔
248
        iedge_Y->debug_info()
4✔
249
    );
4✔
250
}
4✔
251

252
void TensorCopyNode::expand_reshape_mode(
253
    passes::LibNodeExpander::AccessNodeExpand& standalone,
254
    builder::StructuredSDFGBuilder& builder,
255
    structured_control_flow::Sequence& sequence
256
) {
8✔
257
    auto total_elements = this->layout_x_.total_elements();
8✔
258
    if (!symbolic::eq(total_elements, this->layout_y_.total_elements())) {
8✔
NEW
259
        throw InvalidSDFGException(
×
NEW
260
            "TensorCopyNode: Cannot expand because number of elements of layouts do not match: " +
×
NEW
261
            total_elements->__str__() + " != " + this->layout_y_.total_elements()->__str__()
×
NEW
262
        );
×
NEW
263
    }
×
264

265
    auto& dfg = this->get_parent();
8✔
266
    types::Scalar indvar_type(types::PrimitiveType::UInt64);
8✔
267
    auto indvar_container = builder.find_new_name("_i");
8✔
268
    builder.add_container(indvar_container, indvar_type);
8✔
269
    auto indvar = symbolic::symbol(indvar_container);
8✔
270
    auto& map = builder.add_map(
8✔
271
        sequence,
8✔
272
        indvar,
8✔
273
        symbolic::Lt(indvar, total_elements),
8✔
274
        symbolic::zero(),
8✔
275
        symbolic::add(indvar, symbolic::one()),
8✔
276
        structured_control_flow::ScheduleType_Sequential::create(),
8✔
277
        {},
8✔
278
        this->debug_info_
8✔
279
    );
8✔
280

281
    int x_dims = this->layout_x_.dims();
8✔
282
    data_flow::Subset indvars_x;
8✔
283
    indvars_x.reserve(x_dims);
8✔
284
    if (x_dims > 1) {
8✔
285
        std::list<symbolic::Expression> indvars_x_list;
6✔
286
        symbolic::Expression divisor = symbolic::one();
6✔
287
        for (int i = x_dims - 1; i >= 0; i--) {
20✔
288
            auto dim = this->layout_x_.get_dim(i);
14✔
289
            auto divison = symbolic::div(indvar, divisor);
14✔
290
            if (i == 0) {
14✔
291
                indvars_x_list.push_front(divison);
6✔
292
            } else {
8✔
293
                indvars_x_list.push_front(symbolic::mod(divison, dim));
8✔
294
            }
8✔
295
            divisor = symbolic::mul(divisor, dim);
14✔
296
        }
14✔
297
        indvars_x.insert(indvars_x.end(), indvars_x_list.begin(), indvars_x_list.end());
6✔
298
    } else {
6✔
299
        indvars_x.push_back(indvar);
2✔
300
    }
2✔
301

302
    int y_dims = this->layout_y_.dims();
8✔
303
    data_flow::Subset indvars_y;
8✔
304
    indvars_y.reserve(y_dims);
8✔
305
    if (y_dims > 1) {
8✔
306
        std::list<symbolic::Expression> indvars_y_list;
6✔
307
        symbolic::Expression divisor = symbolic::one();
6✔
308
        for (int i = y_dims - 1; i >= 0; i--) {
20✔
309
            auto dim = this->layout_y_.get_dim(i);
14✔
310
            auto division = symbolic::div(indvar, divisor);
14✔
311
            if (i == 0) {
14✔
312
                indvars_y_list.push_front(division);
6✔
313
            } else {
8✔
314
                indvars_y_list.push_front(symbolic::mod(division, dim));
8✔
315
            }
8✔
316
            divisor = symbolic::mul(divisor, dim);
14✔
317
        }
14✔
318
        indvars_y.insert(indvars_y.end(), indvars_y_list.begin(), indvars_y_list.end());
6✔
319
    } else {
6✔
320
        indvars_y.push_back(indvar);
2✔
321
    }
2✔
322

323
    auto& block = builder.add_block(map.root(), {}, this->debug_info_);
8✔
324
    auto& x_access = standalone.add_scalar_input_access(block, X_INPUT_IDX);
8✔
325
    auto& y_access = standalone.add_scalar_input_access(block, Y_INPUT_IDX);
8✔
326

327
    auto& tasklet = builder.add_tasklet(block, data_flow::TaskletCode::assign, "_out", {"_in"}, this->debug_info_);
8✔
328

329
    auto* iedge_X = dfg.in_edge_for_connector(*this, "X");
8✔
330
    if (!iedge_X) {
8✔
NEW
331
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector X");
×
NEW
332
    }
×
333
    builder
8✔
334
        .add_computational_memlet(block, x_access, tasklet, "_in", indvars_x, iedge_X->base_type(), iedge_X->debug_info());
8✔
335

336
    auto* iedge_Y = dfg.in_edge_for_connector(*this, "Y");
8✔
337
    if (!iedge_Y) {
8✔
NEW
338
        throw InvalidSDFGException("TensorCopyNode: Cannot get in edge for connector Y");
×
NEW
339
    }
×
340
    builder.add_computational_memlet(
8✔
341
        block, tasklet, "_out", y_access, indvars_y, iedge_Y->base_type(), iedge_Y->debug_info()
8✔
342
    );
8✔
343
}
8✔
344

345
TensorCopyNode::TensorCopyNode(
346
    size_t element_id,
347
    const DebugInfo& debug_info,
348
    const graph::Vertex vertex,
349
    data_flow::DataFlowGraph& parent,
350
    const TensorLayout& layout_x,
351
    const TensorLayout& layout_y,
352
    const data_flow::ImplementationType& impl_type
353
)
354
    : TensorNode(element_id, debug_info, vertex, parent, LibraryNodeType_TensorCopy, {}, {"X", "Y"}, impl_type),
17✔
355
      layout_x_(layout_x), layout_y_(layout_y) {}
17✔
356

NEW
357
const TensorLayout& TensorCopyNode::layout_x() const { return this->layout_x_; }
×
358

NEW
359
const TensorLayout& TensorCopyNode::layout_y() const { return this->layout_y_; }
×
360

361
bool TensorCopyNode::is_identity_mode() const {
32✔
362
    int dims = this->layout_x_.dims();
32✔
363
    if (dims != this->layout_y_.dims()) {
32✔
364
        return false;
16✔
365
    }
16✔
366
    for (int i = 0; i < dims; i++) {
20✔
367
        if (!symbolic::eq(this->layout_x_.get_dim(i), this->layout_y_.get_dim(i))) {
18✔
368
            return false;
14✔
369
        }
14✔
370
    }
18✔
371
    return true;
2✔
372
}
16✔
373

374
bool TensorCopyNode::is_permutation_mode() const {
15✔
375
    if (this->is_identity_mode()) {
15✔
NEW
376
        return false;
×
NEW
377
    }
×
378
    int dims = this->layout_x_.dims();
15✔
379
    if (dims != this->layout_y_.dims()) {
15✔
380
        return false;
8✔
381
    }
8✔
382
    for (int i = 0; i < dims; i++) {
15✔
383
        bool found = false;
12✔
384
        for (int j = 0; j < dims; j++) {
25✔
385
            if (symbolic::eq(this->layout_x_.get_dim(i), this->layout_y_.get_dim(j))) {
21✔
386
                found = true;
8✔
387
                break;
8✔
388
            }
8✔
389
        }
21✔
390
        if (!found) {
12✔
391
            return false;
4✔
392
        }
4✔
393
    }
12✔
394
    return true;
3✔
395
}
7✔
396

397
bool TensorCopyNode::is_squeeze_mode() const {
12✔
398
    int dims_x = this->layout_x_.dims();
12✔
399
    int dims_y = this->layout_y_.dims();
12✔
400
    symbolic::MultiExpression bigger_shape, smaller_shape;
12✔
401
    if (dims_x < dims_y) {
12✔
402
        bigger_shape = this->layout_y_.shape();
4✔
403
        smaller_shape = this->layout_x_.shape();
4✔
404
    } else if (dims_x > dims_y) {
8✔
405
        bigger_shape = this->layout_x_.shape();
4✔
406
        smaller_shape = this->layout_y_.shape();
4✔
407
    } else {
4✔
408
        return false;
4✔
409
    }
4✔
410

411
    int offset = 0;
8✔
412
    for (int i = 0; i < bigger_shape.size(); i++) {
24✔
413
        if (i - offset >= smaller_shape.size() || !symbolic::eq(bigger_shape[i], smaller_shape[i - offset])) {
20✔
414
            if (symbolic::eq(bigger_shape[i], symbolic::one())) {
12✔
415
                offset++;
8✔
416
            } else {
8✔
417
                return false;
4✔
418
            }
4✔
419
        }
12✔
420
    }
20✔
421
    return true;
4✔
422
}
8✔
423

NEW
424
bool TensorCopyNode::is_reshape_mode() const {
×
NEW
425
    return !this->is_identity_mode() && !this->is_permutation_mode() && !this->is_squeeze_mode();
×
NEW
426
}
×
427

428
void TensorCopyNode::validate(const Function& function) const {
17✔
429
    TensorNode::validate(function);
17✔
430

431
    auto& graph = this->get_parent();
17✔
432

433
    if (graph.in_degree(*this) != 2) {
17✔
NEW
434
        throw InvalidSDFGException(
×
NEW
435
            "TensorCopyNode: Expected exactly 2 inputs (X, Y) but got: " + std::to_string(graph.in_degree(*this))
×
NEW
436
        );
×
NEW
437
    }
×
438
    if (graph.out_degree(*this) != 0) {
17✔
NEW
439
        throw InvalidSDFGException(
×
NEW
440
            "TensorCopyNode: Expected no outputs but got: " + std::to_string(graph.out_degree(*this))
×
NEW
441
        );
×
NEW
442
    }
×
443

444
    // Check that both layouts have the same number of elements
445
    auto x_num_elements = this->layout_x_.total_elements();
17✔
446
    auto y_num_elements = this->layout_y_.total_elements();
17✔
447
    if (!symbolic::eq(x_num_elements, y_num_elements)) {
17✔
NEW
448
        throw InvalidSDFGException(
×
NEW
449
            "TensorCopyNode: Number of elements of layouts do not match: " + x_num_elements->__str__() +
×
NEW
450
            " != " + y_num_elements->__str__()
×
NEW
451
        );
×
NEW
452
    }
×
453
}
17✔
454

455
bool TensorCopyNode::supports_integer_types() const { return true; }
17✔
456

457
using Dir = passes::LibNodeExpander::InputUse;
458

459
passes::LibNodeExpander::ExpandOutcome TensorCopyNode::
460
    expand(passes::LibNodeExpander::ExpandContext& context, structured_control_flow::Block& block) {
17✔
461
    auto standalone = context.replacement_requires_access_nodes({Dir::IndirectRead, Dir::IndirectWrite});
17✔
462

463
    if (!standalone) {
17✔
NEW
464
        return context.unable();
×
NEW
465
    }
×
466

467
    auto& builder = standalone->builder();
17✔
468

469
    // Add a graph after the current block
470
    auto& new_sequence = standalone->replace_with_sequence();
17✔
471

472
    if (this->is_identity_mode()) {
17✔
473
        this->expand_identity_mode(*standalone, builder, new_sequence);
2✔
474
    } else if (this->is_permutation_mode()) {
15✔
475
        this->expand_permutation_mode(*standalone, builder, new_sequence);
3✔
476
    } else if (this->is_squeeze_mode()) {
12✔
477
        this->expand_squeeze_mode(*standalone, builder, new_sequence);
4✔
478
    } else {
8✔
479
        this->expand_reshape_mode(*standalone, builder, new_sequence);
8✔
480
    }
8✔
481

482
    return standalone->successfully_expanded();
17✔
483
}
17✔
484

NEW
485
std::string TensorCopyNode::toStr() const {
×
NEW
486
    return "TensorCopyNode(X: " + this->layout_x_.toStr() + ", Y: " + this->layout_y_.toStr() + ")";
×
NEW
487
}
×
488

NEW
489
symbolic::SymbolSet TensorCopyNode::symbols() const {
×
NEW
490
    symbolic::SymbolSet syms;
×
NEW
491
    this->layout_x_.collect_symbols(syms);
×
NEW
492
    this->layout_y_.collect_symbols(syms);
×
NEW
493
    return syms;
×
NEW
494
}
×
495

NEW
496
symbolic::Expression TensorCopyNode::flop() const { return symbolic::zero(); }
×
497

498
std::unique_ptr<data_flow::DataFlowNode> TensorCopyNode::
NEW
499
    clone(size_t element_id, const graph::Vertex vertex, data_flow::DataFlowGraph& parent) const {
×
NEW
500
    return std::make_unique<TensorCopyNode>(
×
NEW
501
        element_id, this->debug_info_, vertex, parent, this->layout_x_, this->layout_y_, this->implementation_type_
×
NEW
502
    );
×
NEW
503
}
×
504

NEW
505
void TensorCopyNode::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
×
NEW
506
    this->layout_x_.replace_symbols(old_expression, new_expression);
×
NEW
507
    this->layout_y_.replace_symbols(old_expression, new_expression);
×
NEW
508
}
×
509

NEW
510
void TensorCopyNode::replace(const symbolic::ExpressionMapping& replacements) {
×
NEW
511
    this->layout_x_.replace_symbols(replacements);
×
NEW
512
    this->layout_y_.replace_symbols(replacements);
×
NEW
513
}
×
514

NEW
515
nlohmann::json TensorCopyNodeSerializer::serialize(const data_flow::LibraryNode& library_node) {
×
NEW
516
    const auto& copy_node = static_cast<const TensorCopyNode&>(library_node);
×
NEW
517
    nlohmann::json j;
×
518

NEW
519
    j["code"] = copy_node.code().value();
×
520

NEW
521
    serializer::JSONSerializer serializer;
×
NEW
522
    copy_node.layout_x().serialize_to_json(j["layout_x"]);
×
NEW
523
    copy_node.layout_y().serialize_to_json(j["layout_y"]);
×
524

NEW
525
    return j;
×
NEW
526
}
×
527

528
data_flow::LibraryNode& TensorCopyNodeSerializer::deserialize(
529
    const nlohmann::json& j, builder::StructuredSDFGBuilder& builder, structured_control_flow::Block& parent
NEW
530
) {
×
NEW
531
    assert(j.contains("element_id"));
×
NEW
532
    assert(j.contains("code"));
×
NEW
533
    assert(j.contains("layout_x"));
×
NEW
534
    assert(j.contains("layout_y"));
×
NEW
535
    assert(j.contains("debug_info"));
×
536

NEW
537
    TensorLayout layout_x = TensorLayout::deserialize_from_json(j.at("layout_x"));
×
NEW
538
    TensorLayout layout_y = TensorLayout::deserialize_from_json(j.at("layout_y"));
×
539

NEW
540
    sdfg::serializer::JSONSerializer serializer;
×
NEW
541
    DebugInfo debug_info = serializer.json_to_debug_info(j.at("debug_info"));
×
542

NEW
543
    return builder.add_library_node<TensorCopyNode>(parent, debug_info, layout_x, layout_y);
×
NEW
544
}
×
545

546
} // namespace tensor
547
} // namespace math
548
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc