Skip to content

Commit 5a45462

Browse files
committed
sparse tensor data structures
COOTensor init CSRTensor init added SparseTensorAllocator moved SparseTensor to arm_compute/core fixed to_dense method for COOTensor fixed to_sparse and to_dense methods for CSRTensor changed CSR indices; print function moved to the bae class implemented get_value to CSR and COO tensors added SparseIterator Change-Id: Id5ed095587662b750b89cbabd600a286ab9bf53b
1 parent 531a496 commit 5a45462

26 files changed

Lines changed: 2155 additions & 8 deletions

arm_compute/core/Coordinates.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ class Coordinates : public Dimensions<int>
4949
constexpr Coordinates(Ts... coords) : Dimensions{coords...}
5050
{
5151
}
52+
53+
/** Constructor to initialize the coordinates from a vector.
54+
*
55+
* @param[in] coords Vector containing the values to initialize the dimensions.
56+
*/
57+
template <typename T>
58+
constexpr Coordinates(std::vector<T> coords) : Dimensions(coords)
59+
{
60+
}
61+
5262
/** Allow instances of this class to be copy constructed */
5363
constexpr Coordinates(const Coordinates &) = default;
5464
/** Allow instances of this class to be copied */

arm_compute/core/Dimensions.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ class Dimensions
5858
{
5959
}
6060

61+
/** Constructor to initialize the tensor shape with a list of dim values.
62+
*
63+
* @param[in] dims Vector of values to initialize the dimensions.
64+
*/
65+
explicit Dimensions(std::vector<T> dims) : _id(), _num_dimensions{dims.size()}
66+
{
67+
std::copy_n(dims.begin(), std::min(num_max_dimensions, dims.size()), _id.begin());
68+
}
69+
6170
/** Allow instances of this class to be copy constructed */
6271
Dimensions(const Dimensions &) = default;
6372

arm_compute/core/Helpers.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "arm_compute/core/Types.h"
3535
#include "arm_compute/core/Validate.h"
3636
#include "arm_compute/core/Window.h"
37+
#include "arm_compute/core/SparseTensor.h"
3738

3839
#include <array>
3940
#include <cstddef>
@@ -126,6 +127,42 @@ class Iterator
126127
std::array<Dimension, Coordinates::num_max_dimensions> _dims;
127128
};
128129

