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

daisytuner / sdfglib / 15798071638

21 Jun 2025 05:35PM UTC coverage: 63.84% (-0.2%) from 64.022%
15798071638

Pull #97

github

web-flow
Merge bc9208a8e into b1dccd749
Pull Request #97: adds constant assumptions to handle complex symbolic expressions

35 of 46 new or added lines in 6 files covered. (76.09%)

26 existing lines in 4 files now uncovered.

8054 of 12616 relevant lines covered (63.84%)

152.19 hits per line

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

72.37
/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

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

42
    return true;
232✔
43
}
277✔
44

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

66
    return false;
44✔
67
}
45✔
68

69
bool is_monotonic(const Expression& expr, const Symbol& sym, const Assumptions& assums) {
277✔
70
    if (is_monotonic_affine(expr, sym, assums)) {
277✔
71
        return true;
232✔
72
    }
73
    return is_monotonic_pow(expr, sym, assums);
45✔
74
}
277✔
75

76
bool is_contiguous(const Expression& expr, const Symbol& sym, const Assumptions& assums) {
35✔
77
    SymbolVec symbols = {sym};
35✔
78
    auto poly = polynomial(expr, symbols);
35✔
79
    if (poly == SymEngine::null) {
35✔
80
        return false;
×
81
    }
82
    auto coeffs = affine_coefficients(poly, symbols);
35✔
83
    if (coeffs.empty()) {
35✔
84
        return false;
×
85
    }
86
    auto mul = minimum(coeffs[sym], {}, assums);
35✔
87
    if (mul == SymEngine::null) {
35✔
88
        return false;
×
89
    }
90
    auto offset = minimum(coeffs[symbol("__daisy_constant__")], {}, assums);
35✔
91
    if (offset == SymEngine::null) {
35✔
92
        return false;
×
93
    }
94
    if (!SymEngine::is_a<SymEngine::Integer>(*mul) ||
70✔
95
        !SymEngine::is_a<SymEngine::Integer>(*offset)) {
35✔
96
        return false;
×
97
    }
98
    auto mul_int = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(mul);
35✔
99
    auto offset_int = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(offset);
35✔
100
    if (mul_int->as_int() == 1 && offset_int->as_int() == 1) {
35✔
101
        return true;
33✔
102
    }
103

104
    return false;
2✔
105
}
35✔
106

107
bool is_disjoint_isl(const MultiExpression& expr1, const MultiExpression& expr2,
46✔
108
                     const Symbol& indvar, const Assumptions& assums1, const Assumptions& assums2) {
109
    if (expr1.size() != expr2.size()) {
46✔
110
        return false;
×
111
    }
112
    if (expr1.empty()) {
46✔
113
        return false;
×
114
    }
115

116
    isl_ctx* ctx = isl_ctx_alloc();
46✔
117

118
    // Transform both expressions into two maps with separate dimensions
119
    auto expr1_delinearized = delinearize(expr1, assums1);
46✔
120
    auto expr2_delinearized = delinearize(expr2, assums2);
46✔
121
    auto maps = expressions_to_intersection_map_str(expr1_delinearized, expr2_delinearized, indvar,
92✔
122
                                                    assums1, assums2);
46✔
123
    isl_map* map_1 = isl_map_read_from_str(ctx, std::get<0>(maps).c_str());
46✔
124
    isl_map* map_2 = isl_map_read_from_str(ctx, std::get<1>(maps).c_str());
46✔
125
    isl_map* map_3 = isl_map_read_from_str(ctx, std::get<2>(maps).c_str());
46✔
126
    if (!map_1 || !map_2 || !map_3) {
46✔
127
        if (map_1) {
×
128
            isl_map_free(map_1);
×
129
        }
×
130
        if (map_2) {
×
131
            isl_map_free(map_2);
×
132
        }
×
133
        if (map_3) {
×
134
            isl_map_free(map_3);
×
135
        }
×
136
        isl_ctx_free(ctx);
×
137
        return false;
×
138
    }
139

140
    // Find aliasing pairs under the constraint that dimensions are different
141

142
    isl_map* composed = isl_map_apply_domain(map_2, map_3);
46✔
143
    if (!composed) {
46✔
144
        isl_map_free(map_1);
×
145
        if (map_2) {
×
146
            isl_map_free(map_2);
×
147
        }
×
148
        if (map_3) {
×
149
            isl_map_free(map_3);
×
150
        }
×
151
        isl_ctx_free(ctx);
×
152
        return false;
×
153
    }
154
    isl_map* alias_pairs = isl_map_intersect(composed, map_1);
46✔
155
    if (!alias_pairs) {
46✔
156
        if (composed) {
×
157
            isl_map_free(composed);
×
158
        }
×
159
        if (map_1) {
×
160
            isl_map_free(map_1);
×
161
        }
×
162
        isl_ctx_free(ctx);
×
163
        return false;
×
164
    }
165

166
    bool disjoint = isl_map_is_empty(alias_pairs);
46✔
167
    isl_map_free(alias_pairs);
46✔
168
    isl_ctx_free(ctx);
46✔
169

170
    return disjoint;
46✔
171
}
46✔
172

173
bool is_disjoint_monotonic(const MultiExpression& expr1, const MultiExpression& expr2,
49✔
174
                           const Symbol& indvar, const Assumptions& assums1,
175
                           const Assumptions& assums2) {
176
    for (size_t i = 0; i < expr1.size(); i++) {
112✔
177
        auto& dim1 = expr1[i];
66✔
178
        if (expr2.size() <= i) {
66✔
179
            continue;
×
180
        }
181
        auto& dim2 = expr2[i];
66✔
182
        if (!symbolic::eq(dim1, dim2)) {
66✔
183
            continue;
14✔
184
        }
185

186
        // Collect all symbols
187
        symbolic::SymbolSet syms;
52✔
188
        for (auto& sym : symbolic::atoms(dim1)) {
106✔
189
            syms.insert(sym);
54✔
190
        }
191

192
        // Collect all non-constant symbols
193
        bool can_analyze = true;
52✔
194
        for (auto& sym : syms) {
99✔
195
            if (!assums1.at(sym).constant()) {
54✔
196
                if (sym->get_name() != indvar->get_name()) {
7✔
197
                    can_analyze = false;
7✔
198
                    break;
7✔
199
                }
UNCOV
200
            }
×
201
        }
202
        if (!can_analyze) {
52✔
203
            continue;
7✔
204
        }
205

206
        // Check if both dimensions are monotonic in non-constant symbols
207
        if (symbolic::is_monotonic(dim1, indvar, assums1)) {
45✔
208
            return true;
3✔
209
        }
210
    }
52✔
211

212
    return false;
46✔
213
}
49✔
214

215
bool intersects(const MultiExpression& expr1, const MultiExpression& expr2, const Symbol& indvar,
49✔
216
                const Assumptions& assums1, const Assumptions& assums2) {
217
    if (is_disjoint_monotonic(expr1, expr2, indvar, assums1, assums2)) {
49✔
218
        return false;
3✔
219
    }
220
    return !is_disjoint_isl(expr1, expr2, indvar, assums1, assums2);
46✔
221
}
49✔
222

223
}  // namespace symbolic
224
}  // 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