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

daisytuner / docc / 21892992827

10 Feb 2026 05:40PM UTC coverage: 66.315% (-0.2%) from 66.508%
21892992827

push

github

web-flow
Merge pull request #513 from daisytuner/tensor-type

adds tensor type

242 of 431 new or added lines in 18 files covered. (56.15%)

1 existing line in 1 file now uncovered.

23488 of 35419 relevant lines covered (66.31%)

372.32 hits per line

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

50.52
/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) {
11✔
9
    if (shape.empty()) {
11✔
NEW
10
        return {};
×
NEW
11
    }
×
12
    symbolic::MultiExpression strides(shape.size());
11✔
13
    strides.back() = SymEngine::integer(1);
11✔
14
    for (size_t i = shape.size() - 1; i > 0; --i) {
19✔
15
        strides[i - 1] = SymEngine::mul(strides[i], shape[i]);
8✔
16
    }
8✔
17
    return strides;
11✔
18
}
11✔
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),
10✔
22
      strides_(strides_from_shape(shape)), offset_(symbolic::zero()) {};
10✔
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),
13✔
43
      element_type_(std::unique_ptr<Scalar>(static_cast<Scalar*>(element_type.clone().release()))), shape_(shape),
13✔
44
      strides_(strides), offset_(offset) {};
13✔
45

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

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

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

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

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

56
const symbolic::Expression& Tensor::offset() const { return this->offset_; };
9✔
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
TypeID Tensor::type_id() const { return TypeID::Tensor; };
21✔
67

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

74
    if (!(*this->element_type_ == *tensor_type.element_type_)) {
3✔
75
        return false;
1✔
76
    }
1✔
77
    if (!symbolic::eq(this->offset_, tensor_type.offset_)) {
2✔
NEW
78
        return false;
×
NEW
79
    }
×
80

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

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

99
    return true;
1✔
100
};
1✔
101

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

NEW
114
std::string Tensor::print() const {
×
NEW
115
    std::string result = "Tensor(" + this->element_type_->print() + ", shape=[";
×
NEW
116
    for (size_t i = 0; i < this->shape_.size(); ++i) {
×
NEW
117
        result += this->shape_.at(i)->__str__();
×
NEW
118
        if (i < this->shape_.size() - 1) {
×
NEW
119
            result += ", ";
×
NEW
120
        }
×
NEW
121
    }
×
NEW
122
    result += "]";
×
NEW
123
    result += ")";
×
NEW
124
    return result;
×
NEW
125
};
×
126

NEW
127
std::unique_ptr<Tensor> Tensor::newaxis(size_t axis) const {
×
NEW
128
    if (axis > this->shape_.size()) {
×
NEW
129
        throw std::out_of_range("axis out of range for newaxis");
×
NEW
130
    }
×
131

NEW
132
    symbolic::MultiExpression new_shape = this->shape_;
×
NEW
133
    symbolic::MultiExpression new_strides = this->strides_;
×
134

NEW
135
    new_shape.insert(new_shape.begin() + axis, SymEngine::integer(1));
×
NEW
136
    new_strides.insert(new_strides.begin() + axis, SymEngine::integer(0));
×
137

NEW
138
    return std::make_unique<Tensor>(
×
NEW
139
        this->storage_type(),
×
NEW
140
        this->alignment(),
×
NEW
141
        this->initializer(),
×
NEW
142
        *this->element_type_,
×
NEW
143
        new_shape,
×
NEW
144
        new_strides,
×
NEW
145
        this->offset_
×
NEW
146
    );
×
NEW
147
}
×
148

149
std::unique_ptr<Tensor> Tensor::flip(size_t axis) const {
1✔
150
    if (axis >= this->shape_.size()) {
1✔
NEW
151
        throw std::out_of_range("axis out of range for flip");
×
NEW
152
    }
×
153

154
    symbolic::MultiExpression new_strides = this->strides_;
1✔
155

156
    // Negate the stride for the specified axis
157
    new_strides[axis] = SymEngine::neg(this->strides_[axis]);
1✔
158

159
    // Compute new offset: offset += stride * (shape - 1)
160
    auto shape_minus_one = SymEngine::sub(this->shape_[axis], SymEngine::integer(1));
1✔
161
    auto offset_adjustment = SymEngine::mul(this->strides_[axis], shape_minus_one);
1✔
162

163
    symbolic::Expression new_offset = this->offset_;
1✔
164
    if (SymEngine::is_a<SymEngine::Integer>(*offset_adjustment)) {
1✔
165
        new_offset = SymEngine::add(new_offset, offset_adjustment);
1✔
166
    }
1✔
167

168
    return std::make_unique<Tensor>(
1✔
169
        this->storage_type(),
1✔
170
        this->alignment(),
1✔
171
        this->initializer(),
1✔
172
        *this->element_type_,
1✔
173
        this->shape_,
1✔
174
        new_strides,
1✔
175
        new_offset
1✔
176
    );
1✔
177
}
1✔
178

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