130+
class SparseIterator
131+
{
132+
public:
133+
/** Create an iterator for the metadata and allocation contained in the SparseTensor
134+
*
135+
* @param[in] tensor A reference to the tensor to associate to the iterator.
136+
*/
137+
SparseIterator(const SparseTensor &tensor);
138+
139+
/** Returns true if there is at least one more element to iterate */
140+
bool has_next() const;
141+
142+
/** Move to the next non-zero element */
143+
void next();
144+
145+
/** Get the coordinates of the current non-zero element */
146+
Coordinates coordinates() const;
147+
148+
/** Get the value of the current non-zero element */
149+
const uint8_t *value() const;
150+
151+
/** Reset iterator to the beginning */
152+
void reset();
153+
154+
/** Get current index (nth non-zero) */
155+
size_t index() const;
156+
157+
/** Get the number of non-zero elements that are left to iterate */
158+
size_t num_left() const;
159+
160+
private:
161+
const SparseTensor &_tensor;
162+
size_t _index;
163+
size_t _nnz;
164+
};
165+
129166
/** Iterate through the passed window, automatically adjusting the iterators and calling the lambda_functino for each element.
130167
* It passes the x and y positions to the lambda_function for each iteration
131168
*

arm_compute/core/Helpers.inl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ inline Iterator::Iterator(const ITensor *tensor, const Window &win) : Iterator()
101101
{
102102
ARM_COMPUTE_ERROR_ON(tensor == nullptr);
103103
ARM_COMPUTE_ERROR_ON(tensor->info() == nullptr);
104+
ARM_COMPUTE_ERROR_ON_MSG(tensor->info()->is_sparse(), "Sparse tensors are not supported by Iterators. Use a SparseIterator instead");
104105

105106
initialize(tensor->info()->num_dimensions(), tensor->info()->strides_in_bytes(), tensor->buffer(),
106107
tensor->info()->offset_first_element_in_bytes(), win);
@@ -169,6 +170,45 @@ inline void Iterator::reset(const size_t dimension)
169170
}
170171
}
171172

173+
inline SparseIterator::SparseIterator(const SparseTensor &tensor) : _tensor(tensor), _index(0), _nnz(tensor.nnz())
174+
{
175+
}
176+
177+
inline bool SparseIterator::has_next() const
178+
{
179+
return _index < _nnz;
180+
}
181+
182+
inline void SparseIterator::next()
183+
{
184+
++_index;
185+
}
186+
187+
inline Coordinates SparseIterator::coordinates() const
188+
{
189+
return _tensor.get_coordinates(_index);
190+
}
191+
192+
inline const uint8_t *SparseIterator::value() const
193+
{
194+
return _tensor.get_value(coordinates());
195+
}
196+
197+
inline void SparseIterator::reset()
198+
{
199+
_index = 0;
200+
}
201+
202+
inline size_t SparseIterator::index() const
203+
{
204+
return _index;
205+
}
206+
207+
inline size_t SparseIterator::num_left() const
208+
{
209+
return _nnz - _index;
210+
}
211+
172212
inline Coordinates index2coords(const TensorShape &shape, int index)
173213
{
174214
int num_elements = shape.total_size();
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2025 Arm Limited.
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to
8+
* deal in the Software without restriction, including without limitation the
9+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10+
* sell copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
#ifndef ACL_ARM_COMPUTE_CORE_IREDUCIBLETENSOR_H
26+
#define ACL_ARM_COMPUTE_CORE_IREDUCIBLETENSOR_H
27+
28+
#include "arm_compute/core/SparseTensor.h"
29+
#include "arm_compute/runtime/COOTensor.h"
30+
#include "arm_compute/runtime/CSRTensor.h"
31+
32+
namespace arm_compute
33+
{
34+
/** */
35+
class IReducibleTensor
36+
{
37+
public:
38+
virtual ~IReducibleTensor() = default;
39+
/** Convert a dense tensor to sparse tensor with specified sparse dimensions using the default
40+
* sparse tensor representation: COO format.
41+
*
42+
* @param[in] dim sparse dimension
43+
*
44+
* @return A unique pointer to a SparseTensor object.
45+
*/
46+
virtual std::unique_ptr<SparseTensor> to_sparse(size_t dim) const = 0;
47+
/** Convert a dense tensor to COO sparse tensor with specified sparse dimensions.
48+
*
49+
* @param[in] dim sparse dimension
50+
*
51+
* @return A unique pointer to a COOTensor object.
52+
*/
53+
virtual std::unique_ptr<COOTensor> to_coo_sparse(size_t dim) const = 0;
54+
/** Convert a dense tensor to COO sparse tensor with the default sparse dimension.
55+
* For COO format, the number of sparse dimensions is equal to the total number of dimensions.
56+
*
57+
* @return A unique pointer to a COOTensor object.
58+
*/
59+
virtual std::unique_ptr<COOTensor> to_coo_sparse() const = 0;
60+
/** Convert a dense tensor to CSR sparse tensor with specified sparse dimensions.
61+
*
62+
* @param[in] dim sparse dimension
63+
*
64+
* @return A unique pointer to a CSRTensor object.
65+
*/
66+
virtual std::unique_ptr<CSRTensor> to_csr_sparse(size_t dim) const = 0;
67+
/** Convert a dense tensor to CSR sparse tensor with the default sparse dimension.
68+
* For CSR format, the number of sparse dimensions is equal to 2.
69+
*
70+
* @return A unique pointer to a CSRTensor object.
71+
*/
72+
virtual std::unique_ptr<CSRTensor> to_csr_sparse() const = 0;
73+
};
74+
}
75+
76+
#endif // ACL_ARM_COMPUTE_CORE_IREDUCIBLETENSOR_H

arm_compute/core/ITensorInfo.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "arm_compute/core/Coordinates.h"
3232
#include "arm_compute/core/Strides.h"
3333
#include "arm_compute/core/TensorShape.h"
34+
#include "arm_compute/core/TensorFormat.h"
3435
#include "arm_compute/core/Types.h"
3536
#include "arm_compute/core/utils/misc/Utility.h"
3637

