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

daisytuner / docc / 22023884668

14 Feb 2026 08:36PM UTC coverage: 64.903% (-1.4%) from 66.315%
22023884668

Pull #525

github

web-flow
Merge 1d47f8bf2 into 9d01cacd5
Pull Request #525: Step 3 (Native Tensor Support): Refactor Python Frontend

2522 of 3435 new or added lines in 32 files covered. (73.42%)

320 existing lines in 15 files now uncovered.

23204 of 35752 relevant lines covered (64.9%)

370.03 hits per line

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

49.03
/sdfg/src/types/tensor.cpp
1
#include "sdfg/types/tensor.h"
2

3
#include "sdfg/types/scalar.h"
4

5
namespace sdfg {
6
namespace types {
7

8
symbolic::MultiExpression Tensor::strides_from_shape(const symbolic::MultiExpression& shape) {
193✔
9
    if (shape.empty()) {
193✔
10
        return {};
30✔
11
    }
30✔
12
    symbolic::MultiExpression strides(shape.size());
163✔
13
    strides.back() = SymEngine::integer(1);
163✔
14
    for (size_t i = shape.size() - 1; i > 0; --i) {
343✔
15
        strides[i - 1] = SymEngine::mul(strides[i], shape[i]);
180✔
16
    }
180✔
17
    return strides;
163✔
18
}
193✔
19

20
Tensor::Tensor(const Scalar& element_type, const symbolic::MultiExpression& shape)
21
    : element_type_(std::unique_ptr<Scalar>(static_cast<Scalar*>(element_type.clone().release()))), shape_(shape),
192✔
22
      strides_(strides_from_shape(shape)), offset_(symbolic::zero()) {};
192✔
23

24
Tensor::Tensor(
25
    const Scalar& element_type,
26
    const symbolic::MultiExpression& shape,
27
    const symbolic::MultiExpression& strides,
28
    const symbolic::Expression& offset
29
)
30
    : element_type_(std::unique_ptr<Scalar>(static_cast<Scalar*>(element_type.clone().release()))), shape_(shape),
4✔
31
      strides_(strides), offset_(offset) {};
4✔
32

33
Tensor::Tensor(
34
    StorageType storage_type,
35
    size_t alignment,
36
    const std::string& initializer,
37
    const Scalar& element_type,
38
    const symbolic::MultiExpression& shape,
39
    const symbolic::MultiExpression& strides,
40
    const symbolic::Expression& offset
41
)
42
    : IType(storage_type, alignment, initializer),
750✔
43
      element_type_(std::unique_ptr<Scalar>(static_cast<Scalar*>(element_type.clone().release()))), shape_(shape),
750✔
44
      strides_(strides), offset_(offset) {};
750✔
45

46
PrimitiveType Tensor::primitive_type() const { return this->element_type_->primitive_type(); };
358✔
47

48
bool Tensor::is_symbol() const { return false; };
1✔
49

50
const Scalar& Tensor::element_type() const { return *this->element_type_; };
143✔
51

52
const symbolic::MultiExpression& Tensor::shape() const { return this->shape_; };
2,581✔
53

54
const symbolic::MultiExpression& Tensor::strides() const { return this->strides_; };
993✔
55

56
const symbolic::Expression& Tensor::offset() const { return this->offset_; };
81✔
57

58
symbolic::Expression Tensor::total_elements() const {
1✔
59
    symbolic::Expression total = symbolic::one();
1✔
60
    for (const auto& dim : this->shape_) {
1✔
61
        total = symbolic::mul(total, dim);
1✔
62
    }
1✔
63
    return total;
1✔
64
};
1✔
65

66
bool Tensor::is_scalar() const { return this->shape_.empty(); }
1,053✔
67

68
TypeID Tensor::type_id() const { return TypeID::Tensor; };
1,764✔
69

70
bool Tensor::operator==(const IType& other) const {
8✔
71
    if (!dynamic_cast<const Tensor*>(&other)) {
8✔
72
        return false;
×
73
    }
×
74
    const auto& tensor_type = static_cast<const Tensor&>(other);
8✔
75

76
    if (!(*this->element_type_ == *tensor_type.element_type_)) {
8✔
77
        return false;
1✔
78
    }
1✔
79
    if (!symbolic::eq(this->offset_, tensor_type.offset_)) {
7✔
80
        return false;
×
81
    }
×
82

83
    if (this->shape_.size() != tensor_type.shape_.size()) {
7✔
84
        return false;
×
85
    }
×
86
    for (size_t i = 0; i < this->shape_.size(); ++i) {
11✔
87
        if (!symbolic::eq(this->shape_.at(i), tensor_type.shape_.at(i))) {
5✔
88
            return false;
1✔
89
        }
1✔
90
    }
5✔
91

92
    if (this->strides_.size() != tensor_type.strides_.size()) {
6✔
93
        return false;
×
94
    }
×
95
    for (size_t i = 0; i < this->strides_.size(); ++i) {
9✔
96
        if (!symbolic::eq(this->strides_.at(i), tensor_type.strides_.at(i))) {
3✔
97
            return false;
×
98
        }
×
99
    }
3✔
100

101
    return true;
6✔
102
};
6✔
103

104
std::unique_ptr<IType> Tensor::clone() const {
675✔
105
    return std::make_unique<Tensor>(
675✔
106
        this->storage_type(),
675✔
107
        this->alignment(),
675✔
108
        this->initializer(),
675✔
109
        *this->element_type_,
675✔
110
        this->shape_,
675✔
111
        this->strides_,
675✔
112
        this->offset_
675✔
113
    );
675✔
114
};
675✔
115

116
std::string Tensor::print() const {
×
117
    std::string result = "Tensor(" + this->element_type_->print() + ", shape=[";
×
118
    for (size_t i = 0; i < this->shape_.size(); ++i) {
×
119
        result += this->shape_.at(i)->__str__();
×
120
        if (i < this->shape_.size() - 1) {
×
121
            result += ", ";
×
122
        }
×
123
    }
×
124
    result += "]";
×
NEW
125
    result += ", strides=[";
×
NEW
126
    for (size_t i = 0; i < this->strides_.size(); ++i) {
×
NEW
127
        result += this->strides_.at(i)->__str__();
×
NEW
128
        if (i < this->strides_.size() - 1) {
×
NEW
129
            result += ", ";
×
NEW
130
        }
×
NEW
131
    }
×
NEW
132
    result += "]";
×
NEW
133
    if (!symbolic::eq(this->offset_, symbolic::zero())) {
×
NEW
134
        result += ", offset=" + this->offset_->__str__();
×
NEW
135
    }
×
136
    result += ")";
×
137
    return result;
×
138
};
×
139

140
std::unique_ptr<Tensor> Tensor::newaxis(size_t axis) const {
×
141
    if (axis > this->shape_.size()) {
×
142
        throw std::out_of_range("axis out of range for newaxis");
×
143
    }
×
144

145
    symbolic::MultiExpression new_shape = this->shape_;
×
146
    symbolic::MultiExpression new_strides = this->strides_;
×
147

148
    new_shape.insert(new_shape.begin() + axis, SymEngine::integer(1));
×
149
    new_strides.insert(new_strides.begin() + axis, SymEngine::integer(0));
×
150

151
    return std::make_unique<Tensor>(
×
152
        this->storage_type(),
×
153
        this->alignment(),
×
154
        this->initializer(),
×
155
        *this->element_type_,
×
156
        new_shape,
×
157
        new_strides,
×
158
        this->offset_
×
159
    );
×
160
}
×
161

162
std::unique_ptr<Tensor> Tensor::flip(size_t axis) const {
1✔
163
    if (axis >= this->shape_.size()) {
1✔
164
        throw std::out_of_range("axis out of range for flip");
×
165
    }
×
166

167
    symbolic::MultiExpression new_strides = this->strides_;
1✔
168

169
    // Negate the stride for the specified axis
170
    new_strides[axis] = SymEngine::neg(this->strides_[axis]);
1✔
171

172
    // Compute new offset: offset += stride * (shape - 1)
173
    auto shape_minus_one = SymEngine::sub(this->shape_[axis], SymEngine::integer(1));
1✔
174
    auto offset_adjustment = SymEngine::mul(this->strides_[axis], shape_minus_one);
1✔
175

176
    symbolic::Expression new_offset = this->offset_;
1✔
177
    if (SymEngine::is_a<SymEngine::Integer>(*offset_adjustment)) {
1✔
178
        new_offset = SymEngine::add(new_offset, offset_adjustment);
1✔
179
    }
1✔
180

181
    return std::make_unique<Tensor>(
1✔
182
        this->storage_type(),
1✔
183
        this->alignment(),
1✔
184
        this->initializer(),
1✔
185
        *this->element_type_,
1✔
186
        this->shape_,
1✔
187
        new_strides,
1✔
188
        new_offset
1✔
189
    );
1✔
190
}
1✔
191

192
std::unique_ptr<Tensor> Tensor::unsqueeze(size_t axis) const { return this->newaxis(axis); }
×
193

194
std::unique_ptr<Tensor> Tensor::squeeze(size_t axis) const {
×
195
    if (axis >= this->shape_.size()) {
×
196
        throw std::out_of_range("axis out of range for squeeze");
×
197
    }
×
198

199
    if (!SymEngine::is_a<SymEngine::Integer>(*this->shape_.at(axis))) {
×
200
        throw std::invalid_argument("cannot squeeze axis with symbolic size");
×
201
    }
×
202
    auto dim_size = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(this->shape_.at(axis))->as_int();
×
203
    if (dim_size != 1) {
×
204
        throw std::invalid_argument("cannot squeeze axis with size != 1");
×
205
    }
×
206

207
    symbolic::MultiExpression new_shape = this->shape_;
×
208
    symbolic::MultiExpression new_strides = this->strides_;
×
209

210
    new_shape.erase(new_shape.begin() + axis);
×
211
    new_strides.erase(new_strides.begin() + axis);
×
212

213
    return std::make_unique<Tensor>(
×
214
        this->storage_type(),
×
215
        this->alignment(),
×
216
        this->initializer(),
×
217
        *this->element_type_,
×
218
        new_shape,
×
219
        new_strides,
×
220
        this->offset_
×
221
    );
×
222
}
×
223

224
std::unique_ptr<Tensor> Tensor::squeeze() const {
×
225
    symbolic::MultiExpression new_shape;
×
226
    symbolic::MultiExpression new_strides;
×
227

228
    for (size_t i = 0; i < this->shape_.size(); ++i) {
×
229
        bool is_size_one = false;
×
230
        if (SymEngine::is_a<SymEngine::Integer>(*this->shape_.at(i))) {
×
231
            auto dim_size = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(this->shape_.at(i))->as_int();
×
232
            is_size_one = (dim_size == 1);
×
233
        }
×
234

235
        if (!is_size_one) {
×
236
            new_shape.push_back(this->shape_.at(i));
×
237
            new_strides.push_back(this->strides_.at(i));
×
238
        }
×
239
    }
×
240

241
    return std::make_unique<Tensor>(
×
242
        this->storage_type(),
×
243
        this->alignment(),
×
244
        this->initializer(),
×
245
        *this->element_type_,
×
246
        new_shape,
×
247
        new_strides,
×
248
        this->offset_
×
249
    );
×
250
}
×
251

252
std::unique_ptr<Tensor> Tensor::reshape(const symbolic::MultiExpression& new_shape) const {
1✔
253
    // Compute the total number of elements in the current shape
254
    symbolic::Expression total_elements = this->total_elements();
1✔
255

256
    // Compute the total number of elements in the new shape
257
    symbolic::Expression new_total_elements = symbolic::one();
1✔
258
    for (const auto& dim : new_shape) {
2✔
259
        new_total_elements = symbolic::mul(new_total_elements, dim);
2✔
260
    }
2✔
261

262
    // Check if the total number of elements matches
263
    if (!symbolic::eq(total_elements, new_total_elements)) {
1✔
264
        throw std::invalid_argument("total number of elements must match for reshape");
×
265
    }
×
266

267
    // Compute new strides based on the new shape
268
    symbolic::MultiExpression new_strides = strides_from_shape(new_shape);
1✔
269

270
    return std::make_unique<Tensor>(
1✔
271
        this->storage_type(),
1✔
272
        this->alignment(),
1✔
273
        this->initializer(),
1✔
274
        *this->element_type_,
1✔
275
        new_shape,
1✔
276
        new_strides,
1✔
277
        this->offset_
1✔
278
    );
1✔
279
}
1✔
280

281
} // namespace types
282
} // 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