Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions arm_compute/core/Coordinates.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ class Coordinates : public Dimensions<int>
constexpr Coordinates(Ts... coords) : Dimensions{coords...}
{
}

/** Constructor to initialize the coordinates from a vector.
*
* @param[in] coords Vector containing the values to initialize the dimensions.
*/
template <typename T>
constexpr Coordinates(std::vector<T> coords) : Dimensions(coords)
{
}

/** Allow instances of this class to be copy constructed */
constexpr Coordinates(const Coordinates &) = default;
/** Allow instances of this class to be copied */
Expand Down
9 changes: 9 additions & 0 deletions arm_compute/core/Dimensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ class Dimensions
{
}

/** Constructor to initialize the tensor shape with a list of dim values.
*
* @param[in] dims Vector of values to initialize the dimensions.
*/
explicit Dimensions(std::vector<T> dims) : _id(), _num_dimensions{dims.size()}
{
std::copy_n(dims.begin(), std::min(num_max_dimensions, dims.size()), _id.begin());
}

/** Allow instances of this class to be copy constructed */
Dimensions(const Dimensions &) = default;

Expand Down
37 changes: 37 additions & 0 deletions arm_compute/core/Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "arm_compute/core/Types.h"
#include "arm_compute/core/Validate.h"
#include "arm_compute/core/Window.h"
#include "arm_compute/core/SparseTensor.h"

#include <array>
#include <cstddef>
Expand Down Expand Up @@ -126,6 +127,42 @@ class Iterator
std::array<Dimension, Coordinates::num_max_dimensions> _dims;
};

class SparseIterator
{
public:
/** Create an iterator for the metadata and allocation contained in the SparseTensor
*
* @param[in] tensor A reference to the tensor to associate to the iterator.
*/
SparseIterator(const SparseTensor &tensor);

/** Returns true if there is at least one more element to iterate */
bool has_next() const;

/** Move to the next non-zero element */
void next();

/** Get the coordinates of the current non-zero element */
Coordinates coordinates() const;

/** Get the value of the current non-zero element */
const uint8_t *value() const;

/** Reset iterator to the beginning */
void reset();

/** Get current index (nth non-zero) */
size_t index() const;

/** Get the number of non-zero elements that are left to iterate */
size_t num_left() const;

private:
const SparseTensor &_tensor;
size_t _index;
size_t _nnz;
};

/** Iterate through the passed window, automatically adjusting the iterators and calling the lambda_functino for each element.
* It passes the x and y positions to the lambda_function for each iteration
*
Expand Down
40 changes: 40 additions & 0 deletions arm_compute/core/Helpers.inl
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ inline Iterator::Iterator(const ITensor *tensor, const Window &win) : Iterator()
{
ARM_COMPUTE_ERROR_ON(tensor == nullptr);
ARM_COMPUTE_ERROR_ON(tensor->info() == nullptr);
ARM_COMPUTE_ERROR_ON_MSG(tensor->info()->is_sparse(), "Sparse tensors are not supported by Iterators. Use a SparseIterator instead");

initialize(tensor->info()->num_dimensions(), tensor->info()->strides_in_bytes(), tensor->buffer(),
tensor->info()->offset_first_element_in_bytes(), win);
Expand Down Expand Up @@ -169,6 +170,45 @@ inline void Iterator::reset(const size_t dimension)
}
}

inline SparseIterator::SparseIterator(const SparseTensor &tensor) : _tensor(tensor), _index(0), _nnz(tensor.nnz())
{
}

inline bool SparseIterator::has_next() const
{
return _index < _nnz;
}

inline void SparseIterator::next()
{
++_index;
}

inline Coordinates SparseIterator::coordinates() const
{
return _tensor.get_coordinates(_index);
}

inline const uint8_t *SparseIterator::value() const
{
return _tensor.get_value(coordinates());
}

inline void SparseIterator::reset()
{
_index = 0;
}

inline size_t SparseIterator::index() const
{
return _index;
}

inline size_t SparseIterator::num_left() const
{
return _nnz - _index;
}

inline Coordinates index2coords(const TensorShape &shape, int index)
{
int num_elements = shape.total_size();
Expand Down
80 changes: 80 additions & 0 deletions arm_compute/core/IReducibleTensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright (c) 2025 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef ACL_ARM_COMPUTE_CORE_IREDUCIBLETENSOR_H
#define ACL_ARM_COMPUTE_CORE_IREDUCIBLETENSOR_H

#include "arm_compute/core/SparseTensor.h"

namespace arm_compute
{
/** Forward declaration of COOTensor and CSRTensor class */
class COOTensor;
class CSRTensor;

