gctl/lib/core/array.h
2025-02-24 12:09:53 +08:00

2034 lines
48 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/********************************************************
* ██████╗ ██████╗████████╗██╗
* ██╔════╝ ██╔════╝╚══██╔══╝██║
* ██║ ███╗██║ ██║ ██║
* ██║ ██║██║ ██║ ██║
* ╚██████╔╝╚██████╗ ██║ ███████╗
* ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝
* 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 <http://www.gnu.org/licenses/>.
*
* 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
#include <random>
#include <chrono>
// 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 <typename ArrValType> class array;
/*
* Here we define some commonly used array types.
*/
typedef array<int> _1i_array; ///< 1-D integer array
typedef array<float> _1f_array; ///< 1-D single-precision floating-point array
typedef array<double> _1d_array; ///< 1-D double-precision floating-point array
typedef array<std::string> _1s_array; ///< 1-D string array
typedef array<std::complex<float> > _1cf_array; ///< 1-D complex float array
typedef array<std::complex<double> > _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 <typename T>
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 <typename ArrValType>
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.
*/
explicit 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<double*> A(10, nullptr) means that the initial value of all
* elements is nullptr and array<double*> A((double**)B, 10) means that the element value of A is initialized
* with array B If the above expression is written as array<double*> 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<ArrValType> &b);
/**
* @brief Construct a new array object from std::initializer
*
* @param init_val Initial values
*/
explicit array(std::initializer_list<ArrValType> 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<ArrValType>& operator= (const array<ArrValType> &b);
/**
* @brief Overloaded assignment operator for the array template.
*
* @param v Initial value.
* @return Target array.
*/
array<ArrValType>& operator= (ArrValType v);
/**
* @brief Overloaded summation operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType> operator+ (const array<ArrValType> &b);
/**
* @brief Overloaded minus operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType> operator- (const array<ArrValType> &b);
/**
* @brief Overloaded multiple operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType> operator* (const array<ArrValType> &b);
/**
* @brief Overloaded division operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType> operator/ (const array<ArrValType> &b);
/**
* @brief Overloaded summation operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType>& operator+= (const array<ArrValType> &b);
/**
* @brief Overloaded summation operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType>& operator-= (const array<ArrValType> &b);
/**
* @brief Overloaded multiple operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType>& operator*= (const array<ArrValType> &b);
/**
* @brief Overloaded division operator for the array template.
*
* @param a Input array
* @param b Inpur array
* @return Target array
*/
array<ArrValType>& operator/= (const array<ArrValType> &b);
/**
* @brief Overloaded summation operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType> operator+ (const ArrValType &b);
/**
* @brief Overloaded minus operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType> operator- (const ArrValType &b);
/**
* @brief Overloaded multiple operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType> operator* (const ArrValType &b);
/**
* @brief Overloaded division operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType> operator/ (const ArrValType &b);
/**
* @brief Overloaded summation operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*
*/
array<ArrValType>& operator+= (const ArrValType &b);
/**
* @brief Overloaded summation operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType>& operator-= (const ArrValType &b);
/**
* @brief Overloaded multiple operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType>& operator*= (const ArrValType &b);
/**
* @brief Overloaded division operator for the array template.
*
* @param a Input array
* @param b Scale value
* @return Target array
*/
array<ArrValType>& operator/= (const ArrValType &b);
/**
* @brief Compare two arraies.
*
* @return True if the two arraies are equal, false otherwise.
*/
bool operator== (const array<ArrValType> &b) const;
/**
* @brief Compare two arraies.
*
* @return True if the two arraies are not equal, false otherwise.
*/
bool operator!= (const array<ArrValType> &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<ArrValType> &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<ArrValType> &b);
/**
* @brief Resize a new array object from std::initializer
*
* @param init_val Initial values
*/
void resize(std::initializer_list<ArrValType> 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<ArrValType> &b);
/**
* @brief Extract an array
*
* @param b Output array. Must be initialized before use.
* @param st Start index
*/
void slice(array<ArrValType> &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<ArrValType> &b, const array<size_t> &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<ArrValType> &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<ArrValType> begin();
/**
* @brief Return the ending of the iterator
*
* @return iterator
*/
iterator<ArrValType> 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<ArrValType> &b) const;
/**
* @brief Copy the array from a vector.
*
* @param b Target vector.
*/
void input(const std::vector<ArrValType> &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 并行执行指定操作
*
* 对数组中的每个元素并行执行指定的操作,参数为数组元素的引用。
* 例如:[](ArrValType &a){do something here...}
*
* @tparam UnaryOp 一元操作类型 参数为数组元素的引用
* @param op 要执行的操作
*/
template <typename UnaryOp>
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 <typename OutType, typename UnaryOp>
array<OutType> extract(UnaryOp op)
{
array<OutType> 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<size_t>::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<ArrValType> &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) const;
/**
* @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<ArrValType> &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 <typename ArrValType>
array<ArrValType>::array()
{
length_ = 0;
val_ = nullptr;
}
template <typename ArrValType>
array<ArrValType>::array(size_t len)
{
length_ = 0;
val_ = nullptr;
resize(len);
}
template <typename ArrValType>
array<ArrValType>::array(size_t len, ArrValType init_val)
{
length_ = 0;
val_ = nullptr;
resize(len, init_val);
}
template <typename ArrValType>
array<ArrValType>::array(ArrValType *init_array, size_t len)
{
length_ = 0;
val_ = nullptr;
resize(init_array, len);
}
template <typename ArrValType>
array<ArrValType>::array(const array<ArrValType> &b)
{
length_ = 0;
val_ = nullptr;
resize(b);
}
template <typename ArrValType>
array<ArrValType>::array(std::initializer_list<ArrValType> init_val)
{
length_ = 0;
val_ = nullptr;
resize(init_val);
}
template <typename ArrValType>
array<ArrValType>::array(size_t s, ArrValType st, ArrValType inc)
{
length_ = 0;
val_ = nullptr;
resize(s, st, inc);
}
template <typename ArrValType>
array<ArrValType> &array<ArrValType>::operator= (const array<ArrValType> &b)
{
resize(b.size());
for (size_t i = 0; i < length_; i++)
{
val_[i] = b[i];
}
return *this;
}
template <typename ArrValType>
array<ArrValType> &array<ArrValType>::operator= (ArrValType v)
{
for (size_t i = 0; i < length_; i++)
{
val_[i] = v;
}
return *this;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator+ (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator+] Incompatible array sizes.");
}
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = val_[i] + b[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator- (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator-] Incompatible array sizes.");
}
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = val_[i] - b[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator* (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator*] Incompatible array sizes.");
}
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = val_[i] * b[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator/ (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator/] Incompatible array sizes.");
}
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = val_[i] / b[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator+= (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator+=] Incompatible array sizes.");
}
for (size_t i = 0; i < length_; i++)
{
val_[i] += b[i];
}
return *this;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator-= (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator-=] Incompatible array sizes.");
}
for (size_t i = 0; i < length_; i++)
{
val_[i] -= b[i];
}
return *this;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator*= (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator*=] Incompatible array sizes.");
}
for (size_t i = 0; i < length_; i++)
{
val_[i] *= b[i];
}
return *this;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator/= (const array<ArrValType> &b)
{
if (b.size() != length_)
{
throw std::runtime_error("[gctl::array<T>::operator/=] Incompatible array sizes.");
}
for (size_t i = 0; i < length_; i++)
{
val_[i] /= b[i];
}
return *this;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator+ (const ArrValType &b)
{
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = val_[i] + b;
}
return out;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator- (const ArrValType &b)
{
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = b - val_[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator* (const ArrValType &b)
{
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = b*val_[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType> array<ArrValType>::operator/ (const ArrValType &b)
{
array<ArrValType> out(length_);
for (size_t i = 0; i < length_; i++)
{
out[i] = b/val_[i];
}
return out;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator+= (const ArrValType &b)
{
for (size_t i = 0; i < length_; i++)
{
val_[i] += b;
}
return *this;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator-= (const ArrValType &b)
{
for (size_t i = 0; i < length_; i++)
{
val_[i] -= b;
}
return *this;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator*= (const ArrValType &b)
{
for (size_t i = 0; i < length_; i++)
{
val_[i] *= b;
}
return *this;
}
template <typename ArrValType>
array<ArrValType>& array<ArrValType>::operator/= (const ArrValType &b)
{
for (size_t i = 0; i < length_; i++)
{
val_[i] /= b;
}
return *this;
}
template <typename ArrValType>
bool array<ArrValType>::operator== (const array<ArrValType> &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 <typename ArrValType>
bool array<ArrValType>::operator!= (const array<ArrValType> &b) const
{
return !(*this == b);
}
template <typename ArrValType>
bool array<ArrValType>::equals(const array<ArrValType> &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 <typename ArrValType>
array<ArrValType>::~array()
{
clear();
}
template <typename ArrValType>
void array<ArrValType>::resize(size_t len)
{
if (len == 0)
{
throw std::invalid_argument("[gctl::array<T>::resize] Invalid array size.");
}
if (length_ != len)
{
clear();
length_ = len;
val_ = new ArrValType[len];
}
return;
}
template <typename ArrValType>
void array<ArrValType>::resize(size_t len, ArrValType init_val)
{
resize(len);
for (size_t i = 0; i < length_; i++)
{
val_[i] = init_val;
}
return;
}
template <typename ArrValType>
void array<ArrValType>::resize(ArrValType *init_array, size_t len)
{
if (init_array == nullptr)
{
throw std::domain_error("[gctl::array<T>::resize] Invalid pointer.");
}
resize(len);
for (size_t i = 0; i < length_; i++)
{
val_[i] = init_array[i];
}
return;
}
template <typename ArrValType>
void array<ArrValType>::resize(const array<ArrValType> &b)
{
if (!b.empty())
{
resize(b.size());
for (size_t i = 0; i < length_; i++)
{
val_[i] = b[i];
}
}
return;
}
template <typename ArrValType>
void array<ArrValType>::resize(std::initializer_list<ArrValType> init_val)
{
resize(init_val.size());
typename std::initializer_list<ArrValType>::iterator iter = init_val.begin();
for (size_t i = 0; i < length_; i++)
{
val_[i] = *iter;
iter++;
}
return;
}
template <typename ArrValType>
void array<ArrValType>::resize(size_t s, ArrValType st, ArrValType inc)
{
resize(s);
sequence(st, inc);
return;
}
template <typename ArrValType>
void array<ArrValType>::clear()
{
if (val_ != nullptr)
{
delete[] val_;
val_ = nullptr;
length_ = 0;
}
return;
}
template <typename ArrValType>
void array<ArrValType>::assign(ArrValType in_val)
{
for (size_t i = 0; i < length_; i++)
{
val_[i] = in_val;
}
return;
}
template <typename ArrValType>
void array<ArrValType>::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<T>::assign] Invalid segment range.");
return;
}
template <typename ArrValType>
void array<ArrValType>::concat(const array<ArrValType> &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 <typename ArrValType>
void array<ArrValType>::slice(array<ArrValType> &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 <typename ArrValType>
void array<ArrValType>::slice(array<ArrValType> &b, const array<size_t> &ids) const
{
b.resize(ids.size());
for (size_t i = 0; i < ids.size(); i++)
{
b[i] = val_[ids[i]];
}
return;
}
template <typename ArrValType>
void array<ArrValType>::insert(array<ArrValType> &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 <typename ArrValType>
ArrValType *array<ArrValType>::get(size_t index) const
{
if (index >= length_)
throw std::out_of_range("[gctl::array<T>::at] Invalid index.");
return &val_[index];
}
template <typename ArrValType>
ArrValType &array<ArrValType>::at(size_t index)
{
if (index >= length_)
throw std::out_of_range("[gctl::array<T>::at] Invalid index.");
return val_[index];
}
template <typename ArrValType>
ArrValType &array<ArrValType>::at(size_t index) const
{
if (index >= length_)
throw std::out_of_range("[gctl::array<T>::at] Invalid index.");
return val_[index];
}
template <typename ArrValType>
ArrValType &array<ArrValType>::operator[](size_t index) noexcept
{
return val_[index];
}
template <typename ArrValType>
ArrValType &array<ArrValType>::operator[](size_t index) const noexcept
{
return val_[index];
}
template <typename ArrValType>
ArrValType array<ArrValType>::front() const
{
return val_[0];
}
template <typename ArrValType>
ArrValType array<ArrValType>::back() const
{
return val_[length_-1];
}
template <typename ArrValType>
iterator<ArrValType> array<ArrValType>::begin()
{
return iterator<ArrValType>(this->val_, 0);
}
template <typename ArrValType>
iterator<ArrValType> array<ArrValType>::end()
{
return iterator<ArrValType>(this->val_, length_);
}
template <typename ArrValType>
bool array<ArrValType>::empty() const noexcept
{
if (length_ == 0) return true;
else return false;
}
template <typename ArrValType>
size_t array<ArrValType>::size() const noexcept
{
return length_;
}
template <typename ArrValType>
void array<ArrValType>::output(std::vector<ArrValType> &b) const
{
if (!b.empty())
{
b.clear();
}
b.resize(length_);
for (size_t i = 0; i < length_; i++)
{
b[i] = val_[i];
}
return;
}
template <typename ArrValType>
void array<ArrValType>::input(const std::vector<ArrValType> &b)
{
resize(b.size());
for (size_t i = 0; i < length_; i++)
{
val_[i] = b[i];
}
return;
}
#ifdef GCTL_EIGEN
template <typename ArrValType>
void array<ArrValType>::output(Eigen::VectorXd &b) const
{
b.resize(length_);
for (size_t i = 0; i < length_; i++)
{
b[i] = val_[i];
}
return;
}
template <typename ArrValType>
void array<ArrValType>::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 <typename ArrValType>
void array<ArrValType>::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 <typename VecValType>
std::ostream &operator <<(std::ostream &os, const array<VecValType> &a)
{
if (!a.empty())
{
os << a[0];
for (size_t i = 1; i < a.size(); i++)
{
os << " " << a[i];
}
}
return os;
}
template <typename VecValType>
std::istream &operator >>(std::istream &os, array<VecValType> &a)
{
for (size_t i = 0; i < a.size(); i++)
{
os >> a[i];
}
return os;
}
template <typename ArrValType>
void array<ArrValType>::random_float(ArrValType np1, ArrValType np2,
random_type_e mode, unsigned int seed)
{
static_assert(std::is_floating_point<ArrValType>::value,
"gctl::array<T>::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<ArrValType> dist(np1, np2);
for (size_t i = 0; i < length_; i++)
{
val_[i] = dist(generator);
}
return;
}
//添加均匀分布的随机值
std::uniform_real_distribution<ArrValType> dist(np1, np2);
for (size_t i = 0; i < length_; i++)
{
val_[i] = dist(generator);
}
return;
}
template <typename ArrValType>
void array<ArrValType>::random_int(ArrValType np1, ArrValType np2, unsigned int seed)
{
static_assert(std::is_integral<ArrValType>::value,
"gctl::array<T>::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<ArrValType> dist(np1, np2);
for (size_t i = 0; i < length_; i++)
{
val_[i] = dist(generator);
}
return;
}
template <typename ArrValType>
void array<ArrValType>::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<T>::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 <typename ArrValType>
void array<ArrValType>::sequence2d(ArrValType rs, ArrValType rinc,
ArrValType cs, ArrValType cinc, size_t rn, size_t cn)
{
if (rn*cn != length_)
{
throw std::invalid_argument("[gctl::array<T>::sequence2d] Invalid sequence sizes.");
}
array<ArrValType> 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 <typename ArrValType>
void array<ArrValType>::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 std::invalid_argument("[gctl::array<T>::sequence3d] Invalid sequence sizes.");
}
array<ArrValType> 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 <typename ArrValType>
void array<ArrValType>::scale(ArrValType in_val)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
ArrValType array<ArrValType>::dot(const array<ArrValType> &a)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::dot(...) could only be used with an arithmetic type.");
if (length_ != a.size())
{
throw std::runtime_error("Incompatible array sizes. gctl::array<T>::dot(...)");
}
ArrValType s = (ArrValType) 0;
for (size_t i = 0; i < length_; i++)
{
s += val_[i]*a[i];
}
return s;
}
template <typename ArrValType>
ArrValType array<ArrValType>::sum() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
ArrValType array<ArrValType>::mean() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::mean(...) could only be used with an arithmetic type.");
if (length_ == 0) return ArrValType{};
return sum()/static_cast<ArrValType>(length_);
}
template <typename ArrValType>
ArrValType array<ArrValType>::variance() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::variance(...) could only be used with an arithmetic type.");
if (length_ == 0 || val_ == nullptr) return ArrValType{};
ArrValType m = mean();
ArrValType d = ArrValType(0);
for (size_t i = 0; i < length_; i++)
{
d += (val_[i] - m)*(val_[i] - m);
}
return d/static_cast<ArrValType>(length_);
}
template <typename ArrValType>
ArrValType array<ArrValType>::std() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::std(...) could only be used with an arithmetic type.");
if (length_ == 0 || val_ == nullptr) return ArrValType{};
ArrValType m = mean(), s = ArrValType(0);
for (size_t i = 0; i < length_; i++)
{
s += (val_[i] - m)*(val_[i] - m);
}
return sqrt(s/static_cast<ArrValType>(length_));
}
template <typename ArrValType>
ArrValType array<ArrValType>::rms() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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<ArrValType>(length_));
}
template <typename ArrValType>
ArrValType array<ArrValType>::max() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
ArrValType array<ArrValType>::min() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
ArrValType array<ArrValType>::module(norm_type_e n_type) const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
ArrValType array<ArrValType>::normalize(ArrValType norm, norm_type_e n_type)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
void array<ArrValType>::orth(array<ArrValType> &b)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::orth(...) could only be used with an arithmetic type.");
if (length_ != b.size())
{
throw std::runtime_error("[gctl::array<T>::orth] Incompatible array size.");
}
ArrValType product = dot(b);
for (int i = 0; i < length_; i++)
{
b[i] = b[i] - product*val_[i];
}
return;
}
template <typename ArrValType>
void array<ArrValType>::log2linear(const ArrValType &base)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 <typename ArrValType>
void array<ArrValType>::linear2log(ArrValType base)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::linear2log(...) could only be used with an arithmetic type.");
if (length_ == 0 || val_ == nullptr) return;
for (size_t i = 0; i < length_; i++)
{
if (val_[i] <= ArrValType(0)) continue; // 跳过非正值
val_[i] = std::log(val_[i])/std::log(base);
}
}
template <typename ArrValType>
ArrValType array<ArrValType>::std_unbiased() const
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::std_unbiased(...) could only be used with an arithmetic type.");
if (length_ < 2) return 0;
ArrValType mn = mean();
ArrValType d = (ArrValType) 0;
for (size_t i = 0; i < length_; i++)
{
d = d + (val_[i] - mn)*(val_[i] - mn);
}
return sqrt(d/(length_ - 1));
}
template <typename ArrValType>
void array<ArrValType>::set2range(ArrValType min, ArrValType max, range_type_e rt)
{
static_assert(std::is_arithmetic<ArrValType>::value,
"gctl::array<T>::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 = amin<val_[i]?amin:val_[i];
amax = amax>val_[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<max?amax:max;
for (size_t i = 0; i < length_; i++)
{
val_[i] = (max2 - min2)*(val_[i] - amin)/(amax - amin) + min2;
}
return;
}
template <typename ArrValType>
bool array<ArrValType>::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 <typename ArrValType>
bool array<ArrValType>::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 <typename ArrValType>
size_t array<ArrValType>::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 <typename ArrValType>
void array<ArrValType>::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