/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * 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" #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 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 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 Clear memory space and reset variables. */ void clear(); /** * @brief Set all elements to the given value. * * @param[in] in_val Input value. */ void assign_all(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 append_array(const array &b); /** * @brief Extract an array * * @param b Output array. Must be initialized before use. * @param st Start index */ void extract_array(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 extract_array(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(array &b, size_t st = 0); /** * @brief Get element value at the given index. * * @note This function could be called by a pointer. * * @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 could be called by a pointer. * * @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); /** * @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; /** * @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. * * @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; /** * @brief Return the length of the class member array. * * @return Length. */ size_t size() const; /** * @brief Copy the array to a vector. * * @param b Target vector. */ void export_vector(std::vector &b) const; /** * @brief Copy the array from a vector. * * @param b Target vector. */ void import_vector(const std::vector &b); #ifdef GCTL_EIGEN /** * @brief Copy the array to a Eigen3 vector. * * @param b Target vector. */ void export_eigen_vector(Eigen::VectorXd &b) const; /** * @brief Copy the array from a Eigen3 vector. * * @param b Target vector. */ void import_eigen_vector(const Eigen::VectorXd &b); #endif // GCTL_EIGEN /** * @brief element operate function pointer * */ typedef void (*foreach_a_ptr)(ArrValType *ele_ptr, size_t id); /** * @brief Operate on each and every element * * @param func operation function */ void for_each(foreach_a_ptr func); /** * @brief Display the elements. * */ void show(std::ostream &os = std::cout, char sep = ' '); }; 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::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) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator+(...)"); } #endif // GCTL_CHECK_SIZE 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) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator-(...)"); } #endif // GCTL_CHECK_SIZE 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) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator*(...)"); } #endif // GCTL_CHECK_SIZE 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) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator/(...)"); } #endif // GCTL_CHECK_SIZE 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) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator+=(...)"); } #endif // GCTL_CHECK_SIZE for (size_t i = 0; i < length_; i++) { val_[i] += b[i]; } return *this; } template array& array::operator-= (const array &b) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator-=(...)"); } #endif // GCTL_CHECK_SIZE for (size_t i = 0; i < length_; i++) { val_[i] -= b[i]; } return *this; } template array& array::operator*= (const array &b) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator*=(...)"); } #endif // GCTL_CHECK_SIZE for (size_t i = 0; i < length_; i++) { val_[i] *= b[i]; } return *this; } template array& array::operator/= (const array &b) { #ifdef GCTL_CHECK_SIZE if (b.size() != length_) { throw std::runtime_error("Incompatible array sizes. gctl::array::operator/=(...)"); } #endif // GCTL_CHECK_SIZE for (size_t i = 0; i < length_; i++) { val_[i] /= b[i]; } return *this; } template array::~array() { clear(); } template void array::resize(size_t len) { if (len == 0) { throw std::invalid_argument("Invalid array size. gctl::array::resize(...)"); } 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("Invalid pointer. gctl::array::resize(...)"); } 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::clear() { if (val_ != nullptr) { delete[] val_; val_ = nullptr; length_ = 0; } return; } template void array::assign_all(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("Invalid segment range. From gctl::array::assign(...)"); return; } template void array::append_array(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::extract_array(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::extract_array(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(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 { #ifdef GCTL_CHECK_BOUNDER if (index >= length_) throw std::out_of_range("Invalid index. gctl::array::get(...)"); #endif // GCTL_CHECK_BOUNDER return &val_[index]; } template ArrValType &array::at(size_t index) { #ifdef GCTL_CHECK_BOUNDER if (index >= length_) throw std::out_of_range("Invalid index. gctl::array::at(...)"); #endif // GCTL_CHECK_BOUNDER return val_[index]; } template ArrValType &array::at(size_t index) const { #ifdef GCTL_CHECK_BOUNDER if (index >= length_) throw std::out_of_range("Invalid index. gctl::array::at(...)"); #endif // GCTL_CHECK_BOUNDER return val_[index]; } template ArrValType &array::operator[](size_t index) { return val_[index]; } template ArrValType &array::operator[](size_t index) const { 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 { if (length_ == 0) return true; else return false; } template size_t array::size() const { return length_; } template void array::export_vector(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::import_vector(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::export_eigen_vector(Eigen::VectorXd &b) const { b.resize(length_); for (size_t i = 0; i < length_; i++) { b[i] = val_[i]; } return; } template void array::import_eigen_vector(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; } } #endif // _GCTL_ARRAY_H /** * @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. */ // void random(ArrValType np1, ArrValType np2, random_type_e mode = RdNormal, unsigned int seed = 0); /** * @brief Set elements' value as a sequent. * * @param st_val Start value. * @param inc Increasement. */ //void sequent(ArrValType st_val, ArrValType inc); /** * @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 mean value. * * @return mean value. */ //ArrValType mean() const; /** * @brief Return the standard deviation value. * * @return std value. */ //ArrValType std() 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 Normalize the array to the given module value * * @param norm targeting norm-value * @param n_type Norm-type */ //void normalize(ArrValType norm = 1.0, norm_type_e n_type = L2); /* template void array::random(ArrValType np1, ArrValType np2, random_type_e mode, unsigned int seed) { 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::sequent(ArrValType st_val, ArrValType inc) { for (size_t i = 0; i < length_; i++) { val_[i] = st_val + i*inc; } return; } template void array::scale(ArrValType in_val) { for (size_t i = 0; i < length_; i++) { val_[i] *= in_val; } return; } template ArrValType array::dot(const array &a) { if (length_ != a.size()) { throw std::runtime_error("Incompatible array sizes. gctl::array::dot(...)"); } ArrValType sum = 0; for (size_t i = 0; i < length_; i++) { sum += val_[i]*a[i]; } return sum; } template ArrValType array::mean() const { if (length_ == 0) throw std::invalid_argument("Invalid array size. gctl::array::mean(...)"); ArrValType m = 0; for (size_t i = 0; i < length_; i++) { m += val_[i]; } return m/length_; } template ArrValType array::std() const { if (length_ == 0) throw std::invalid_argument("Invalid array size. gctl::array::std(...)"); if (length_ == 1) return 0; ArrValType m = mean(), s = 0; for (size_t i = 0; i < length_; i++) { s += (val_[i] - m)*(val_[i] - m); } return sqrt(s/length_); } template ArrValType array::rms() const { if (length_ == 0) throw std::invalid_argument("Invalid array size. gctl::array::rms(...)"); ArrValType m = 0; for (size_t i = 0; i < length_; i++) { m += val_[i]*val_[i]; } return sqrt(m/length_); } template ArrValType array::max() const { if (length_ == 0) throw std::invalid_argument("Invalid array size. gctl::array::max(...)"); 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 { if (length_ == 0) throw std::invalid_argument("Invalid array size. gctl::array::min(...)"); ArrValType m = val_[0]; for (size_t i = 1; i < length_; i++) { m = std::min(val_[i], m); } return m; } template void array::normalize(ArrValType norm, norm_type_e n_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 (norm_sum <= GCTL_ZERO) { return; } for (size_t i = 0; i < length_; i++) { val_[i] = val_[i]*norm/norm_sum; } return; } */