/** Interface for all reducible tensors, i.e. all tensors that can be
* converted to a sparse representation.
*/
class IReducibleTensor
{
public:
virtual ~IReducibleTensor() = default;
/** Convert a dense tensor to sparse tensor with specified sparse dimensions using the default
* sparse tensor representation: COO format.
*
* @param[in] dim sparse dimension
*
* @return A unique pointer to a SparseTensor object.
*/
virtual std::unique_ptr<SparseTensor> to_sparse(size_t dim) const = 0;
/** Convert a dense tensor to COO sparse tensor with specified sparse dimensions.
*
* @param[in] dim sparse dimension
*
* @return A unique pointer to a COOTensor object.
*/
virtual std::unique_ptr<COOTensor> to_coo_sparse(size_t dim) const = 0;
/** Convert a dense tensor to COO sparse tensor with the default sparse dimension.
* For COO format, the number of sparse dimensions is equal to the total number of dimensions.
*
* @return A unique pointer to a COOTensor object.
*/
virtual std::unique_ptr<COOTensor> to_coo_sparse() const = 0;
/** Convert a dense tensor to CSR sparse tensor with specified sparse dimensions.
*
* @param[in] dim sparse dimension
*
* @return A unique pointer to a CSRTensor object.
*/
virtual std::unique_ptr<CSRTensor> to_csr_sparse(size_t dim) const = 0;
/** Convert a dense tensor to CSR sparse tensor with the default sparse dimension.
* For CSR format, the number of sparse dimensions is equal to 2.
*
* @return A unique pointer to a CSRTensor object.
*/
virtual std::unique_ptr<CSRTensor> to_csr_sparse() const = 0;
};
}

#endif // ACL_ARM_COMPUTE_CORE_IREDUCIBLETENSOR_H
18 changes: 18 additions & 0 deletions arm_compute/core/ITensorInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "arm_compute/core/Coordinates.h"
#include "arm_compute/core/Strides.h"
#include "arm_compute/core/TensorShape.h"
#include "arm_compute/core/TensorFormat.h"
#include "arm_compute/core/Types.h"
#include "arm_compute/core/utils/misc/Utility.h"