NEW
181
std::unique_ptr<Tensor> Tensor::squeeze(size_t axis) const {
×
NEW
182
    if (axis >= this->shape_.size()) {
×
NEW
183
        throw std::out_of_range("axis out of range for squeeze");
×
NEW
184
    }
×
185

NEW
186
    if (!SymEngine::is_a<SymEngine::Integer>(*this->shape_.at(axis))) {
×
NEW
187
        throw std::invalid_argument("cannot squeeze axis with symbolic size");
×
NEW
188
    }
×
NEW
189
    auto dim_size = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(this->shape_.at(axis))->as_int();
×
NEW
190
    if (dim_size != 1) {
×
NEW
191
        throw std::invalid_argument("cannot squeeze axis with size != 1");
×
NEW
192
    }
×
193

NEW
194
    symbolic::MultiExpression new_shape = this->shape_;
×
NEW
195
    symbolic::MultiExpression new_strides = this->strides_;
×
196

NEW
197
    new_shape.erase(new_shape.begin() + axis);
×
NEW
198
    new_strides.erase(new_strides.begin() + axis);
×
199

NEW
200
    return std::make_unique<Tensor>(
×
NEW
201
        this->storage_type(),
×
NEW
202
        this->alignment(),
×
NEW
203
        this->initializer(),
×
NEW
204
        *this->element_type_,
×
NEW
205
        new_shape,
×
NEW
206
        new_strides,
×
NEW
207
        this->offset_
×
NEW
208
    );
×
NEW
209
}
×
210

NEW
211
std::unique_ptr<Tensor> Tensor::squeeze() const {
×
NEW
212
    symbolic::MultiExpression new_shape;
×
NEW
213
    symbolic::MultiExpression new_strides;
×
214

NEW
215
    for (size_t i = 0; i < this->shape_.size(); ++i) {
×
NEW
216
        bool is_size_one = false;
×
NEW
217
        if (SymEngine::is_a<SymEngine::Integer>(*this->shape_.at(i))) {
×
NEW
218
            auto dim_size = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(this->shape_.at(i))->as_int();
×
NEW
219
            is_size_one = (dim_size == 1);
×
NEW
220
        }
×
221

NEW
222
        if (!is_size_one) {
×
NEW
223
            new_shape.push_back(this->shape_.at(i));
×
NEW
224
            new_strides.push_back(this->strides_.at(i));
×
NEW
225
        }
×
NEW
226
    }
×
227

NEW
228
    return std::make_unique<Tensor>(
×
NEW
229
        this->storage_type(),
×
NEW
230
        this->alignment(),
×
NEW
231
        this->initializer(),
×
NEW
232
        *this->element_type_,
×
NEW
233
        new_shape,
×
NEW
234
        new_strides,
×
NEW
235
        this->offset_
×
NEW
236
    );
×
NEW
237
}
×
238

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

243
    // Compute the total number of elements in the new shape
244
    symbolic::Expression new_total_elements = symbolic::one();
1✔
245
    for (const auto& dim : new_shape) {
2✔
246
        new_total_elements = symbolic::mul(new_total_elements, dim);
2✔
247
    }
2✔
248

249
    // Check if the total number of elements matches
250
    if (!symbolic::eq(total_elements, new_total_elements)) {
1✔
NEW
251
        throw std::invalid_argument("total number of elements must match for reshape");
×
NEW
252
    }
×
253

254
    // Compute new strides based on the new shape
255
    symbolic::MultiExpression new_strides = strides_from_shape(new_shape);
1✔
256

257
    return std::make_unique<Tensor>(
1✔
258
        this->storage_type(),
1✔
259
        this->alignment(),
1✔
260
        this->initializer(),
1✔
261
        *this->element_type_,
1✔
262
        new_shape,
1✔
263
        new_strides,
1✔
264
        this->offset_
1✔
265
    );
1✔
266
}
1✔
267

268
} // namespace types
269
} // 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