/* Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University Copyright Equnior ASA This file is part of the Open Porous Media project (OPM). OPM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OPM 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 OPM. If not, see . */ #ifndef included_ArrayClass #define included_ArrayClass #include "common/ArraySize.h" #include #include #include #include #include #include #include #include #include /*! * Class Array is a multi-dimensional array class written by Mark Berrill */ template class Array final { public: // Constructors / assignment operators /*! * Create a new empty Array */ Array(); /*! * Create an Array with the given size * @param N Size of the array */ explicit Array(const ArraySize &N); /*! * Create a new 1D Array with the given number of elements * @param N Number of elements in the array */ explicit Array(size_t N); /*! * Create a new 2D Array with the given number of rows and columns * @param N_rows Number of rows * @param N_columns Number of columns */ explicit Array(size_t N_rows, size_t N_columns); /*! * Create a new 3D Array with the given number of rows and columns * @param N1 Number of rows * @param N2 Number of columns * @param N3 Number of elements in the third dimension */ explicit Array(size_t N1, size_t N2, size_t N3); /*! * Create a new 4D Array with the given number of rows and columns * @param N1 Number of elements in the first dimension * @param N2 Number of elements in the second dimension * @param N3 Number of elements in the third dimension * @param N4 Number of elements in the fourth dimension */ explicit Array(size_t N1, size_t N2, size_t N3, size_t N4); /*! * Create a new 4D Array with the given number of rows and columns * @param N1 Number of elements in the first dimension * @param N2 Number of elements in the second dimension * @param N3 Number of elements in the third dimension * @param N4 Number of elements in the fourth dimension * @param N5 Number of elements in the fifth dimension */ explicit Array(size_t N1, size_t N2, size_t N3, size_t N4, size_t N5); /*! * Create a multi-dimensional Array with the given number of elements * @param N Number of elements in each dimension * @param data Optional raw array to copy the src data */ explicit Array(const std::vector &N, const TYPE *data = nullptr); /*! * Create a 1D Array using a string that mimic's MATLAB * @param range Range of the data */ explicit Array(std::string range); /*! * Create a 1D Array with the given initializer list * @param data Input data */ Array(std::initializer_list data); /*! * Create a 2D Array with the given initializer lists * @param data Input data */ Array(std::initializer_list> data); /*! * Copy constructor * @param rhs Array to copy */ Array(const Array &rhs); /*! * Move constructor * @param rhs Array to copy */ Array(Array &&rhs); /*! * Assignment operator * @param rhs Array to copy */ Array &operator=(const Array &rhs); /*! * Move assignment operator * @param rhs Array to copy */ Array &operator=(Array &&rhs); /*! * Assignment operator * @param rhs std::vector to copy */ Array &operator=(const std::vector &rhs); //! Is copyable? inline bool isCopyable() const { return d_isCopyable; } //! Set is copyable inline void setCopyable(bool flag) { d_isCopyable = flag; } //! Is fixed size? inline bool isFixedSize() const { return d_isFixedSize; } //! Set is copyable inline void setFixedSize(bool flag) { d_isFixedSize = flag; } public: // Views/copies/subset /*! * Create a multi-dimensional Array view to a raw block of data * @param N Number of elements in each dimension * @param data Pointer to the data */ static std::unique_ptr view(const ArraySize &N, std::shared_ptr data); /*! * Create a multi-dimensional Array view to a raw block of data * @param N Number of elements in each dimension * @param data Pointer to the data */ static std::unique_ptr constView(const ArraySize &N, std::shared_ptr const &data); /*! * Make this object a view of the src * @param src Source vector to take the view of */ void view2(Array &src); /*! * Make this object a view of the data * @param N Number of elements in each dimension * @param data Pointer to the data */ void view2(const ArraySize &N, std::shared_ptr data); /*! * Make this object a view of the raw data (expert use only). * Use view2( N, shared_ptr(data,[](TYPE*){}) ) instead. * Note: this interface is not recommended as it does not protect from * the src data being deleted while still being used by the Array. * Additionally for maximum performance it does not set the internal shared_ptr * so functions like getPtr and resize will not work correctly. * @param ndim Number of dimensions * @param dims Number of elements in each dimension * @param data Pointer to the data * @param isCopyable Once the view is created, can the array be copied * @param isFixedSize Once the view is created, is the array size fixed */ inline void viewRaw(int ndim, const size_t *dims, TYPE *data, bool isCopyable = true, bool isFixedSize = true) { viewRaw(ArraySize(ndim, dims), data, isCopyable, isFixedSize); } /*! * Make this object a view of the raw data (expert use only). * Use view2( N, shared_ptr(data,[](TYPE*){}) ) instead. * Note: this interface is not recommended as it does not protect from * the src data being deleted while still being used by the Array. * Additionally for maximum performance it does not set the internal shared_ptr * so functions like getPtr and resize will not work correctly. * @param N Number of elements in each dimension * @param data Pointer to the data * @param isCopyable Once the view is created, can the array be copied * @param isFixedSize Once the view is created, is the array size fixed */ void viewRaw(const ArraySize &N, TYPE *data, bool isCopyable = true, bool isFixedSize = true); /*! * Create an array view of the given data (expert use only). * Use view2( N, shared_ptr(data,[](TYPE*){}) ) instead. * Note: this interface is not recommended as it does not protect from * the src data being deleted while still being used by the Array. * Additionally for maximum performance it does not set the internal shared_ptr * so functions like getPtr and resize will not work correctly. * @param N Number of elements in each dimension * @param data Pointer to the data */ static inline Array staticView(const ArraySize &N, TYPE *data) { Array x; x.viewRaw(N, data, true, true); return x; } /*! * Convert an array of one type to another. This may or may not allocate new memory. * @param array Input array */ template static inline std::unique_ptr> convert(std::shared_ptr> array) { auto array2 = std::make_unique>(array->size()); array2.copy(*array); return array2; } /*! * Convert an array of one type to another. This may or may not allocate new memory. * @param array Input array */ template static inline std::unique_ptr> convert(std::shared_ptr> array) { auto array2 = std::make_unique>(array->size()); array2.copy(*array); return array2; } /*! * Copy and convert data from another array to this array * @param array Source array */ template void inline copy(const Array &array) { resize(array.size()); copy(array.data()); } /*! * Copy and convert data from a raw vector to this array. * Note: The current array must be allocated to the proper size first. * @param data Source data */ template inline void copy(const TYPE2 *data); /*! * Copy and convert data from this array to a raw vector. * @param data Source data */ template inline void copyTo(TYPE2 *data) const; /*! * Copy and convert data from this array to a new array */ template Array> inline cloneTo() const { Array> dst(this->size()); copyTo(dst.data()); return dst; } /*! swap the raw data pointers for the Arrays after checking for compatibility */ void swap(Array &other); /*! * Fill the array with the given value * @param y Value to fill */ inline void fill(const TYPE &y) { for (auto &x : *this) x = y; } /*! * Scale the array by the given value * @param y Value to scale by */ template inline void scale(const TYPE2 &y) { for (auto &x : *this) x *= y; } /*! * Set the values of this array to pow(base, exp) * @param base Base array * @param exp Exponent value */ void pow(const Array &base, const TYPE &exp); //! Destructor ~Array(); //! Clear the data in the array void clear(); //! Return the size of the Array inline int ndim() const { return d_size.ndim(); } //! Return the size of the Array inline const ArraySize &size() const { return d_size; } //! Return the size of the Array inline size_t size(int d) const { return d_size[d]; } //! Return the size of the Array inline size_t length() const { return d_size.length(); } //! Return true if the Array is empty inline bool empty() const { return d_size.length() == 0; } //! Return true if the Array is not empty inline operator bool() const { return d_size.length() != 0; } /*! * Resize the Array * @param N NUmber of elements */ inline void resize(size_t N) { resize(ArraySize(N)); } /*! * Resize the Array * @param N_row Number of rows * @param N_col Number of columns */ inline void resize(size_t N_row, size_t N_col) { resize(ArraySize(N_row, N_col)); } /*! * Resize the Array * @param N1 Number of rows * @param N2 Number of columns * @param N3 Number of elements in the third dimension */ inline void resize(size_t N1, size_t N2, size_t N3) { resize(ArraySize(N1, N2, N3)); } /*! * Resize the Array * @param N Number of elements in each dimension */ void resize(const ArraySize &N); /*! * Resize the given dimension of the array * @param dim The dimension to resize * @param N Number of elements for the given dimension * @param value Value to initialize new elements */ void resizeDim(int dim, size_t N, const TYPE &value); /*! * Reshape the Array (total size of array will not change) * @param N Number of elements in each dimension */ void reshape(const ArraySize &N); /*! * Remove singleton dimensions. */ void squeeze(); /*! * Reshape the Array so that the number of dimensions is the * max of ndim and the largest dim>1. * @param ndim Desired number of dimensions */ inline void setNdim(int ndim) { d_size.setNdim(ndim); } /*! * Subset the Array * @param index Index to subset (imin,imax,jmin,jmax,kmin,kmax,...) */ Array subset(const std::vector &index) const; /*! * Subset the Array * @param index Index to subset (ix:kx:jx,iy:ky:jy,...) */ Array subset(const std::vector> &index) const; /*! * Copy data from an array into a subset of this array * @param index Index of the subset (imin,imax,jmin,jmax,kmin,kmax,...) * @param subset The subset array to copy from */ void copySubset(const std::vector &index, const Array &subset); /*! * Copy data from an array into a subset of this array * @param index Index of the subset * @param subset The subset array to copy from */ void copySubset(const std::vector> &index, const Array &subset); /*! * Add data from an array into a subset of this array * @param index Index of the subset (imin,imax,jmin,jmax,kmin,kmax,...) * @param subset The subset array to add from */ void addSubset(const std::vector &index, const Array &subset); /*! * Add data from an array into a subset of this array * @param index Index of the subset * @param subset The subset array to add from */ void addSubset(const std::vector> &index, const Array &subset); public: // Accessors /*! * Access the desired element * @param i The row index */ ARRAY_ATTRIBUTE inline TYPE &operator()(size_t i) { return d_data[d_size.index(i)]; } /*! * Access the desired element * @param i The row index */ ARRAY_ATTRIBUTE inline const TYPE &operator()(size_t i) const { return d_data[d_size.index(i)]; } /*! * Access the desired element * @param i The row index * @param j The column index */ ARRAY_ATTRIBUTE inline TYPE &operator()(size_t i, size_t j) { return d_data[d_size.index(i, j)]; } /*! * Access the desired element * @param i The row index * @param j The column index */ ARRAY_ATTRIBUTE inline const TYPE &operator()(size_t i, size_t j) const { return d_data[d_size.index(i, j)]; } /*! * Access the desired element * @param i The row index * @param j The column index * @param k The third index */ ARRAY_ATTRIBUTE inline TYPE &operator()(size_t i, size_t j, size_t k) { return d_data[d_size.index(i, j, k)]; } /*! * Access the desired element * @param i The row index * @param j The column index * @param k The third index */ ARRAY_ATTRIBUTE inline const TYPE &operator()(size_t i, size_t j, size_t k) const { return d_data[d_size.index(i, j, k)]; } /*! * Access the desired element * @param i1 The first index * @param i2 The second index * @param i3 The third index * @param i4 The fourth index */ ARRAY_ATTRIBUTE inline TYPE &operator()(size_t i1, size_t i2, size_t i3, size_t i4) { return d_data[d_size.index(i1, i2, i3, i4)]; } /*! * Access the desired element * @param i1 The first index * @param i2 The second index * @param i3 The third index * @param i4 The fourth index */ ARRAY_ATTRIBUTE inline const TYPE &operator()(size_t i1, size_t i2, size_t i3, size_t i4) const { return d_data[d_size.index(i1, i2, i3, i4)]; } /*! * Access the desired element * @param i1 The first index * @param i2 The second index * @param i3 The third index * @param i4 The fourth index * @param i5 The fifth index */ ARRAY_ATTRIBUTE inline TYPE &operator()(size_t i1, size_t i2, size_t i3, size_t i4, size_t i5) { return d_data[d_size.index(i1, i2, i3, i4, i5)]; } /*! * Access the desired element * @param i1 The first index * @param i2 The second index * @param i3 The third index * @param i4 The fourth index * @param i5 The fifth index */ ARRAY_ATTRIBUTE inline const TYPE & operator()(size_t i1, size_t i2, size_t i3, size_t i4, size_t i5) const { return d_data[d_size.index(i1, i2, i3, i4, i5)]; } /*! * Access the desired element as a raw pointer * @param i The global index */ ARRAY_ATTRIBUTE inline TYPE *ptr(size_t i) { return i >= d_size.length() ? nullptr : &d_data[i]; } /*! * Access the desired element as a raw pointer * @param i The global index */ ARRAY_ATTRIBUTE inline const TYPE *ptr(size_t i) const { return i >= d_size.length() ? nullptr : &d_data[i]; } //! Get iterator to beginning of data inline TYPE *begin() { return d_data; } //! Get iterator to beginning of data inline const TYPE *begin() const { return d_data; } //! Get iterator to beginning of data inline TYPE *end() { return d_data + d_size.length(); } //! Get iterator to beginning of data inline const TYPE *end() const { return d_data + d_size.length(); } //! Return the pointer to the raw data inline std::shared_ptr getPtr() { return d_ptr; } //! Return the pointer to the raw data inline std::shared_ptr getPtr() const { return d_ptr; } //! Return the pointer to the raw data ARRAY_ATTRIBUTE inline TYPE *data() { return d_data; } //! Return the pointer to the raw data ARRAY_ATTRIBUTE inline const TYPE *data() const { return d_data; } public: // Operator overloading //! Check if two matrices are equal // Equality means the dimensions and data have to be identical bool operator==(const Array &rhs) const; //! Check if two matrices are not equal inline bool operator!=(const Array &rhs) const { return !this->operator==(rhs); } //! Add another array Array &operator+=(const Array &rhs); //! Subtract another array Array &operator-=(const Array &rhs); //! Add a scalar Array &operator+=(const TYPE &rhs); //! Subtract a scalar Array &operator-=(const TYPE &rhs); public: // Math operations //! Concatenates the arrays along the dimension dim. static Array cat(const std::vector &x, int dim = 0); //! Concatenates the arrays along the dimension dim. static Array cat(const std::initializer_list &x, int dim = 0); //! Concatenates the arrays along the dimension dim. static Array cat(size_t N_array, const Array *x, int dim); //! Concatenates a given array with the current array void cat(const Array &x, int dim = 0); //! Initialize the array with random values (defined from the function table) //void rand(); //! Return true if NaNs are present bool NaNs() const; //! Return the smallest value TYPE min() const; //! Return the largest value TYPE max() const; //! Return the sum of all elements TYPE sum() const; //! Return the mean of all elements TYPE mean() const; //! Return the min of all elements in a given direction Array min(int dir) const; //! Return the max of all elements in a given direction Array max(int dir) const; //! Return the sum of all elements in a given direction Array sum(int dir) const; //! Return the smallest value TYPE min(const std::vector &index) const; //! Return the largest value TYPE max(const std::vector &index) const; //! Return the sum of all elements TYPE sum(const std::vector &index) const; //! Return the mean of all elements TYPE mean(const std::vector &index) const; //! Return the smallest value TYPE min(const std::vector> &index) const; //! Return the largest value TYPE max(const std::vector> &index) const; //! Return the sum of all elements TYPE sum(const std::vector> &index) const; //! Return the mean of all elements TYPE mean(const std::vector> &index) const; //! Find all elements that match the operator std::vector find(const TYPE &value, std::function compare) const; //! Print an array void print(std::ostream &os, const std::string &name = "A", const std::string &prefix = "") const; //! Transpose an array Array reverseDim() const; /*! * @brief Shift dimensions * @details Shifts the dimensions of the array by N. When N is positive, * shiftDim shifts the dimensions to the left and wraps the * N leading dimensions to the end. When N is negative, * shiftDim shifts the dimensions to the right and pads with singletons. * @param N Desired shift */ Array shiftDim(int N) const; /*! * @brief Permute array dimensions * @details Rearranges the dimensions of the array so that they * are in the order specified by the vector index. * The array produced has the same values as A but the order of the subscripts * needed to access any particular element are rearranged as specified. * @param index Desired order of the subscripts */ Array permute(const std::vector &index) const; //! Replicate an array a given number of times in each direction Array repmat(const std::vector &N) const; //! Coarsen an array using the given filter Array coarsen(const Array &filter) const; //! Coarsen an array using the given filter Array coarsen(const std::vector &ratio, std::function filter) const; /*! * Perform a element-wise operation y = f(x) * @param[in] fun The function operation * @param[in] x The input array */ static Array transform(std::function fun, const Array &x); /*! * Perform a element-wise operation z = f(x,y) * @param[in] fun The function operation * @param[in] x The first array * @param[in] y The second array */ static Array transform(std::function fun, const Array &x, const Array &y); /*! * axpby operation: this = alpha*x + beta*this * @param[in] alpha alpha * @param[in] x x * @param[in] beta beta */ void axpby(const TYPE &alpha, const Array &x, const TYPE &beta); /*! * Linear interpolation * @param[in] x Position as a decimal index */ inline TYPE interp(const std::vector &x) const { return interp(x.data()); } /*! * Linear interpolation * @param[in] x Position as a decimal index */ TYPE interp(const double *x) const; /** * \fn equals (Array & const rhs, TYPE tol ) * \brief Determine if two Arrays are equal using an absolute tolerance * \param[in] rhs Vector to compare to * \param[in] tol Tolerance of comparison * \return True iff \f$||\mathit{rhs} - x||_\infty < \mathit{tol}\f$ */ bool equals(const Array &rhs, TYPE tol = 0.000001) const; private: bool d_isCopyable; // Can the array be copied bool d_isFixedSize; // Can the array be resized ArraySize d_size; // Size of each dimension TYPE *d_data; // Raw pointer to data in array std::shared_ptr d_ptr; // Shared pointer to data in array void allocate(const ArraySize &N); private: inline void checkSubsetIndex(const std::vector> &range) const; inline std::vector> convert(const std::vector &index) const; static inline void getSubsetArrays(const std::vector> &range, std::array &first, std::array &last, std::array &inc, std::array &N); }; /******************************************************** * ostream operator * ********************************************************/ inline std::ostream &operator<<(std::ostream &out, const ArraySize &s) { out << "[" << s[0]; for (size_t i = 1; i < s.ndim(); i++) out << "," << s[i]; out << "]"; return out; } /******************************************************** * Math operations * ********************************************************/ template inline Array operator+(const Array &a, const Array &b) { Array c; const auto &op = [](const TYPE &a, const TYPE &b) { return a + b; }; FUN::transform(op, a, b, c); return c; } template inline Array operator-(const Array &a, const Array &b) { Array c; const auto &op = [](const TYPE &a, const TYPE &b) { return a - b; }; FUN::transform(op, a, b, c); return c; } template inline Array operator*(const Array &a, const Array &b) { Array c; FUN::multiply(a, b, c); return c; } template inline Array operator*(const Array &a, const std::vector &b) { Array b2, c; b2.viewRaw({b.size()}, const_cast(b.data())); FUN::multiply(a, b2, c); return c; } template inline Array operator*(const TYPE &a, const Array &b) { auto c = b; c.scale(a); return c; } template inline Array operator*(const Array &a, const TYPE &b) { auto c = a; c.scale(b); return c; } /******************************************************** * Copy array * ********************************************************/ template template inline void Array::copy(const TYPE2 *data) { if (std::is_same::value) { std::copy(data, data + d_size.length(), d_data); } else { for (size_t i = 0; i < d_size.length(); i++) d_data[i] = static_cast(data[i]); } } template template inline void Array::copyTo(TYPE2 *data) const { if (std::is_same::value) { std::copy(d_data, d_data + d_size.length(), data); } else { for (size_t i = 0; i < d_size.length(); i++) data[i] = static_cast(d_data[i]); } } /******************************************************** * Convience typedefs * * Copy array * ********************************************************/ typedef Array DoubleArray; typedef Array IntArray; #endif