Expand Down Expand Up @@ -105,6 +106,13 @@ class ITensorInfo : public misc::ICloneable<ITensorInfo>
* @return Reference to this ITensorInfo object
*/
virtual ITensorInfo &set_format(Format format) = 0;
/** Set the tensor format of an already initialized tensor.
*
* @param[in] tensor format to distinguish between dense and sparse tensors.
*
* @return Reference to this ITensorInfo object
*/
virtual ITensorInfo &set_tensor_format(TensorFormat tf) = 0;
/** Set the shape of an already initialized tensor.
*
* @warning Changing the shape requires to recompute the strides and is
Expand Down Expand Up @@ -261,6 +269,16 @@ class ITensorInfo : public misc::ICloneable<ITensorInfo>
* @return True if the tensor size can be changed.
*/
virtual bool is_resizable() const = 0;
/** Flag indicating whether the tensor is sparse.
*
* @return True if the tensor format different from TensorFormat::Dense.
*/
virtual bool is_sparse() const = 0;
/** Returns the format of the Tensor
*
* @return True if the tensor is an instance of SparseTensor.
*/
virtual TensorFormat tensor_format() const = 0;
/** Set the tensor as dynamic/static
*
* @param[in] dynamic True if tensor is dynamic
Expand Down
102 changes: 102 additions & 0 deletions arm_compute/core/SparseTensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2025 Arm Limited.
*
* SPDX-License-Identifier: MIT
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

#ifndef ACL_ARM_COMPUTE_RUNTIME_SPARSETENSOR_H
#define ACL_ARM_COMPUTE_RUNTIME_SPARSETENSOR_H

#include "arm_compute/core/ITensor.h"
#include "arm_compute/core/Types.h"

#include <functional>
#include <stdexcept>

typedef std::function<bool(const void *)> predicate_t;

namespace arm_compute
{
/** Common base class for all sparse tensors */
class SparseTensor : public ITensor
{
public:
/** Prevent instances of this class to be constructed by the default constructor */
SparseTensor() = delete;
/** Prevent instances of this class to be copy constructed */
SparseTensor(const SparseTensor&) = delete;
/** Prevent instances of this class to be copied */
SparseTensor& operator=(const SparseTensor&) = delete;
~SparseTensor() = default;

/** Returns the number of sparse dimensions */
size_t sparse_dim() const;
/** Returns the number of dense dimensions */
size_t dense_dim() const;
/** Returns the (total) number of dimensions */
size_t dim() const;
/** Returns true if the tensor is hybrid (contains both sparse and dense dimensions)
*
* @note A sparse tensor is hybrid if it has at least one dense dimension.
*/
bool is_hybrid() const;
/** Returns the ratio of zero-valued elements to the total number of elements */
float sparsity() const;
/** Returns the ratio of non-zero elements to the total number of elements */
float density() const;
/** Returns the dense volume */
uint32_t dense_volume(size_t sparse_dim) const;
/** Returns the number of non zero elements */
virtual size_t nnz() const = 0;
/** Converts the sparse tensor to a dense tensor */
virtual std::unique_ptr<ITensor> to_dense() = 0;
/** Returns the coordinates of the n-th (non-zero) element.
*
* @param nth The *zero-base* index of the element
*
* @return The coordinates of the element
*/
virtual Coordinates get_coordinates(size_t nth) const = 0;
/** Returns a pointer to the n-th (non-zero) element. If the element specified by
* the coordinates is zero, nullptr is returned.
*
* @param nth The *zero-base* index of the element
*
* @return The value of the element
*
* @note The value has size dense_volume(sparse_dim()).
*/
virtual const uint8_t *get_value(Coordinates coords) const = 0;

protected:
SparseTensor(size_t dim, size_t sparse_dim);

std::function<bool(const void *)> make_is_nonzero_predicate(DataType dt) const;
bool has_non_zero_elements(uint8_t *arr, size_t len, size_t element_size, predicate_t is_non_zero) const;
void print_values(std::ostream &os, const uint8_t *data, size_t offset, size_t count) const;

private:
size_t _total_dim;
size_t _sparse_dim;
};
}

#endif // ACL_ARM_COMPUTE_RUNTIME_SPARSETENSOR_H
12 changes: 12 additions & 0 deletions arm_compute/core/SubTensorInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "arm_compute/core/Strides.h"
#include "arm_compute/core/TensorInfo.h"
#include "arm_compute/core/TensorShape.h"
#include "arm_compute/core/TensorFormat.h"

#include <cstddef>
#include <memory>
Expand Down Expand Up @@ -200,6 +201,17 @@ class SubTensorInfo final : public ITensorInfo
ARM_COMPUTE_ERROR_ON(_parent == nullptr);
return _parent->is_resizable();
}
bool is_sparse() const override
{
ARM_COMPUTE_ERROR_ON(_parent == nullptr);
return _parent->is_sparse();
}
ITensorInfo &set_tensor_format(TensorFormat tf) override;
TensorFormat tensor_format() const override
{
ARM_COMPUTE_ERROR_ON(_parent == nullptr);
return _parent->tensor_format();
}
ITensorInfo &set_dynamic(bool dynamic) override;
bool is_dynamic() const override
{
Expand Down
Loading