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

daisytuner / sdfglib / 15822095523

23 Jun 2025 10:43AM UTC coverage: 63.824% (-0.02%) from 63.84%
15822095523

push

github

web-flow
Merge pull request #99 from daisytuner/delinearization

adds support for delinearizing affine expressions

69 of 103 new or added lines in 8 files covered. (66.99%)

3 existing lines in 2 files now uncovered.

8084 of 12666 relevant lines covered (63.82%)

149.74 hits per line

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

70.16
/src/symbolic/maps.cpp
1
#include "sdfg/symbolic/maps.h"
2

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

7
#include "sdfg/symbolic/extreme_values.h"
8
#include "sdfg/symbolic/polynomials.h"
9
#include "sdfg/symbolic/utils.h"
10

11
namespace sdfg {
12
namespace symbolic {
13
namespace maps {
14

15
bool is_monotonic_affine(const Expression& expr, const Symbol& sym, const Assumptions& assums) {
41✔
16
    SymbolVec symbols = {sym};
41✔
17
    auto poly = polynomial(expr, symbols);
41✔
18
    if (poly == SymEngine::null) {
41✔
19
        return false;
×
20
    }
21
    auto coeffs = affine_coefficients(poly, symbols);
41✔
22
    if (coeffs.empty()) {
41✔
23
        return false;
1✔
24
    }
25
    auto mul = minimum(coeffs[sym], {}, assums);
40✔
26
    if (mul == SymEngine::null) {
40✔
27
        return false;
×
28
    }
29
    if (!SymEngine::is_a<SymEngine::Integer>(*mul)) {
40✔
UNCOV
30
        return false;
×
31
    }
32
    auto mul_int = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(mul);
40✔
33
    if (mul_int->as_int() <= 0) {
40✔
34
        return false;
5✔
35
    }
36

37
    return true;
35✔
38
}
41✔
39

40
bool is_monotonic_pow(const Expression& expr, const Symbol& sym, const Assumptions& assums) {
6✔
41
    if (SymEngine::is_a<SymEngine::Pow>(*expr)) {
6✔
42
        auto pow = SymEngine::rcp_dynamic_cast<const SymEngine::Pow>(expr);
1✔
43
        auto base = pow->get_base();
1✔
44
        auto exp = pow->get_exp();
1✔
45
        if (SymEngine::is_a<SymEngine::Integer>(*exp) &&
2✔
46
            SymEngine::is_a<SymEngine::Symbol>(*base)) {
1✔
47
            auto exp_int = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(exp);
1✔
48
            if (exp_int->as_int() <= 0) {
1✔
49
                return false;
×
50
            }
51
            auto base_sym = SymEngine::rcp_static_cast<const SymEngine::Symbol>(base);
1✔
52
            auto ub_sym = minimum(base_sym, {}, assums);
1✔
53
            if (ub_sym == SymEngine::null) {
1✔
54
                return false;
×
55
            }
56
            auto positive = symbolic::Ge(ub_sym, symbolic::integer(0));
1✔
57
            return symbolic::is_true(positive);
1✔
58
        }
1✔
59
    }
1✔
60

61
    return false;
5✔
62
}
6✔
63

64
bool is_monotonic(const Expression& expr, const Symbol& sym, const Assumptions& assums) {
41✔
65
    if (is_monotonic_affine(expr, sym, assums)) {
41✔
66
        return true;
35✔
67
    }
68
    return is_monotonic_pow(expr, sym, assums);
6✔
69
}
41✔
70

71
bool is_disjoint_isl(const MultiExpression& expr1, const MultiExpression& expr2,
13✔
72
                     const Symbol& indvar, const Assumptions& assums1, const Assumptions& assums2) {
73
    if (expr1.size() != expr2.size()) {
13✔
74
        return false;
×
75
    }
76
    if (expr1.empty()) {
13✔
77
        return false;
×
78
    }
79

80
    isl_ctx* ctx = isl_ctx_alloc();
13✔
81

82
    // Transform both expressions into two maps with separate dimensions
83
    auto expr1_delinearized = delinearize(expr1, assums1);
13✔
84
    auto expr2_delinearized = delinearize(expr2, assums2);
13✔
85
    auto maps = expressions_to_intersection_map_str(expr1_delinearized, expr2_delinearized, indvar,
26✔
86
                                                    assums1, assums2);
13✔
87
    isl_map* map_1 = isl_map_read_from_str(ctx, std::get<0>(maps).c_str());
13✔
88
    isl_map* map_2 = isl_map_read_from_str(ctx, std::get<1>(maps).c_str());
13✔
89
    isl_map* map_3 = isl_map_read_from_str(ctx, std::get<2>(maps).c_str());
13✔
90
    if (!map_1 || !map_2 || !map_3) {
13✔
91
        if (map_1) {
×
92
            isl_map_free(map_1);
×
93
        }
×
94
        if (map_2) {
×
95
            isl_map_free(map_2);
×
96
        }
×
97
        if (map_3) {
×
98
            isl_map_free(map_3);
×
99
        }
×
100
        isl_ctx_free(ctx);
×
101
        return false;
×
102
    }
103

104
    // Find aliasing pairs under the constraint that dimensions are different
105

106
    isl_map* composed = isl_map_apply_domain(map_2, map_3);
13✔
107
    if (!composed) {
13✔
108
        isl_map_free(map_1);
×
109
        if (map_2) {
×
110
            isl_map_free(map_2);
×
111
        }
×
112
        if (map_3) {
×
113
            isl_map_free(map_3);
×
114
        }
×
115
        isl_ctx_free(ctx);
×
116
        return false;
×
117
    }
118
    isl_map* alias_pairs = isl_map_intersect(composed, map_1);
13✔
119
    if (!alias_pairs) {
13✔
120
        if (composed) {
×
121
            isl_map_free(composed);
×
122
        }
×
123
        if (map_1) {
×
124
            isl_map_free(map_1);
×
125
        }
×
126
        isl_ctx_free(ctx);
×
127
        return false;
×
128
    }
129

130
    bool disjoint = isl_map_is_empty(alias_pairs);
13✔
131
    isl_map_free(alias_pairs);
13✔
132
    isl_ctx_free(ctx);
13✔
133

134
    return disjoint;
13✔
135
}
13✔
136

137
bool is_disjoint_monotonic(const MultiExpression& expr1, const MultiExpression& expr2,
49✔
138
                           const Symbol& indvar, const Assumptions& assums1,
139
                           const Assumptions& assums2) {
140
    for (size_t i = 0; i < expr1.size(); i++) {
73✔
141
        auto& dim1 = expr1[i];
60✔
142
        if (expr2.size() <= i) {
60✔
143
            continue;
×
144
        }
145
        auto& dim2 = expr2[i];
60✔
146
        if (!symbolic::eq(dim1, dim2)) {
60✔
147
            continue;
14✔
148
        }
149

150
        // Collect all symbols
151
        symbolic::SymbolSet syms;
46✔
152
        for (auto& sym : symbolic::atoms(dim1)) {
94✔
153
            syms.insert(sym);
48✔
154
        }
155

156
        // Collect all non-constant symbols
157
        bool can_analyze = true;
46✔
158
        for (auto& sym : syms) {
89✔
159
            if (!assums1.at(sym).constant()) {
48✔
160
                if (sym->get_name() != indvar->get_name()) {
5✔
161
                    can_analyze = false;
5✔
162
                    break;
5✔
163
                }
164
            }
×
165
        }
166
        if (!can_analyze) {
46✔
167
            continue;
5✔
168
        }
169

170
        // Check if both dimensions are monotonic in non-constant symbols
171
        if (is_monotonic(dim1, indvar, assums1)) {
41✔
172
            return true;
36✔
173
        }
174
    }
46✔
175

176
    return false;
13✔
177
}
49✔
178

179
bool intersects(const MultiExpression& expr1, const MultiExpression& expr2, const Symbol& indvar,
49✔
180
                const Assumptions& assums1, const Assumptions& assums2) {
181
    if (is_disjoint_monotonic(expr1, expr2, indvar, assums1, assums2)) {
49✔
182
        return false;
36✔
183
    }
184
    return !is_disjoint_isl(expr1, expr2, indvar, assums1, assums2);
13✔
185
}
49✔
186

187
}  // namespace maps
188
}  // namespace symbolic
189
}  // 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