@@ -105,6 +106,13 @@ class ITensorInfo : public misc::ICloneable<ITensorInfo>
105106
* @return Reference to this ITensorInfo object
106107
*/
107108
virtual ITensorInfo &set_format(Format format) = 0;
109+
/** Set the tensor format of an already initialized tensor.
110+
*
111+
* @param[in] tensor format to distinguish between dense and sparse tensors.
112+
*
113+
* @return Reference to this ITensorInfo object
114+
*/
115+
virtual ITensorInfo &set_tensor_format(TensorFormat tf) = 0;
108116
/** Set the shape of an already initialized tensor.
109117
*
110118
* @warning Changing the shape requires to recompute the strides and is
@@ -261,6 +269,16 @@ class ITensorInfo : public misc::ICloneable<ITensorInfo>
261269
* @return True if the tensor size can be changed.
262270
*/
263271
virtual bool is_resizable() const = 0;
272+
/** Flag indicating whether the tensor is sparse.
273+
*
274+
* @return True if the tensor format different from TensorFormat::Dense.
275+
*/
276+
virtual bool is_sparse() const = 0;
277+
/** Returns the format of the Tensor
278+
*
279+
* @return True if the tensor is an instance of SparseTensor.
280+
*/
281+
virtual TensorFormat tensor_format() const = 0;
264282
/** Set the tensor as dynamic/static
265283
*
266284
* @param[in] dynamic True if tensor is dynamic

arm_compute/core/SparseTensor.h

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2025 Arm Limited.
3+
*
4+
* SPDX-License-Identifier: MIT
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to
8+
* deal in the Software without restriction, including without limitation the
9+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10+
* sell copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
#ifndef ACL_ARM_COMPUTE_RUNTIME_SPARSETENSOR_H
26+
#define ACL_ARM_COMPUTE_RUNTIME_SPARSETENSOR_H
27+
28+
#include "arm_compute/core/ITensor.h"
29+
#include "arm_compute/core/Types.h"
30+
31+
#include <functional>
32+
#include <stdexcept>
33+
34+
typedef std::function<bool(const void *)> predicate_t;
35+
36+
namespace arm_compute
37+
{
38+
/** Common base class for all sparse tensors */
39+
class SparseTensor : public ITensor
40+
{
41+
public:
42+
/** Prevent instances of this class to be constructed by the default constructor */
43+
SparseTensor() = delete;
44+
/** Prevent instances of this class to be copy constructed */
45+
SparseTensor(const SparseTensor&) = delete;
46+
/** Prevent instances of this class to be copied */
47+
SparseTensor& operator=(const SparseTensor&) = delete;
48+
~SparseTensor() = default;
49+
50+
/** Returns the number of sparse dimensions */
51+
size_t sparse_dim() const;
52+
/** Returns the number of dense dimensions */
53+
size_t dense_dim() const;
54+
/** Returns the (total) number of dimensions */
55+
size_t dim() const;
56+
/** Returns true if the tensor is hybrid (contains both sparse and dense dimensions)
57+
*
58+
* @note A sparse tensor is hybrid if it has at least one dense dimension.
59+
*/
60+
bool is_hybrid() const;
61+
/** Returns the ratio of zero-valued elements to the total number of elements */
62+
float sparsity() const;
63+
/** Returns the ratio of non-zero elements to the total number of elements */
64+
float density() const;
65+
/** Returns the dense volume */
66+
uint32_t dense_volume(size_t sparse_dim) const;
67+
/** Returns the number of non zero elements */
68+
virtual size_t nnz() const = 0;
69+
/** Converts the sparse tensor to a dense tensor */
70+
virtual std::unique_ptr<ITensor> to_dense() = 0;
71+
/** Returns the coordinates of the n-th (non-zero) element.
72+
*
73+
* @param nth The *zero-base* index of the element
74+
*
75+
* @return The coordinates of the element
76+
*/
77+
virtual Coordinates get_coordinates(size_t nth) const = 0;
78+
/** Returns a pointer to the n-th (non-zero) element. If the element specified by
79+
* the coordinates is zero, nullptr is returned.
80+
*
81+
* @param nth The *zero-base* index of the element
82+
*
83+
* @return The value of the element
84+
*
85+
* @note The value has size dense_volume(sparse_dim()).
86+
*/
87+
virtual const uint8_t *get_value(Coordinates coords) const = 0;
88+
89+
protected:
90+
SparseTensor(size_t dim, size_t sparse_dim);
91+
92+
std::function<bool(const void *)> make_is_nonzero_predicate(DataType dt) const;
93+
bool has_non_zero_elements(uint8_t *arr, size_t len, size_t element_size, predicate_t is_non_zero) const;
94+
void print_values(std::ostream &os, const uint8_t *data, size_t offset, size_t count) const;
95+
96+
private:
97+
size_t _total_dim;
98+
size_t _sparse_dim;
99+
};
100+
}
101+
102+
#endif // ACL_ARM_COMPUTE_RUNTIME_SPARSETENSOR_H

arm_compute/core/SubTensorInfo.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "arm_compute/core/Strides.h"
3535
#include "arm_compute/core/TensorInfo.h"
3636
#include "arm_compute/core/TensorShape.h"
37+
#include "arm_compute/core/TensorFormat.h"
3738

3839
#include <cstddef>
3940
#include <memory>
@@ -200,6 +201,17 @@ class SubTensorInfo final : public ITensorInfo
200201
ARM_COMPUTE_ERROR_ON(_parent == nullptr);
201202
return _parent->is_resizable();
202203
}
204+
bool is_sparse() const override
205+
{
206+
ARM_COMPUTE_ERROR_ON(_parent == nullptr);
207+
return _parent->is_sparse();
208+
}
209+
ITensorInfo &set_tensor_format(TensorFormat tf) override;
210+
TensorFormat tensor_format() const override
211+
{
212+
ARM_COMPUTE_ERROR_ON(_parent == nullptr);
213+
return _parent->tensor_format();
214+
}
203215
ITensorInfo &set_dynamic(bool dynamic) override;
204216
bool is_dynamic() const override
205217
{

0 commit comments

Comments
 (0)