aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeresa Charlin <teresa.charlinreyes@arm.com>2020-06-23 18:30:57 +0100
committerTeresa Charlin <teresa.charlinreyes@arm.com>2020-07-03 19:53:30 +0100
commit11f6ace7cd8bf8dd2cf40bdab57a66bfb0f25f0e (patch)
tree2c2d34a5a734f38f03fd8d104095f9cbca5165d1
parent1f2494456b64cb50009c279cac34ee17286ed4ed (diff)
downloadarmnn-11f6ace7cd8bf8dd2cf40bdab57a66bfb0f25f0e.tar.gz
IVGCVSW-5020 Refactor TensorShape to host dynamic tensors and scalar values
Signed-off-by: Teresa Charlin <teresa.charlinreyes@arm.com> Change-Id: I63f97fad080dbfeec6433c2548f0311173051a6a
-rw-r--r--include/armnn/Tensor.hpp109
-rw-r--r--include/armnn/Types.hpp7
-rw-r--r--src/armnn/Tensor.cpp258
-rw-r--r--src/armnn/test/TensorTest.cpp205
4 files changed, 547 insertions, 32 deletions
diff --git a/include/armnn/Tensor.hpp b/include/armnn/Tensor.hpp
index 545b71a03f..9e49f75d25 100644
--- a/include/armnn/Tensor.hpp
+++ b/include/armnn/Tensor.hpp
@@ -23,31 +23,130 @@ public:
/// Empty (invalid) constructor.
TensorShape();
- TensorShape(unsigned int numDimensions);
-
+ /// Constructor for TensorShape
+ /// @param numDimensions - Tensor rank.
+ /// @param initDimensionsSpecificity (optional) - value to initialize the specificity of each dimension size.
+ explicit TensorShape(unsigned int numDimensions, bool initDimensionsSpecificity = true);
+
+ /// Constructor for TensorShape
+ /// @param numDimensions - Tensor rank.
+ /// @param dimensionSizes - Size of each of dimension.
TensorShape(unsigned int numDimensions, const unsigned int* dimensionSizes);
+ /// Constructor for TensorShape
+ /// @param dimensionSizeList - Size of each of dimension.
TensorShape(std::initializer_list<unsigned int> dimensionSizeList);
+ /// Copy Constructor for TensorShape
+ /// @param other - TensorShape to copy from.
TensorShape(const TensorShape& other);
+ /// Constructor for TensorShape
+ /// @param numDimensions - Tensor rank.
+ /// @param dimensionSizes - Size of each of dimension.
+ /// @param dimensionsSpecificity - Flags to indicate which dimension has its size specified.
+ TensorShape(unsigned int numDimensions, const unsigned int* dimensionSizes, const bool* dimensionsSpecificity);
+
+ /// Constructor for TensorShape
+ /// @param dimensionSizeList - Size of each of dimension.
+ /// @param dimensionsSpecificityList - Flags to indicate which dimension size is specified.
+ TensorShape(std::initializer_list<unsigned int> dimensionSizeList,
+ std::initializer_list<bool> dimensionsSpecificityList);
+
+ /// Constructor for TensorShape
+ /// @param dimensionality - Parameter to indicate if the Tensor is a Scalar, a Tensor of known dimensionality
+ /// or a Tensor of unknown dimensionality.
+ explicit TensorShape(Dimensionality dimensionality);
+
+ /// Assignation function
+ /// @param other - TensorShape to copy from.
TensorShape& operator=(const TensorShape& other);
+ /// Read only operator
+ /// @param i - Dimension index.
unsigned int operator[](unsigned int i) const;
+ /// Read and write operator
+ /// @param i - Dimension index.
unsigned int& operator[](unsigned int i);
+ /// Equality comparison operator
+ /// @param other - TensorShape to compare with.
bool operator==(const TensorShape& other) const;
+
+ /// Inequality comparison operator
+ /// @param other - TensorShape to compare with.
bool operator!=(const TensorShape& other) const;
- unsigned int GetNumDimensions() const { return m_NumDimensions; }
+ /// Function that returns the tensor rank.
+ /// @return - Tensor rank.
+ unsigned int GetNumDimensions() const;
+
+ /// Function that calculates the tensor elements by multiplying all dimension size which are Specified.
+ /// @return - Total number of elements in the tensor.
unsigned int GetNumElements() const;
+ /// Function that returns the tensor type.
+ /// @return - Parameter to indicate if the Tensor is a scalar, a Tensor of known dimensionality or
+ /// a Tensor of unknown dimensionality
+ Dimensionality GetDimensionality() const { return m_Dimensionality; }
+
+ /// Gets information about if the dimension size has been specified or not
+ /// @param i - Dimension index.
+ /// @return - Flag to indicate if the dimension "i" has a specified size.
+ bool GetDimensionSpecificity(unsigned int i) const;
+
+ /// Sets the tensor rank and therefore the Dimensionality is set to Specified if it was not.
+ /// @param numDimensions - Tensor rank.
+ /// @param initDimensionsSpecificity (optional) - value to initialize the specificity of each dimension size.
+ void SetNumDimensions(unsigned int numDimensions, bool initDimensionsSpecificity = false);
+
+ /// Sets the size of the indicated dimension and Specificity for that dimension is set to true.
+ /// @param i - Dimension index.
+ /// @param dimensionSize - size of one dimension.
+ void SetDimensionSize(unsigned int i, unsigned int dimensionSize);
+
+ /// Checks if there is at least one dimension not specified. AND of all array elements.
+ /// @return - True when all dimension sizes are specified. False when at least one dimension size is not specified.
+ bool AreAllDimensionsSpecified() const;
+
+ /// Checks if there is at least one dimension specified. OR of all array elements.
+ /// @return - True at least one dimension sizes is specified. False when all dimension sizes are not specified.
+ bool IsAtLeastOneDimensionSpecified() const;
+
private:
- std::array<unsigned int, MaxNumOfTensorDimensions> m_Dimensions;
- unsigned int m_NumDimensions;
+ /// Array of the dimension sizes.
+ std::array<unsigned int, MaxNumOfTensorDimensions> m_Dimensions{};
+ /// Array of flags to indicate if the size of each of the dimensions is specified or not
+ std::array<bool, MaxNumOfTensorDimensions> m_DimensionsSpecificity = {true};
+
+ /// Tensor rank
+ unsigned int m_NumDimensions{};
+
+ /// Tensor type: Specified, NotSpecified or Scalar.
+ Dimensionality m_Dimensionality = Dimensionality::Specified;
+
+ /// Checks if the dimension index given is within range.
+ /// @param i - Dimension index.
void CheckDimensionIndex(unsigned int i) const;
+
+ /// Checks if the tensor rank given is within range.
+ /// @param numDimensions - Tensor rank.
+ static void CheckValidNumDimensions(unsigned int numDimensions) ;
+
+ /// Checks if the size of the dimension index given is specified.
+ /// @param i - Dimension index.
+ void CheckDimensionSpecified(unsigned int i) const;
+
+ /// Checks if this is a scalar.
+ void CheckScalar() const;
+
+ /// Checks if the number of dimensions is unknown, i.e. rank is unspecified.
+ void CheckUnspecifiedNumDimensions() const;
+
+ /// Checks if the number of dimensions is known, i.e. rank is specified.
+ void CheckSpecifiedNumDimensions() const;
};
class TensorInfo
diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp
index fb6f134766..11d807cd89 100644
--- a/include/armnn/Types.hpp
+++ b/include/armnn/Types.hpp
@@ -106,6 +106,13 @@ enum class ResizeMethod
NearestNeighbor = 1
};
+enum class Dimensionality
+{
+ NotSpecified = 0,
+ Specified = 1,
+ Scalar = 2
+};
+
///
/// The padding method modifies the output of pooling layers.
/// In both supported methods, the values are ignored (they are
diff --git a/src/armnn/Tensor.cpp b/src/armnn/Tensor.cpp
index 7cb2f0ea13..6ad46c59c9 100644
--- a/src/armnn/Tensor.cpp
+++ b/src/armnn/Tensor.cpp
@@ -12,6 +12,8 @@
#include <boost/numeric/conversion/cast.hpp>
+#include <iostream>
+
#include <sstream>
namespace armnn
@@ -22,81 +24,147 @@ namespace armnn
// ---
TensorShape::TensorShape()
- : m_NumDimensions(0)
+ : m_NumDimensions(0), m_Dimensionality(Dimensionality::Specified)
{
}
-TensorShape::TensorShape(unsigned int numDimensions)
- : m_NumDimensions(numDimensions)
+TensorShape::TensorShape(unsigned int numDimensions, bool initDimensionsSpecificity)
+ : m_NumDimensions(numDimensions), m_Dimensionality(Dimensionality::Specified)
{
- if (numDimensions < 1)
- {
- throw InvalidArgumentException("Tensor numDimensions must be greater than 0");
- }
-
- if (numDimensions > MaxNumOfTensorDimensions)
- {
- throw InvalidArgumentException("Tensor numDimensions must be less than or equal to MaxNumOfTensorDimensions");
- }
+ CheckValidNumDimensions(numDimensions);
std::fill(m_Dimensions.begin(), m_Dimensions.begin() + m_NumDimensions, 0);
+ std::fill(m_DimensionsSpecificity.begin(), m_DimensionsSpecificity.begin() + m_NumDimensions,
+ initDimensionsSpecificity);
}
TensorShape::TensorShape(const unsigned int numDimensions, const unsigned int* const dimensionSizes)
- : m_NumDimensions(numDimensions)
+ : m_NumDimensions(numDimensions), m_Dimensionality(Dimensionality::Specified)
{
- if (numDimensions < 1)
- {
- throw InvalidArgumentException("Tensor numDimensions must be greater than 0");
- }
+ CheckValidNumDimensions(numDimensions);
- if (numDimensions > MaxNumOfTensorDimensions)
+ if (dimensionSizes == nullptr)
{
- throw InvalidArgumentException("Tensor numDimensions must be less than or equal to MaxNumOfTensorDimensions");
+ throw InvalidArgumentException("Tensor dimensionSizes must not be NULL");
}
+ std::copy(dimensionSizes, dimensionSizes + numDimensions, m_Dimensions.begin());
+ std::fill(m_DimensionsSpecificity.begin(), m_DimensionsSpecificity.begin() + m_NumDimensions, true);
+}
+
+TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList)
+ : TensorShape(boost::numeric_cast<unsigned int>(dimensionSizeList.size()), dimensionSizeList.begin())
+{
+}
+
+TensorShape::TensorShape(unsigned int numDimensions,
+ const unsigned int* const dimensionSizes,
+ const bool* const dimensionsSpecificity)
+ : m_NumDimensions(numDimensions), m_Dimensionality(Dimensionality::Specified)
+{
+ CheckValidNumDimensions(numDimensions);
+
if (dimensionSizes == nullptr)
{
throw InvalidArgumentException("Tensor dimensionSizes must not be NULL");
}
+ if (dimensionsSpecificity == nullptr)
+ {
+ throw InvalidArgumentException("Tensor dimensionsSpecificity must not be NULL");
+ }
+
std::copy(dimensionSizes, dimensionSizes + numDimensions, m_Dimensions.begin());
+ std::copy(dimensionsSpecificity, dimensionsSpecificity + numDimensions, m_DimensionsSpecificity.begin());
}
-TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList)
- : TensorShape(boost::numeric_cast<unsigned int>(dimensionSizeList.size()), dimensionSizeList.begin())
+TensorShape::TensorShape(std::initializer_list<unsigned int> dimensionSizeList,
+ std::initializer_list<bool> dimensionsSpecificityList)
{
+ auto numDimensions = static_cast<unsigned int>(dimensionSizeList.size());
+ if (dimensionsSpecificityList.size() != numDimensions)
+ {
+ throw InvalidArgumentException("Tensors dimensionSizeList and dimensionsSpecificityList must be same size");
+ }
+
+ *this = TensorShape(numDimensions, dimensionSizeList.begin(), dimensionsSpecificityList.begin());
+}
+
+TensorShape::TensorShape(Dimensionality dimensionality)
+: m_Dimensionality(dimensionality)
+{
+ switch (dimensionality)
+ {
+ case Dimensionality::Specified:
+ throw InvalidArgumentException("Use other constructor to specify the rest of the values, this one is only "
+ "for tensors that have an unknown number of dimensions or that are scalar");
+ break;
+ case Dimensionality::NotSpecified:
+ m_NumDimensions = 0;
+ m_Dimensions = {0};
+ m_DimensionsSpecificity = {false};
+ break;
+ case Dimensionality::Scalar:
+ m_NumDimensions = 1;
+ m_Dimensions = {1};
+ m_DimensionsSpecificity = {true};
+ break;
+ default:
+ throw InvalidArgumentException("Invalid Dimensionality value");
+ }
}
TensorShape::TensorShape(const TensorShape& other)
- : m_NumDimensions(other.m_NumDimensions)
+ : m_NumDimensions(other.m_NumDimensions), m_Dimensionality(other.m_Dimensionality)
{
std::copy(other.m_Dimensions.cbegin(), other.m_Dimensions.cbegin() + other.m_NumDimensions, m_Dimensions.begin());
+ std::copy(other.m_DimensionsSpecificity.cbegin(), other.m_DimensionsSpecificity.cbegin() + other.m_NumDimensions,
+ m_DimensionsSpecificity.begin());
}
TensorShape& TensorShape::operator =(const TensorShape& other)
{
m_NumDimensions = other.m_NumDimensions;
+ m_Dimensionality = other.m_Dimensionality;
std::copy(other.m_Dimensions.cbegin(), other.m_Dimensions.cbegin() + other.m_NumDimensions, m_Dimensions.begin());
+ std::copy(other.m_DimensionsSpecificity.cbegin(), other.m_DimensionsSpecificity.cbegin() + other.m_NumDimensions,
+ m_DimensionsSpecificity.begin());
return *this;
}
+// read
unsigned int TensorShape::operator[](unsigned int i) const
{
+ CheckUnspecifiedNumDimensions();
CheckDimensionIndex(i);
+ CheckDimensionSpecified(i);
+
return m_Dimensions.at(i);
}
+// read and write
unsigned int& TensorShape::operator[](unsigned int i)
{
+ if (Dimensionality::Scalar == m_Dimensionality)
+ {
+ std::stringstream errorMessage;
+ errorMessage << "TensorShape with Dimensionality::Scalar must be const to use operator[]";
+ throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
+ }
+ CheckUnspecifiedNumDimensions();
CheckDimensionIndex(i);
+ CheckDimensionSpecified(i);
+
return m_Dimensions.at(i);
}
bool TensorShape::operator==(const TensorShape& other) const
{
return ((m_NumDimensions == other.m_NumDimensions) &&
- std::equal(m_Dimensions.cbegin(), m_Dimensions.cbegin() + m_NumDimensions, other.m_Dimensions.cbegin()));
+ (m_Dimensionality == other.m_Dimensionality) &&
+ std::equal(m_Dimensions.cbegin(), m_Dimensions.cbegin() + m_NumDimensions, other.m_Dimensions.cbegin()) &&
+ std::equal(m_DimensionsSpecificity.cbegin(), m_DimensionsSpecificity.cbegin() + m_NumDimensions,
+ other.m_DimensionsSpecificity.cbegin()));
}
bool TensorShape::operator!=(const TensorShape& other) const
@@ -104,20 +172,104 @@ bool TensorShape::operator!=(const TensorShape& other) const
return !(*this == other);
}
+unsigned int TensorShape::GetNumDimensions() const
+{
+ CheckUnspecifiedNumDimensions();
+
+ return m_NumDimensions;
+}
+
unsigned int TensorShape::GetNumElements() const
{
+ CheckUnspecifiedNumDimensions();
+
if (m_NumDimensions == 0)
{
return 0;
}
unsigned int count = 1;
- for (unsigned int i = 0; i < m_NumDimensions; i++)
+ bool atLeastOneDimensionSpecified = false;
+ for (unsigned int i = 0; i < m_NumDimensions; ++i)
+ {
+ if (m_DimensionsSpecificity[i] && m_Dimensions[i] != 0)
+ {
+ atLeastOneDimensionSpecified = true;
+ count *= m_Dimensions[i];
+ }
+ }
+
+ if (atLeastOneDimensionSpecified)
+ {
+ return count;
+ }
+ else
{
- count *= m_Dimensions[i];
+ return 0;
}
+}
- return count;
+bool TensorShape:: GetDimensionSpecificity(unsigned int i) const
+{
+ CheckUnspecifiedNumDimensions();
+ CheckDimensionIndex(i);
+
+ return m_DimensionsSpecificity[i];
+}
+
+void TensorShape::SetNumDimensions(unsigned int numDimensions, bool initDimensionsSpecificity)
+{
+ CheckScalar();
+ CheckSpecifiedNumDimensions();
+ CheckValidNumDimensions(numDimensions);
+
+ m_NumDimensions = numDimensions;
+ m_Dimensionality = Dimensionality::Specified;
+ std::fill(m_Dimensions.begin(), m_Dimensions.begin() + m_NumDimensions, 0);
+ std::fill(m_DimensionsSpecificity.begin(), m_DimensionsSpecificity.begin() + m_NumDimensions,
+ initDimensionsSpecificity);
+}
+
+void TensorShape::SetDimensionSize(unsigned int i, unsigned int dimensionSize)
+{
+ CheckScalar();
+ CheckUnspecifiedNumDimensions();
+ CheckDimensionIndex(i);
+
+ m_Dimensions[i] = dimensionSize;
+ m_DimensionsSpecificity[i] = true;
+}
+
+bool TensorShape::AreAllDimensionsSpecified() const
+{
+ CheckUnspecifiedNumDimensions();
+
+ bool areAllDimensionsSpecified = true;
+ for (unsigned int i = 0; i < m_NumDimensions; ++i)
+ {
+ if (!m_DimensionsSpecificity[i])
+ {
+ areAllDimensionsSpecified = false;
+ break;
+ }
+ }
+ return areAllDimensionsSpecified;
+}
+
+bool TensorShape::IsAtLeastOneDimensionSpecified() const
+{
+ CheckUnspecifiedNumDimensions();
+
+ bool isAtLeastOneDimensionSpecified = false;
+ for (unsigned int i = 0; i < m_NumDimensions; ++i)
+ {
+ if (m_DimensionsSpecificity[i])
+ {
+ isAtLeastOneDimensionSpecified = true;
+ break;
+ }
+ }
+ return isAtLeastOneDimensionSpecified;
}
void TensorShape::CheckDimensionIndex(unsigned int i) const
@@ -130,6 +282,60 @@ void TensorShape::CheckDimensionIndex(unsigned int i) const
}
}
+void TensorShape::CheckValidNumDimensions(unsigned int numDimensions)
+{
+ if (numDimensions < 1)
+ {
+ throw InvalidArgumentException("Tensor numDimensions must be greater than 0", CHECK_LOCATION());
+ }
+
+ if (numDimensions > MaxNumOfTensorDimensions)
+ {
+ throw InvalidArgumentException("Tensor numDimensions must be less than or equal to MaxNumOfTensorDimensions"
+ , CHECK_LOCATION());
+ }
+}
+
+void TensorShape::CheckDimensionSpecified(unsigned int i) const
+{
+ if (!m_DimensionsSpecificity[i])
+ {
+ std::stringstream errorMessage;
+ errorMessage << "Dimension index: " << i << " not specified. Tensor shape not inferred yet.";
+ throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
+ }
+}
+
+void TensorShape::CheckScalar() const
+{
+ if (Dimensionality::Scalar == m_Dimensionality)
+ {
+ std::stringstream errorMessage;
+ errorMessage << "Invalid action on a tensor shape that holds a scalar value.";
+ throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
+ }
+}
+
+void TensorShape::CheckUnspecifiedNumDimensions() const
+{
+ if (Dimensionality::NotSpecified == m_Dimensionality)
+ {
+ std::stringstream errorMessage;
+ errorMessage << "Invalid action on a tensor shape that has unknown number of dimensions.";
+ throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
+ }
+}
+
+void TensorShape::CheckSpecifiedNumDimensions() const
+{
+ if (Dimensionality::Specified == m_Dimensionality)
+ {
+ std::stringstream errorMessage;
+ errorMessage << "Invalid action on a tensor shape that has known number of dimensions.";
+ throw InvalidArgumentException(errorMessage.str(), CHECK_LOCATION());
+ }
+}
+
// ---
// --- TensorInfo
// ---
diff --git a/src/armnn/test/TensorTest.cpp b/src/armnn/test/TensorTest.cpp
index 2e28a9ae7d..ed3925539b 100644
--- a/src/armnn/test/TensorTest.cpp
+++ b/src/armnn/test/TensorTest.cpp
@@ -4,6 +4,8 @@
//
#include <boost/test/unit_test.hpp>
#include <armnn/Tensor.hpp>
+#include <armnn/utility/IgnoreUnused.hpp>
+
namespace armnn
{
@@ -135,12 +137,16 @@ BOOST_AUTO_TEST_CASE(ModifyTensorInfo)
BOOST_AUTO_TEST_CASE(TensorShapeOperatorBrackets)
{
+ const TensorShape constShape({0,1,2,3});
TensorShape shape({0,1,2,3});
+
// Checks version of operator[] which returns an unsigned int.
BOOST_TEST(shape[2] == 2);
- // Checks the version of operator[] which returns a reference.
shape[2] = 20;
BOOST_TEST(shape[2] == 20);
+
+ // Checks the version of operator[] which returns a reference.
+ BOOST_TEST(constShape[2] == 2);
}
BOOST_AUTO_TEST_CASE(TensorInfoPerAxisQuantization)
@@ -177,4 +183,201 @@ BOOST_AUTO_TEST_CASE(TensorInfoPerAxisQuantization)
BOOST_CHECK(tensorInfo1.GetQuantizationDim().value() == 1);
}
+BOOST_AUTO_TEST_CASE(TensorShape_scalar)
+{
+ float mutableDatum = 3.1416f;
+
+ const armnn::TensorShape shape (armnn::Dimensionality::Scalar );
+ armnn::TensorInfo info ( shape, DataType::Float32 );
+ const armnn::Tensor tensor ( info, &mutableDatum );
+
+ BOOST_CHECK(armnn::Dimensionality::Scalar == shape.GetDimensionality());
+ float scalarValue = *reinterpret_cast<float*>(tensor.GetMemoryArea());
+ BOOST_CHECK_MESSAGE(mutableDatum == scalarValue, "Scalar value is " << scalarValue);
+
+ armnn::TensorShape shape_equal;
+ armnn::TensorShape shape_different;
+ shape_equal = shape;
+ BOOST_TEST(shape_equal == shape);
+ BOOST_TEST(shape_different != shape);
+ BOOST_CHECK_MESSAGE(1 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
+ BOOST_CHECK_MESSAGE(1 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(0));
+ BOOST_CHECK(shape.AreAllDimensionsSpecified());
+ BOOST_CHECK(shape.IsAtLeastOneDimensionSpecified());
+
+ BOOST_TEST(1 == shape[0]);
+ BOOST_TEST(1 == tensor.GetShape()[0]);
+ BOOST_TEST(1 == tensor.GetInfo().GetShape()[0]);
+ BOOST_CHECK_THROW( shape[1], InvalidArgumentException );
+
+ float newMutableDatum = 42.f;
+ std::memcpy(tensor.GetMemoryArea(), &newMutableDatum, sizeof(float));
+ scalarValue = *reinterpret_cast<float*>(tensor.GetMemoryArea());
+ BOOST_CHECK_MESSAGE(newMutableDatum == scalarValue, "Scalar value is " << scalarValue);
+}
+
+BOOST_AUTO_TEST_CASE(TensorShape_DynamicTensorType1_unknownNumberDimensions)
+{
+ float mutableDatum = 3.1416f;
+
+ armnn::TensorShape shape (armnn::Dimensionality::NotSpecified );
+ armnn::TensorInfo info ( shape, DataType::Float32 );
+ armnn::Tensor tensor ( info, &mutableDatum );
+
+ BOOST_CHECK(armnn::Dimensionality::NotSpecified == shape.GetDimensionality());
+ BOOST_CHECK_THROW( shape[0], InvalidArgumentException );
+ BOOST_CHECK_THROW( shape.GetNumElements(), InvalidArgumentException );
+ BOOST_CHECK_THROW( shape.GetNumDimensions(), InvalidArgumentException );
+
+ armnn::TensorShape shape_equal;
+ armnn::TensorShape shape_different;
+ shape_equal = shape;
+ BOOST_TEST(shape_equal == shape);
+ BOOST_TEST(shape_different != shape);
+}
+
+BOOST_AUTO_TEST_CASE(TensorShape_DynamicTensorType1_unknownAllDimensionsSizes)
+{
+ float mutableDatum = 3.1416f;
+
+ armnn::TensorShape shape ( 3, false );
+ armnn::TensorInfo info ( shape, DataType::Float32 );
+ armnn::Tensor tensor ( info, &mutableDatum );
+
+ BOOST_CHECK(armnn::Dimensionality::Specified == shape.GetDimensionality());
+ BOOST_CHECK_MESSAGE(0 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
+ BOOST_CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(0));
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(1));
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(2));
+ BOOST_CHECK(!shape.AreAllDimensionsSpecified());
+ BOOST_CHECK(!shape.IsAtLeastOneDimensionSpecified());
+
+ armnn::TensorShape shape_equal;
+ armnn::TensorShape shape_different;
+ shape_equal = shape;
+ BOOST_TEST(shape_equal == shape);
+ BOOST_TEST(shape_different != shape);
+}
+
+BOOST_AUTO_TEST_CASE(TensorShape_DynamicTensorType1_unknownSomeDimensionsSizes)
+{
+ std::vector<float> mutableDatum { 42.f, 42.f, 42.f,
+ 0.0f, 0.1f, 0.2f };
+
+ armnn::TensorShape shape ( {2, 0, 3}, {true, false, true} );
+ armnn::TensorInfo info ( shape, DataType::Float32 );
+ armnn::Tensor tensor ( info, &mutableDatum );
+
+ BOOST_CHECK(armnn::Dimensionality::Specified == shape.GetDimensionality());
+ BOOST_CHECK_MESSAGE(6 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
+ BOOST_CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(0));
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(1));
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(2));
+ BOOST_CHECK(!shape.AreAllDimensionsSpecified());
+ BOOST_CHECK(shape.IsAtLeastOneDimensionSpecified());
+
+ BOOST_CHECK_THROW(shape[1], InvalidArgumentException);
+ BOOST_CHECK_THROW(tensor.GetShape()[1], InvalidArgumentException);
+ BOOST_CHECK_THROW(tensor.GetInfo().GetShape()[1], InvalidArgumentException);
+
+ BOOST_TEST(2 == shape[0]);
+ BOOST_TEST(2 == tensor.GetShape()[0]);
+ BOOST_TEST(2 == tensor.GetInfo().GetShape()[0]);
+ BOOST_CHECK_THROW( shape[1], InvalidArgumentException );
+
+ BOOST_TEST(3 == shape[2]);
+ BOOST_TEST(3 == tensor.GetShape()[2]);
+ BOOST_TEST(3 == tensor.GetInfo().GetShape()[2]);
+
+ armnn::TensorShape shape_equal;
+ armnn::TensorShape shape_different;
+ shape_equal = shape;
+ BOOST_TEST(shape_equal == shape);
+ BOOST_TEST(shape_different != shape);
+}
+
+BOOST_AUTO_TEST_CASE(TensorShape_DynamicTensorType1_transitionFromUnknownToKnownDimensionsSizes)
+{
+ std::vector<float> mutableDatum { 42.f, 42.f, 42.f,
+ 0.0f, 0.1f, 0.2f };
+
+ armnn::TensorShape shape (armnn::Dimensionality::NotSpecified );
+ armnn::TensorInfo info ( shape, DataType::Float32 );
+ armnn::Tensor tensor ( info, &mutableDatum );
+
+ // Specify the number of dimensions
+ shape.SetNumDimensions(3);
+ BOOST_CHECK(armnn::Dimensionality::Specified == shape.GetDimensionality());
+ BOOST_CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(0));
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(1));
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(2));
+ BOOST_CHECK(!shape.AreAllDimensionsSpecified());
+ BOOST_CHECK(!shape.IsAtLeastOneDimensionSpecified());
+
+ // Specify dimension 0 and 2.
+ shape.SetDimensionSize(0, 2);
+ shape.SetDimensionSize(2, 3);
+ BOOST_CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK_MESSAGE(6 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(0));
+ BOOST_CHECK(false == shape.GetDimensionSpecificity(1));
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(2));
+ BOOST_CHECK(!shape.AreAllDimensionsSpecified());
+ BOOST_CHECK(shape.IsAtLeastOneDimensionSpecified());
+
+ info.SetShape(shape);
+ armnn::Tensor tensor2( info, &mutableDatum );
+ BOOST_TEST(2 == shape[0]);
+ BOOST_TEST(2 == tensor2.GetShape()[0]);
+ BOOST_TEST(2 == tensor2.GetInfo().GetShape()[0]);
+
+ BOOST_CHECK_THROW(shape[1], InvalidArgumentException);
+ BOOST_CHECK_THROW(tensor.GetShape()[1], InvalidArgumentException);
+ BOOST_CHECK_THROW(tensor.GetInfo().GetShape()[1], InvalidArgumentException);
+
+ BOOST_TEST(3 == shape[2]);
+ BOOST_TEST(3 == tensor2.GetShape()[2]);
+ BOOST_TEST(3 == tensor2.GetInfo().GetShape()[2]);
+
+ armnn::TensorShape shape_equal;
+ armnn::TensorShape shape_different;
+ shape_equal = shape;
+ BOOST_TEST(shape_equal == shape);
+ BOOST_TEST(shape_different != shape);
+
+ // Specify dimension 1.
+ shape.SetDimensionSize(1, 5);
+ BOOST_CHECK_MESSAGE(3 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK_MESSAGE(30 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(0));
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(1));
+ BOOST_CHECK(true == shape.GetDimensionSpecificity(2));
+ BOOST_CHECK(shape.AreAllDimensionsSpecified());
+ BOOST_CHECK(shape.IsAtLeastOneDimensionSpecified());
+}
+
+BOOST_AUTO_TEST_CASE(Tensor_emptyConstructors)
+{
+ auto shape = armnn::TensorShape();
+ BOOST_CHECK_MESSAGE( 0 == shape.GetNumDimensions(), "Number of dimensions is " << shape.GetNumDimensions());
+ BOOST_CHECK_MESSAGE( 0 == shape.GetNumElements(), "Number of elements is " << shape.GetNumElements());
+ BOOST_CHECK( armnn::Dimensionality::Specified == shape.GetDimensionality());
+ BOOST_CHECK( shape.AreAllDimensionsSpecified());
+ BOOST_CHECK_THROW( shape[0], InvalidArgumentException );
+
+ auto tensor = armnn::Tensor();
+ BOOST_CHECK_MESSAGE( 0 == tensor.GetNumDimensions(), "Number of dimensions is " << tensor.GetNumDimensions());
+ BOOST_CHECK_MESSAGE( 0 == tensor.GetNumElements(), "Number of elements is " << tensor.GetNumElements());
+ BOOST_CHECK_MESSAGE( 0 == tensor.GetShape().GetNumDimensions(), "Number of dimensions is " <<
+ tensor.GetShape().GetNumDimensions());
+ BOOST_CHECK_MESSAGE( 0 == tensor.GetShape().GetNumElements(), "Number of dimensions is " <<
+ tensor.GetShape().GetNumElements());
+ BOOST_CHECK( armnn::Dimensionality::Specified == tensor.GetShape().GetDimensionality());
+ BOOST_CHECK( tensor.GetShape().AreAllDimensionsSpecified());
+ BOOST_CHECK_THROW( tensor.GetShape()[0], InvalidArgumentException );
+}
BOOST_AUTO_TEST_SUITE_END()