core: Add ValArray and ValArrayTestSuite
core: Improve operator<< implementation, to not represent all numbers with the real and the imaginary parts, instead use the operator<< of each of the types (Thanks to Peter Barnes) core: Improve operator<< to remove unnecessary "\t" and remove "std::endl" flush from each row of the matrix (Thanks to Peter Barnes) core: Improve constructor that accepts std::vector and copies it into the std::valarray, use std::copy operator (Thanks to Peter Barnes) core: Move out inline implementations from ValArray class outside from the class declaration (Thanks to Peter Barnes) core: Move implementations from val-array.cc file into val-array.h file to have achieve truely template ValArray (Thanks to Peter Barnes) core: Use stl library and std::equal for the operator == (Thanks to Peter Barnes) core: Use stl library and std::equal and lambda expression in IsAlmostEqual (Thanks to Peter Barnes) core: Use size_t for the index in the ValArray instead of uint16_t (Thanks to Peter Barnes) Use auto in ValArrayTestCase to be more consistent Improve Doxygen Remove cast to (uint16_t) core: Remove definition of ValArray for int, double, complex,they are not needed any more after moving all implementation to the header file Remove accidentally added new lines in core/CMakeLists.
This commit is contained in:
@@ -313,6 +313,7 @@ set(header_files
|
||||
model/watchdog.h
|
||||
model/realtime-simulator-impl.h
|
||||
model/wall-clock-synchronizer.h
|
||||
model/val-array.h
|
||||
)
|
||||
|
||||
set(test_sources
|
||||
@@ -348,6 +349,7 @@ set(test_sources
|
||||
test/type-id-test-suite.cc
|
||||
test/type-traits-test-suite.cc
|
||||
test/watchdog-test-suite.cc
|
||||
test/val-array-test-suite.cc
|
||||
)
|
||||
|
||||
# Build core lib
|
||||
|
||||
743
src/core/model/val-array.h
Normal file
743
src/core/model/val-array.h
Normal file
@@ -0,0 +1,743 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Biljana Bojovic <bbojovic@cttc.es>
|
||||
*/
|
||||
#ifndef VAL_ARRAY_H
|
||||
#define VAL_ARRAY_H
|
||||
|
||||
#include <ns3/assert.h>
|
||||
#include <ns3/simple-ref-count.h>
|
||||
|
||||
#include <complex>
|
||||
#include <valarray>
|
||||
#include <vector>
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
|
||||
/**
|
||||
* \ingroup Matrices
|
||||
*
|
||||
* \brief ValArray is a class to efficiently store 3D array. The class is general
|
||||
* enough to represent 1D array or 2D arrays. ValArray also provides basic
|
||||
* algebra element-wise operations over the whole array (1D, 2D, 3D).
|
||||
*
|
||||
* Main characteristics of ValArray are the following:
|
||||
*
|
||||
* - ValArray uses std::valarray to efficiently store data.
|
||||
*
|
||||
* - In general, the elements are stored in memory as a sequence of consecutive
|
||||
* 2D arrays. The dimensions of 2D arrays are defined by numRows and numCols,
|
||||
* while the number of 2D arrays is defined by numPages. Notice that if we set
|
||||
* the number of pages to 1, we will have only a single 2D array. If we
|
||||
* additionally set numRows or numCols to 1, we will have 1D array.
|
||||
*
|
||||
* - All 2D arrays have the same dimensions, i.e. numRows and numCols.
|
||||
*
|
||||
* - 2D arrays are stored in column-major order, which is the default
|
||||
* order in Eigen and Armadillo libraries, which allows a straightforward mapping
|
||||
* of any page (2D array) within ValArray to Eigen or Armadillo matrices.
|
||||
*
|
||||
* Examples of column-major order:
|
||||
*
|
||||
* a) in the case of a 2D array, we will have in memory the following order of
|
||||
* elements, assuming that the indexes are rowIndex, colIndex, pageIndex:
|
||||
*
|
||||
* a000 a100 a010 a110 a020 a120.
|
||||
*
|
||||
* b) in the case of a 3D array, e.g, if there are two 2D arrays of 2x3 dimensions
|
||||
* we will have in memory the following order of elements,
|
||||
* assuming that the indexes are rowIndex, colIndex, pageIndex:
|
||||
*
|
||||
* a000 a100 a010 a110 a020 a120 a001 a101 a011 a111 a021 a121.
|
||||
*
|
||||
* - The access to the elements is implemented in operators:
|
||||
* - operator (rowIndex) and operator[] (rowIndex) for 1D array (assuming colIndex=0, pageIndex=0),
|
||||
* - operator (rowIndex,colIndex) for 2D array (assuming pageIndex=0) and
|
||||
* - operator(rowIndex, colIndex, pageIndex) for 3D array.
|
||||
*
|
||||
* Definition of ValArray as a template class allows using different numerical
|
||||
* types as the elements of the vectors/matrices, e.g., complex numbers, double,
|
||||
* int, etc.
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
class ValArray : public SimpleRefCount<ValArray<T>>
|
||||
{
|
||||
public:
|
||||
// instruct the compiler to generate the default constructor
|
||||
ValArray<T>() = default;
|
||||
/**
|
||||
* \brief Constructor that creates "numPages" number of 2D arrays that are of
|
||||
* dimensions "numRows"x"numCols", and are initialized with all-zero elements.
|
||||
* If only 1 parameter, numRows, is provided then a single 1D array is being created.
|
||||
* \param numRows the number of rows
|
||||
* \param numCols the number of columns
|
||||
* \param numPages the number of pages
|
||||
*/
|
||||
ValArray<T>(uint16_t numRows, uint16_t numCols = 1, uint16_t numPages = 1);
|
||||
/**
|
||||
* \brief Constructor creates a single 1D array of values.size () elements and 1 column,
|
||||
* and uses std::valarray<T> values to initialize the elements.
|
||||
* \param values std::valarray<T> that will be used to initialize elements of 1D array
|
||||
*/
|
||||
explicit ValArray<T>(const std::valarray<T>& values);
|
||||
/**
|
||||
* \brief Constructor creates a single 1D array of values.size () elements and 1 column,
|
||||
* and moves std::valarray<T> values to initialize the elements.
|
||||
* \param values std::valarray<T> that will be moved to initialize elements of 1D array
|
||||
*/
|
||||
ValArray<T>(std::valarray<T>&& values);
|
||||
/**
|
||||
* \brief Constructor creates a single 1D array of values.size () elements and 1 column,
|
||||
* and uses values std::vector<T> to initialize the elements.
|
||||
* \param values std::vector<T> that will be used to initialize elements of 1D array
|
||||
*/
|
||||
explicit ValArray<T>(const std::vector<T>& values);
|
||||
/**
|
||||
* \brief Constructor creates a single 2D array of numRows and numCols, and uses
|
||||
* std::valarray<T> values to initialize the elements.
|
||||
* \param numRows the number of rows
|
||||
* \param numCols the number of columns
|
||||
* \param values valarray<T> that will be used to initialize elements of 3D array
|
||||
*/
|
||||
ValArray<T>(uint16_t numRows, uint16_t numCols, const std::valarray<T>& values);
|
||||
/**
|
||||
* \brief Constructor creates a single 2D array of numRows and numCols, and moves
|
||||
* std::valarray<T> values to initialize the elements.
|
||||
* \param numRows the number of rows
|
||||
* \param numCols the number of columns
|
||||
* \param values valarray<T> that will be used to initialize elements of 3D array
|
||||
*/
|
||||
ValArray<T>(uint16_t numRows, uint16_t numCols, std::valarray<T>&& values);
|
||||
/**
|
||||
* \brief Constructor creates the 3D array of numRows x numCols x numPages dimensions,
|
||||
* and uses std::valarray<T> values to initialize all the 2D arrays, where first
|
||||
* numRows*numCols elements will belong to the first 2D array.
|
||||
* \param numRows the number of rows
|
||||
* \param numCols the number of columns
|
||||
* \param numPages the number of pages
|
||||
* \param values valarray<T> that will be used to initialize elements of 3D array
|
||||
*/
|
||||
ValArray<T>(uint16_t numRows,
|
||||
uint16_t numCols,
|
||||
uint16_t numPages,
|
||||
const std::valarray<T>& values);
|
||||
/**
|
||||
* \brief Constructor creates the 3D array of numRows x numCols x numPages dimensions,
|
||||
* and moves std::valarray<T> values to initialize all the 2D arrays, where first
|
||||
* numRows*numCols elements will belong to the first 2D array.
|
||||
* \param numRows the number of rows
|
||||
* \param numCols the number of columns
|
||||
* \param numPages the number of pages
|
||||
* \param values valarray<T> that will be used to initialize elements of 3D array
|
||||
*/
|
||||
ValArray<T>(uint16_t numRows, uint16_t numCols, uint16_t numPages, std::valarray<T>&& values);
|
||||
/** instruct the compiler to generate the implicitly declared destructor*/
|
||||
virtual ~ValArray<T>() = default;
|
||||
/** instruct the compiler to generate the implicitly declared copy constructor*/
|
||||
ValArray<T>(const ValArray<T>&) = default;
|
||||
/**
|
||||
* \brief Copy assignment operator.
|
||||
* Instruct the compiler to generate the implicitly declared copy assignment operator.
|
||||
* \return a reference to the assigned object
|
||||
*/
|
||||
ValArray<T>& operator=(const ValArray<T>&) = default;
|
||||
/** instruct the compiler to generate the implicitly declared move constructor*/
|
||||
ValArray<T>(ValArray<T>&&) noexcept = default;
|
||||
/**
|
||||
* \brief Move assignment operator.
|
||||
* Instruct the compiler to generate the implicitly declared move assignment operator.
|
||||
* \return a reference to the assigned object
|
||||
*/
|
||||
ValArray<T>& operator=(ValArray<T>&&) noexcept = default;
|
||||
/**
|
||||
* \returns Number of rows
|
||||
*/
|
||||
uint16_t GetNumRows() const;
|
||||
/**
|
||||
* \returns Number of columns
|
||||
*/
|
||||
uint16_t GetNumCols() const;
|
||||
/**
|
||||
* \returns Number of pages, i.e., the number of 2D arrays
|
||||
*/
|
||||
uint16_t GetNumPages() const;
|
||||
/**
|
||||
* \returns Total number of elements
|
||||
*/
|
||||
size_t GetSize() const;
|
||||
/**
|
||||
* \brief Access operator, with bound-checking in debug profile
|
||||
* \param rowIndex The index of the row
|
||||
* \param colIndex The index of the column
|
||||
* \param pageIndex The index of the page
|
||||
* \returns A const reference to the element with with rowIndex, colIndex and pageIndex indices.
|
||||
*/
|
||||
T& operator()(uint16_t rowIndex, uint16_t colIndex, uint16_t pageIndex);
|
||||
/**
|
||||
* \brief Const access operator, with bound-checking in debug profile
|
||||
* \param rowIndex The index of the row
|
||||
* \param colIndex The index of the column
|
||||
* \param pageIndex The index of the page
|
||||
* \returns A const reference to the element with with rowIndex, colIndex and pageIndex indices.
|
||||
*/
|
||||
const T& operator()(uint16_t rowIndex, uint16_t colIndex, uint16_t pageIndex) const;
|
||||
/**
|
||||
* \brief Access operator for 2D ValArrays.
|
||||
* Assuming that the third dimension is equal to 1, e.g. ValArray contains
|
||||
* a single 2D array.
|
||||
* Note: intentionally not implemented through three parameters access operator,
|
||||
* to avoid accidental mistakes by user, e.g., providing 2 parameters when
|
||||
* 3 are necessary, but access operator would return valid value if default
|
||||
* value of pages provided is 0.
|
||||
* \param rowIndex The index of the row
|
||||
* \param colIndex The index of the column
|
||||
* \returns A reference to the element with the specified indices
|
||||
*/
|
||||
T& operator()(uint16_t rowIndex, uint16_t colIndex);
|
||||
/**
|
||||
* \brief Const access operator for 2D ValArrays.
|
||||
* Assuming that the third dimension is equal to 1, e.g. ValArray contains
|
||||
* a single 2D array.
|
||||
* \param rowIndex row index
|
||||
* \param colIndex column index
|
||||
* \returns a Const reference to the value with the specified row and column index.
|
||||
*/
|
||||
const T& operator()(uint16_t rowIndex, uint16_t colIndex) const;
|
||||
/**
|
||||
* \brief Single-element access operator() for 1D ValArrays.
|
||||
* Assuming that the number of columns and pages is equal to 1, e.g. ValArray
|
||||
* contains a single column or a single row.
|
||||
*
|
||||
* Note: intentionally not implemented through three parameters access operator,
|
||||
* to avoid accidental mistakes by user, e.g., providing 1 parameters when
|
||||
* 2 or 3 are necessary.
|
||||
* \param index The index of the 1D ValArray.
|
||||
* \returns A reference to the value with the specified index.
|
||||
*/
|
||||
T& operator()(uint16_t index);
|
||||
/**
|
||||
* \brief Single-element access operator() for 1D ValArrays.
|
||||
* \param index The index of the 1D ValArray.
|
||||
* \returns The const reference to the values with the specified index.
|
||||
*/
|
||||
const T& operator()(uint16_t index) const;
|
||||
/**
|
||||
* \brief Element-wise multiplication with a scalar value.
|
||||
* \param rhs A scalar value of type T
|
||||
* \returns ValArray in which each element has been multiplied by the given
|
||||
* scalar value.
|
||||
*/
|
||||
ValArray<T> operator*(const T& rhs) const;
|
||||
/**
|
||||
* \brief operator+ definition for ValArray<T>.
|
||||
* \param rhs The rhs ValArray to be added to this ValArray.
|
||||
* \return the ValArray instance that holds the results of the operator+
|
||||
*/
|
||||
ValArray<T> operator+(const ValArray<T>& rhs) const;
|
||||
/**
|
||||
* \brief binary operator- definition for ValArray<T>.
|
||||
* \param rhs The rhs ValArray to be subtracted from this ValArray.
|
||||
* \return the ValArray instance that holds the results of the operator-
|
||||
*/
|
||||
ValArray<T> operator-(const ValArray<T>& rhs) const;
|
||||
/**
|
||||
* \brief unary operator- definition for ValArray<T>.
|
||||
* \return the ValArray instance that holds the results of the operator-
|
||||
*/
|
||||
ValArray<T> operator-() const;
|
||||
/**
|
||||
* \brief operator+= definition for ValArray<T>.
|
||||
* \param rhs The rhs ValArray to be added to this ValArray.
|
||||
* \return a reference to this ValArray instance
|
||||
*/
|
||||
ValArray<T>& operator+=(const ValArray<T>& rhs);
|
||||
/**
|
||||
* \brief operator-= definition for ValArray<T>.
|
||||
* \param rhs The rhs ValArray to be subtracted from this ValArray.
|
||||
** \return a reference to this ValArray instance
|
||||
*/
|
||||
ValArray<T>& operator-=(const ValArray<T>& rhs);
|
||||
/**
|
||||
* \brief operator== definition for ValArray<T>.
|
||||
* \param rhs The ValArray instance to be compared with lhs ValArray instance
|
||||
* \return true if rhs ValArray is equal to this ValArray, otherwise it returns false
|
||||
*/
|
||||
bool operator==(const ValArray<T>& rhs) const;
|
||||
/**
|
||||
* \brief operator!= definition for ValArray<T>.
|
||||
* \param rhs The ValArray instance to be compared with lhs ValArray instance
|
||||
* \return true if rhs ValArray is not equal to this ValArray, otherwise it returns true
|
||||
*/
|
||||
bool operator!=(const ValArray<T>& rhs) const;
|
||||
/**
|
||||
* \brief Compare Valarray up to a given absolute tolerance. This operation
|
||||
* is element-wise operation, i.e., the elements with the same indices from
|
||||
* the lhs and rhs ValArray are being compared, allowing the tolerance defined
|
||||
* byt "tol" parameter.
|
||||
* \param rhs The rhs ValArray
|
||||
* \param tol The absolute tolerance
|
||||
* \returns true if the differences in each element-wise comparison is less
|
||||
* or equal to tol.
|
||||
*/
|
||||
bool IsAlmostEqual(const ValArray<T>& rhs, T tol) const;
|
||||
/**
|
||||
* \brief Get a data pointer to a specific 2D array for use in linear
|
||||
* algebra libraries
|
||||
* \param pageIndex The index of the desired 2D array
|
||||
* \returns a pointer to the data elements of the 2D array
|
||||
*/
|
||||
T* GetPagePtr(uint16_t pageIndex);
|
||||
/**
|
||||
* \brief Get a data pointer to a specific 2D array for use in linear
|
||||
* algebra libraries
|
||||
* \param pageIndex An index of the desired 2D array
|
||||
* \returns a pointer to the data elements of the 2D array
|
||||
*/
|
||||
const T* GetPagePtr(uint16_t pageIndex) const;
|
||||
/**
|
||||
* \brief Checks whether rhs and lhs ValArray objects have the same dimensions.
|
||||
* \param rhs The rhs ValArray
|
||||
* \returns true if the dimensions of lhs and rhs are equal, otherwise it returns false
|
||||
*/
|
||||
bool EqualDims(const ValArray<T>& rhs) const;
|
||||
/**
|
||||
* \brief Function that asserts if the dimensions of lhs and rhs ValArray are
|
||||
* not equal and prints a message with the matrices dimensions.
|
||||
* \param rhs the rhs ValArray
|
||||
*/
|
||||
void AssertEqualDims(const ValArray<T>& rhs) const;
|
||||
/**
|
||||
* \brief Single-element access operator[] that can be used to access a specific
|
||||
* element of 1D ValArray. It mimics operator[] from std::vector.
|
||||
* This function is introduced for compatibility with ns-3 usage of 1D arrays,
|
||||
* which are usually represented through std::vector operators in spectrum
|
||||
* and antenna module.
|
||||
*
|
||||
* \param index The index of the element to be returned
|
||||
* \returns A reference to a specific element from the underlying std::valarray.
|
||||
*/
|
||||
T& operator[](size_t index);
|
||||
/**
|
||||
* \brief Const access operator that can be used to access a specific element of
|
||||
* 1D ValArray.
|
||||
*
|
||||
* \param index The index of the element to be returned
|
||||
* \returns A const reference to a specific element from the underlying std::valarray.
|
||||
*/
|
||||
const T& operator[](size_t index) const;
|
||||
/**
|
||||
* \brief Returns underlying values. This function allows to directly work
|
||||
* with the underlying values, which can be faster then using access operators.
|
||||
* \returns A const reference to the underlying std::valarray<T>.
|
||||
*/
|
||||
const std::valarray<T>& GetValues() const;
|
||||
/**
|
||||
* \brief Alternative access operator to access a specific element.
|
||||
* \param row the row index of the element to be obtained
|
||||
* \param col the col index of the element to be obtained
|
||||
* \param page the page index of the element to be obtained
|
||||
* \return a reference to the element of this ValArray
|
||||
*/
|
||||
T& Elem(size_t row, size_t col, size_t page);
|
||||
/**
|
||||
* \brief Alternative const access operator to access a specific element.
|
||||
* \param row the row index of the element to be obtained
|
||||
* \param col the column index of the element to be obtained
|
||||
* \param page the page index of the element to be obtained
|
||||
* \return a const reference to the element of this ValArray
|
||||
*/
|
||||
const T& Elem(size_t row, size_t col, size_t page) const;
|
||||
|
||||
protected:
|
||||
uint16_t m_numRows =
|
||||
0; //!< The size of the first dimension, i.e., the number of rows of each 2D array
|
||||
uint16_t m_numCols =
|
||||
0; //!< The size of the second dimension, i.e., the number of columns of each 2D array
|
||||
uint16_t m_numPages = 0; //!< The size of the third dimension, i.e., the number of 2D arrays
|
||||
std::valarray<T> m_values; //!< The data values
|
||||
};
|
||||
|
||||
/*************************************************
|
||||
** Class ValArray inline implementations
|
||||
************************************************/
|
||||
|
||||
template <class T>
|
||||
inline uint16_t
|
||||
ValArray<T>::GetNumRows() const
|
||||
{
|
||||
return m_numRows;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline uint16_t
|
||||
ValArray<T>::GetNumCols() const
|
||||
{
|
||||
return m_numCols;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline uint16_t
|
||||
ValArray<T>::GetNumPages() const
|
||||
{
|
||||
return m_numPages;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline size_t
|
||||
ValArray<T>::GetSize() const
|
||||
{
|
||||
return m_values.size();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T&
|
||||
ValArray<T>::operator()(uint16_t rowIndex, uint16_t colIndex, uint16_t pageIndex)
|
||||
{
|
||||
NS_ASSERT_MSG(rowIndex < m_numRows, "Row index out of bounds");
|
||||
NS_ASSERT_MSG(colIndex < m_numCols, "Column index out of bounds");
|
||||
NS_ASSERT_MSG(pageIndex < m_numPages, "Pages index out of bounds");
|
||||
size_t index = (rowIndex + m_numRows * (colIndex + m_numCols * pageIndex));
|
||||
return m_values[index];
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const T&
|
||||
ValArray<T>::operator()(uint16_t rowIndex, uint16_t colIndex, uint16_t pageIndex) const
|
||||
{
|
||||
NS_ASSERT_MSG(rowIndex < m_numRows, "Row index out of bounds");
|
||||
NS_ASSERT_MSG(colIndex < m_numCols, "Column index out of bounds");
|
||||
NS_ASSERT_MSG(pageIndex < m_numPages, "Pages index out of bounds");
|
||||
size_t index = (rowIndex + m_numRows * (colIndex + m_numCols * pageIndex));
|
||||
return m_values[index];
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T&
|
||||
ValArray<T>::operator()(uint16_t rowIndex, uint16_t colIndex)
|
||||
{
|
||||
NS_ASSERT_MSG(m_numPages == 1, "Cannot use 2D access operator for 3D ValArray.");
|
||||
return (*this)(rowIndex, colIndex, 0);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const T&
|
||||
ValArray<T>::operator()(uint16_t rowIndex, uint16_t colIndex) const
|
||||
{
|
||||
NS_ASSERT_MSG(m_numPages == 1, "Cannot use 2D access operator for 3D ValArray.");
|
||||
return (*this)(rowIndex, colIndex, 0);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T&
|
||||
ValArray<T>::operator()(uint16_t index)
|
||||
{
|
||||
NS_ASSERT_MSG(index < m_values.size(),
|
||||
"Invalid index to 1D ValArray. The size of the array should be set through "
|
||||
"constructor.");
|
||||
NS_ASSERT_MSG(((m_numRows == 1 || m_numCols == 1) && (m_numPages == 1)) ||
|
||||
(m_numRows == 1 && m_numCols == 1),
|
||||
"Access operator allowed only for 1D ValArray.");
|
||||
return m_values[index];
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const T&
|
||||
ValArray<T>::operator()(uint16_t index) const
|
||||
{
|
||||
NS_ASSERT_MSG(index < m_values.size(),
|
||||
"Invalid index to 1D ValArray.The size of the array should be set through "
|
||||
"constructor.");
|
||||
NS_ASSERT_MSG(((m_numRows == 1 || m_numCols == 1) && (m_numPages == 1)) ||
|
||||
(m_numRows == 1 && m_numCols == 1),
|
||||
"Access operator allowed only for 1D ValArray.");
|
||||
return m_values[index];
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline ValArray<T>
|
||||
ValArray<T>::operator*(const T& rhs) const
|
||||
{
|
||||
return ValArray<T>(m_numRows,
|
||||
m_numCols,
|
||||
m_numPages,
|
||||
m_values * std::valarray<T>(rhs, m_numRows * m_numCols * m_numPages));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ValArray<T>
|
||||
ValArray<T>::operator+(const ValArray<T>& rhs) const
|
||||
{
|
||||
AssertEqualDims(rhs);
|
||||
return ValArray<T>(m_numRows, m_numCols, m_numPages, m_values + rhs.m_values);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ValArray<T>
|
||||
ValArray<T>::operator-(const ValArray<T>& rhs) const
|
||||
{
|
||||
AssertEqualDims(rhs);
|
||||
return ValArray<T>(m_numRows, m_numCols, m_numPages, m_values - rhs.m_values);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ValArray<T>
|
||||
ValArray<T>::operator-() const
|
||||
{
|
||||
return ValArray<T>(m_numRows, m_numCols, m_numPages, -m_values);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ValArray<T>&
|
||||
ValArray<T>::operator+=(const ValArray<T>& rhs)
|
||||
{
|
||||
AssertEqualDims(rhs);
|
||||
m_values += rhs.m_values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ValArray<T>&
|
||||
ValArray<T>::operator-=(const ValArray<T>& rhs)
|
||||
{
|
||||
AssertEqualDims(rhs);
|
||||
m_values -= rhs.m_values;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T*
|
||||
ValArray<T>::GetPagePtr(uint16_t pageIndex)
|
||||
{
|
||||
NS_ASSERT_MSG(pageIndex < m_numPages, "Invalid page index.");
|
||||
return &(m_values[m_numRows * m_numCols * pageIndex]);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const T*
|
||||
ValArray<T>::GetPagePtr(uint16_t pageIndex) const
|
||||
{
|
||||
NS_ASSERT_MSG(pageIndex < m_numPages, "Invalid page index.");
|
||||
return &(m_values[m_numRows * m_numCols * pageIndex]);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline bool
|
||||
ValArray<T>::EqualDims(const ValArray<T>& rhs) const
|
||||
{
|
||||
return (m_numRows == rhs.m_numRows) && (m_numCols == rhs.m_numCols) &&
|
||||
(m_numPages == rhs.m_numPages);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T&
|
||||
ValArray<T>::operator[](size_t index)
|
||||
{
|
||||
return (*this)(index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const T&
|
||||
ValArray<T>::operator[](size_t index) const
|
||||
{
|
||||
return (*this)(index);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline const std::valarray<T>&
|
||||
ValArray<T>::GetValues() const
|
||||
{
|
||||
return m_values;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T&
|
||||
ValArray<T>::Elem(size_t row, size_t col, size_t page)
|
||||
{
|
||||
return (*this)(row, col, page);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline const T&
|
||||
ValArray<T>::Elem(size_t row, size_t col, size_t page) const
|
||||
{
|
||||
return (*this)(row, col, page);
|
||||
};
|
||||
|
||||
/*************************************************
|
||||
** Class ValArray non-inline implementations
|
||||
************************************************/
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(uint16_t numRows, uint16_t numCols, uint16_t numPages)
|
||||
: m_numRows{numRows},
|
||||
m_numCols{numCols},
|
||||
m_numPages{numPages}
|
||||
{
|
||||
m_values.resize(m_numRows * m_numCols * m_numPages);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(const std::valarray<T>& values)
|
||||
: m_numRows{(uint16_t)values.size()},
|
||||
m_numCols{1},
|
||||
m_numPages{1},
|
||||
m_values{values}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(std::valarray<T>&& values)
|
||||
: m_numRows{(uint16_t)values.size()},
|
||||
m_numCols{1},
|
||||
m_numPages{1},
|
||||
m_values{std::move(values)}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(const std::vector<T>& values)
|
||||
: m_numRows{(uint16_t)values.size()},
|
||||
m_numCols{1},
|
||||
m_numPages{1}
|
||||
{
|
||||
m_values.resize(values.size());
|
||||
std::copy(values.begin(), values.end(), std::begin(m_values));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(uint16_t numRows, uint16_t numCols, const std::valarray<T>& values)
|
||||
: m_numRows{numRows},
|
||||
m_numCols{numCols},
|
||||
m_numPages{1},
|
||||
m_values{values}
|
||||
{
|
||||
NS_ASSERT_MSG(m_numRows * m_numCols == values.size(),
|
||||
"Dimensions and the initialization array size do not match.");
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(uint16_t numRows, uint16_t numCols, std::valarray<T>&& values)
|
||||
: m_numRows{numRows},
|
||||
m_numCols{numCols},
|
||||
m_numPages{1}
|
||||
{
|
||||
NS_ASSERT_MSG(m_numRows * m_numCols == values.size(),
|
||||
"Dimensions and the initialization array size do not match.");
|
||||
m_values = std::move(values);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(uint16_t numRows,
|
||||
uint16_t numCols,
|
||||
uint16_t numPages,
|
||||
const std::valarray<T>& values)
|
||||
: m_numRows{numRows},
|
||||
m_numCols{numCols},
|
||||
m_numPages{numPages},
|
||||
m_values{values}
|
||||
{
|
||||
NS_ASSERT_MSG(m_numRows * m_numCols * m_numPages == values.size(),
|
||||
"Dimensions and the initialization array size do not match.");
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ValArray<T>::ValArray(uint16_t numRows,
|
||||
uint16_t numCols,
|
||||
uint16_t numPages,
|
||||
std::valarray<T>&& values)
|
||||
: m_numRows{numRows},
|
||||
m_numCols{numCols},
|
||||
m_numPages{numPages}
|
||||
{
|
||||
NS_ASSERT_MSG(m_numRows * m_numCols * m_numPages == values.size(),
|
||||
"Dimensions and the initialization array size do not match.");
|
||||
m_values = std::move(values);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ValArray<T>::operator==(const ValArray<T>& rhs) const
|
||||
{
|
||||
return EqualDims(rhs) &&
|
||||
std::equal(std::begin(m_values), std::end(m_values), std::begin(rhs.m_values));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ValArray<T>::operator!=(const ValArray<T>& rhs) const
|
||||
{
|
||||
return !((*this) == rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
ValArray<T>::IsAlmostEqual(const ValArray<T>& rhs, T tol) const
|
||||
{
|
||||
return EqualDims(rhs) && std::equal(std::begin(m_values),
|
||||
std::end(m_values),
|
||||
std::begin(rhs.m_values),
|
||||
[tol](T lhsValue, T rhsValue) {
|
||||
return lhsValue == rhsValue ||
|
||||
std::abs(lhsValue - rhsValue) <= std::abs(tol);
|
||||
});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
ValArray<T>::AssertEqualDims(const ValArray<T>& rhs) const
|
||||
{
|
||||
NS_ASSERT_MSG(EqualDims(rhs),
|
||||
"Dimensions mismatch: "
|
||||
"lhs (rows, cols, pages) = ("
|
||||
<< m_numRows << ", " << m_numCols << ", " << m_numPages
|
||||
<< ") and "
|
||||
"rhs (rows, cols, pages) = ("
|
||||
<< rhs.m_numRows << ", " << rhs.m_numCols << ", " << rhs.m_numPages << ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Overloads output stream operator.
|
||||
* \tparam T the type of the ValArray for which will be called this function
|
||||
* \param os a reference to the output stream
|
||||
* \param a the ValArray instance using type T
|
||||
* \return a reference to the output stream
|
||||
*/
|
||||
template <class T>
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, const ValArray<T>& a)
|
||||
{
|
||||
os << "\n";
|
||||
for (auto p = 0; p != a.GetNumPages(); ++p)
|
||||
{
|
||||
os << "Page " << p << ":\n";
|
||||
for (auto i = 0; i != a.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j != a.GetNumCols(); ++j)
|
||||
{
|
||||
os << "\t" << a(i, j, p);
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif // VAL_ARRAY_H
|
||||
282
src/core/test/val-array-test-suite.cc
Normal file
282
src/core/test/val-array-test-suite.cc
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Centre Tecnologic de Telecomunicacions de Catalunya (CTTC)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Biljana Bojovic <bbojovic@cttc.es>
|
||||
*/
|
||||
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/val-array.h"
|
||||
|
||||
/**
|
||||
* \ingroup core-tests
|
||||
*/
|
||||
|
||||
namespace ns3
|
||||
{
|
||||
namespace tests
|
||||
{
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE("ValArrayTest");
|
||||
|
||||
/**
|
||||
* @brief ValArray test case for testing ValArray class
|
||||
*
|
||||
* @tparam T the template parameter that can be a complex number, double or int
|
||||
*/
|
||||
template <class T>
|
||||
class ValArrayTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
/** Default constructor*/
|
||||
ValArrayTestCase<T>() = default;
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param [in] name reference name
|
||||
*/
|
||||
ValArrayTestCase<T>(const std::string name);
|
||||
|
||||
/** Destructor. */
|
||||
~ValArrayTestCase<T>() override;
|
||||
/**
|
||||
* \brief Copy constructor.
|
||||
* Instruct the compiler to generate the implicitly declared copy constructor
|
||||
*/
|
||||
ValArrayTestCase<T>(const ValArrayTestCase<T>&) = default;
|
||||
/**
|
||||
* \brief Copy assignment operator.
|
||||
* Instruct the compiler to generate the implicitly declared copy assignment operator.
|
||||
* \return A reference to this ValArrayTestCase
|
||||
*/
|
||||
ValArrayTestCase<T>& operator=(const ValArrayTestCase<T>&) = default;
|
||||
/**
|
||||
* \brief Move constructor.
|
||||
* Instruct the compiler to generate the implicitly declared move constructor
|
||||
*/
|
||||
ValArrayTestCase<T>(ValArrayTestCase<T>&&) noexcept = default;
|
||||
/**
|
||||
* \brief Move assignment operator.
|
||||
* Instruct the compiler to generate the implicitly declared copy constructor
|
||||
* \return A reference to this ValArrayTestCase
|
||||
*/
|
||||
ValArrayTestCase<T>& operator=(ValArrayTestCase<T>&&) noexcept = default;
|
||||
|
||||
protected:
|
||||
private:
|
||||
void DoRun() override;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
ValArrayTestCase<T>::ValArrayTestCase(const std::string name)
|
||||
: TestCase(name)
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ValArrayTestCase<T>::~ValArrayTestCase<T>()
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void
|
||||
ValArrayTestCase<T>::DoRun()
|
||||
{
|
||||
ValArray<T> v1 = ValArray<T>(2, 3);
|
||||
for (auto i = 0; i < v1.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j < v1.GetNumCols(); ++j)
|
||||
{
|
||||
v1(i, j) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ValArray<T> v2 = ValArray<T>(v1);
|
||||
NS_TEST_ASSERT_MSG_EQ(v1.GetNumRows(), v2.GetNumRows(), "The number of rows are not equal.");
|
||||
NS_TEST_ASSERT_MSG_EQ(v1.GetNumCols(), v2.GetNumCols(), "The number of cols are not equal.");
|
||||
|
||||
// test copy constructor
|
||||
for (auto i = 0; i < v1.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j < v1.GetNumCols(); ++j)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(v1(i, j), v2(i, j), "The elements are not equal.");
|
||||
}
|
||||
}
|
||||
|
||||
// test assign constructor
|
||||
ValArray<T> v3 = v1;
|
||||
NS_TEST_ASSERT_MSG_EQ(v1.GetNumRows(), v3.GetNumRows(), "The number of rows are not equal.");
|
||||
NS_TEST_ASSERT_MSG_EQ(v1.GetNumCols(), v3.GetNumCols(), "The number of cols are not equal.");
|
||||
for (auto i = 0; i < v1.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j < v1.GetNumCols(); ++j)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(v1(i, j), v2(i, j), "The elements are not equal.");
|
||||
}
|
||||
}
|
||||
|
||||
// test move assignment operator
|
||||
ValArray<T> v4;
|
||||
NS_LOG_INFO("v1 size before move: " << v1.GetSize());
|
||||
NS_LOG_INFO("v4 size before move: " << v4.GetSize());
|
||||
v4 = std::move(v1);
|
||||
NS_LOG_INFO("v1 size after move: " << v1.GetSize());
|
||||
NS_LOG_INFO("v4 size after move: " << v4.GetSize());
|
||||
NS_TEST_ASSERT_MSG_NE(v1.GetSize(), v4.GetSize(), "The number of elements are equal.");
|
||||
|
||||
// test move constructor
|
||||
NS_LOG_INFO("v3 size before move: " << v3.GetSize());
|
||||
ValArray<T> v5(std::move(v3));
|
||||
NS_LOG_INFO("v3 size after move: " << v3.GetSize());
|
||||
NS_TEST_ASSERT_MSG_NE(v3.GetSize(), v5.GetSize(), "The number of elements are equal.");
|
||||
|
||||
// test constructor with initialization valArray
|
||||
std::valarray<int> initArray1{0, 1, 2, 3, 4, 5, 6, 7};
|
||||
std::valarray<T> valArray1(initArray1.size()); // length is 8 elements
|
||||
for (size_t i = 0; i < initArray1.size(); i++)
|
||||
{
|
||||
valArray1[i] = static_cast<T>(initArray1[i]);
|
||||
}
|
||||
ValArray<T> v6 = ValArray<T>(2, 4, valArray1);
|
||||
|
||||
// test constructro that moves valArray
|
||||
NS_LOG_INFO("valarray1 size before move: " << valArray1.size());
|
||||
ValArray<T> v11 = ValArray<T>(2, 4, std::move(valArray1));
|
||||
NS_LOG_INFO("valarray1 size after move: " << valArray1.size());
|
||||
NS_LOG_INFO("v11 size after move: " << v11.GetSize());
|
||||
|
||||
// test whether column-major order was respected during the initialization and
|
||||
// also in the access operator if we iterate over rows first we should find 0, 2, 4, 6, ...
|
||||
std::valarray<int> initArray2{0, 2, 4, 6, 1, 3, 5, 7};
|
||||
auto testIndex = 0;
|
||||
for (auto i = 0; i < v6.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j < v6.GetNumCols(); ++j)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(v6(i, j),
|
||||
static_cast<T>(initArray2[testIndex]),
|
||||
"The values are not equal.");
|
||||
testIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// test constructor with initialization valArray for 3D array
|
||||
std::valarray<int> initArray3{0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
std::valarray<T> valArray2(initArray3.size()); // length is 8 elements
|
||||
for (size_t i = 0; i < initArray3.size(); i++)
|
||||
{
|
||||
valArray2[i] = static_cast<T>(initArray3[i]);
|
||||
}
|
||||
|
||||
ValArray<T> v7 = ValArray<T>(2, 4, 2, valArray2);
|
||||
// test whether column-major order was respected during the initialization and
|
||||
// also in the access operator
|
||||
// if we iterate over rows first we should find 0, 2, 4, 6, ...
|
||||
std::valarray<int> initArray4{0, 2, 4, 6, 1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7};
|
||||
testIndex = 0;
|
||||
for (auto p = 0; p < v7.GetNumPages(); ++p)
|
||||
{
|
||||
for (auto i = 0; i < v7.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j < v7.GetNumCols(); ++j)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(v7(i, j, p),
|
||||
static_cast<T>(initArray4[testIndex]),
|
||||
"The values are not equal.");
|
||||
testIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// multiplication with a scalar value with 3D array
|
||||
ValArray<T> v8 = v7 * (static_cast<T>(5.0));
|
||||
for (auto p = 0; p < v8.GetNumPages(); ++p)
|
||||
{
|
||||
for (auto i = 0; i < v8.GetNumRows(); ++i)
|
||||
{
|
||||
for (auto j = 0; j < v8.GetNumCols(); ++j)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ(v7(i, j, p) * (static_cast<T>(5.0)),
|
||||
v8(i, j, p),
|
||||
"The values are not equal");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_LOG_INFO("v8 = v7 * 5:" << v8);
|
||||
// test +, - (binary, unary) operators
|
||||
NS_LOG_INFO("v8 + v8" << v8 + v8);
|
||||
NS_LOG_INFO("v8 - v8" << v8 - v8);
|
||||
NS_LOG_INFO("-v8" << -v8);
|
||||
|
||||
// test += and -= assignment operators
|
||||
ValArray<T> v9(v8.GetNumRows(), v8.GetNumCols(), v8.GetNumPages());
|
||||
v9 += v8;
|
||||
NS_LOG_INFO("v9 += v8" << v9);
|
||||
ValArray<T> v10(v8.GetNumRows(), v8.GetNumCols(), v8.GetNumPages());
|
||||
v10 -= v8;
|
||||
NS_LOG_INFO("v10 -= v8" << v10);
|
||||
|
||||
// test == and != operators
|
||||
NS_TEST_ASSERT_MSG_EQ(bool(v9 == v8), true, "Matrices v8 and v9 should be equal");
|
||||
NS_TEST_ASSERT_MSG_EQ(bool(v10 == v8), false, "Matrices v8 and v10 should not be equal");
|
||||
NS_TEST_ASSERT_MSG_EQ(bool(v10 != v8), true, "Matrices v8 and v10 should not be equal");
|
||||
// test whether arrays are equal when they have different lengths
|
||||
NS_TEST_ASSERT_MSG_NE(ValArray<int>(std::valarray({1, 2, 3})),
|
||||
ValArray<int>(std::valarray({1, 2, 3, 4})),
|
||||
"Arrays should not be equal, they have different dimensions.");
|
||||
|
||||
// test the function IsAlmostEqual
|
||||
v9(0, 0, 0) = v9(0, 0, 0) + static_cast<T>(1);
|
||||
NS_TEST_ASSERT_MSG_EQ(v9.IsAlmostEqual(v8, 2) && (v9 != v8),
|
||||
true,
|
||||
"Matrices should be almost equal, but not equal.");
|
||||
|
||||
// test the inicialization with std::vector
|
||||
ValArray<T> v12 = ValArray(std::vector<T>({1, 2, 3}));
|
||||
NS_LOG_INFO("v12:" << v12);
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup valArray-tests
|
||||
* ValArray test suite
|
||||
*
|
||||
* \brief The test checks the correct behaviour of ValArray class
|
||||
*/
|
||||
class ValArrayTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
/** Constructor. */
|
||||
ValArrayTestSuite();
|
||||
};
|
||||
|
||||
ValArrayTestSuite::ValArrayTestSuite()
|
||||
: TestSuite("val-array-test")
|
||||
{
|
||||
AddTestCase(new ValArrayTestCase<double>("Test ValArray<double>"));
|
||||
AddTestCase(new ValArrayTestCase<std::complex<double>>("Test ValArray<std::complex<double>>"));
|
||||
AddTestCase(new ValArrayTestCase<int>("Test ValArray<int>"));
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup valArray-tests
|
||||
* ValArrayTestSuite instance variable.
|
||||
*/
|
||||
static ValArrayTestSuite g_valArrayTestSuite;
|
||||
|
||||
} // namespace tests
|
||||
} // namespace ns3
|
||||
Reference in New Issue
Block a user