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

daisytuner / sdfglib / 20770413849

06 Jan 2026 10:50PM UTC coverage: 62.168% (+21.4%) from 40.764%
20770413849

push

github

web-flow
Merge pull request #433 from daisytuner/clang-coverage

updates clang coverage flags

14988 of 24109 relevant lines covered (62.17%)

88.57 hits per line

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

82.3
/src/symbolic/utils.cpp
1
#include "sdfg/symbolic/utils.h"
2

3
#include <isl/ctx.h>
4
#include <isl/set.h>
5
#include <isl/space.h>
6

7
#include "sdfg/builder/sdfg_builder.h"
8
#include "sdfg/codegen/language_extensions/c_language_extension.h"
9
#include "sdfg/symbolic/assumptions.h"
10
#include "sdfg/symbolic/extreme_values.h"
11
#include "sdfg/symbolic/polynomials.h"
12
#include "sdfg/symbolic/symbolic.h"
13

14
namespace sdfg {
15
namespace symbolic {
16

17
builder::SDFGBuilder builder("sdfg", FunctionType_CPU);
18
codegen::CSymbolicPrinter c_printer(builder.subject(), "", false);
19

20
std::string expression_to_map_str(const MultiExpression& expr, const Assumptions& assums) {
72✔
21
    // Get all symbols
22
    symbolic::SymbolSet syms;
72✔
23
    for (auto& expr : expr) {
72✔
24
        auto syms_expr = symbolic::atoms(expr);
72✔
25
        syms.insert(syms_expr.begin(), syms_expr.end());
72✔
26
    }
72✔
27

28
    // Distinguish between dimensions and parameters
29
    std::vector<std::string> dimensions;
72✔
30
    SymbolSet dimensions_syms;
72✔
31
    std::vector<std::string> parameters;
72✔
32
    SymbolSet parameters_syms;
72✔
33
    for (auto& sym : syms) {
72✔
34
        if (assums.find(sym) == assums.end() && assums.at(sym).constant()) {
18✔
35
            if (parameters_syms.find(sym) != parameters_syms.end()) {
×
36
                continue;
×
37
            }
×
38
            parameters.push_back(sym->get_name());
×
39
            parameters_syms.insert(sym);
×
40
        } else {
18✔
41
            if (dimensions_syms.find(sym) != dimensions_syms.end()) {
18✔
42
                continue;
×
43
            }
×
44
            dimensions.push_back(sym->get_name());
18✔
45
            dimensions_syms.insert(sym);
18✔
46
        }
18✔
47
    }
18✔
48

49
    // Generate constraints
50
    SymbolSet seen;
72✔
51
    auto constraints_syms = generate_constraints(syms, assums, seen);
72✔
52

53
    // Extend parameters with additional symbols from constraints
54
    for (auto& con : constraints_syms) {
72✔
55
        auto con_syms = symbolic::atoms(con);
60✔
56
        for (auto& con_sym : con_syms) {
84✔
57
            if (dimensions_syms.find(con_sym) == dimensions_syms.end()) {
84✔
58
                if (parameters_syms.find(con_sym) != parameters_syms.end()) {
40✔
59
                    continue;
22✔
60
                }
22✔
61
                parameters.push_back(con_sym->get_name());
18✔
62
                parameters_syms.insert(con_sym);
18✔
63
            }
18✔
64
        }
84✔
65
    }
60✔
66

67
    // Define map
68
    std::stringstream map_ss;
72✔
69
    if (!parameters.empty()) {
72✔
70
        std::sort(parameters.begin(), parameters.end());
10✔
71
        map_ss << "[";
10✔
72
        map_ss << helpers::join(parameters, ", ");
10✔
73
        map_ss << "] -> ";
10✔
74
    }
10✔
75
    map_ss << "{ [" + helpers::join(dimensions, ", ") + "] -> [";
72✔
76
    for (size_t i = 0; i < expr.size(); i++) {
144✔
77
        auto dim = expr[i];
72✔
78
        map_ss << c_printer.apply(dim);
72✔
79
        if (i < expr.size() - 1) {
72✔
80
            map_ss << ", ";
×
81
        }
×
82
    }
72✔
83
    map_ss << "] ";
72✔
84

85
    std::vector<std::string> constraints;
72✔
86
    for (auto& con : constraints_syms) {
72✔
87
        auto con_str = constraint_to_isl_str(con);
60✔
88
        if (!con_str.empty()) {
60✔
89
            constraints.push_back(con_str);
52✔
90
        }
52✔
91
    }
60✔
92
    for (auto& dim : dimensions) {
72✔
93
        auto sym = symbolic::symbol(dim);
18✔
94
        auto map_func = assums.at(sym).map();
18✔
95
        if (map_func == SymEngine::null) {
18✔
96
            continue;
14✔
97
        }
14✔
98
        if (!SymEngine::is_a<SymEngine::Add>(*map_func)) {
4✔
99
            continue;
×
100
        }
×
101
        auto args = SymEngine::rcp_static_cast<const SymEngine::Add>(map_func)->get_args();
4✔
102
        if (args.size() != 2) {
4✔
103
            continue;
×
104
        }
×
105
        auto arg0 = args[0];
4✔
106
        auto arg1 = args[1];
4✔
107
        if (!symbolic::eq(arg0, symbolic::symbol(dim))) {
4✔
108
            arg0 = args[1];
4✔
109
            arg1 = args[0];
4✔
110
        }
4✔
111
        if (!symbolic::eq(arg0, symbolic::symbol(dim))) {
4✔
112
            continue;
×
113
        }
×
114
        if (!SymEngine::is_a<SymEngine::Integer>(*arg1)) {
4✔
115
            continue;
×
116
        }
×
117
        if (symbolic::eq(arg1, symbolic::one())) {
4✔
118
            continue;
4✔
119
        }
4✔
120
        auto lb = assums.at(sym).lower_bound_deprecated();
×
121
        if (!SymEngine::is_a<SymEngine::Integer>(*lb)) {
×
122
            continue;
×
123
        }
×
124

125
        std::string iter = "__daisy_iterator_" + dim;
×
126
        std::string con = "exists " + iter + " : " + dim + " = " + c_printer.apply(lb) + " + " + iter + " * " +
×
127
                          c_printer.apply(arg1);
×
128
        constraints.push_back(con);
×
129
    }
×
130
    if (!constraints.empty()) {
72✔
131
        map_ss << " : ";
18✔
132
        map_ss << helpers::join(constraints, " and ");
18✔
133
    }
18✔
134

135
    map_ss << " }";
72✔
136

137
    std::string map = map_ss.str();
72✔
138
    return map;
72✔
139
}
72✔
140

141
std::tuple<std::string, std::string, std::string> expressions_to_intersection_map_str(
142
    const MultiExpression& expr1,
143
    const MultiExpression& expr2,
144
    const Symbol indvar,
145
    const Assumptions& assums1,
146
    const Assumptions& assums2
147
) {
58✔
148
    // Get all symbols
149
    symbolic::SymbolSet syms;
58✔
150
    for (auto& expr : expr1) {
72✔
151
        auto syms_expr = symbolic::atoms(expr);
72✔
152
        syms.insert(syms_expr.begin(), syms_expr.end());
72✔
153
    }
72✔
154
    for (auto& expr : expr2) {
72✔
155
        auto syms_expr = symbolic::atoms(expr);
72✔
156
        syms.insert(syms_expr.begin(), syms_expr.end());
72✔
157
    }
72✔
158

159
    // Distinguish between dimensions and parameters
160
    std::vector<std::string> dimensions;
58✔
161
    SymbolSet dimensions_syms;
58✔
162
    std::vector<std::string> parameters;
58✔
163
    SymbolSet parameters_syms;
58✔
164
    for (auto& sym : syms) {
81✔
165
        if (sym->get_name() != indvar->get_name() && assums1.at(sym).constant() && assums2.at(sym).constant()) {
81✔
166
            if (parameters_syms.find(sym) != parameters_syms.end()) {
12✔
167
                continue;
×
168
            }
×
169
            parameters.push_back(sym->get_name());
12✔
170
            parameters_syms.insert(sym);
12✔
171
        } else {
69✔
172
            if (dimensions_syms.find(sym) != dimensions_syms.end()) {
69✔
173
                continue;
×
174
            }
×
175
            dimensions.push_back(sym->get_name());
69✔
176
            dimensions_syms.insert(sym);
69✔
177
        }
69✔
178
    }
81✔
179

180
    // Generate constraints
181
    SymbolSet seen;
58✔
182
    auto constraints_syms_1 = generate_constraints(syms, assums1, seen);
58✔
183
    seen.clear();
58✔
184
    auto constraints_syms_2 = generate_constraints(syms, assums2, seen);
58✔
185

186
    // Extend parameters with additional symbols from constraints
187
    for (auto& con : constraints_syms_1) {
342✔
188
        auto con_syms = symbolic::atoms(con);
342✔
189
        for (auto& con_sym : con_syms) {
455✔
190
            if (dimensions_syms.find(con_sym) == dimensions_syms.end()) {
455✔
191
                if (parameters_syms.find(con_sym) != parameters_syms.end()) {
248✔
192
                    continue;
185✔
193
                }
185✔
194
                parameters.push_back(con_sym->get_name());
63✔
195
                parameters_syms.insert(con_sym);
63✔
196
            }
63✔
197
        }
455✔
198
    }
342✔
199
    for (auto& con : constraints_syms_2) {
344✔
200
        auto con_syms = symbolic::atoms(con);
344✔
201
        for (auto& con_sym : con_syms) {
458✔
202
            if (dimensions_syms.find(con_sym) == dimensions_syms.end()) {
458✔
203
                if (parameters_syms.find(con_sym) != parameters_syms.end()) {
248✔
204
                    continue;
248✔
205
                }
248✔
206
                parameters.push_back(con_sym->get_name());
×
207
                parameters_syms.insert(con_sym);
×
208
            }
×
209
        }
458✔
210
    }
344✔
211

212
    // Define two maps
213
    std::stringstream map_1_ss;
58✔
214
    std::stringstream map_2_ss;
58✔
215
    if (!parameters.empty()) {
58✔
216
        map_1_ss << "[";
50✔
217
        map_1_ss << helpers::join(parameters, ", ");
50✔
218
        map_1_ss << "] -> ";
50✔
219
        map_2_ss << "[";
50✔
220
        map_2_ss << helpers::join(parameters, ", ");
50✔
221
        map_2_ss << "] -> ";
50✔
222
    }
50✔
223
    map_1_ss << "{ [";
58✔
224
    map_2_ss << "{ [";
58✔
225
    for (size_t i = 0; i < dimensions.size(); i++) {
127✔
226
        map_1_ss << dimensions[i] + "_1";
69✔
227
        map_2_ss << dimensions[i] + "_2";
69✔
228
        if (i < dimensions.size() - 1) {
69✔
229
            map_1_ss << ", ";
20✔
230
            map_2_ss << ", ";
20✔
231
        }
20✔
232
    }
69✔
233
    map_1_ss << "] -> [";
58✔
234
    map_2_ss << "] -> [";
58✔
235
    for (size_t i = 0; i < expr1.size(); i++) {
130✔
236
        auto dim = expr1[i];
72✔
237
        for (auto& iter : dimensions) {
113✔
238
            dim = symbolic::subs(dim, symbolic::symbol(iter), symbolic::symbol(iter + "_1"));
113✔
239
        }
113✔
240
        map_1_ss << c_printer.apply(dim);
72✔
241
        if (i < expr1.size() - 1) {
72✔
242
            map_1_ss << ", ";
14✔
243
        }
14✔
244
    }
72✔
245
    for (size_t i = 0; i < expr2.size(); i++) {
130✔
246
        auto dim = expr2[i];
72✔
247
        for (auto& iter : dimensions) {
113✔
248
            dim = symbolic::subs(dim, symbolic::symbol(iter), symbolic::symbol(iter + "_2"));
113✔
249
        }
113✔
250
        map_2_ss << c_printer.apply(dim);
72✔
251
        if (i < expr2.size() - 1) {
72✔
252
            map_2_ss << ", ";
14✔
253
        }
14✔
254
    }
72✔
255
    map_1_ss << "] ";
58✔
256
    map_2_ss << "] ";
58✔
257

258
    std::vector<std::string> constraints_1;
58✔
259
    // Add bounds
260
    for (auto& con : constraints_syms_1) {
342✔
261
        auto con_1 = con;
342✔
262
        for (auto& iter : dimensions) {
565✔
263
            con_1 = symbolic::subs(con_1, symbolic::symbol(iter), symbolic::symbol(iter + "_1"));
565✔
264
        }
565✔
265
        auto con_str_1 = constraint_to_isl_str(con_1);
342✔
266
        if (con_str_1.empty()) {
342✔
267
            continue;
54✔
268
        }
54✔
269
        constraints_1.push_back(con_str_1);
288✔
270
    }
288✔
271
    for (auto& dim : dimensions) {
69✔
272
        auto sym = symbolic::symbol(dim);
69✔
273
        auto map_func = assums1.at(sym).map();
69✔
274
        if (map_func == SymEngine::null) {
69✔
275
            continue;
2✔
276
        }
2✔
277
        if (!SymEngine::is_a<SymEngine::Add>(*map_func)) {
67✔
278
            continue;
×
279
        }
×
280
        auto args = SymEngine::rcp_static_cast<const SymEngine::Add>(map_func)->get_args();
67✔
281
        if (args.size() != 2) {
67✔
282
            continue;
×
283
        }
×
284
        auto arg0 = args[0];
67✔
285
        auto arg1 = args[1];
67✔
286
        if (!symbolic::eq(arg0, symbolic::symbol(dim))) {
67✔
287
            arg0 = args[1];
67✔
288
            arg1 = args[0];
67✔
289
        }
67✔
290
        if (!symbolic::eq(arg0, symbolic::symbol(dim))) {
67✔
291
            continue;
×
292
        }
×
293
        if (!SymEngine::is_a<SymEngine::Integer>(*arg1)) {
67✔
294
            continue;
×
295
        }
×
296
        if (symbolic::eq(arg1, symbolic::one())) {
67✔
297
            continue;
65✔
298
        }
65✔
299
        auto lb = assums2.at(sym).lower_bound_deprecated();
2✔
300
        if (!SymEngine::is_a<SymEngine::Integer>(*lb)) {
2✔
301
            continue;
×
302
        }
×
303

304
        std::string dim1 = dim + "_1";
2✔
305
        std::string iter = "__daisy_iterator_" + dim1;
2✔
306
        std::string con = "exists " + iter + " : " + dim1 + " = " + c_printer.apply(lb) + " + " + iter + " * " +
2✔
307
                          c_printer.apply(arg1);
2✔
308
        constraints_1.push_back(con);
2✔
309
    }
2✔
310
    if (!constraints_1.empty()) {
58✔
311
        map_1_ss << " : ";
51✔
312
        map_1_ss << helpers::join(constraints_1, " and ");
51✔
313
    }
51✔
314
    map_1_ss << " }";
58✔
315

316
    std::vector<std::string> constraints_2;
58✔
317
    for (auto& con : constraints_syms_2) {
344✔
318
        auto con_2 = con;
344✔
319
        for (auto& iter : dimensions) {
569✔
320
            con_2 = symbolic::subs(con_2, symbolic::symbol(iter), symbolic::symbol(iter + "_2"));
569✔
321
        }
569✔
322
        auto con_str_2 = constraint_to_isl_str(con_2);
344✔
323
        if (con_str_2.empty()) {
344✔
324
            continue;
55✔
325
        }
55✔
326
        constraints_2.push_back(con_str_2);
289✔
327
    }
289✔
328
    for (auto& dim : dimensions) {
69✔
329
        auto sym = symbolic::symbol(dim);
69✔
330
        auto map_func = assums2.at(sym).map();
69✔
331
        if (map_func.is_null()) {
69✔
332
            continue;
1✔
333
        }
1✔
334
        if (!SymEngine::is_a<SymEngine::Add>(*map_func)) {
68✔
335
            continue;
×
336
        }
×
337
        auto args = SymEngine::rcp_static_cast<const SymEngine::Add>(map_func)->get_args();
68✔
338
        if (args.size() != 2) {
68✔
339
            continue;
×
340
        }
×
341
        auto arg0 = args[0];
68✔
342
        auto arg1 = args[1];
68✔
343
        if (!symbolic::eq(arg0, symbolic::symbol(dim))) {
68✔
344
            arg0 = args[1];
68✔
345
            arg1 = args[0];
68✔
346
        }
68✔
347
        if (!symbolic::eq(arg0, symbolic::symbol(dim))) {
68✔
348
            continue;
×
349
        }
×
350
        if (!SymEngine::is_a<SymEngine::Integer>(*arg1)) {
68✔
351
            continue;
×
352
        }
×
353
        if (symbolic::eq(arg1, symbolic::one())) {
68✔
354
            continue;
66✔
355
        }
66✔
356
        auto lb = assums2.at(sym).lower_bound_deprecated();
2✔
357
        if (!SymEngine::is_a<SymEngine::Integer>(*lb)) {
2✔
358
            continue;
×
359
        }
×
360

361
        std::string dim2 = dim + "_2";
2✔
362
        std::string iter = "__daisy_iterator_" + dim2;
2✔
363
        std::string con = "exists " + iter + " : " + dim2 + " = " + c_printer.apply(lb) + " + " + iter + " * " +
2✔
364
                          c_printer.apply(arg1);
2✔
365
        constraints_2.push_back(con);
2✔
366
    }
2✔
367
    if (!constraints_2.empty()) {
58✔
368
        map_2_ss << " : ";
51✔
369
        map_2_ss << helpers::join(constraints_2, " and ");
51✔
370
    }
51✔
371
    map_2_ss << " }";
58✔
372

373
    std::stringstream map_3_ss;
58✔
374
    map_3_ss << "{ [";
58✔
375
    for (size_t i = 0; i < dimensions.size(); i++) {
127✔
376
        map_3_ss << dimensions[i] + "_2";
69✔
377
        if (i < dimensions.size() - 1) {
69✔
378
            map_3_ss << ", ";
20✔
379
        }
20✔
380
    }
69✔
381
    map_3_ss << "] -> [";
58✔
382
    for (size_t i = 0; i < dimensions.size(); i++) {
127✔
383
        map_3_ss << dimensions[i] + "_1";
69✔
384
        if (i < dimensions.size() - 1) {
69✔
385
            map_3_ss << ", ";
20✔
386
        }
20✔
387
    }
69✔
388
    map_3_ss << "]";
58✔
389
    std::vector<std::string> monotonicity_constraints;
58✔
390
    if (dimensions_syms.find(indvar) != dimensions_syms.end()) {
58✔
391
        monotonicity_constraints.push_back(indvar->get_name() + "_1 != " + indvar->get_name() + "_2");
34✔
392
    }
34✔
393
    if (!monotonicity_constraints.empty()) {
58✔
394
        map_3_ss << " : ";
34✔
395
        map_3_ss << helpers::join(monotonicity_constraints, " and ");
34✔
396
    }
34✔
397
    map_3_ss << " }";
58✔
398

399
    std::string map_1 = map_1_ss.str();
58✔
400
    std::string map_2 = map_2_ss.str();
58✔
401
    std::string map_3 = map_3_ss.str();
58✔
402

403
    return {map_1, map_2, map_3};
58✔
404
}
58✔
405

406
ExpressionSet generate_constraints(SymbolSet& syms, const Assumptions& assums, SymbolSet& seen) {
940✔
407
    ExpressionSet constraints;
940✔
408
    for (auto& sym : syms) {
1,185✔
409
        if (assums.find(sym) == assums.end()) {
1,185✔
410
            continue;
8✔
411
        }
8✔
412
        if (seen.find(sym) != seen.end()) {
1,177✔
413
            continue;
859✔
414
        }
859✔
415
        seen.insert(sym);
318✔
416

417
        auto ub = assums.at(sym).upper_bound_deprecated();
318✔
418
        auto lb = assums.at(sym).lower_bound_deprecated();
318✔
419
        if (!symbolic::eq(ub, SymEngine::Inf)) {
318✔
420
            if (SymEngine::is_a<SymEngine::Min>(*ub)) {
243✔
421
                auto min = SymEngine::rcp_static_cast<const SymEngine::Min>(ub);
117✔
422
                auto args = min->get_args();
117✔
423
                for (auto& arg : args) {
242✔
424
                    auto con = symbolic::Le(sym, arg);
242✔
425
                    auto con_syms = symbolic::atoms(con);
242✔
426
                    constraints.insert(con);
242✔
427

428
                    auto con_cons = generate_constraints(con_syms, assums, seen);
242✔
429
                    constraints.insert(con_cons.begin(), con_cons.end());
242✔
430
                }
242✔
431
            } else {
126✔
432
                auto con = symbolic::Le(sym, ub);
126✔
433
                auto con_syms = symbolic::atoms(con);
126✔
434
                constraints.insert(con);
126✔
435

436
                auto con_cons = generate_constraints(con_syms, assums, seen);
126✔
437
                constraints.insert(con_cons.begin(), con_cons.end());
126✔
438
            }
126✔
439
        }
243✔
440
        if (!symbolic::eq(lb, SymEngine::NegInf)) {
318✔
441
            if (SymEngine::is_a<SymEngine::Max>(*lb)) {
318✔
442
                auto max = SymEngine::rcp_static_cast<const SymEngine::Max>(lb);
66✔
443
                auto args = max->get_args();
66✔
444
                for (auto& arg : args) {
132✔
445
                    auto con = symbolic::Ge(sym, arg);
132✔
446
                    auto con_syms = symbolic::atoms(con);
132✔
447
                    constraints.insert(con);
132✔
448

449
                    auto con_cons = generate_constraints(con_syms, assums, seen);
132✔
450
                    constraints.insert(con_cons.begin(), con_cons.end());
132✔
451
                }
132✔
452
            } else {
252✔
453
                auto con = symbolic::Ge(sym, lb);
252✔
454
                auto con_syms = symbolic::atoms(con);
252✔
455
                constraints.insert(con);
252✔
456

457
                auto con_cons = generate_constraints(con_syms, assums, seen);
252✔
458
                constraints.insert(con_cons.begin(), con_cons.end());
252✔
459
            }
252✔
460
        }
318✔
461
    }
318✔
462
    return constraints;
940✔
463
}
940✔
464

465
std::string constraint_to_isl_str(const Expression con) {
746✔
466
    if (SymEngine::is_a<SymEngine::StrictLessThan>(*con)) {
746✔
467
        auto le = SymEngine::rcp_static_cast<const SymEngine::StrictLessThan>(con);
×
468
        auto lhs = le->get_arg1();
×
469
        auto rhs = le->get_arg2();
×
470
        if (SymEngine::is_a<SymEngine::Infty>(*lhs) || SymEngine::is_a<SymEngine::Infty>(*rhs)) {
×
471
            return "";
×
472
        }
×
473
        auto res = c_printer.apply(con);
×
474
        return res;
×
475
    } else if (SymEngine::is_a<SymEngine::LessThan>(*con)) {
746✔
476
        auto le = SymEngine::rcp_static_cast<const SymEngine::LessThan>(con);
744✔
477
        auto lhs = le->get_arg1();
744✔
478
        auto rhs = le->get_arg2();
744✔
479
        if (SymEngine::is_a<SymEngine::Infty>(*lhs) || SymEngine::is_a<SymEngine::Infty>(*rhs)) {
744✔
480
            return "";
115✔
481
        }
115✔
482
        auto res = c_printer.apply(con);
629✔
483
        return res;
629✔
484
    } else if (SymEngine::is_a<SymEngine::Equality>(*con)) {
744✔
485
        auto eq = SymEngine::rcp_static_cast<const SymEngine::Equality>(con);
×
486
        auto lhs = eq->get_arg1();
×
487
        auto rhs = eq->get_arg2();
×
488
        if (SymEngine::is_a<SymEngine::Infty>(*lhs) || SymEngine::is_a<SymEngine::Infty>(*rhs)) {
×
489
            return "";
×
490
        }
×
491
        auto res = c_printer.apply(con);
×
492
        return res;
×
493
    } else if (SymEngine::is_a<SymEngine::Unequality>(*con)) {
2✔
494
        auto ne = SymEngine::rcp_static_cast<const SymEngine::Unequality>(con);
×
495
        auto lhs = ne->get_arg1();
×
496
        auto rhs = ne->get_arg2();
×
497
        if (SymEngine::is_a<SymEngine::Infty>(*lhs) || SymEngine::is_a<SymEngine::Infty>(*rhs)) {
×
498
            return "";
×
499
        }
×
500
        auto res = c_printer.apply(con);
×
501
        return res;
×
502
    }
×
503

504
    return "";
2✔
505
}
746✔
506

507
void canonicalize_map_dims(isl_map* map, const std::string& in_prefix, const std::string& out_prefix) {
72✔
508
    int n_in = isl_map_dim(map, isl_dim_in);
72✔
509
    int n_out = isl_map_dim(map, isl_dim_out);
72✔
510

511
    for (int i = 0; i < n_in; ++i) {
90✔
512
        std::string name = in_prefix + std::to_string(i);
18✔
513
        map = isl_map_set_dim_name(map, isl_dim_in, i, name.c_str());
18✔
514
    }
18✔
515

516
    for (int i = 0; i < n_out; ++i) {
144✔
517
        std::string name = out_prefix + std::to_string(i);
72✔
518
        map = isl_map_set_dim_name(map, isl_dim_out, i, name.c_str());
72✔
519
    }
72✔
520
}
72✔
521

522
MultiExpression delinearize(const MultiExpression& expr, const Assumptions& assums) {
158✔
523
    MultiExpression delinearized;
158✔
524
    for (auto& dim : expr) {
170✔
525
        // Check if more than two symbols are involved
526
        SymbolVec symbols;
170✔
527
        for (auto& sym : atoms(dim)) {
211✔
528
            if (!assums.at(sym).constant() || !assums.at(sym).map().is_null()) {
211✔
529
                symbols.push_back(sym);
151✔
530
            }
151✔
531
        }
211✔
532
        if (symbols.size() < 1) {
170✔
533
            delinearized.push_back(dim);
71✔
534
            continue;
71✔
535
        }
71✔
536

537
        // Step 1: Get polynomial form and affine coefficients
538
        auto poly = polynomial(dim, symbols);
99✔
539
        if (poly == SymEngine::null) {
99✔
540
            delinearized.push_back(dim);
×
541
            continue;
×
542
        }
×
543
        auto aff_coeffs = affine_coefficients(poly, symbols);
99✔
544
        if (aff_coeffs.empty()) {
99✔
545
            delinearized.push_back(dim);
×
546
            continue;
×
547
        }
×
548
        auto offset = aff_coeffs.at(symbolic::symbol("__daisy_constant__"));
99✔
549
        aff_coeffs.erase(symbolic::symbol("__daisy_constant__"));
99✔
550

551
        // Step 2: Peel-off dimensions
552
        bool success = true;
99✔
553
        Expression remaining = symbolic::sub(dim, offset);
99✔
554
        std::vector<Expression> peeled_dims;
99✔
555
        while (!aff_coeffs.empty()) {
230✔
556
            // Find the symbol with largest stride (= largest atom count)
557
            Symbol new_dim = SymEngine::null;
149✔
558
            size_t max_atom_count = 0;
149✔
559
            for (const auto& [sym, coeff] : aff_coeffs) {
247✔
560
                size_t atom_count = symbolic::atoms(coeff).size();
247✔
561
                if (atom_count > max_atom_count || new_dim.is_null()) {
247✔
562
                    max_atom_count = atom_count;
202✔
563
                    new_dim = sym;
202✔
564
                }
202✔
565
            }
247✔
566
            if (new_dim.is_null()) {
149✔
567
                break;
×
568
            }
×
569

570
            // Symbol must be nonnegative
571
            auto sym_lb = minimum(new_dim, {}, assums);
149✔
572
            if (sym_lb.is_null()) {
149✔
573
                break;
14✔
574
            }
14✔
575
            auto sym_cond = symbolic::Ge(sym_lb, symbolic::zero());
135✔
576
            if (!symbolic::is_true(sym_cond)) {
135✔
577
                break;
1✔
578
            }
1✔
579

580
            // Stride must be positive
581
            Expression stride = aff_coeffs.at(new_dim);
134✔
582
            auto stride_lb = minimum(stride, {}, assums);
134✔
583
            if (stride_lb.is_null()) {
134✔
584
                break;
×
585
            }
×
586
            auto stride_cond = symbolic::Ge(stride_lb, symbolic::one());
134✔
587
            if (!symbolic::is_true(stride_cond)) {
134✔
588
                break;
3✔
589
            }
3✔
590

591
            // Peel off the dimension
592
            remaining = symbolic::sub(remaining, symbolic::mul(stride, new_dim));
131✔
593
            remaining = symbolic::expand(remaining);
131✔
594
            remaining = symbolic::simplify(remaining);
131✔
595

596
            // Check if remainder is within bounds
597

598
            // remaining must be nonnegative
599
            auto rem_lb = minimum(remaining, {}, assums);
131✔
600
            if (rem_lb.is_null()) {
131✔
601
                break;
×
602
            }
×
603
            auto cond_zero = symbolic::Ge(rem_lb, symbolic::zero());
131✔
604
            if (!symbolic::is_true(cond_zero)) {
131✔
605
                break;
×
606
            }
×
607

608
            // remaining must be less than stride
609
            auto ub_stride = maximum(stride, {}, assums);
131✔
610
            auto ub_remaining = maximum(remaining, {}, assums);
131✔
611
            auto cond_stride = symbolic::Ge(ub_stride, ub_remaining);
131✔
612
            if (!symbolic::is_true(cond_stride)) {
131✔
613
                break;
×
614
            }
×
615

616
            // Add offset contribution of peeled dimension
617
            auto [q, r] = polynomial_div(offset, stride);
131✔
618
            offset = r;
131✔
619
            auto final_dim = symbolic::add(new_dim, q);
131✔
620

621
            peeled_dims.push_back(final_dim);
131✔
622
            aff_coeffs.erase(new_dim);
131✔
623
        }
131✔
624
        // Not all dimensions could be peeled off
625
        if (!aff_coeffs.empty()) {
99✔
626
            delinearized.push_back(dim);
18✔
627
            continue;
18✔
628
        }
18✔
629
        // Offset did not reduce to zero
630
        if (!symbolic::eq(offset, symbolic::zero())) {
81✔
631
            delinearized.push_back(dim);
×
632
            continue;
×
633
        }
×
634

635
        // Success
636
        for (auto& peeled_dim : peeled_dims) {
131✔
637
            delinearized.push_back(peeled_dim);
131✔
638
        }
131✔
639
    }
81✔
640

641
    return delinearized;
158✔
642
}
158✔
643

644
} // namespace symbolic
645
} // 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

© 2026 Coveralls, Inc