/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #ifndef _GCTL_ARRAY_H #define _GCTL_ARRAY_H // library's head files #include "../gctl_config.h" #include "enum.h" #include "macro.h" #include "vector_t.h" #include "exceptions.h" #include "random" #include "chrono" #ifdef GCTL_EIGEN /*The followings bypass a bug that VsCode's IntelliSense reports incorrect errors when using eigen3 library*/ #if __INTELLISENSE__ #undef __ARM_NEON #undef __ARM_NEON__ #endif #include "Eigen/Dense" #include "Eigen/Sparse" #endif // GCTL_EIGEN #ifdef GCTL_OPENMP #include "omp.h" #endif // GCTL_OPENMP namespace gctl { template class array; /* * Here we define some commonly used array types. */ typedef array _1i_array; ///< 1-D integer array typedef array _1f_array; ///< 1-D single-precision floating-point array typedef array _1d_array; ///< 1-D double-precision floating-point array typedef array _1s_array; ///< 1-D string array typedef array> _1cf_array; ///< 1-D complex float array typedef array> _1cd_array; ///< 1-D complex double array /** * @brief Iterator template. This could be used to enable the use of iteration algorithms for array-like objects. * */ template class iterator { private: T *iter; public: iterator(T *para, size_t n) {iter = para + n;} virtual ~iterator(){} T &operator*() {return *iter;} bool operator!=(const iterator &that) {return this->iter != that.iter;} iterator &operator++() {++iter; return *this;} }; /** * @brief 1-D array class template * * @tparam ArrValType template array */ template class array { protected: ArrValType *val_; ///< Pointer of the array size_t length_; ///< Length of the array public: /** * @brief Default constructor. */ array(); /** * @brief Construct an array with the given length. * * @param[in] len Length of the array. Must be equal to or bigger than zero. */ array(size_t len); /** * @brief Construct an array with the given length and initial values. * * @param[in] len Length of the array. Must be equal to or bigger than zero. * @param[in] init_val Initial value of the elements. */ array(size_t len, ArrValType init_val); /** * @brief Construct an array with the given length and fill elements using a native c++ array. * * @note Note that if you use an native c++ array to initialize the array template, the pointer * must be first variable and the length is last variable. This design is mainly to avoid unclear function * calls. Consider an array of pointers array A(10, nullptr) means that the initial value of all * elements is nullptr and array A((double**)B, 10) means that the element value of A is initialized * with array B If the above expression is written as array A(10, B), the compiler cannot call the * function correctly. Because it cannot be judged whether we want to use the initial value or * the array to initialize the array. * * @param init_array Pointer of the native c++ array. * @param[in] len Length of the input c++ array. Must be equal to or bigger than zero. */ array(ArrValType *init_array, size_t len); /** * @brief Copy constructor. * * @param[in] b Original array. */ array(const array &b); /** * @brief Construct a new array object from std::initializer * * @param init_val Initial values */ array(std::initializer_list init_val); /** * @brief Construct a new array object as a sequence * * @param s Size of the sequence. * @param st Start value * @param inc Invrease interval */ array(size_t s, ArrValType st, ArrValType inc); /** * @brief Overloaded assignment operator for the array template. * * @param[in] b Original array. * * @return Target array. */ array& operator= (const array &b); /** * @brief Overloaded assignment operator for the array template. * * @param v Initial value. * @return Target array. */ array& operator= (ArrValType v); /** * @brief Overloaded summation operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array operator+ (const array &b); /** * @brief Overloaded minus operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array operator- (const array &b); /** * @brief Overloaded multiple operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array operator* (const array &b); /** * @brief Overloaded division operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array operator/ (const array &b); /** * @brief Overloaded summation operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array& operator+= (const array &b); /** * @brief Overloaded summation operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array& operator-= (const array &b); /** * @brief Overloaded multiple operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array& operator*= (const array &b); /** * @brief Overloaded division operator for the array template. * * @param a Input array * @param b Inpur array * @return Target array */ array& operator/= (const array &b); /** * @brief Overloaded summation operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array operator+ (const ArrValType &b); /** * @brief Overloaded minus operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array operator- (const ArrValType &b); /** * @brief Overloaded multiple operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array operator* (const ArrValType &b); /** * @brief Overloaded division operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array operator/ (const ArrValType &b); /** * @brief Overloaded summation operator for the array template. * * @param a Input array * @param b Scale value * @return Target array * */ array& operator+= (const ArrValType &b); /** * @brief Overloaded summation operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array& operator-= (const ArrValType &b); /** * @brief Overloaded multiple operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array& operator*= (const ArrValType &b); /** * @brief Overloaded division operator for the array template. * * @param a Input array * @param b Scale value * @return Target array */ array& operator/= (const ArrValType &b); /** * @brief Compare two arraies. * * @return True if the two arraies are equal, false otherwise. */ bool operator== (const array &b) const; /** * @brief Compare two arraies. * * @return True if the two arraies are not equal, false otherwise. */ bool operator!= (const array &b) const; /** * @brief Compare two arraies. * * @param b Input array * @param eps Tolerance for flaoting point number * * @return True if the two arraies are not equal, false otherwise. */ bool equals(const array &b, ArrValType eps = ArrValType{}) const; /** * @brief Destructor */ virtual ~array(); /** * @brief Set the length of the array to the given value. * * @note If the input length is not equal to the existing length of the array, * the previous array is destroyed and reconstructed. * * @param[in] len Length of the array. Must be equal to or bigger than zero. */ void resize(size_t len); /** * @brief Set the length of the array to the given value, and fill elements with initial values. * * @note If the input length is not equal to the existing length of the array, * the previous array is destroyed and reconstructed. * * @param[in] len Length of the array. Must be equal to or bigger than zero. * @param[in] init_val Initial value of the elements. */ void resize(size_t len, ArrValType init_val); /** * @brief Set the length of the array to the given value, and fill elements using a native c++ array. * * @note If the input length is not equal to the existing length of the array, * the previous array is destroyed and reconstructed. * * @param init_array Pointer of the native c++ array. * @param[in] len Length of the input c++ array. Must be equal to or bigger than zero. */ void resize(ArrValType *init_array, size_t len); /** * @brief Copy a array to the array. * * @note If the length of the input array is not equal to the existing length of the array, * the previous array is destroyed and reconstructed. * * @param[in] b Original array */ void resize(const array &b); /** * @brief Resize a new array object from std::initializer * * @param init_val Initial values */ void resize(std::initializer_list init_val); /** * @brief Resize a new array object as a sequence * * @param s Size of the sequence. * @param st Start value * @param inc Invrease interval */ void resize(size_t s, ArrValType st, ArrValType inc); /** * @brief Clear memory space and reset variables. */ void clear(); /** * @brief Set all elements to the given value. * * @param[in] in_val Input value. */ void assign(ArrValType in_val); /** * @brief Set value to segments of an array. * * @param in_val Input value * @param st Starting index * @param range segment range */ void assign(ArrValType in_val, size_t st, size_t range); /** * @brief Append an array to the end of the existing one * * @param b Input array */ void concat(const array &b); /** * @brief Extract an array * * @param b Output array. Must be initialized before use. * @param st Start index */ void slice(array &b, size_t st = 0) const; /** * @brief Extract an array * * @param b Output array * @param ids Index of the extracting elements. Must be initialized before use. */ void slice(array &b, const array &ids) const; /** * @brief Insert data from an input array * * @param b The input array * @param st The inserting point. The default is zero */ void insert(array &b, size_t st = 0); /** * @brief Get element value at the given index. * * @note This function will check if the index was out of range. * * @param[in] index index value. * * @return element's value. */ ArrValType &at(size_t index); /** * @brief Get element value at the given index (Constant). * * @note This function will check if the index was out of range. * * @param[in] index index value. * * @return element's value. */ ArrValType &at(size_t index) const; /** * @brief Get element value at the given index. * * @note This function could not be called by a pointer. * * @param[in] index index value. * * @return element's value. */ ArrValType &operator[](size_t index) noexcept; /** * @brief Get element value at the given index . * * @note This function could not be called by a pointer. * * @param[in] index index value. * * @return element's value. */ ArrValType &operator[](size_t index) const noexcept; /** * @brief Get the first element * * @return element value */ ArrValType front() const; /** * @brief Get the last element * * @return element value */ ArrValType back() const; /** * @brief Return the begining of the iterator * * @return iterator */ iterator begin(); /** * @brief Return the ending of the iterator * * @return iterator */ iterator end(); /** * @brief Get the pointer to a element at the given index. * * @note This function will check if the index was out of range. * * @param[in] index index value. * * @return Pointer to the element */ ArrValType *get(size_t index = 0) const; /** * @brief Discriminate if the array is empty. * * @return True for empty. False other wise. */ bool empty() const noexcept; /** * @brief Return the length of the class member array. * * @return Length. */ size_t size() const noexcept; /** * @brief Copy the array to a vector. * * @param b Target vector. */ void output(std::vector &b) const; /** * @brief Copy the array from a vector. * * @param b Target vector. */ void input(const std::vector &b); #ifdef GCTL_EIGEN /** * @brief Copy the array to a Eigen3 vector. * * @param b Target vector. */ void output(Eigen::VectorXd &b) const; /** * @brief Copy the array from a Eigen3 vector. * * @param b Target vector. */ void input(const Eigen::VectorXd &b); #endif // GCTL_EIGEN /** * @brief element operate function pointer * */ typedef void (*foreach_a_ptr)(ArrValType &ele_ptr, size_t id); /** * @brief 并行执行指定操作 * * 对数组中的每个元素并行执行指定的操作,参数为数组元素的引用。 * 例如:[](ArrValType &a){do something here...} * * @tparam UnaryOp 一元操作类型 参数为数组元素的引用 * @param op 要执行的操作 */ template void for_each(UnaryOp op) { #pragma omp parallel for for (size_t i = 0; i < length_; i++) { op(val_[i]); } return; } /** * @brief 并行执行提取操作(比如提取结构体的成员变量数组) * * 对数组中的每个元素并行执行给定的操作并将输出组成一个新数组,参数为数组元素的常引用。 * 例如:[](const ArrValType &a)->OutType{do something here...} * * @tparam UnaryOp 一元操作类型 参数为数组元素的引用 * @param op 要执行的操作 */ template array extract(UnaryOp op) { array arr(length_); #pragma omp parallel for for (size_t i = 0; i < length_; i++) { arr[i] = op(val_[i]); } return arr; } /** * @brief Display the elements. * */ void show(std::ostream &os = std::cout, char sep = ' '); /** * @brief Initialize the array with selected random types. * * @param[in] np1 Mean (Gauss) or low bound value (Even) * @param[in] np2 Standard deviation (Gauss) or hig bound value (Even). * @param[in] mode Random types. 'RdNormal' for Gaussian distributed numbers and * 'RdUniform' for even distributed numbers. * @param[in] seed Random seed. Input 0 to select the seed based on the current time. */ void random_float(ArrValType np1, ArrValType np2, random_type_e mode = RdNormal, unsigned int seed = 0); /** * @brief Initialize the array with selected random types. * * @param[in] np1 Low bound value. * @param[in] np2 Hig bound value. * @param[in] seed Random seed. Input 0 to select the seed based on the current time. */ void random_int(ArrValType np1, ArrValType np2, unsigned int seed = 0); /** * @brief Set elements' value as a sequent. * * @param st_val Start value of the sequent. * @param inc Increasement of the sequent. * @param st_id Start index. The default starts from the first element * @param size Operating size. The default operates on all elements * @param space Indexing spacing. you can skip elements when create the sequent. The default is no skipping. */ void sequence(ArrValType st_val, ArrValType inc, size_t st_id = 0, size_t size = std::numeric_limits::max(), size_t space = 0); /** * @brief Assign values as a 2D sequence. * * @param rs Start value of the row sequence * @param rinc Increase value of the row sequence * @param cs Start value of the column sequence * @param cinc Increase value of the column sequence * @param rn Row nnumber * @param cn Column number */ void sequence2d(ArrValType rs, ArrValType rinc, ArrValType cs, ArrValType cinc, size_t rn, size_t cn); /** * @brief Assign values as a 3D sequence. * * @param ls Start value of the layer sequence * @param linc Increase value of the layer sequence * @param rs Start value of the row sequence * @param rinc Increase value of the row sequence * @param cs Start value of the column sequence * @param cinc Increase value of the column sequence * @param ln Layer number * @param rn Row nnumber * @param cn Column number */ void sequence3d(ArrValType ls, ArrValType linc, ArrValType rs, ArrValType rinc, ArrValType cs, ArrValType cinc, size_t ln, size_t rn, size_t cn); /** * @brief Scale elements * * @param in_val input factor */ void scale(ArrValType in_val); /** * @brief Dot product of two arrays. * * @param a Input array. Must be the same length_. * @return dot product */ ArrValType dot(const array &a); /** * @brief Return the sum of all elements. * * @return sum value. */ ArrValType sum() const; /** * @brief Return the mean value. * * @return mean value. */ ArrValType mean() const; /** * @brief Return the variance value. * * @return Variance value. */ ArrValType variance() const; /** * @brief Return the standard deviation value. * * @return std value. */ ArrValType std() const; /** * @brief Return the unbiased standard deviation value. * * @return std value. */ ArrValType std_unbiased() const; /** * @brief Return the root mean square value. * * @return RMS value. */ ArrValType rms() const; /** * @brief Return the maximal value. * * @return maximal value. */ ArrValType max() const; /** * @brief Return the minimal value. * * @return minimal value. */ ArrValType min() const; /** * @brief 计算数组的模长 * * @param[in] n_type 模长的计算类型 * * @return 返回的模长 */ ArrValType module(norm_type_e n_type = L2); /** * @brief Normalize the array to the given module value * * @param norm targeting norm-value * @param n_type Norm-type * * @return The module */ ArrValType normalize(ArrValType norm = 1.0, norm_type_e n_type = L2); /** * @brief 计算一个向量相对于另一个向量的正交向量 * * @param b 输入的数组,计算后的正交向量以引用的形式返回 */ void orth(array &b); /** * @brief Assign values as a power sequence. * * @param base Power base */ void log2linear(const ArrValType &base); /** * @brief Convert values to a log root. * * @param base Log base */ void linear2log(ArrValType base); /** * @brief Set values to a range. * * @param min Lower bound * @param max Higher bound * @param rt Bounder type * */ void set2range(ArrValType min, ArrValType max, range_type_e rt = HardScale); /** * @brief 检查是否存在等于指定值的元素 * * @param value 要比较的值 * @return 如果存在等于指定值的元素返回true,否则返回false */ bool any_of(const ArrValType& value) const; /** * @brief 检查是否所有元素都等于指定值 * * @param value 要比较的值 * @return 如果所有元素都等于指定值返回true,否则返回false */ bool all_of(const ArrValType& value) const; /** * @brief 统计等于指定值的元素个数 * * @param value 要统计的值 * @return 等于指定值的元素个数 */ size_t count(const ArrValType& value) const; /** * @brief 获取数组的内存使用量 * * @return 数组占用的总内存量MB */ void memory_usage(std::ostream &os = std::cout) const noexcept; }; template array::array() { length_ = 0; val_ = nullptr; } template array::array(size_t len) { length_ = 0; val_ = nullptr; resize(len); } template array::array(size_t len, ArrValType init_val) { length_ = 0; val_ = nullptr; resize(len, init_val); } template array::array(ArrValType *init_array, size_t len) { length_ = 0; val_ = nullptr; resize(init_array, len); } template array::array(const array &b) { length_ = 0; val_ = nullptr; resize(b); } template array::array(std::initializer_list init_val) { length_ = 0; val_ = nullptr; resize(init_val); } template array::array(size_t s, ArrValType st, ArrValType inc) { length_ = 0; val_ = nullptr; resize(s, st, inc); } template array &array::operator= (const array &b) { resize(b.size()); for (size_t i = 0; i < length_; i++) { val_[i] = b[i]; } return *this; } template array &array::operator= (ArrValType v) { for (size_t i = 0; i < length_; i++) { val_[i] = v; } return *this; } template array array::operator+ (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator+] Incompatible array sizes."); } array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = val_[i] + b[i]; } return out; } template array array::operator- (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator-] Incompatible array sizes."); } array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = val_[i] - b[i]; } return out; } template array array::operator* (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator*] Incompatible array sizes."); } array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = val_[i] * b[i]; } return out; } template array array::operator/ (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator/] Incompatible array sizes."); } array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = val_[i] / b[i]; } return out; } template array& array::operator+= (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator+=] Incompatible array sizes."); } for (size_t i = 0; i < length_; i++) { val_[i] += b[i]; } return *this; } template array& array::operator-= (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator-=] Incompatible array sizes."); } for (size_t i = 0; i < length_; i++) { val_[i] -= b[i]; } return *this; } template array& array::operator*= (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator*=] Incompatible array sizes."); } for (size_t i = 0; i < length_; i++) { val_[i] *= b[i]; } return *this; } template array& array::operator/= (const array &b) { if (b.size() != length_) { throw std::runtime_error("[gctl::array::operator/=] Incompatible array sizes."); } for (size_t i = 0; i < length_; i++) { val_[i] /= b[i]; } return *this; } template array array::operator+ (const ArrValType &b) { array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = val_[i] + b; } return out; } template array array::operator- (const ArrValType &b) { array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = b - val_[i]; } return out; } template array array::operator* (const ArrValType &b) { array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = b*val_[i]; } return out; } template array array::operator/ (const ArrValType &b) { array out(length_); for (size_t i = 0; i < length_; i++) { out[i] = b/val_[i]; } return out; } template array& array::operator+= (const ArrValType &b) { for (size_t i = 0; i < length_; i++) { val_[i] += b; } return *this; } template array& array::operator-= (const ArrValType &b) { for (size_t i = 0; i < length_; i++) { val_[i] -= b; } return *this; } template array& array::operator*= (const ArrValType &b) { for (size_t i = 0; i < length_; i++) { val_[i] *= b; } return *this; } template array& array::operator/= (const ArrValType &b) { for (size_t i = 0; i < length_; i++) { val_[i] /= b; } return *this; } template bool array::operator== (const array &b) const { if (length_ != b.size()) return false; for (size_t i = 0; i < length_; i++) { if (val_[i] != b[i]) return false; } return true; } template bool array::operator!= (const array &b) const { return !(*this == b); } template bool array::equals(const array &b, ArrValType eps) const { if (length_ != b.size()) return false; if (eps == ArrValType{}) { for (size_t i = 0; i < length_; i++) { if (val_[i] != b[i]) return false; } } else { for (size_t i = 0; i < length_; i++) { if (std::abs(val_[i] - b[i]) > eps) return false; } } return true; } template array::~array() { clear(); } template void array::resize(size_t len) { if (len == 0) { throw std::invalid_argument("[gctl::array::resize] Invalid array size."); } if (length_ != len) { clear(); length_ = len; val_ = new ArrValType[len]; } return; } template void array::resize(size_t len, ArrValType init_val) { resize(len); for (size_t i = 0; i < length_; i++) { val_[i] = init_val; } return; } template void array::resize(ArrValType *init_array, size_t len) { if (init_array == nullptr) { throw std::domain_error("[gctl::array::resize] Invalid pointer."); } resize(len); for (size_t i = 0; i < length_; i++) { val_[i] = init_array[i]; } return; } template void array::resize(const array &b) { if (!b.empty()) { resize(b.size()); for (size_t i = 0; i < length_; i++) { val_[i] = b[i]; } } return; } template void array::resize(std::initializer_list init_val) { resize(init_val.size()); typename std::initializer_list::iterator iter = init_val.begin(); for (size_t i = 0; i < length_; i++) { val_[i] = *iter; iter++; } return; } template void array::resize(size_t s, ArrValType st, ArrValType inc) { resize(s); sequence(st, inc); return; } template void array::clear() { if (val_ != nullptr) { delete[] val_; val_ = nullptr; length_ = 0; } return; } template void array::assign(ArrValType in_val) { for (size_t i = 0; i < length_; i++) { val_[i] = in_val; } return; } template void array::assign(ArrValType in_val, size_t st, size_t range) { if (st + range <= length_) { for (size_t i = st; i < st + range; i++) { val_[i] = in_val; } return; } throw std::runtime_error("[gctl::array::assign] Invalid segment range."); return; } template void array::concat(const array &b) { ArrValType *t = new ArrValType [length_ + b.size()]; for (size_t i = 0; i < length_; i++) { t[i] = val_[i]; } for (size_t i = 0; i < b.size(); i++) { t[i + length_] = b[i]; } delete[] val_; val_ = t; length_ += b.size(); return; } template void array::slice(array &b, size_t st) const { if (b.size() + st <= length_) { for (size_t i = 0; i < b.size(); i++) { b[i] = val_[i + st]; } } else { size_t c = 0; for (size_t i = st; i < length_; i++) { b[c] = val_[i]; c++; } } return; } template void array::slice(array &b, const array &ids) const { b.resize(ids.size()); for (size_t i = 0; i < ids.size(); i++) { b[i] = val_[ids[i]]; } return; } template void array::insert(array &b, size_t st) { if (b.size() + st <= length_) { for (size_t i = 0; i < b.size(); i++) { val_[i + st] = b[i]; } } else { size_t c = 0; for (size_t i = st; i < length_; i++) { val_[i] = b[c]; c++; } } return; } template ArrValType *array::get(size_t index) const { if (index >= length_) throw std::out_of_range("[gctl::array::at] Invalid index."); return &val_[index]; } template ArrValType &array::at(size_t index) { if (index >= length_) throw std::out_of_range("[gctl::array::at] Invalid index."); return val_[index]; } template ArrValType &array::at(size_t index) const { if (index >= length_) throw std::out_of_range("[gctl::array::at] Invalid index."); return val_[index]; } template ArrValType &array::operator[](size_t index) noexcept { return val_[index]; } template ArrValType &array::operator[](size_t index) const noexcept { return val_[index]; } template ArrValType array::front() const { return val_[0]; } template ArrValType array::back() const { return val_[length_-1]; } template iterator array::begin() { return iterator(this->val_, 0); } template iterator array::end() { return iterator(this->val_, length_); } template bool array::empty() const noexcept { if (length_ == 0) return true; else return false; } template size_t array::size() const noexcept { return length_; } template void array::output(std::vector &b) const { if (!b.empty()) { b.clear(); } b.resize(length_); for (size_t i = 0; i < length_; i++) { b[i] = val_[i]; } return; } template void array::input(const std::vector &b) { resize(b.size()); for (size_t i = 0; i < length_; i++) { val_[i] = b[i]; } return; } #ifdef GCTL_EIGEN template void array::output(Eigen::VectorXd &b) const { b.resize(length_); for (size_t i = 0; i < length_; i++) { b[i] = val_[i]; } return; } template void array::input(const Eigen::VectorXd &b) { resize(b.size()); for (size_t i = 0; i < length_; i++) { val_[i] = b[i]; } return; } #endif // GCTL_EIGEN /* template void array::for_each(foreach_a_ptr func) { for (size_t i = 0; i < length_; i++) { func(val_[i], i); } return; } */ template void array::show(std::ostream &os, char sep) { if (length_ != 0) { os << val_[0]; for (size_t i = 1; i < length_; i++) { os << sep << val_[i]; } os << std::endl; } return; } template std::ostream &operator <<(std::ostream &os, const array &a) { if (!a.empty()) { os << a[0]; for (size_t i = 1; i < a.size(); i++) { os << " " << a[i]; } } return os; } template std::istream &operator >>(std::istream &os, array &a) { for (size_t i = 0; i < a.size(); i++) { os >> a[i]; } return os; } template void array::random_float(ArrValType np1, ArrValType np2, random_type_e mode, unsigned int seed) { static_assert(std::is_floating_point::value, "gctl::array::random_float(...) could only be used with a float point type."); if (seed == 0) seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); if (mode == RdNormal) { //添加高斯分布的随机值 std::normal_distribution dist(np1, np2); for (size_t i = 0; i < length_; i++) { val_[i] = dist(generator); } return; } //添加均匀分布的随机值 std::uniform_real_distribution dist(np1, np2); for (size_t i = 0; i < length_; i++) { val_[i] = dist(generator); } return; } template void array::random_int(ArrValType np1, ArrValType np2, unsigned int seed) { static_assert(std::is_integral::value, "gctl::array::random_int(...) could only be used with an integral type."); if (seed == 0) seed = std::chrono::system_clock::now().time_since_epoch().count(); std::default_random_engine generator(seed); //添加均匀分布的随机值 std::uniform_int_distribution dist(np1, np2); for (size_t i = 0; i < length_; i++) { val_[i] = dist(generator); } return; } template void array::sequence(ArrValType st_val, ArrValType inc, size_t st_id, size_t size, size_t space) { if (st_id >= length_) throw std::runtime_error("[gctl::array::sequence] Invalid index."); size = GCTL_MIN(size, length_); if (size > 0) { val_[st_id] = st_val; size--; size_t id = st_id; size_t id2 = st_id + space + 1; while (id2 < length_ && size > 0) { val_[id2] = val_[id] + inc; id = id2; id2 += space + 1; size--; } } return; } template void array::sequence2d(ArrValType rs, ArrValType rinc, ArrValType cs, ArrValType cinc, size_t rn, size_t cn) { if (rn*cn != length_) { throw invalid_argument("[gctl::array::sequence2d] Invalid sequence sizes."); } array out_x(cn), out_y(rn); out_x.sequence(cs, cinc); out_y.sequence(rs, rinc); for (size_t i = 0; i < rn; i++) { for (size_t j = 0; j < cn; j++) { val_[j + i*cn] = out_x[j] + out_y[i]; } } return; } template void array::sequence3d(ArrValType ls, ArrValType linc, ArrValType rs, ArrValType rinc, ArrValType cs, ArrValType cinc, size_t ln, size_t rn, size_t cn) { if (ln*rn*cn != length_) { throw invalid_argument("[gctl::array::sequence3d] Invalid sequence sizes."); } array out_x(cn), out_y(rn), out_z(ln); out_x.sequence(cs, cinc); out_y.sequence(rs, rinc); out_z.sequence(ls, linc); for (size_t k = 0; k < ln; k++) { for (size_t i = 0; i < rn; i++) { for (size_t j = 0; j < cn; j++) { val_[j + i*cn + k*rn*cn] = out_x[j] + out_y[i] + out_z[k]; } } } return; } template void array::scale(ArrValType in_val) { static_assert(std::is_arithmetic::value, "gctl::array::scale(...) could only be used with an arithmetic type."); for (size_t i = 0; i < length_; i++) { val_[i] = val_[i]*in_val; } return; } template ArrValType array::dot(const array &a) { static_assert(std::is_arithmetic::value, "gctl::array::dot(...) could only be used with an arithmetic type."); if (length_ != a.size()) { throw std::runtime_error("Incompatible array sizes. gctl::array::dot(...)"); } ArrValType s = 0; for (size_t i = 0; i < length_; i++) { s += val_[i]*a[i]; } return s; } template ArrValType array::sum() const { static_assert(std::is_arithmetic::value, "gctl::array::sum(...) could only be used with an arithmetic type."); if (length_ == 0) return ArrValType{}; ArrValType s = val_[0]; #pragma omp parallel for reduction(+:s) for (size_t i = 1; i < length_; i++) { s += val_[i]; } return s; } template ArrValType array::mean() const { static_assert(std::is_arithmetic::value, "gctl::array::mean(...) could only be used with an arithmetic type."); if (length_ == 0) return ArrValType{}; return sum()/static_cast(length_); } template ArrValType array::std() const { static_assert(std::is_arithmetic::value, "gctl::array::std(...) could only be used with an arithmetic type."); if (length_ == 0 || length_ == 1) return ArrValType{}; ArrValType m = mean(), s = 0; for (size_t i = 0; i < length_; i++) { s += (val_[i] - m)*(val_[i] - m); } return sqrt(s/static_cast(length_)); } template ArrValType array::rms() const { static_assert(std::is_arithmetic::value, "gctl::array::rms(...) could only be used with an arithmetic type."); if (length_ == 0) return ArrValType{}; ArrValType m = 0; for (size_t i = 0; i < length_; i++) { m += val_[i]*val_[i]; } return sqrt(m/static_cast(length_)); } template ArrValType array::max() const { static_assert(std::is_arithmetic::value, "gctl::array::max(...) could only be used with an arithmetic type."); if (length_ == 0) return ArrValType{}; ArrValType m = val_[0]; for (size_t i = 1; i < length_; i++) { m = std::max(val_[i], m); } return m; } template ArrValType array::min() const { static_assert(std::is_arithmetic::value, "gctl::array::min(...) could only be used with an arithmetic type."); if (length_ == 0) return ArrValType{}; ArrValType m = val_[0]; for (size_t i = 1; i < length_; i++) { m = std::min(val_[i], m); } return m; } template ArrValType array::module(norm_type_e n_type) { static_assert(std::is_arithmetic::value, "gctl::array::module(...) could only be used with an arithmetic type."); ArrValType norm_sum = 0.0; if (n_type == L0) { int n = 0; for (size_t i = 0; i < length_; i++) { if (val_[i] != 0.0) { n++; } } norm_sum = (ArrValType) n; } if (n_type == L1) { for (size_t i = 0; i < length_; i++) { norm_sum += GCTL_FABS(val_[i]); } } if (n_type == L2) { for (size_t i = 0; i < length_; i++) { norm_sum += val_[i] * val_[i]; } norm_sum = sqrt(norm_sum); } if (n_type == Linf) { norm_sum = val_[0]; for (int i = 1; i < length_; i++) { norm_sum = GCTL_MAX(norm_sum, val_[i]); } } return norm_sum; } template ArrValType array::normalize(ArrValType norm, norm_type_e n_type) { static_assert(std::is_arithmetic::value, "gctl::array::normalize(...) could only be used with an arithmetic type."); ArrValType norm_sum = module(n_type); if (norm_sum <= GCTL_ZERO) return 0; for (size_t i = 0; i < length_; i++) { val_[i] = val_[i]*norm/norm_sum; } return norm_sum; } template void array::orth(array &b) { static_assert(std::is_arithmetic::value, "gctl::array::orth(...) could only be used with an arithmetic type."); if (length_ != b.size()) { throw runtime_error("[gctl::array::orth] Incompatible array size."); } ArrValType product = dot(b); for (int i = 0; i < length_; i++) { b[i] = b[i] - product*val_[i]; } return; } template void array::log2linear(const ArrValType &base) { static_assert(std::is_arithmetic::value, "gctl::array::logspace(...) could only be used with an arithmetic type."); for (size_t i = 0; i < length_; i++) { val_[i] = pow(base, val_[i]); } return; } template void array::linear2log(ArrValType base) { static_assert(std::is_arithmetic::value, "gctl::array::linear2log(...) could only be used with an arithmetic type."); for (size_t i = 0; i < length_; ++i) { val_[i] = log(val_[i])/log(base); } return; } template ArrValType array::variance() const { static_assert(std::is_arithmetic::value, "gctl::array::variance(...) could only be used with an arithmetic type."); if (length_ == 0) return ArrValType{}; ArrValType mn = mean(); ArrValType d = 0; for (size_t i = 0; i < length_; i++) { d = d + (val_[i] - mn)*(val_[i] - mn); } return d/static_cast(length_); } template ArrValType array::std_unbiased() const { static_assert(std::is_arithmetic::value, "gctl::array::std_unbiased(...) could only be used with an arithmetic type."); if (length_ < 2) return 0; ArrValType mn = mean(); ArrValType d = 0; for (size_t i = 0; i < length_; i++) { d = d + (val_[i] - mn)*(val_[i] - mn); } return sqrt(d/(length_ - 1)); } template void array::set2range(ArrValType min, ArrValType max, range_type_e rt) { static_assert(std::is_arithmetic::value, "gctl::array::set2range(...) could only be used with an arithmetic type."); ArrValType amin = val_[0], amax = val_[0]; for (size_t i = 1; i < length_; i++) { amin = aminval_[i]?amax:val_[i]; } if (rt == HardScale) { for (size_t i = 0; i < length_; i++) { val_[i] = (max - min)*(val_[i] - amin)/(amax - amin) + min; } return; } if (amin >= min && amax <= max) return; // aleardy in the range, nothing to be done if (rt == CutOff) { for (size_t i = 0; i < length_; i++) { if (val_[i] > max) val_[i] = max; if (val_[i] < min) val_[i] = min; } return; } // Soft Scale ArrValType min2 = amin>min?amin:min; ArrValType max2 = amax bool array::any_of(const ArrValType& value) const { bool result = false; #pragma omp parallel for reduction(|:result) for (size_t i = 0; i < length_; i++) { result = result || (val_[i] == value); } return result; } template bool array::all_of(const ArrValType& value) const { bool result = true; #pragma omp parallel for reduction(&:result) for (size_t i = 0; i < length_; i++) { result = result && (val_[i] == value); } return result; } template size_t array::count(const ArrValType& value) const { size_t result = 0; #pragma omp parallel for reduction(+:result) for (size_t i = 0; i < length_; i++) { if (val_[i] == value) ++result; } return result; } template void array::memory_usage(std::ostream &os) const noexcept { size_t byte = sizeof(*this) + length_ * sizeof(ArrValType); if (byte/1073741824 > 0) os << byte/1073741824 << " GB\n"; else if (byte/1048576 > 0) os << byte/1048576 << " MB\n"; else if (byte/1024 > 0) os << byte/1024 << " KB\n"; else os << byte << " B\n"; return; } } #endif // _GCTL_ARRAY_H