From e65322d3664f5a80f2cf2ca5ae60a93695eb5424 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 2 Jul 2018 22:10:38 -0500 Subject: [PATCH 01/30] Convert univariate probability distributions --- CMakeLists.txt | 1 + src/constants.h | 5 ++ src/distribution.cpp | 137 +++++++++++++++++++++++++++++++++++++++++++ src/distribution.h | 78 ++++++++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 src/distribution.cpp create mode 100644 src/distribution.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c94f4df5fd..10484f161e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -384,6 +384,7 @@ add_library(libopenmc SHARED src/tallies/trigger.F90 src/tallies/trigger_header.F90 src/cell.cpp + src/distribution.cpp src/initialize.cpp src/finalize.cpp src/geometry_aux.cpp diff --git a/src/constants.h b/src/constants.h index 016a6b3484..24a23196c9 100644 --- a/src/constants.h +++ b/src/constants.h @@ -86,6 +86,11 @@ extern "C" double FP_PRECISION; constexpr double INFTY {std::numeric_limits::max()}; constexpr int C_NONE {-1}; +// Interpolation rules +enum class Interpolation { + histogram, lin_lin, lin_log, log_lin, log_log +}; + } // namespace openmc #endif // CONSTANTS_H diff --git a/src/distribution.cpp b/src/distribution.cpp new file mode 100644 index 0000000000..323a03de50 --- /dev/null +++ b/src/distribution.cpp @@ -0,0 +1,137 @@ +#include "distribution.h" + +#include +#include +#include + +#include "error.h" +#include "math_functions.h" +#include "random_lcg.h" + +namespace openmc { + +Discrete::Discrete(const double* x, const double* p, int n) + : x_{x, x+n}, p_{p, p+n} +{ + // Renormalize density function so that it sums to unity + double norm = std::accumulate(p_.begin(), p_.end(), 0.0); + for (auto& p_i : p_) + p_i /= norm; +} + + +double Discrete::sample() +{ + int n = x_.size(); + if (n > 1) { + double xi = prn(); + double c = 0.0; + for (int i = 0; i < n; ++i) { + c += p_[i]; + if (xi < c) return x_[i]; + } + // throw exception? + } else { + return x_[0]; + } +} + + +double Uniform::sample() +{ + return a_ + prn()*(b_ - a_); +} + + +double Maxwell::sample() +{ + return maxwell_spectrum_c(theta_); +} + + +double Watt::sample() +{ + return watt_spectrum_c(a_, b_); +} + + +Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) + : x_{x, x+n}, p_{p, p+n}, interp_{interp}, c_(n, 0.0) +{ + // Check interpolation parameter + if (interp_ != Interpolation::histogram && + interp_ != Interpolation::lin_lin) { + openmc::fatal_error("Only histogram and linear-linear interpolation " + "for tabular distribution is supported."); + } + + // Calculate cumulative distribution function + for (int i = 1; i < n; ++i) { + if (interp_ == Interpolation::histogram) { + c_[i] = c_[i-1] + p_[i-1]*(x_[i] - x_[i-1]); + } else if (interp_ == Interpolation::lin_lin) { + c_[i] = c_[i-1] + 0.5*(p_[i-1] + p_[i]) * (x_[i] - x_[i-1]); + } + } + + // Normalize density and distribution functions + for (int i = 0; i < n; ++i) { + p_[i] = p_[i]/c_[n-1]; + c_[i] = c_[i]/c_[n-1]; + } +} + + +double Tabular::sample() +{ + // Sample value of CDF + double c = prn(); + + // Find first CDF bin which is above the sampled value + double c_i = c_[0]; + int i; + size_t n = c_.size(); + for (i = 0; i < n - 1; ++i) { + if (c <= c_[i+1]) break; + c_i = c_[i+1]; + } + + // Determine bounding PDF values + double x_i = x_[i]; + double p_i = p_[i]; + + if (interp_ == Interpolation::histogram) { + // Histogram interpolation + if (p_i > 0.0) { + return x_i + (c - c_i)/p_i; + } else { + return x_i; + } + } else { + // Linear-linear interpolation + double x_i1 = x_[i + 1]; + double p_i1 = p_[i + 1]; + + double m = (p_i1 - p_i)/(x_i1 - x_i); + if (m == 0.0) { + return x_i + (c - c_i)/p_i; + } else { + return x_i + (std::sqrt(std::max(0.0, p_i*p_i + 2*m*(c - c_i))) - p_i)/m; + } + } +} + + +double Equiprobable::sample() +{ + size_t n = x_.size(); + + double r = prn(); + int i = std::floor((n - 1)*r); + + double xl = x_[i]; + double xr = x_[i+i]; + return xl + ((n - 1)*r - i) * (xr - xl); +} + +} // namespace openmc diff --git a/src/distribution.h b/src/distribution.h new file mode 100644 index 0000000000..675acf9761 --- /dev/null +++ b/src/distribution.h @@ -0,0 +1,78 @@ +#ifndef DISTRIBUTION_H +#define DISTRIBUTION_H + +#include + +#include "constants.h" + +namespace openmc { + +class Distribution { +public: + virtual double sample() = 0; + virtual ~Distribution() = default; +}; + + +class Discrete : public Distribution { +public: + Discrete(const double* x, const double* p, int n); + double sample(); +private: + std::vector x_; + std::vector p_; +}; + + +class Uniform : public Distribution { +public: + Uniform(double a, double b) : a_{a}, b_{b} {}; + double sample(); +private: + double a_; + double b_; +}; + + +class Maxwell : public Distribution { +public: + Maxwell(double theta) : theta_{theta} { }; + double sample(); +private: + double theta_; +}; + + +class Watt : public Distribution { +public: + Watt(double a, double b) : a_{a}, b_{b} { }; + double sample(); +private: + double a_; + double b_; +}; + + +class Tabular : public Distribution { +public: + Tabular(const double* x, const double* p, int n, Interpolation interp); + double sample(); +private: + std::vector x_; + std::vector p_; + std::vector c_; + Interpolation interp_; +}; + + +class Equiprobable : public Distribution { +public: + Equiprobable(const double* x, int n) : x_{x, x+n} { }; + double sample(); +private: + std::vector x_; +}; + +} // namespace openmc + +#endif // DISTRIBUTION_H From f8e035d12da289e4820a995f0573b34d3bf167c3 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 5 Jul 2018 07:01:19 -0500 Subject: [PATCH 02/30] Convert multivariate probability distributions --- CMakeLists.txt | 2 + src/distribution.cpp | 177 ++++++++++++++++++++++++++++++----- src/distribution.h | 84 ++++++++++++++--- src/distribution_multi.cpp | 51 ++++++++++ src/distribution_multi.h | 73 +++++++++++++++ src/distribution_spatial.cpp | 97 +++++++++++++++++++ src/distribution_spatial.h | 69 ++++++++++++++ src/math_functions.cpp | 8 ++ src/math_functions.h | 9 +- src/xml_interface.cpp | 12 ++- src/xml_interface.h | 18 ++++ 11 files changed, 557 insertions(+), 43 deletions(-) create mode 100644 src/distribution_multi.cpp create mode 100644 src/distribution_multi.h create mode 100644 src/distribution_spatial.cpp create mode 100644 src/distribution_spatial.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 10484f161e..24b0bef569 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -385,6 +385,8 @@ add_library(libopenmc SHARED src/tallies/trigger_header.F90 src/cell.cpp src/distribution.cpp + src/distribution_multi.cpp + src/distribution_spatial.cpp src/initialize.cpp src/finalize.cpp src/geometry_aux.cpp diff --git a/src/distribution.cpp b/src/distribution.cpp index 323a03de50..01255f2d75 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -1,26 +1,40 @@ #include "distribution.h" -#include -#include -#include +#include // for copy +#include // for sqrt, floor, max +#include // for back_inserter +#include // for accumulate +#include // for string, stod #include "error.h" #include "math_functions.h" #include "random_lcg.h" +#include "xml_interface.h" namespace openmc { +//============================================================================== +// Discrete implementation +//============================================================================== + +Discrete::Discrete(pugi::xml_node node) +{ + auto params = get_node_array(node, "parameters"); + + std::size_t n = params.size(); + std::copy(params.begin(), params.begin() + n/2, std::back_inserter(x_)); + std::copy(params.begin() + n/2, params.end(), std::back_inserter(p_)); + + normalize(); +} + Discrete::Discrete(const double* x, const double* p, int n) : x_{x, x+n}, p_{p, p+n} { - // Renormalize density function so that it sums to unity - double norm = std::accumulate(p_.begin(), p_.end(), 0.0); - for (auto& p_i : p_) - p_i /= norm; + normalize(); } - -double Discrete::sample() +double Discrete::sample() const { int n = x_.size(); if (n > 1) { @@ -36,28 +50,107 @@ double Discrete::sample() } } +void Discrete::normalize() +{ + // Renormalize density function so that it sums to unity + double norm = std::accumulate(p_.begin(), p_.end(), 0.0); + for (auto& p_i : p_) + p_i /= norm; +} -double Uniform::sample() +//============================================================================== +// Uniform implementation +//============================================================================== + +Uniform::Uniform(pugi::xml_node node) +{ + auto params = get_node_array(node, "parameters"); + if (params.size() != 2) + openmc::fatal_error("Uniform distribution must have two " + "parameters specified."); + + a_ = params.at(0); + b_ = params.at(1); +} + +double Uniform::sample() const { return a_ + prn()*(b_ - a_); } +//============================================================================== +// Maxwell implementation +//============================================================================== -double Maxwell::sample() +Maxwell::Maxwell(pugi::xml_node node) +{ + theta_ = std::stod(get_node_value(node, "parameters")); +} + +double Maxwell::sample() const { return maxwell_spectrum_c(theta_); } +//============================================================================== +// Watt implementation +//============================================================================== -double Watt::sample() +Watt::Watt(pugi::xml_node node) +{ + auto params = get_node_array(node, "parameters"); + if (params.size() != 2) + openmc::fatal_error("Watt energy distribution must have two " + "parameters specified."); + + a_ = params.at(0); + b_ = params.at(1); +} + +double Watt::sample() const { return watt_spectrum_c(a_, b_); } +//============================================================================== +// Tabular implementation +//============================================================================== -Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) - : x_{x, x+n}, p_{p, p+n}, interp_{interp}, c_(n, 0.0) +Tabular::Tabular(pugi::xml_node node) { + if (check_for_node(node, "interpolation")) { + std::string temp = get_node_value(node, "interpolation"); + if (temp == "histogram") { + interp_ = Interpolation::histogram; + } else if (temp == "linear-linear") { + interp_ = Interpolation::lin_lin; + } else { + openmc::fatal_error("Unknown interpolation type for distribution: " + temp); + } + } else { + interp_ = Interpolation::histogram; + } + + // Read and initialize tabular distribution + auto params = get_node_array(node, "parameters"); + std::size_t n = params.size() / 2; + const double* x = params.data(); + const double* p = x + n; + init(x, p, n); +} + +Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp, const double* c) + : interp_{interp} +{ + init(x, p, n, c); +} + +void Tabular::init(const double* x, const double* p, std::size_t n, const double* c) +{ + // Copy x/p arrays into vectors + std::copy(x, x + n, std::back_inserter(x_)); + std::copy(p, p + n, std::back_inserter(p_)); + // Check interpolation parameter if (interp_ != Interpolation::histogram && interp_ != Interpolation::lin_lin) { @@ -66,11 +159,17 @@ Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) } // Calculate cumulative distribution function - for (int i = 1; i < n; ++i) { - if (interp_ == Interpolation::histogram) { - c_[i] = c_[i-1] + p_[i-1]*(x_[i] - x_[i-1]); - } else if (interp_ == Interpolation::lin_lin) { - c_[i] = c_[i-1] + 0.5*(p_[i-1] + p_[i]) * (x_[i] - x_[i-1]); + if (c) { + std::copy(c, c + n, std::back_inserter(c_)); + } else { + c_.resize(n); + c_[0] = 0.0; + for (int i = 1; i < n; ++i) { + if (interp_ == Interpolation::histogram) { + c_[i] = c_[i-1] + p_[i-1]*(x_[i] - x_[i-1]); + } else if (interp_ == Interpolation::lin_lin) { + c_[i] = c_[i-1] + 0.5*(p_[i-1] + p_[i]) * (x_[i] - x_[i-1]); + } } } @@ -81,8 +180,7 @@ Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp) } } - -double Tabular::sample() +double Tabular::sample() const { // Sample value of CDF double c = prn(); @@ -90,7 +188,7 @@ double Tabular::sample() // Find first CDF bin which is above the sampled value double c_i = c_[0]; int i; - size_t n = c_.size(); + std::size_t n = c_.size(); for (i = 0; i < n - 1; ++i) { if (c <= c_[i+1]) break; c_i = c_[i+1]; @@ -121,10 +219,13 @@ double Tabular::sample() } } +//============================================================================== +// Equiprobable implementation +//============================================================================== -double Equiprobable::sample() +double Equiprobable::sample() const { - size_t n = x_.size(); + std::size_t n = x_.size(); double r = prn(); int i = std::floor((n - 1)*r); @@ -134,4 +235,32 @@ double Equiprobable::sample() return xl + ((n - 1)*r - i) * (xr - xl); } +//============================================================================== +// Helper function +//============================================================================== + +UPtrDist distribution_from_xml(pugi::xml_node node) +{ + if (!check_for_node(node, "type")) + openmc::fatal_error("Distribution type must be specified."); + + // Determine type of distribution + std::string type = get_node_value(node, "type"); + + // Allocate extension of Distribution + if (type == "uniform") { + return UPtrDist{new Uniform(node)}; + } else if (type == "maxwell") { + return UPtrDist{new Maxwell(node)}; + } else if (type == "watt") { + return UPtrDist{new Watt(node)}; + } else if (type == "discrete") { + return UPtrDist{new Discrete(node)}; + } else if (type == "tabular") { + return UPtrDist{new Tabular(node)}; + } else { + openmc::fatal_error("Invalid distribution type: " + type); + } +} + } // namespace openmc diff --git a/src/distribution.h b/src/distribution.h index 675acf9761..705db53dab 100644 --- a/src/distribution.h +++ b/src/distribution.h @@ -1,78 +1,136 @@ #ifndef DISTRIBUTION_H #define DISTRIBUTION_H -#include +#include // for size_t +#include // for unique_ptr +#include // for vector #include "constants.h" +#include "pugixml.hpp" namespace openmc { +//============================================================================== +//! Abstract class representing a univariate probability distribution +//============================================================================== + class Distribution { public: - virtual double sample() = 0; + virtual double sample() const = 0; virtual ~Distribution() = default; }; +//============================================================================== +//! A discrete distribution (probability mass function) +//============================================================================== class Discrete : public Distribution { public: + explicit Discrete(pugi::xml_node node); Discrete(const double* x, const double* p, int n); - double sample(); + + //! Sample a value from the distribution + double sample() const; private: std::vector x_; std::vector p_; + + void normalize(); }; +//============================================================================== +//! Uniform distribution over the interval [a,b] +//============================================================================== class Uniform : public Distribution { public: + explicit Uniform(pugi::xml_node node); Uniform(double a, double b) : a_{a}, b_{b} {}; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: double a_; double b_; }; +//============================================================================== +//! Maxwellian distribution of form c*E*exp(-E/a) +//============================================================================== class Maxwell : public Distribution { public: + explicit Maxwell(pugi::xml_node node); Maxwell(double theta) : theta_{theta} { }; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: double theta_; }; +//============================================================================== +//! Watt fission spectrum with form c*exp(-E/a)*sinh(sqrt(b*E)) +//============================================================================== class Watt : public Distribution { public: + explicit Watt(pugi::xml_node node); Watt(double a, double b) : a_{a}, b_{b} { }; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: double a_; double b_; }; +//============================================================================== +//! Histogram or linear-linear interpolated tabular distribution +//============================================================================== class Tabular : public Distribution { public: - Tabular(const double* x, const double* p, int n, Interpolation interp); - double sample(); + explicit Tabular(pugi::xml_node node); + Tabular(const double* x, const double* p, int n, Interpolation interp, + const double* c=nullptr); + + //! Sample a value from the distribution + double sample() const; private: - std::vector x_; - std::vector p_; - std::vector c_; - Interpolation interp_; + std::vector x_; //!< tabulated independent variable + std::vector p_; //!< tabulated probability density + std::vector c_; //!< cumulative distribution at tabulated values + Interpolation interp_; //!< interpolation rule + + //! Initialize tabulated probability density function + //! @param x Array of values for independent variable + //! @param p Array of tabulated probabilities + //! @param n Number of tabulated values + void init(const double* x, const double* p, std::size_t n, + const double* c=nullptr); }; +//============================================================================== +//! +//============================================================================== class Equiprobable : public Distribution { public: + explicit Equiprobable(pugi::xml_node node); Equiprobable(const double* x, int n) : x_{x, x+n} { }; - double sample(); + + //! Sample a value from the distribution + double sample() const; private: std::vector x_; }; + +using UPtrDist = std::unique_ptr; + +UPtrDist distribution_from_xml(pugi::xml_node node); + } // namespace openmc #endif // DISTRIBUTION_H diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp new file mode 100644 index 0000000000..36184f7527 --- /dev/null +++ b/src/distribution_multi.cpp @@ -0,0 +1,51 @@ +#include "distribution_multi.h" + +#include // for move +#include // for sqrt, sin, cos, max + +#include "constants.h" +#include "math_functions.h" +#include "random_lcg.h" + +namespace openmc { + +//============================================================================== +// PolarAzimuthal implementation +//============================================================================== + +PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) : + UnitSphereDistribution{u}, mu_{std::move(mu)}, phi_{std::move(phi)} { } + +Direction PolarAzimuthal::sample() const +{ + // Sample cosine of polar angle + double mu = mu_->sample(); + if (mu == 1.0) return u_ref; + + // Sample azimuthal angle + double phi = phi_->sample(); + return rotate_angle(u_ref, mu, &phi); +} + +//============================================================================== +// Isotropic implementation +//============================================================================== + +Direction Isotropic::sample() const +{ + double phi = 2.0*PI*prn(); + double mu = 2.0*prn() - 1.0; + return {mu, std::sqrt(1.0 - mu*mu) * std::cos(phi), + std::sqrt(1.0 - mu*mu) * std::sin(phi)}; +} + +//============================================================================== +// Monodirectional implementation +//============================================================================== + +Direction Monodirectional::sample() const +{ + return u_ref; +} + +} // namespace openmc diff --git a/src/distribution_multi.h b/src/distribution_multi.h new file mode 100644 index 0000000000..2d4dab42c1 --- /dev/null +++ b/src/distribution_multi.h @@ -0,0 +1,73 @@ +#ifndef DISTRIBUTION_MULTI_H +#define DISTRIBUTION_MULTI_H + +#include + +#include "distribution.h" +#include "position.h" + +namespace openmc { + +//============================================================================== +//! Probability density function for points on the unit sphere. Extensions of +//! this type are used to sample angular distributions for starting sources +//============================================================================== + +class UnitSphereDistribution { +public: + UnitSphereDistribution() { }; + explicit UnitSphereDistribution(Direction u) : u_ref{u} { }; + virtual ~UnitSphereDistribution() = default; + + //! Sample a direction from the distribution + //! \return Direction sampled + virtual Direction sample() const = 0; + + Direction u_ref {0.0, 0.0, 1.0}; //!< reference direction +}; + +//============================================================================== +//! Explicit distribution of polar and azimuthal angles +//============================================================================== + +class PolarAzimuthal : public UnitSphereDistribution { +public: + PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi); + + //! Sample a direction from the distribution + //! \return Direction sampled + Direction sample() const; +private: + UPtrDist mu_; //!< Distribution of polar angle + UPtrDist phi_; //!< Distribution of azimuthal angle +}; + +//============================================================================== +//! Uniform distribution on the unit sphere +//============================================================================== + +class Isotropic : public UnitSphereDistribution { +public: + Isotropic() { }; + + //! Sample a direction from the distribution + //! \return Sampled direction + Direction sample() const; +}; + +//============================================================================== +//! Monodirectional distribution +//============================================================================== + +class Monodirectional : public UnitSphereDistribution { +public: + Monodirectional(Direction u) : UnitSphereDistribution{u} { }; + + //! Sample a direction from the distribution + //! \return Sampled direction + Direction sample() const; +}; + +} // namespace openmc + +#endif // DISTRIBUTION_MULTI_H diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp new file mode 100644 index 0000000000..d870a5f93a --- /dev/null +++ b/src/distribution_spatial.cpp @@ -0,0 +1,97 @@ +#include "distribution_spatial.h" + +#include "error.h" +#include "random_lcg.h" +#include "xml_interface.h" + +namespace openmc { + +//============================================================================== +// CartesianIndependent implementation +//============================================================================== + +CartesianIndependent::CartesianIndependent(pugi::xml_node node) +{ + // Read distribution for x coordinate + if (check_for_node(node, "x")) { + pugi::xml_node node_dist = node.child("x"); + x_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at x=0 + double x[] {0.0}; + double p[] {1.0}; + x_ = UPtrDist{new Discrete{x, p, 1}}; + } + + // Read distribution for y coordinate + if (check_for_node(node, "y")) { + pugi::xml_node node_dist = node.child("y"); + y_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at y=0 + double x[] {0.0}; + double p[] {1.0}; + y_ = UPtrDist{new Discrete{x, p, 1}}; + } + + // Read distribution for z coordinate + if (check_for_node(node, "z")) { + pugi::xml_node node_dist = node.child("z"); + z_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at z=0 + double x[] {0.0}; + double p[] {1.0}; + z_ = UPtrDist{new Discrete{x, p, 1}}; + } +} + +Position CartesianIndependent::sample() const +{ + return {x_->sample(), y_->sample(), z_->sample()}; +} + +//============================================================================== +// SpatialBox implementation +//============================================================================== + +SpatialBox::SpatialBox(pugi::xml_node node) +{ + // Read lower-right/upper-left coordinates + auto params = get_node_array(node, "parameters"); + if (params.size() != 6) + openmc::fatal_error("Box/fission spatial source must have six " + "parameters specified."); + + lower_left_ = Position{params[0], params[1], params[2]}; + upper_right_ = Position{params[3], params[4], params[5]}; +} + +Position SpatialBox::sample() const +{ + Position xi {prn(), prn(), prn()}; + return lower_left_ + xi*(upper_right_ - lower_left_); +} + +//============================================================================== +// SpatialPoint implementation +//============================================================================== + +SpatialPoint::SpatialPoint(pugi::xml_node node) +{ + // Read location of point source + auto params = get_node_array(node, "parameters"); + if (params.size() != 3) + openmc::fatal_error("Point spatial source must have three " + "parameters specified."); + + // Set position + r_ = Position{params.data()}; +} + +Position SpatialPoint::sample() const +{ + return r_; +} + +} // namespace openmc diff --git a/src/distribution_spatial.h b/src/distribution_spatial.h new file mode 100644 index 0000000000..9b32a6344f --- /dev/null +++ b/src/distribution_spatial.h @@ -0,0 +1,69 @@ +#ifndef OPENMC_DISTRIBTUION_SPATIAL_H +#define OPENMC_DISTRIBUTION_SPATIAL_H + +#include "pugixml.hpp" + +#include "distribution.h" +#include "position.h" + +namespace openmc { + +//============================================================================== +//! Probability density function for points in Euclidean space +//============================================================================== + +class SpatialDistribution { +public: + virtual Position sample() const = 0; + virtual ~SpatialDistribution() = default; +}; + +//============================================================================== +//! Distribution of points specified by independent distributions in x,y,z +//============================================================================== + +class CartesianIndependent : public SpatialDistribution { +public: + explicit CartesianIndependent(pugi::xml_node node); + + //! Sample a position from the distribution + Position sample() const; +private: + UPtrDist x_; //!< Distribution of x coordinates + UPtrDist y_; //!< Distribution of y coordinates + UPtrDist z_; //!< Distribution of z coordinates +}; + +//============================================================================== +//! Uniform distribution of points over a box +//============================================================================== + +class SpatialBox : public SpatialDistribution { +public: + explicit SpatialBox(pugi::xml_node node); + + //! Sample a position from the distribution + Position sample() const; +private: + Position lower_left_; + Position upper_right_; + bool only_fissionable {false}; +}; + +//============================================================================== +//! Distribution at a single point +//============================================================================== + +class SpatialPoint : public SpatialDistribution { +public: + explicit SpatialPoint(pugi::xml_node node); + + //! Sample a position from the distribution + Position sample() const; +private: + Position r_; +}; + +} // namespace openmc + +#endif // OPENMC_DISTRIBUTION_SPATIAL_H diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 3342e3a912..ddb7506af7 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -623,6 +623,14 @@ void rotate_angle_c(double uvw[3], double mu, double* phi) { } +Direction rotate_angle(Direction u, double mu, double* phi) +{ + double uvw[] {u.x, u.y, u.z}; + rotate_angle_c(uvw, mu, phi); + return {uvw[0], uvw[1], uvw[2]}; +} + + double maxwell_spectrum_c(double T) { // Set the random numbers double r1 = prn(); diff --git a/src/math_functions.h b/src/math_functions.h index 566e68ea60..78aa166b32 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -1,13 +1,14 @@ //! \file math_functions.h //! A collection of elementary math functions. -#ifndef MATH_FUNCTIONS_H -#define MATH_FUNCTIONS_H +#ifndef OPENMC_MATH_FUNCTIONS_H +#define OPENMC_MATH_FUNCTIONS_H #include #include #include "constants.h" +#include "position.h" #include "random_lcg.h" @@ -106,6 +107,8 @@ extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); extern "C" void rotate_angle_c(double uvw[3], double mu, double* phi); +Direction rotate_angle(Direction u, double mu, double* phi); + //============================================================================== //! Samples an energy from the Maxwell fission distribution based on a direct //! sampling scheme. @@ -202,4 +205,4 @@ extern "C" double spline_integrate_c(int n, const double x[], const double y[], const double z[], double xa, double xb); } // namespace openmc -#endif // MATH_FUNCTIONS_H +#endif // OPENMC_MATH_FUNCTIONS_H diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index b4fcc524c6..7f3222a524 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -9,7 +9,7 @@ namespace openmc { std::string -get_node_value(pugi::xml_node node, const char *name) +get_node_value_str(pugi::xml_node node, const char* name) { // Search for either an attribute or child tag and get the data as a char*. const pugi::char_t *value_char; @@ -23,9 +23,15 @@ get_node_value(pugi::xml_node node, const char *name) << node.name() << "\" XML node"; fatal_error(err_msg); } + return value_char; +} - // Convert to lowercase string. - std::string value(value_char); + +std::string +get_node_value(pugi::xml_node node, const char *name) +{ + // Get char* and convert to lowercase string. + std::string value {get_node_value_str(node, name)}; std::transform(value.begin(), value.end(), value.begin(), ::tolower); // Remove whitespace. diff --git a/src/xml_interface.h b/src/xml_interface.h index de89018efe..b12e6185b6 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -1,6 +1,7 @@ #ifndef XML_INTERFACE_H #define XML_INTERFACE_H +#include // for stringstream #include #include @@ -15,7 +16,24 @@ check_for_node(pugi::xml_node node, const char *name) return node.attribute(name) || node.child(name); } +std::string get_node_value_str(pugi::xml_node node, const char *name); std::string get_node_value(pugi::xml_node node, const char *name); +template +std::vector get_node_array(pugi::xml_node node, const char* name) +{ + // Get value of node attribute/child + std::string s {get_node_value_str(node, name)}; + + // Read values one by one into vector + std::stringstream iss {s}; + T value; + std::vector values; + while (iss >> value) + values.push_back(value); + + return values; +} + } // namespace openmc #endif // XML_INTERFACE_H From 1a9f2a27d7214bbed0d6c92a3b9c539a873a58c0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 6 Jul 2018 10:49:24 -0500 Subject: [PATCH 03/30] Include xtensor as vendored header-only library --- CMakeLists.txt | 12 +- vendor/xtensor/CMakeLists.txt | 191 ++ .../xtensor/include/xtensor/xaccumulator.hpp | 266 ++ vendor/xtensor/include/xtensor/xadapt.hpp | 322 +++ vendor/xtensor/include/xtensor/xarray.hpp | 550 ++++ vendor/xtensor/include/xtensor/xassign.hpp | 783 ++++++ .../include/xtensor/xaxis_iterator.hpp | 197 ++ vendor/xtensor/include/xtensor/xbroadcast.hpp | 412 +++ .../include/xtensor/xbuffer_adaptor.hpp | 623 +++++ vendor/xtensor/include/xtensor/xbuilder.hpp | 918 ++++++ vendor/xtensor/include/xtensor/xcomplex.hpp | 251 ++ vendor/xtensor/include/xtensor/xconcepts.hpp | 113 + vendor/xtensor/include/xtensor/xcontainer.hpp | 1418 ++++++++++ vendor/xtensor/include/xtensor/xcsv.hpp | 169 ++ vendor/xtensor/include/xtensor/xeval.hpp | 57 + vendor/xtensor/include/xtensor/xexception.hpp | 219 ++ .../xtensor/include/xtensor/xexpression.hpp | 307 ++ vendor/xtensor/include/xtensor/xfixed.hpp | 818 ++++++ vendor/xtensor/include/xtensor/xfunction.hpp | 1184 ++++++++ .../xtensor/include/xtensor/xfunctor_view.hpp | 1349 +++++++++ vendor/xtensor/include/xtensor/xgenerator.hpp | 401 +++ .../xtensor/include/xtensor/xindex_view.hpp | 745 +++++ vendor/xtensor/include/xtensor/xinfo.hpp | 139 + vendor/xtensor/include/xtensor/xio.hpp | 634 +++++ vendor/xtensor/include/xtensor/xiterable.hpp | 824 ++++++ vendor/xtensor/include/xtensor/xiterator.hpp | 1123 ++++++++ vendor/xtensor/include/xtensor/xjson.hpp | 183 ++ vendor/xtensor/include/xtensor/xlayout.hpp | 93 + vendor/xtensor/include/xtensor/xmath.hpp | 2146 ++++++++++++++ vendor/xtensor/include/xtensor/xnoalias.hpp | 110 + vendor/xtensor/include/xtensor/xnorm.hpp | 477 ++++ vendor/xtensor/include/xtensor/xnpy.hpp | 702 +++++ .../xtensor/include/xtensor/xoffset_view.hpp | 41 + vendor/xtensor/include/xtensor/xoperation.hpp | 843 ++++++ vendor/xtensor/include/xtensor/xoptional.hpp | 503 ++++ .../include/xtensor/xoptional_assembly.hpp | 661 +++++ .../xtensor/xoptional_assembly_base.hpp | 948 +++++++ .../xtensor/xoptional_assembly_storage.hpp | 551 ++++ vendor/xtensor/include/xtensor/xrandom.hpp | 314 +++ vendor/xtensor/include/xtensor/xreducer.hpp | 1039 +++++++ vendor/xtensor/include/xtensor/xscalar.hpp | 1108 ++++++++ vendor/xtensor/include/xtensor/xsemantic.hpp | 656 +++++ vendor/xtensor/include/xtensor/xshape.hpp | 119 + vendor/xtensor/include/xtensor/xslice.hpp | 970 +++++++ vendor/xtensor/include/xtensor/xsort.hpp | 316 +++ vendor/xtensor/include/xtensor/xstorage.hpp | 1346 +++++++++ .../xtensor/include/xtensor/xstrided_view.hpp | 1307 +++++++++ .../include/xtensor/xstrided_view_base.hpp | 773 ++++++ vendor/xtensor/include/xtensor/xstrides.hpp | 451 +++ vendor/xtensor/include/xtensor/xtensor.hpp | 479 ++++ .../include/xtensor/xtensor_config.hpp | 63 + .../include/xtensor/xtensor_forward.hpp | 216 ++ .../xtensor/include/xtensor/xtensor_simd.hpp | 160 ++ vendor/xtensor/include/xtensor/xutils.hpp | 1040 +++++++ vendor/xtensor/include/xtensor/xvectorize.hpp | 101 + vendor/xtensor/include/xtensor/xview.hpp | 1538 +++++++++++ .../xtensor/include/xtensor/xview_utils.hpp | 274 ++ vendor/xtensor/xtensor.pc.in | 8 + vendor/xtensor/xtensorConfig.cmake.in | 21 + vendor/xtl/CMakeLists.txt | 113 + vendor/xtl/include/xtl/xany.hpp | 453 +++ vendor/xtl/include/xtl/xbase64.hpp | 75 + .../xtl/include/xtl/xbasic_fixed_string.hpp | 2250 +++++++++++++++ vendor/xtl/include/xtl/xclosure.hpp | 387 +++ vendor/xtl/include/xtl/xcomplex.hpp | 1337 +++++++++ vendor/xtl/include/xtl/xcomplex_sequence.hpp | 576 ++++ vendor/xtl/include/xtl/xdynamic_bitset.hpp | 1125 ++++++++ vendor/xtl/include/xtl/xfunctional.hpp | 28 + vendor/xtl/include/xtl/xhash.hpp | 187 ++ .../xtl/include/xtl/xhierarchy_generator.hpp | 72 + vendor/xtl/include/xtl/xiterator_base.hpp | 196 ++ vendor/xtl/include/xtl/xjson.hpp | 40 + vendor/xtl/include/xtl/xmeta_utils.hpp | 482 ++++ vendor/xtl/include/xtl/xoptional.hpp | 1425 ++++++++++ vendor/xtl/include/xtl/xoptional_sequence.hpp | 621 +++++ vendor/xtl/include/xtl/xproxy_wrapper.hpp | 48 + vendor/xtl/include/xtl/xsequence.hpp | 173 ++ vendor/xtl/include/xtl/xtl_config.hpp | 16 + vendor/xtl/include/xtl/xtype_traits.hpp | 141 + vendor/xtl/include/xtl/xvariant.hpp | 155 ++ vendor/xtl/include/xtl/xvariant_impl.hpp | 2457 +++++++++++++++++ vendor/xtl/xtlConfig.cmake.in | 21 + 82 files changed, 45958 insertions(+), 2 deletions(-) create mode 100644 vendor/xtensor/CMakeLists.txt create mode 100644 vendor/xtensor/include/xtensor/xaccumulator.hpp create mode 100644 vendor/xtensor/include/xtensor/xadapt.hpp create mode 100644 vendor/xtensor/include/xtensor/xarray.hpp create mode 100644 vendor/xtensor/include/xtensor/xassign.hpp create mode 100644 vendor/xtensor/include/xtensor/xaxis_iterator.hpp create mode 100644 vendor/xtensor/include/xtensor/xbroadcast.hpp create mode 100644 vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp create mode 100644 vendor/xtensor/include/xtensor/xbuilder.hpp create mode 100644 vendor/xtensor/include/xtensor/xcomplex.hpp create mode 100644 vendor/xtensor/include/xtensor/xconcepts.hpp create mode 100644 vendor/xtensor/include/xtensor/xcontainer.hpp create mode 100644 vendor/xtensor/include/xtensor/xcsv.hpp create mode 100644 vendor/xtensor/include/xtensor/xeval.hpp create mode 100644 vendor/xtensor/include/xtensor/xexception.hpp create mode 100644 vendor/xtensor/include/xtensor/xexpression.hpp create mode 100644 vendor/xtensor/include/xtensor/xfixed.hpp create mode 100644 vendor/xtensor/include/xtensor/xfunction.hpp create mode 100644 vendor/xtensor/include/xtensor/xfunctor_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xgenerator.hpp create mode 100644 vendor/xtensor/include/xtensor/xindex_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xinfo.hpp create mode 100644 vendor/xtensor/include/xtensor/xio.hpp create mode 100644 vendor/xtensor/include/xtensor/xiterable.hpp create mode 100644 vendor/xtensor/include/xtensor/xiterator.hpp create mode 100644 vendor/xtensor/include/xtensor/xjson.hpp create mode 100644 vendor/xtensor/include/xtensor/xlayout.hpp create mode 100644 vendor/xtensor/include/xtensor/xmath.hpp create mode 100644 vendor/xtensor/include/xtensor/xnoalias.hpp create mode 100644 vendor/xtensor/include/xtensor/xnorm.hpp create mode 100644 vendor/xtensor/include/xtensor/xnpy.hpp create mode 100644 vendor/xtensor/include/xtensor/xoffset_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xoperation.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional_assembly.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional_assembly_base.hpp create mode 100644 vendor/xtensor/include/xtensor/xoptional_assembly_storage.hpp create mode 100644 vendor/xtensor/include/xtensor/xrandom.hpp create mode 100644 vendor/xtensor/include/xtensor/xreducer.hpp create mode 100644 vendor/xtensor/include/xtensor/xscalar.hpp create mode 100644 vendor/xtensor/include/xtensor/xsemantic.hpp create mode 100644 vendor/xtensor/include/xtensor/xshape.hpp create mode 100644 vendor/xtensor/include/xtensor/xslice.hpp create mode 100644 vendor/xtensor/include/xtensor/xsort.hpp create mode 100644 vendor/xtensor/include/xtensor/xstorage.hpp create mode 100644 vendor/xtensor/include/xtensor/xstrided_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xstrided_view_base.hpp create mode 100644 vendor/xtensor/include/xtensor/xstrides.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor_config.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor_forward.hpp create mode 100644 vendor/xtensor/include/xtensor/xtensor_simd.hpp create mode 100644 vendor/xtensor/include/xtensor/xutils.hpp create mode 100644 vendor/xtensor/include/xtensor/xvectorize.hpp create mode 100644 vendor/xtensor/include/xtensor/xview.hpp create mode 100644 vendor/xtensor/include/xtensor/xview_utils.hpp create mode 100644 vendor/xtensor/xtensor.pc.in create mode 100644 vendor/xtensor/xtensorConfig.cmake.in create mode 100644 vendor/xtl/CMakeLists.txt create mode 100644 vendor/xtl/include/xtl/xany.hpp create mode 100644 vendor/xtl/include/xtl/xbase64.hpp create mode 100644 vendor/xtl/include/xtl/xbasic_fixed_string.hpp create mode 100644 vendor/xtl/include/xtl/xclosure.hpp create mode 100644 vendor/xtl/include/xtl/xcomplex.hpp create mode 100644 vendor/xtl/include/xtl/xcomplex_sequence.hpp create mode 100644 vendor/xtl/include/xtl/xdynamic_bitset.hpp create mode 100644 vendor/xtl/include/xtl/xfunctional.hpp create mode 100644 vendor/xtl/include/xtl/xhash.hpp create mode 100644 vendor/xtl/include/xtl/xhierarchy_generator.hpp create mode 100644 vendor/xtl/include/xtl/xiterator_base.hpp create mode 100644 vendor/xtl/include/xtl/xjson.hpp create mode 100644 vendor/xtl/include/xtl/xmeta_utils.hpp create mode 100644 vendor/xtl/include/xtl/xoptional.hpp create mode 100644 vendor/xtl/include/xtl/xoptional_sequence.hpp create mode 100644 vendor/xtl/include/xtl/xproxy_wrapper.hpp create mode 100644 vendor/xtl/include/xtl/xsequence.hpp create mode 100644 vendor/xtl/include/xtl/xtl_config.hpp create mode 100644 vendor/xtl/include/xtl/xtype_traits.hpp create mode 100644 vendor/xtl/include/xtl/xvariant.hpp create mode 100644 vendor/xtl/include/xtl/xvariant_impl.hpp create mode 100644 vendor/xtl/xtlConfig.cmake.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 24b0bef569..668e37899e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES Clang) endif() -list(APPEND cxxflags -std=c++11 -O2) +list(APPEND cxxflags -std=c++14 -O2) if(debug) list(REMOVE_ITEM cxxflags -O2) list(APPEND cxxflags -g -O0) @@ -236,6 +236,14 @@ message(STATUS "Linker flags: ${ldflags}") add_library(pugixml vendor/pugixml/pugixml.cpp) target_include_directories(pugixml PUBLIC vendor/pugixml/) +#=============================================================================== +# xtensor header-only library +#=============================================================================== + +add_subdirectory(vendor/xtl) +add_subdirectory(vendor/xtensor) +target_link_libraries(xtensor INTERFACE xtl) + #=============================================================================== # RPATH information #=============================================================================== @@ -453,7 +461,7 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml - faddeeva) + faddeeva xtensor) #=============================================================================== # openmc executable diff --git a/vendor/xtensor/CMakeLists.txt b/vendor/xtensor/CMakeLists.txt new file mode 100644 index 0000000000..d4d3b355d6 --- /dev/null +++ b/vendor/xtensor/CMakeLists.txt @@ -0,0 +1,191 @@ +############################################################################ +# Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# # +# Distributed under the terms of the BSD 3-Clause License. # +# # +# The full license is in the file LICENSE, distributed with this software. # +############################################################################ + +cmake_minimum_required(VERSION 3.1) +project(xtensor) + +set(XTENSOR_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) + +# Versionning +# =========== + +file(STRINGS "${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_config.hpp" xtensor_version_defines + REGEX "#define XTENSOR_VERSION_(MAJOR|MINOR|PATCH)") +foreach(ver ${xtensor_version_defines}) + if(ver MATCHES "#define XTENSOR_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$") + set(XTENSOR_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "") + endif() +endforeach() +set(${PROJECT_NAME}_VERSION + ${XTENSOR_VERSION_MAJOR}.${XTENSOR_VERSION_MINOR}.${XTENSOR_VERSION_PATCH}) +message(STATUS "Building xtensor v${${PROJECT_NAME}_VERSION}") + +# Dependencies +# ============ + +#find_package(xtl 0.4.9 REQUIRED) + +#message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") + +#find_package(nlohmann_json 3.1.1) + +# Build +# ===== + +set(XTENSOR_HEADERS + ${XTENSOR_INCLUDE_DIR}/xtensor/xaccumulator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xadapt.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xarray.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xassign.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xaxis_iterator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xbroadcast.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xbuffer_adaptor.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xbuilder.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xcomplex.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xconcepts.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xcontainer.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xcsv.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xeval.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexception.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xfixed.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xfunction.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xfunctor_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xgenerator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xindex_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xinfo.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xio.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xiterable.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xiterator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xjson.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xlayout.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmath.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xnoalias.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xnorm.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xnpy.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xoffset_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xoperation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_base.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_storage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xrandom.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xreducer.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xsemantic.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xshape.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xslice.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xsort.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xstorage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xstrided_view.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xstrided_view_base.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xstrides.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_config.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_forward.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_simd.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xutils.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xvectorize.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xview.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xview_utils.hpp +) + +add_library(xtensor INTERFACE) +target_include_directories(xtensor INTERFACE $ + $) +target_link_libraries(xtensor INTERFACE xtl) + +OPTION(XTENSOR_ENABLE_ASSERT "xtensor bound check" OFF) +OPTION(XTENSOR_CHECK_DIMENSION "xtensor dimension check" OFF) +OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) +OPTION(BUILD_TESTS "xtensor test suite" OFF) +OPTION(BUILD_BENCHMARK "xtensor benchmark" OFF) +OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) +OPTION(DOWNLOAD_GBENCHMARK "download google benchmark and build from source" ON) +OPTION(DEFAULT_COLUMN_MAJOR "set default layout to column major" OFF) +OPTION(DISABLE_VS2017 "disables the compilation of some test with Visual Studio 2017" OFF) + +if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) + set(BUILD_TESTS ON) +endif() + +if(XTENSOR_ENABLE_ASSERT OR XTENSOR_CHECK_DIMENSION) + add_definitions(-DXTENSOR_ENABLE_ASSERT) +endif() + +if(XTENSOR_CHECK_DIMENSION) + add_definitions(-DXTENSOR_ENABLE_CHECK_DIMENSION) +endif() + +if(XTENSOR_USE_XSIMD) + add_definitions(-DXTENSOR_USE_XSIMD) + find_package(xsimd 4.1.6 REQUIRED) + message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") + target_link_libraries(xtensor INTERFACE xsimd) +endif() + +if(DEFAULT_COLUMN_MAJOR) + add_definitions(-DXTENSOR_DEFAULT_LAYOUT=layout_type::column_major) +endif() + +if(DISABLE_VS2017) + add_definitions(-DDISABLE_VS2017) +endif() + +if(BUILD_TESTS) + add_subdirectory(test) +endif() + +if(BUILD_BENCHMARK) + add_subdirectory(benchmark) +endif() + +# Installation +# ============ + +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + +install(TARGETS xtensor + EXPORT ${PROJECT_NAME}-targets) + +# Makes the project importable from the build directory +export(EXPORT ${PROJECT_NAME}-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake") + +install(FILES ${XTENSOR_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xtensor) + +set(XTENSOR_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE + STRING "install path for xtensorConfig.cmake") + +configure_package_config_file(${PROJECT_NAME}Config.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${XTENSOR_CMAKECONFIG_INSTALL_DIR}) + +# xtensor is header-only and does not depend on the architecture. +# Remove CMAKE_SIZEOF_VOID_P from xtensorConfigVersion.cmake so that an xtensorConfig.cmake +# generated for a 64 bit target can be used for 32 bit targets and vice versa. +set(_XTENSOR_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) +unset(CMAKE_SIZEOF_VOID_P) +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + VERSION ${${PROJECT_NAME}_VERSION} + COMPATIBILITY AnyNewerVersion) +set(CMAKE_SIZEOF_VOID_P ${_XTENSOR_CMAKE_SIZEOF_VOID_P}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${XTENSOR_CMAKECONFIG_INSTALL_DIR}) +install(EXPORT ${PROJECT_NAME}-targets + FILE ${PROJECT_NAME}Targets.cmake + DESTINATION ${XTENSOR_CMAKECONFIG_INSTALL_DIR}) + +configure_file(${PROJECT_NAME}.pc.in + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/") diff --git a/vendor/xtensor/include/xtensor/xaccumulator.hpp b/vendor/xtensor/include/xtensor/xaccumulator.hpp new file mode 100644 index 0000000000..f2b446ff36 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaccumulator.hpp @@ -0,0 +1,266 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ACCUMULATOR_HPP +#define XTENSOR_ACCUMULATOR_HPP + +#include +#include +#include +#include + +#include "xexpression.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + +#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate + + /************** + * accumulate * + **************/ + + template + struct xaccumulator_functor + : public std::tuple + { + using self_type = xaccumulator_functor; + using base_type = std::tuple; + using accumulate_functor_type = ACCUMULATE_FUNC; + using init_functor_type = INIT_FUNC; + + xaccumulator_functor() + : base_type() + { + } + + template + xaccumulator_functor(RF&& accumulate_func) + : base_type(std::forward(accumulate_func), INIT_FUNC()) + { + } + + template + xaccumulator_functor(RF&& accumulate_func, IF&& init_func) + : base_type(std::forward(accumulate_func), std::forward(init_func)) + { + } + }; + + template + auto make_xaccumulator_functor(RF&& accumulate_func) + { + using accumulator_type = xaccumulator_functor>; + return accumulator_type(std::forward(accumulate_func)); + } + + template + auto make_xaccumulator_functor(RF&& accumulate_func, IF&& init_func) + { + using accumulator_type = xaccumulator_functor, std::remove_reference_t>; + return accumulator_type(std::forward(accumulate_func), std::forward(init_func)); + } + + namespace detail + { + template + xarray::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS) + { + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + } + + template + xarray::value_type> accumulator_impl(F&&, E&&, EVS) + { + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + } + + template + struct xaccumulator_return_type + { + using type = xarray; + }; + + template + struct xaccumulator_return_type, R> + { + using type = xtensor; + }; + + template + using xaccumulator_return_type_t = typename xaccumulator_return_type::type; + + template + inline auto accumulator_init_with_f(F&& f, E& e, std::size_t axis) + { + // this function is the equivalent (but hopefully faster) to (if axis == 1) + // e[:, 0, :, :, ...] = f(e[:, 0, :, :, ...]) + // so that all "first" values are initialized in a first pass + + std::size_t outer_loop_size, inner_loop_size, outer_stride, inner_stride, pos = 0; + + auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { + outer_loop_size = std::accumulate(first, first + ax, + std::size_t(1), std::multiplies()); + inner_loop_size = std::accumulate(first + ax + 1, last, + std::size_t(1), std::multiplies()); + }; + + auto set_loop_strides = [&outer_stride, &inner_stride](auto first, auto last, std::ptrdiff_t ax) { + outer_stride = ax == 0 ? 1 : *std::min_element(first, first + ax); + inner_stride = (ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last); + }; + + set_loop_sizes(e.shape().begin(), e.shape().end(), static_cast(axis)); + set_loop_strides(e.strides().begin(), e.strides().end(), static_cast(axis)); + + if (e.layout() == layout_type::column_major) + { + // swap for better memory locality (smaller stride in the inner loop) + std::swap(outer_loop_size, inner_loop_size); + std::swap(outer_stride, inner_stride); + } + + for (std::size_t i = 0; i < outer_loop_size; ++i) + { + pos = i * outer_stride; + for (std::size_t j = 0; j < inner_loop_size; ++j) + { + e.storage()[pos] = f(e.storage()[pos]); + pos += inner_stride; + } + } + } + + template + inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate) + { + using accumulate_functor = std::decay_t(f))>; + using function_return_type = typename accumulate_functor::result_type; + using result_type = xaccumulator_return_type_t, function_return_type>; + + if (axis >= e.dimension()) + { + throw std::runtime_error("Axis larger than expression dimension in accumulator."); + } + + result_type result = e; // assign + make a copy, we need it anyways + + std::size_t inner_stride = result.strides()[axis]; + std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) + std::size_t outer_loop_size = 0; + std::size_t inner_loop_size = 0; + + auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { + outer_loop_size = std::accumulate(first, + first + ax, + std::size_t(1), std::multiplies()); + + inner_loop_size = std::accumulate(first + ax, + last, + std::size_t(1), std::multiplies()); + }; + + if (result_type::static_layout == layout_type::row_major) + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); + } + else + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); + std::swap(inner_loop_size, outer_loop_size); + } + + std::size_t pos = 0; + + inner_loop_size = inner_loop_size - inner_stride; + + // activate the init loop if we have an init function other than identity + if (!std::is_same(f)), xtl::identity>::value) + { + accumulator_init_with_f(std::get<1>(f), result, axis); + } + + pos = 0; + for (std::size_t i = 0; i < outer_loop_size; ++i) + { + for (std::size_t j = 0; j < inner_loop_size; ++j) + { + result.storage()[pos + inner_stride] = std::get<0>(f)(result.storage()[pos], + result.storage()[pos + inner_stride]); + pos += outer_stride; + } + pos += inner_stride; + } + return result; + } + + template + inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate) + { + using accumulate_functor = std::decay_t(f))>; + using T = typename accumulate_functor::result_type; + + using result_type = xtensor; + std::size_t sz = e.size(); + auto result = result_type::from_shape({sz}); + + auto it = e.template begin(); + + result.storage()[0] = std::get<1>(f)(*it); + ++it; + + for (std::size_t idx = 0; it != e.template end(); ++it) + { + result.storage()[idx + 1] = std::get<0>(f)(result.storage()[idx], *it); + ++idx; + } + return result; + } + } + + /** + * Accumulate and flatten array + * **NOTE** This function is not lazy! + * + * @param f functor to use for accumulation + * @param e xexpression to be accumulated + * @param evaluation_strategy evaluation strategy of the accumulation + * + * @return returns xarray filled with accumulated values + */ + template ::value, int> = 0> + inline auto accumulate(F&& f, E&& e, EVS evaluation_strategy = EVS()) + { + // Note we need to check is_integral above in order to prohibit EVS = int, and not taking the std::size_t + // overload below! + return detail::accumulator_impl(std::forward(f), std::forward(e), evaluation_strategy); + } + + /** + * Accumulate over axis + * **NOTE** This function is not lazy! + * + * @param f Functor to use for accumulation + * @param e xexpression to accumulate + * @param axis Axis to perform accumulation over + * @param evaluation_strategy evaluation strategy of the accumulation + * + * @return returns xarray filled with accumulated values + */ + template + inline auto accumulate(F&& f, E&& e, std::size_t axis, EVS evaluation_strategy = EVS()) + { + return detail::accumulator_impl(std::forward(f), std::forward(e), axis, evaluation_strategy); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xadapt.hpp b/vendor/xtensor/include/xtensor/xadapt.hpp new file mode 100644 index 0000000000..b080bd0b7d --- /dev/null +++ b/vendor/xtensor/include/xtensor/xadapt.hpp @@ -0,0 +1,322 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ADAPT_HPP +#define XTENSOR_ADAPT_HPP + +#include +#include +#include +#include + +#include + +#include "xarray.hpp" +#include "xtensor.hpp" + +namespace xt +{ + namespace detail + { + template + struct array_size_impl; + + template + struct array_size_impl> + { + static constexpr std::size_t value = N; + }; + + template + using array_size = array_size_impl>; + } + + /************************** + * xarray_adaptor builder * + **************************/ + + /** + * Constructs an xarray_adaptor of the given stl-like container, + * with the specified shape and layout. + * @param container the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >::value, int> = 0> + xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l = L); + + /** + * Constructs an xarray_adaptor of the given stl-like container, + * with the specified shape and strides. + * @param container the container to adapt + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides); + + /** + * Constructs an xarray_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>, + typename std::enable_if_t>::value, int> = 0> + xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + + /** + * Constructs an xarray_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>, + typename std::enable_if_t>::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + + /*************************** + * xtensor_adaptor builder * + ***************************/ + + /** + * Constructs a 1-D xtensor_adaptor of the given stl-like container, + * with the specified layout_type. + * @param container the container to adapt + * @param l the layout_type of the xtensor_adaptor + */ + template + xtensor_adaptor + adapt(C&& container, layout_type l = L); + + /** + * Constructs an xtensor_adaptor of the given stl-like container, + * with the specified shape and layout_type. + * @param container the container to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template >::value, int> = 0> + xtensor_adaptor::value, L> + adapt(C&& container, const SC& shape, layout_type l = L); + + /** + * Constructs an xtensor_adaptor of the given stl-like container, + * with the specified shape and strides. + * @param container the container to adapt + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + */ + template >::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xtensor_adaptor::value, layout_type::dynamic> + adapt(C&& container, SC&& shape, SS&& strides); + + /** + * Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array, + * with the specified layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>> + xtensor_adaptor, O, A>, 1, L> + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()); + + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>, + typename std::enable_if_t>::value, int> = 0> + xtensor_adaptor, O, A>, detail::array_size::value, L> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template >>>, + typename std::enable_if_t>::value, int> = 0, + typename std::enable_if_t>::value, int> = 0> + xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + + /***************************************** + * xarray_adaptor builder implementation * + *****************************************/ + + // shape only - container version + template >::value, int>> + inline xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l) + { + using return_type = xarray_adaptor, L, std::decay_t>; + return return_type(std::forward(container), shape, l); + } + + // shape and strides - container version + template >::value, int>, + typename std::enable_if_t>::value, int>> + inline xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides) + { + using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + // shape only - buffer version + template >::value, int>> + inline xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } + + // shape and strides - buffer version + template >::value, int>, + typename std::enable_if_t>::value, int>> + inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor>; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + /****************************************** + * xtensor_adaptor builder implementation * + ******************************************/ + + // 1-D case - container version + template + inline xtensor_adaptor + adapt(C&& container, layout_type l) + { + const std::array::size_type, 1> shape{container.size()}; + using return_type = xtensor_adaptor, 1, L>; + return return_type(std::forward(container), shape, l); + } + + // shape only - container version + template >::value, int>> + inline xtensor_adaptor::value, L> + adapt(C&& container, const SC& shape, layout_type l) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, L>; + return return_type(std::forward(container), shape, l); + } + + // shape and strides - container version + template >::value, int>, + typename std::enable_if_t>::value, int>> + inline xtensor_adaptor::value, layout_type::dynamic> + adapt(C&& container, SC&& shape, SS&& strides) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, layout_type::dynamic>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + // 1-D case - buffer version + template + inline xtensor_adaptor, O, A>, 1, L> + adapt(P&& pointer, typename A::size_type size, O, layout_type l, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + const std::array shape{size}; + return return_type(std::move(buf), shape, l); + } + + // shape only - buffer version + template >::value, int>> + inline xtensor_adaptor, O, A>, detail::array_size::value, L> + adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } + + // shape and strides - buffer version + template >::value, int>, + typename std::enable_if_t>::value, int>> + inline xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> + adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) + { + using buffer_type = xbuffer_adaptor, O, A>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xarray.hpp b/vendor/xtensor/include/xtensor/xarray.hpp new file mode 100644 index 0000000000..7c51f28124 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xarray.hpp @@ -0,0 +1,550 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ARRAY_HPP +#define XTENSOR_ARRAY_HPP + +#include +#include +#include + +#include + +#include "xbuffer_adaptor.hpp" +#include "xcontainer.hpp" +#include "xsemantic.hpp" + +namespace xt +{ + + /******************************** + * xarray_container declaration * + ********************************/ + + template + struct xcontainer_inner_types> + { + using storage_type = EC; + using shape_type = SC; + using strides_type = shape_type; + using backstrides_type = shape_type; + using inner_shape_type = shape_type; + using inner_strides_type = strides_type; + using inner_backstrides_type = backstrides_type; + using temporary_type = xarray_container; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xarray_container + * @brief Dense multidimensional container with tensor semantic. + * + * The xarray_container class implements a dense multidimensional container + * with tensor semantic. + * + * @tparam EC The type of the container holding the elements. + * @tparam L The layout_type of the container. + * @tparam SC The type of the containers holding the shape and the strides. + * @tparam Tag The expression tag. + * @sa xarray + */ + template + class xarray_container : public xstrided_container>, + public xcontainer_semantic> + { + public: + + using self_type = xarray_container; + using base_type = xstrided_container; + using semantic_base = xcontainer_semantic; + using storage_type = typename base_type::storage_type; + using allocator_type = typename base_type::allocator_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using shape_type = typename base_type::shape_type; + using inner_shape_type = typename base_type::inner_shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using inner_strides_type = typename base_type::inner_strides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + + xarray_container(); + explicit xarray_container(const shape_type& shape, layout_type l = L); + explicit xarray_container(const shape_type& shape, const_reference value, layout_type l = L); + explicit xarray_container(const shape_type& shape, const strides_type& strides); + explicit xarray_container(const shape_type& shape, const strides_type& strides, const_reference value); + explicit xarray_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides); + + xarray_container(const value_type& t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + xarray_container(nested_initializer_list_t t); + + template + static xarray_container from_shape(S&& s); + + ~xarray_container() = default; + + xarray_container(const xarray_container&) = default; + xarray_container& operator=(const xarray_container&) = default; + + xarray_container(xarray_container&&) = default; + xarray_container& operator=(xarray_container&&) = default; + + template + xarray_container(const xexpression& e); + + template + xarray_container& operator=(const xexpression& e); + + private: + + storage_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + friend class xcontainer>; + }; + + /****************************** + * xarray_adaptor declaration * + ******************************/ + + template + struct xcontainer_inner_types> + { + using storage_type = std::remove_reference_t; + using shape_type = SC; + using strides_type = shape_type; + using backstrides_type = shape_type; + using inner_shape_type = shape_type; + using inner_strides_type = strides_type; + using inner_backstrides_type = backstrides_type; + using temporary_type = xarray_container, L, SC, Tag>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xarray_adaptor + * @brief Dense multidimensional container adaptor with + * tensor semantic. + * + * The xarray_adaptor class implements a dense multidimensional + * container adaptor with tensor semantic. It is used to provide + * a multidimensional container semantic and a tensor semantic to + * stl-like containers. + * + * @tparam EC The closure for the container type to adapt. + * @tparam L The layout_type of the adaptor. + * @tparam SC The type of the containers holding the shape and the strides. + * @tparam Tag The expression tag. + */ + template + class xarray_adaptor : public xstrided_container>, + public xcontainer_semantic> + { + public: + + using container_closure_type = EC; + + using self_type = xarray_adaptor; + using base_type = xstrided_container; + using semantic_base = xcontainer_semantic; + using storage_type = typename base_type::storage_type; + using allocator_type = typename base_type::allocator_type; + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + + xarray_adaptor(storage_type&& storage); + xarray_adaptor(const storage_type& storage); + + template + xarray_adaptor(D&& storage, const shape_type& shape, layout_type l = L); + + template + xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides); + + ~xarray_adaptor() = default; + + xarray_adaptor(const xarray_adaptor&) = default; + xarray_adaptor& operator=(const xarray_adaptor&); + + xarray_adaptor(xarray_adaptor&&) = default; + xarray_adaptor& operator=(xarray_adaptor&&); + xarray_adaptor& operator=(temporary_type&&); + + template + xarray_adaptor& operator=(const xexpression& e); + + private: + + container_closure_type m_storage; + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + + friend class xcontainer>; + }; + + /*********************************** + * xarray_container implementation * + ***********************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Allocates an uninitialized xarray_container that holds 0 element. + */ + template + inline xarray_container::xarray_container() + : base_type(), m_storage(1, value_type()) + { + } + + /** + * Allocates an uninitialized xarray_container with the specified shape and + * layout_type. + * @param shape the shape of the xarray_container + * @param l the layout_type of the xarray_container + */ + template + inline xarray_container::xarray_container(const shape_type& shape, layout_type l) + : base_type() + { + base_type::resize(shape, l); + } + + /** + * Allocates an xarray_container with the specified shape and layout_type. Elements + * are initialized to the specified value. + * @param shape the shape of the xarray_container + * @param value the value of the elements + * @param l the layout_type of the xarray_container + */ + template + inline xarray_container::xarray_container(const shape_type& shape, const_reference value, layout_type l) + : base_type() + { + base_type::resize(shape, l); + std::fill(m_storage.begin(), m_storage.end(), value); + } + + /** + * Allocates an uninitialized xarray_container with the specified shape and strides. + * @param shape the shape of the xarray_container + * @param strides the strides of the xarray_container + */ + template + inline xarray_container::xarray_container(const shape_type& shape, const strides_type& strides) + : base_type() + { + base_type::resize(shape, strides); + } + + /** + * Allocates an uninitialized xarray_container with the specified shape and strides. + * Elements are initialized to the specified value. + * @param shape the shape of the xarray_container + * @param strides the strides of the xarray_container + * @param value the value of the elements + */ + template + inline xarray_container::xarray_container(const shape_type& shape, const strides_type& strides, const_reference value) + : base_type() + { + base_type::resize(shape, strides); + std::fill(m_storage.begin(), m_storage.end(), value); + } + + /** + * Allocates an xarray_container that holds a single element initialized to the + * specified value. + * @param t the value of the element + */ + template + inline xarray_container::xarray_container(const value_type& t) + : base_type() + { + base_type::resize(xt::shape(t), true); + nested_copy(m_storage.begin(), t); + } + + /** + * Allocates an xarray_container by moving specified data, shape and strides + * + * @param storage the data for the xarray_container + * @param shape the shape of the xarray_container + * @param strides the strides of the xarray_container + */ + template + inline xarray_container::xarray_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides) + : base_type(std::move(shape), std::move(strides)), m_storage(std::move(storage)) + { + } + //@} + + /** + * @name Constructors from initializer list + */ + //@{ + /** + * Allocates a one-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a two-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a three-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a four-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + + /** + * Allocates a five-dimensional xarray_container. + * @param t the elements of the xarray_container + */ + template + inline xarray_container::xarray_container(nested_initializer_list_t t) + : base_type() + { + base_type::resize(xt::shape(t)); + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } + //@} + + /** + * Allocates and returns an xarray_container with the specified shape. + * @param s the shape of the xarray_container + */ + template + template + inline xarray_container xarray_container::from_shape(S&& s) + { + shape_type shape = xtl::forward_sequence(s); + return self_type(shape); + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended copy constructor. + */ + template + template + inline xarray_container::xarray_container(const xexpression& e) + : base_type() + { + // Avoids unintialized data because of (m_shape == shape) condition + // in resize (called by assign), which is always true when dimension == 0. + if (e.derived_cast().dimension() == 0) + { + detail::resize_data_container(m_storage, std::size_t(1)); + } + semantic_base::assign(e); + } + + /** + * The extended assignment operator. + */ + template + template + inline auto xarray_container::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + inline auto xarray_container::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xarray_container::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + /****************** + * xarray_adaptor * + ******************/ + + /** + * @name Constructors + */ + //@{ + /** + * Constructs an xarray_adaptor of the given stl-like container. + * @param storage the container to adapt + */ + template + inline xarray_adaptor::xarray_adaptor(storage_type&& storage) + : base_type(), m_storage(std::move(storage)) + { + } + + /** + * Constructs an xarray_adaptor of the given stl-like container. + * @param storage the container to adapt + */ + template + inline xarray_adaptor::xarray_adaptor(const storage_type& storage) + : base_type(), m_storage(storage) + { + } + + /** + * Constructs an xarray_adaptor of the given stl-like container, + * with the specified shape and layout_type. + * @param storage the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template + template + inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, layout_type l) + : base_type(), m_storage(std::forward(storage)) + { + base_type::resize(shape, l); + } + + /** + * Constructs an xarray_adaptor of the given stl-like container, + * with the specified shape and strides. + * @param storage the container to adapt + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template + template + inline xarray_adaptor::xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides) + : base_type(), m_storage(std::forward(storage)) + { + base_type::resize(shape, strides); + } + //@} + + template + inline auto xarray_adaptor::operator=(const xarray_adaptor& rhs) -> self_type& + { + base_type::operator=(rhs); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xarray_adaptor::operator=(xarray_adaptor&& rhs) -> self_type& + { + base_type::operator=(std::move(rhs)); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xarray_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + base_type::shape_impl() = std::move(const_cast(rhs.shape())); + base_type::strides_impl() = std::move(const_cast(rhs.strides())); + base_type::backstrides_impl() = std::move(const_cast(rhs.backstrides())); + m_storage = std::move(rhs.storage()); + return *this; + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xarray_adaptor::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + inline auto xarray_adaptor::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xarray_adaptor::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xassign.hpp b/vendor/xtensor/include/xtensor/xassign.hpp new file mode 100644 index 0000000000..1b2f4c00d2 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xassign.hpp @@ -0,0 +1,783 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ASSIGN_HPP +#define XTENSOR_ASSIGN_HPP + +#include +#include +#include + +#include + +#include "xconcepts.hpp" +#include "xexpression.hpp" +#include "xiterator.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /******************** + * Assign functions * + ********************/ + + template + void assign_data(xexpression& e1, const xexpression& e2, bool trivial); + + template + void assign_xexpression(xexpression& e1, const xexpression& e2); + + template + void computed_assign(xexpression& e1, const xexpression& e2); + + template + void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f); + + template + void assert_compatible_shape(const xexpression& e1, const xexpression& e2); + + template + void strided_assign(E1& e1, const E2& e2, std::false_type /*disable*/); + + template + void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/); + + /************************ + * xexpression_assigner * + ************************/ + + template + class xexpression_assigner_base; + + template <> + class xexpression_assigner_base + { + public: + + template + static void assign_data(xexpression& e1, const xexpression& e2, bool trivial); + }; + + template + class xexpression_assigner : public xexpression_assigner_base + { + public: + + using base_type = xexpression_assigner_base; + + template + static void assign_xexpression(xexpression& e1, const xexpression& e2); + + template + static void computed_assign(xexpression& e1, const xexpression& e2); + + template + static void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f); + + template + static void assert_compatible_shape(const xexpression& e1, const xexpression& e2); + + private: + + template + static bool resize(xexpression& e1, const xexpression& e2); + }; + + /***************** + * data_assigner * + *****************/ + + template + class data_assigner + { + public: + + using lhs_iterator = typename E1::stepper; + using rhs_iterator = typename E2::const_stepper; + using shape_type = typename E1::shape_type; + using index_type = xindex_type_t; + using size_type = typename lhs_iterator::size_type; + using difference_type = typename lhs_iterator::difference_type; + + data_assigner(E1& e1, const E2& e2); + + void run(); + + void step(size_type i); + void step(size_type i, size_type n); + void reset(size_type i); + + void to_end(layout_type); + + private: + + E1& m_e1; + + lhs_iterator m_lhs; + rhs_iterator m_rhs; + + index_type m_index; + }; + + /******************** + * trivial_assigner * + ********************/ + + template + struct trivial_assigner + { + template + static void run(E1& e1, const E2& e2); + }; + + /*********************************** + * Assign functions implementation * + ***********************************/ + + template + inline void assign_data(xexpression& e1, const xexpression& e2, bool trivial) + { + using tag = xexpression_tag_t; + xexpression_assigner::assign_data(e1, e2, trivial); + } + + template + inline void assign_xexpression(xexpression& e1, const xexpression& e2) + { + xtl::mpl::static_if::value>([&](auto self) + { + self(e2).derived_cast().assign_to(e1); + }, /*else*/ [&](auto /*self*/) + { + using tag = xexpression_tag_t; + xexpression_assigner::assign_xexpression(e1, e2); + }); + } + + template + inline void computed_assign(xexpression& e1, const xexpression& e2) + { + using tag = xexpression_tag_t; + xexpression_assigner::computed_assign(e1, e2); + } + + template + inline void scalar_computed_assign(xexpression& e1, const E2& e2, F&& f) + { + using tag = xexpression_tag_t; + xexpression_assigner::scalar_computed_assign(e1, e2, std::forward(f)); + } + + template + inline void assert_compatible_shape(const xexpression& e1, const xexpression& e2) + { + using tag = xexpression_tag_t; + xexpression_assigner::assert_compatible_shape(e1, e2); + } + + /*************************************** + * xexpression_assigner implementation * + ***************************************/ + + namespace detail + { + template + inline bool is_trivial_broadcast(const E1& e1, const E2& e2) + { + return (E1::contiguous_layout && E2::contiguous_layout && (E1::static_layout == E2::static_layout)) + || e2.is_trivial_broadcast(e1.strides()); + } + + template + inline bool is_trivial_broadcast(const xview&, const E2&) + { + return false; + } + + template > + struct forbid_simd_assign + { + static constexpr bool value = true; + }; + + // Double steps check for xfunction because the default + // parameter void_t of forbid_simd_assign prevents additional + // specializations. + template + struct xfunction_forbid_simd; + + template + struct forbid_simd_assign().template load_simd(typename E::size_type(0)))>> + { + static constexpr bool value = false || xfunction_forbid_simd::value; + }; + + template + struct xfunction_forbid_simd + { + static constexpr bool value = false; + }; + + template + struct xfunction_forbid_simd> + { + static constexpr bool value = xtl::disjunction< + std::integral_constant::type>::value>...>::value; + }; + + template + struct has_simd_apply : std::false_type {}; + + template + struct has_simd_apply)>> + : std::true_type + { + }; + + template + struct has_step_leading : std::false_type + { + }; + + template + struct has_step_leading().step_leading())>> + : std::true_type + { + }; + + template + struct use_strided_loop + { + static constexpr bool stepper_deref() { return std::is_reference::value; } + static constexpr bool value = has_strides::value && has_step_leading::value && stepper_deref(); + }; + + template + struct use_strided_loop> + { + static constexpr bool value = true; + }; + + template + struct use_strided_loop> + { + static constexpr bool value = xtl::conjunction>...>::value && + has_simd_apply>::value; + }; + } + + template + struct xassign_traits + { + // constexpr methods instead of constexpr data members avoid the need of difinitions at namespace + // scope of these data members (since they are odr-used). + static constexpr bool contiguous_layout() { return E1::contiguous_layout && E2::contiguous_layout; } + static constexpr bool same_type() { return std::is_same::value; } + static constexpr bool simd_size() { return xsimd::simd_traits::size > 1; } + static constexpr bool forbid_simd() { return detail::forbid_simd_assign::value; } + static constexpr bool simd_assign() { return contiguous_layout() && same_type() && simd_size() && !forbid_simd(); } + static constexpr bool simd_strided_loop() { return same_type() && simd_size() && detail::use_strided_loop::value && detail::use_strided_loop::value; } + }; + + template + inline void xexpression_assigner_base::assign_data(xexpression& e1, const xexpression& e2, bool trivial) + { + E1& de1 = e1.derived_cast(); + const E2& de2 = e2.derived_cast(); + + bool trivial_broadcast = trivial && detail::is_trivial_broadcast(de1, de2); + + if (trivial_broadcast) + { + constexpr bool simd_assign = xassign_traits::simd_assign(); + trivial_assigner::run(de1, de2); + } + else if (xassign_traits::simd_strided_loop()) + { + strided_assign(de1, de2, std::integral_constant::simd_strided_loop()>{}); + } + else + { + data_assigner assigner(de1, de2); + assigner.run(); + } + } + + template + template + inline void xexpression_assigner::assign_xexpression(xexpression& e1, const xexpression& e2) + { + bool trivial_broadcast = resize(e1, e2); + base_type::assign_data(e1, e2, trivial_broadcast); + } + + template + template + inline void xexpression_assigner::computed_assign(xexpression& e1, const xexpression& e2) + { + using shape_type = typename E1::shape_type; + using size_type = typename E1::size_type; + + E1& de1 = e1.derived_cast(); + const E2& de2 = e2.derived_cast(); + + size_type dim = de2.dimension(); + shape_type shape = xtl::make_sequence(dim, size_type(0)); + bool trivial_broadcast = de2.broadcast_shape(shape, true); + + if (dim > de1.dimension() || shape > de1.shape()) + { + typename E1::temporary_type tmp(shape); + base_type::assign_data(tmp, e2, trivial_broadcast); + de1.assign_temporary(std::move(tmp)); + } + else + { + base_type::assign_data(e1, e2, trivial_broadcast); + } + } + + template + template + inline void xexpression_assigner::scalar_computed_assign(xexpression& e1, const E2& e2, F&& f) + { + E1& d = e1.derived_cast(); + using size_type = typename E1::size_type; + auto dst = d.storage().begin(); + for (size_type i = d.size(); i > 0; --i) + { + *dst = f(*dst, e2); + ++dst; + } + } + + template + template + inline void xexpression_assigner::assert_compatible_shape(const xexpression& e1, const xexpression& e2) + { + const E1& de1 = e1.derived_cast(); + const E2& de2 = e2.derived_cast(); + if (!broadcastable(de2.shape(), de1.shape())) + { + throw_broadcast_error(de2.shape(), de1.shape()); + } + } + + template + template + inline bool xexpression_assigner::resize(xexpression& e1, const xexpression& e2) + { + using shape_type = typename E1::shape_type; + using size_type = typename E1::size_type; + const E2& de2 = e2.derived_cast(); + size_type size = de2.dimension(); + shape_type shape = xtl::make_sequence(size, size_type(0)); + bool trivial_broadcast = de2.broadcast_shape(shape, true); + e1.derived_cast().resize(std::move(shape)); + return trivial_broadcast; + } + + /******************************** + * data_assigner implementation * + ********************************/ + + template + inline data_assigner::data_assigner(E1& e1, const E2& e2) + : m_e1(e1), m_lhs(e1.stepper_begin(e1.shape())), + m_rhs(e2.stepper_begin(e1.shape())), + m_index(xtl::make_sequence(e1.shape().size(), size_type(0))) + { + } + + template + inline void data_assigner::run() + { + using size_type = typename E1::size_type; + using argument_type = std::decay_t; + using result_type = std::decay_t; + constexpr bool is_narrowing = is_narrowing_conversion::value; + + size_type s = m_e1.size(); + for (size_type i = 0; i < s; ++i) + { + *m_lhs = conditional_cast(*m_rhs); + stepper_tools::increment_stepper(*this, m_index, m_e1.shape()); + } + } + + template + inline void data_assigner::step(size_type i) + { + m_lhs.step(i); + m_rhs.step(i); + } + + template + inline void data_assigner::step(size_type i, size_type n) + { + m_lhs.step(i, n); + m_rhs.step(i, n); + } + + template + inline void data_assigner::reset(size_type i) + { + m_lhs.reset(i); + m_rhs.reset(i); + } + + template + inline void data_assigner::to_end(layout_type l) + { + m_lhs.to_end(l); + m_rhs.to_end(l); + } + + /*********************************** + * trivial_assigner implementation * + ***********************************/ + + template + template + inline void trivial_assigner::run(E1& e1, const E2& e2) + { + using lhs_align_mode = xsimd::container_alignment_t; + constexpr bool is_aligned = std::is_same::value; + using rhs_align_mode = std::conditional_t; + using value_type = std::common_type_t; + using simd_type = xsimd::simd_type; + using size_type = typename E1::size_type; + size_type size = e1.size(); + size_type simd_size = simd_type::size; + + size_type align_begin = is_aligned ? 0 : xsimd::get_alignment_offset(e1.data(), size, simd_size); + size_type align_end = align_begin + ((size - align_begin) & ~(simd_size - 1)); + + for (size_type i = 0; i < align_begin; ++i) + { + e1.data_element(i) = e2.data_element(i); + } + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } + for (size_type i = align_end; i < size; ++i) + { + e1.data_element(i) = e2.data_element(i); + } + } + + namespace assigner_detail + { + template + inline void assign_loop(It src, Ot dst, std::size_t n) + { + for(; n > 0; --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } + } + + template + inline void trivial_assigner_run_impl(E1& e1, const E2& e2, std::true_type) + { + using size_type = typename E1::size_type; + auto src = e2.storage_cbegin(); + auto dst = e1.storage_begin(); + assign_loop(src, dst, e1.size()); + } + + template + inline void trivial_assigner_run_impl(E1&, const E2&, std::false_type) + { + XTENSOR_PRECONDITION(false, + "Internal error: trivial_assigner called with unrelated types."); + } + } + + template <> + template + inline void trivial_assigner::run(E1& e1, const E2& e2) + { + using is_convertible = std::is_convertible::value_type, + typename std::decay_t::value_type>; + // If the types are not compatible, this function is still instantiated but never called. + // To avoid compilation problems in effectively unused code trivial_assigner_run_impl is + // empty in this case. + assigner_detail::trivial_assigner_run_impl(e1, e2, is_convertible()); + } + + /*********************** + * Strided assign loop * + ***********************/ + + namespace strided_assign_detail + { + template + struct idx_tools; + + template <> + struct idx_tools + { + template + static void next_idx(T& outer_index, T& outer_shape) + { + auto i = outer_index.size(); + for (; i > 0; --i) + { + if (outer_index[i - 1] + 1 >= outer_shape[i - 1]) + { + outer_index[i - 1] = 0; + } + else + { + outer_index[i - 1]++; + break; + } + } + } + }; + + template <> + struct idx_tools + { + template + static void next_idx(T& outer_index, T& outer_shape) + { + using size_type = typename T::size_type; + size_type i = 0; + auto sz = outer_index.size(); + for (; i < sz; ++i) + { + if (outer_index[i] + 1 >= outer_shape[i]) + { + outer_index[i] = 0; + } + else + { + outer_index[i]++; + break; + } + } + } + }; + + template + struct check_strides_functor + { + using strides_type = S; + + check_strides_functor(const S& strides) + : m_cut(L == layout_type::row_major ? 0 : strides.size()), + m_strides(strides) + { + } + + template + std::enable_if_t + operator()(const T& el) + { + auto var = check_strides_overlap::get(m_strides, el.strides()); + if (var > m_cut) + { + m_cut = var; + } + return m_cut; + } + + template + std::enable_if_t + operator()(const T& el) + { + auto var = check_strides_overlap::get(m_strides, el.strides()); + if (var < m_cut) + { + m_cut = var; + } + return m_cut; + } + + template + std::size_t operator()(const xt::xscalar& /*el*/) + { + return m_cut; + } + + template + std::size_t operator()(const xt::xfunction& xf) + { + xt::for_each(*this, xf.arguments()); + return m_cut; + } + + private: + + std::size_t m_cut; + const strides_type& m_strides; + }; + + template + auto get_loop_sizes(const E1& e1, const E2& e2) + { + std::size_t cut = 0; + + // TODO! if E1 is !contigous --> initialize cut to sensible value! + if (e1.strides().back() == 1) + { + auto csf = check_strides_functor(e1.strides()); + cut = csf(e2); + } + else if (e1.strides().front() == 1) + { + auto csf = check_strides_functor(e1.strides()); + cut = csf(e2); + } + + using shape_value_type = typename E1::shape_type::value_type; + std::size_t outer_loop_size = static_cast( + std::accumulate(e1.shape().begin(), e1.shape().begin() + static_cast(cut), + shape_value_type(1), std::multiplies{})); + std::size_t inner_loop_size = static_cast( + std::accumulate(e1.shape().begin() + static_cast(cut), e1.shape().end(), + shape_value_type(1), std::multiplies{})); + + if (e1.strides().back() != 1) // column major mode + { + std::swap(outer_loop_size, inner_loop_size); + } + + return std::make_tuple(inner_loop_size, outer_loop_size, cut); + } + } + + template + void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/) + { + bool fallback = false, is_row_major = true; + + std::size_t inner_loop_size, outer_loop_size, cut; + std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2); + + if (E1::static_layout == layout_type::row_major || e1.strides().back() == 1) // row major case + { + if (cut == e1.dimension()) + { + fallback = true; + } + } + else if (E1::static_layout == layout_type::column_major || e1.strides().front() == 1) // col major case + { + is_row_major = false; + if (cut == 0) + { + fallback = true; + } + } + else + { + fallback = true; + } + + if (fallback) + { + data_assigner assigner(e1, e2); + assigner.run(); + return; + } + + // TODO can we get rid of this and use `shape_type`? + dynamic_shape idx; + + using iterator_type = decltype(e1.shape().begin()); + iterator_type max_shape_begin, max_shape_end; + if (is_row_major) + { + xt::resize_container(idx, cut); + max_shape_begin = e1.shape().begin(); + max_shape_end = e1.shape().begin() + static_cast(cut); + } + else + { + xt::resize_container(idx, e1.shape().size() - cut); + max_shape_begin = e1.shape().begin() + static_cast(cut); + max_shape_end = e1.shape().end(); + } + + // add this when we have std::array index! + // std::fill(idx.begin(), idx.end(), 0); + + dynamic_shape max(max_shape_begin, max_shape_end); + + using simd_type = xsimd::simd_type; + + std::size_t simd_size = inner_loop_size / simd_type::size; + std::size_t simd_rest = inner_loop_size % simd_type::size; + + auto fct_stepper = e2.stepper_begin(e1.shape()); + auto res_stepper = e1.stepper_begin(e1.shape()); + + // TODO in 1D case this is ambigous -- could be RM or CM. + // Use default layout to make decision + std::size_t step_dim = 0; + if (!is_row_major) // row major case + { + step_dim = cut; + } + + for (std::size_t ox = 0; ox < outer_loop_size; ++ox) + { + for (std::size_t i = 0; i < simd_size; i++) + { + res_stepper.template store_simd(fct_stepper.template step_simd()); + } + for (std::size_t i = 0; i < simd_rest; ++i) + { + *(res_stepper) = *(fct_stepper); + res_stepper.step_leading(); + fct_stepper.step_leading(); + } + + is_row_major ? + strided_assign_detail::idx_tools::next_idx(idx, max) : + strided_assign_detail::idx_tools::next_idx(idx, max); + + fct_stepper.to_begin(); + + // need to step E1 as well if not contigous assign (e.g. view) + if (!E1::contiguous_layout) + { + res_stepper.to_begin(); + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + res_stepper.step(i + step_dim, idx[i]); + } + } + else + { + for (std::size_t i = 0; i < idx.size(); ++i) + { + fct_stepper.step(i + step_dim, idx[i]); + } + } + } + } + + template + inline void strided_assign(E1& /*e1*/, const E2& /*e2*/, std::false_type /*disable*/) + { + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp new file mode 100644 index 0000000000..e544791b82 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp @@ -0,0 +1,197 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_AXIS_ITERATOR_HPP +#define XTENSOR_AXIS_ITERATOR_HPP + +#include + +#include "xview.hpp" + +namespace xt +{ + + /****************** + * xaxis_iterator * + ******************/ + + template + class xaxis_iterator + { + public: + + using self_type = xaxis_iterator; + + using xexpression_type = std::decay_t; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + using value_type = xview; + using reference = std::remove_reference_t>; + using pointer = xtl::xclosure_pointer>>; + + using iterator_category = std::forward_iterator_tag; + + xaxis_iterator(); + template + xaxis_iterator(CTA&& e, size_type index); + + self_type& operator++(); + self_type operator++(int); + + reference operator*() const; + pointer operator->() const; + + bool equal(const self_type& rhs) const; + + private: + + using storing_type = xtl::ptr_closure_type_t; + mutable storing_type p_expression; + size_type m_index; + + template + std::enable_if_t::value, std::add_lvalue_reference_t>> + deref(T val) const; + + template + std::enable_if_t::value, T> + deref(T& val) const; + + template + std::enable_if_t::value, T> + get_storage_init(CTA&& e) const; + + template + std::enable_if_t::value, T> + get_storage_init(CTA&& e) const; + }; + + template + bool operator==(const xaxis_iterator& lhs, const xaxis_iterator& rhs); + + template + bool operator!=(const xaxis_iterator& lhs, const xaxis_iterator& rhs); + + template + auto axis_begin(E&& e); + + template + auto axis_end(E&& e); + + /********************************* + * xaxis_iterator implementation * + *********************************/ + + template + template + inline std::enable_if_t::value, std::add_lvalue_reference_t>> + xaxis_iterator::deref(T val) const + { + return *val; + } + + template + template + inline std::enable_if_t::value, T> + xaxis_iterator::deref(T& val) const + { + return val; + } + + template + template + inline std::enable_if_t::value, T> + xaxis_iterator::get_storage_init(CTA&& e) const + { + return &e; + } + + template + template + inline std::enable_if_t::value, T> + xaxis_iterator::get_storage_init(CTA&& e) const + { + return e; + } + + template + inline xaxis_iterator::xaxis_iterator() + : p_expression(nullptr), m_index(0) + { + } + + template + template + inline xaxis_iterator::xaxis_iterator(CTA&& e, size_type index) + : p_expression(get_storage_init(std::forward(e))), m_index(index) + { + } + + template + inline auto xaxis_iterator::operator++() -> self_type& + { + ++m_index; + return *this; + } + + template + inline auto xaxis_iterator::operator++(int) -> self_type + { + self_type tmp(*this); + ++(*this); + return tmp; + } + + template + inline auto xaxis_iterator::operator*() const -> reference + { + return view(deref(p_expression), size_type(m_index)); + } + + template + inline auto xaxis_iterator::operator->() const -> pointer + { + return xtl::closure_pointer(operator*()); + } + + template + inline bool xaxis_iterator::equal(const self_type& rhs) const + { + return p_expression == rhs.p_expression && m_index == rhs.m_index; + } + + template + inline bool operator==(const xaxis_iterator& lhs, const xaxis_iterator& rhs) + { + return lhs.equal(rhs); + } + + template + inline bool operator!=(const xaxis_iterator& lhs, const xaxis_iterator& rhs) + { + return !(lhs == rhs); + } + + template + inline auto axis_begin(E&& e) + { + using return_type = xaxis_iterator>; + using size_type = typename std::decay_t::size_type; + return return_type(std::forward(e), size_type(0)); + } + + template + inline auto axis_end(E&& e) + { + using return_type = xaxis_iterator>; + using size_type = typename std::decay_t::size_type; + return return_type(std::forward(e), size_type(e.shape()[0])); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xbroadcast.hpp b/vendor/xtensor/include/xtensor/xbroadcast.hpp new file mode 100644 index 0000000000..77c04f0416 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xbroadcast.hpp @@ -0,0 +1,412 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_BROADCAST_HPP +#define XTENSOR_BROADCAST_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xscalar.hpp" +#include "xstrides.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /************* + * broadcast * + *************/ + + template + auto broadcast(E&& e, const S& s); + +#ifdef X_OLD_CLANG + template + auto broadcast(E&& e, std::initializer_list s); +#else + template + auto broadcast(E&& e, const I (&s)[L]); +#endif + + /************** + * xbroadcast * + **************/ + + template + class xbroadcast; + + template + struct xiterable_inner_types> + { + using xexpression_type = std::decay_t; + using inner_shape_type = promote_shape_t; + using const_stepper = typename xexpression_type::const_stepper; + using stepper = const_stepper; + }; + + /** + * @class xbroadcast + * @brief Broadcasted xexpression to a specified shape. + * + * The xbroadcast class implements the broadcasting of an \ref xexpression + * to a specified shape. xbroadcast is not meant to be used directly, but + * only with the \ref broadcast helper functions. + * + * @tparam CT the closure type of the \ref xexpression to broadcast + * @tparam X the type of the specified shape. + * + * @sa broadcast + */ + template + class xbroadcast : public xexpression>, + public xconst_iterable> + { + public: + + using self_type = xbroadcast; + using xexpression_type = std::decay_t; + + using value_type = typename xexpression_type::value_type; + using reference = typename xexpression_type::reference; + using const_reference = typename xexpression_type::const_reference; + using pointer = typename xexpression_type::pointer; + using const_pointer = typename xexpression_type::const_pointer; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + + using iterable_base = xconst_iterable; + using inner_shape_type = typename iterable_base::inner_shape_type; + using shape_type = inner_shape_type; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + static constexpr layout_type static_layout = xexpression_type::static_layout; + //static constexpr bool contiguous_layout = xexpression_type::contiguous_layout; + static constexpr bool contiguous_layout = false; + + template + xbroadcast(CTA&& e, S&& s); + + size_type size() const noexcept; + size_type dimension() const noexcept; + const inner_shape_type& shape() const noexcept; + layout_type layout() const noexcept; + + template + const_reference operator()(Args... args) const; + + template + const_reference at(Args... args) const; + + template + const_reference unchecked(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + template ::value>> + void assign_to(xexpression& e) const; + + private: + + CT m_e; + inner_shape_type m_shape; + }; + + /**************************** + * broadcast implementation * + ****************************/ + + /** + * @brief Returns an \ref xexpression broadcasting the given expression to + * a specified shape. + * + * @tparam e the \ref xexpression to broadcast + * @tparam s the specified shape to broadcast. + * + * The returned expression either hold a const reference to \p e or a copy + * depending on whether \p e is an lvalue or an rvalue. + */ + template + inline auto broadcast(E&& e, const S& s) + { + using broadcast_type = xbroadcast, S>; + using shape_type = typename broadcast_type::shape_type; + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + } + +#ifdef X_OLD_CLANG + template + inline auto broadcast(E&& e, std::initializer_list s) + { + using broadcast_type = xbroadcast, std::vector>; + using shape_type = typename broadcast_type::shape_type; + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + } +#else + template + inline auto broadcast(E&& e, const I (&s)[L]) + { + using broadcast_type = xbroadcast, std::array>; + using shape_type = typename broadcast_type::shape_type; + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + } +#endif + + /***************************** + * xbroadcast implementation * + *****************************/ + + /** + * @name Constructor + */ + //@{ + /** + * Constructs an xbroadcast expression broadcasting the specified + * \ref xexpression to the given shape + * + * @param e the expression to broadcast + * @param s the shape to apply + */ + template + template + inline xbroadcast::xbroadcast(CTA&& e, S&& s) + : m_e(std::forward(e)), m_shape(std::forward(s)) + { + xt::broadcast_shape(m_e.shape(), m_shape); + } + //@} + + /** + * @name Size and shape + */ + /** + * Returns the size of the expression. + */ + template + inline auto xbroadcast::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xbroadcast::dimension() const noexcept -> size_type + { + return m_shape.size(); + } + + /** + * Returns the shape of the expression. + */ + template + inline auto xbroadcast::shape() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + /** + * Returns the layout_type of the expression. + */ + template + inline layout_type xbroadcast::layout() const noexcept + { + return m_e.layout(); + } + //@} + + /** + * @name Data + */ + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the expression. + */ + template + template + inline auto xbroadcast::operator()(Args... args) const -> const_reference + { + return m_e(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xbroadcast::at(Args... args) const -> const_reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the expression, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xbroadcast::unchecked(Args... args) const -> const_reference + { + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices in the sequence should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xbroadcast::operator[](const S& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xbroadcast::operator[](std::initializer_list index) const -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xbroadcast::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the function. + */ + template + template + inline auto xbroadcast::element(It, It last) const -> const_reference + { + return m_e.element(last - dimension(), last); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the function to the specified parameter. + * @param shape the result shape + * @param reuse_cache parameter for internal optimization + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xbroadcast::broadcast_shape(S& shape, bool) const + { + return xt::broadcast_shape(m_shape, shape); + } + + /** + * Compares the specified strides with those of the container to see whether + * the broadcasting is trivial. + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xbroadcast::is_trivial_broadcast(const S& strides) const noexcept + { + return dimension() == m_e.dimension() && + std::equal(m_shape.cbegin(), m_shape.cend(), m_e.shape().cbegin()) && + m_e.is_trivial_broadcast(strides); + } + //@} + + template + template + inline auto xbroadcast::stepper_begin(const S& shape) const noexcept -> const_stepper + { + // Could check if (broadcastable(shape, m_shape) + return m_e.stepper_begin(shape); + } + + template + template + inline auto xbroadcast::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + // Could check if (broadcastable(shape, m_shape) + return m_e.stepper_end(shape, l); + } + + template + template + inline void xbroadcast::assign_to(xexpression& e) const + { + auto& ed = e.derived_cast(); + ed.resize(m_shape); + std::fill(ed.begin(), ed.end(), m_e()); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp new file mode 100644 index 0000000000..d8d3316859 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp @@ -0,0 +1,623 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_BUFFER_ADAPTOR_HPP +#define XTENSOR_BUFFER_ADAPTOR_HPP + +#include +#include +#include +#include +#include + +#include + +#include "xstorage.hpp" + +namespace xt +{ + /****************************** + * xbuffer_adator declaration * + ******************************/ + + struct no_ownership + { + }; + + struct acquire_ownership + { + }; + + template >>> + class xbuffer_adaptor; + + /********************************* + * xbuffer_adator implementation * + *********************************/ + + namespace detail + { + template + class xbuffer_storage + { + public: + + using self_type = xbuffer_storage; + using allocator_type = A; + using value_type = typename allocator_type::value_type; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_storage(); + + template + xbuffer_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + pointer p_data; + size_type m_size; + }; + + template + class xbuffer_owner_storage + { + public: + + using self_type = xbuffer_owner_storage; + using allocator_type = A; + using value_type = typename allocator_type::value_type; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_owner_storage() = default; + + template + xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + + ~xbuffer_owner_storage(); + + xbuffer_owner_storage(const self_type&) = delete; + self_type& operator=(const self_type&); + + xbuffer_owner_storage(self_type&&); + self_type& operator=(self_type&&); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + allocator_type get_allocator() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + xtl::xclosure_wrapper m_data; + size_type m_size; + bool m_moved_from; + allocator_type m_allocator; + }; + + template + struct get_buffer_storage + { + using type = xbuffer_storage; + }; + + template + struct get_buffer_storage + { + using type = xbuffer_owner_storage; + }; + + template + using buffer_storage_t = typename get_buffer_storage::type; + } + + template + class xbuffer_adaptor : private detail::buffer_storage_t + { + public: + + using base_type = detail::buffer_storage_t; + using self_type = xbuffer_adaptor; + using allocator_type = typename base_type::allocator_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using temporary_type = uvector; + + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + + using iterator = pointer; + using const_iterator = const_pointer; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + xbuffer_adaptor() = default; + + template + xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + + ~xbuffer_adaptor() = default; + + xbuffer_adaptor(const self_type&) = default; + self_type& operator=(const self_type&) = default; + + xbuffer_adaptor(self_type&&) = default; + xbuffer_adaptor& operator=(self_type&&) = default; + + self_type& operator=(temporary_type&&); + + bool empty() const noexcept; + using base_type::size; + using base_type::resize; + + reference operator[](size_type i); + const_reference operator[](size_type i) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + iterator begin(); + iterator end(); + + const_iterator begin() const; + const_iterator end() const; + const_iterator cbegin() const; + const_iterator cend() const; + + reverse_iterator rbegin(); + reverse_iterator rend(); + + const_reverse_iterator rbegin() const; + const_reverse_iterator rend() const; + const_reverse_iterator crbegin() const; + const_reverse_iterator crend() const; + + using base_type::data; + using base_type::swap; + }; + + template + bool operator==(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator!=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator<(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator<=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator>(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + bool operator>=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs); + + template + void swap(xbuffer_adaptor& lhs, + xbuffer_adaptor& rhs) noexcept; + + /************************************ + * temporary_container metafunction * + ************************************/ + + template + struct temporary_container + { + using type = C; + }; + + template + struct temporary_container> + { + using type = typename xbuffer_adaptor::temporary_type; + }; + + template + using temporary_container_t = typename temporary_container::type; + + /********************************** + * xbuffer_storage implementation * + **********************************/ + + namespace detail + { + template + inline xbuffer_storage::xbuffer_storage() + : p_data(nullptr), m_size(0) + { + } + + template + template + inline xbuffer_storage::xbuffer_storage(P&& data, size_type size, const allocator_type&) + : p_data(std::forward

(data)), m_size(size) + { + } + + template + inline auto xbuffer_storage::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xbuffer_storage::resize(size_type size) + { + if (size != m_size) + { + throw std::runtime_error("xbuffer_storage not resizable"); + } + } + + template + inline auto xbuffer_storage::data() noexcept -> pointer + { + return p_data; + } + + template + inline auto xbuffer_storage::data() const noexcept -> const_pointer + { + return p_data; + } + + template + inline void xbuffer_storage::swap(self_type& rhs) noexcept + { + using std::swap; + swap(p_data, rhs.p_data); + swap(m_size, rhs.m_size); + } + } + + /**************************************** + * xbuffer_owner_storage implementation * + ****************************************/ + + namespace detail + { + template + template + inline xbuffer_owner_storage::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc) + : m_data(std::forward

(data)), m_size(size), m_moved_from(false), m_allocator(alloc) + { + } + + template + inline xbuffer_owner_storage::~xbuffer_owner_storage() + { + if (!m_moved_from) + { + safe_destroy_deallocate(m_allocator, m_data.get(), m_size); + m_size = 0; + } + } + + template + inline auto xbuffer_owner_storage::operator=(const self_type& rhs) -> self_type& + { + using std::swap; + if (this != &rhs) + { + allocator_type al = std::allocator_traits::select_on_container_copy_construction(rhs.get_allocator()); + pointer tmp = safe_init_allocate(al, rhs.m_size); + if (xtrivially_default_constructible::value) + { + std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); + } + else + { + std::copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp); + } + swap(m_data.get(), tmp); + m_size = rhs.m_size; + swap(m_allocator, al); + safe_destroy_deallocate(al, tmp, m_size); + } + return *this; + } + + template + inline xbuffer_owner_storage::xbuffer_owner_storage(self_type&& rhs) + : m_data(std::move(rhs.m_data)), m_size(std::move(rhs.m_size)), m_moved_from(std::move(rhs.m_moved_from)), m_allocator(std::move(rhs.m_allocator)) + { + rhs.m_moved_from = true; + rhs.m_size = 0; + } + + template + inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& + { + swap(rhs); + rhs.m_moved_from = true; + return *this; + } + + template + inline auto xbuffer_owner_storage::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_owner_storage::resize(size_type size) + { + using std::swap; + if (size != m_size) + { + pointer tmp = safe_init_allocate(m_allocator, size); + swap(m_data.get(), tmp); + swap(m_size, size); + safe_destroy_deallocate(m_allocator, tmp, size); + } + } + + template + inline auto xbuffer_owner_storage::data() noexcept -> pointer + { + return m_data.get(); + } + + template + inline auto xbuffer_owner_storage::data() const noexcept -> const_pointer + { + return m_data.get(); + } + + template + inline auto xbuffer_owner_storage::get_allocator() const noexcept -> allocator_type + { + return allocator_type(m_allocator); + } + + template + inline void xbuffer_owner_storage::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_data, rhs.m_data); + swap(m_size, rhs.m_size); + swap(m_allocator, rhs.m_allocator); + } + } + + /********************************** + * xbuffer_adaptor implementation * + **********************************/ + + template + template + inline xbuffer_adaptor::xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc) + : base_type(std::forward

(data), size, alloc) + { + } + + template + inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& + { + base_type::resize(tmp.size()); + std::copy(tmp.cbegin(), tmp.cend(), begin()); + return *this; + } + + template + bool xbuffer_adaptor::empty() const noexcept + { + return size() == 0; + } + + template + inline auto xbuffer_adaptor::operator[](size_type i) -> reference + { + return data()[i]; + } + + template + inline auto xbuffer_adaptor::operator[](size_type i) const -> const_reference + { + return data()[i]; + } + + template + inline auto xbuffer_adaptor::front() -> reference + { + return data()[0]; + } + + template + inline auto xbuffer_adaptor::front() const -> const_reference + { + return data()[0]; + } + + template + inline auto xbuffer_adaptor::back() -> reference + { + return data()[size() - 1]; + } + + template + inline auto xbuffer_adaptor::back() const -> const_reference + { + return data()[size() - 1]; + } + + template + inline auto xbuffer_adaptor::begin() -> iterator + { + return data(); + } + + template + inline auto xbuffer_adaptor::end() -> iterator + { + return data() + size(); + } + + template + inline auto xbuffer_adaptor::begin() const -> const_iterator + { + return data(); + } + + template + inline auto xbuffer_adaptor::end() const -> const_iterator + { + return data() + size(); + } + + template + inline auto xbuffer_adaptor::cbegin() const -> const_iterator + { + return begin(); + } + + template + inline auto xbuffer_adaptor::cend() const -> const_iterator + { + return end(); + } + + template + inline auto xbuffer_adaptor::rbegin() -> reverse_iterator + { + return reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor::rend() -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor::rbegin() const -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor::rend() const -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor::crbegin() const -> const_reverse_iterator + { + return rbegin(); + } + + template + inline auto xbuffer_adaptor::crend() const -> const_reverse_iterator + { + return rend(); + } + + template + inline bool operator==(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + inline bool operator!=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less()); + } + + template + inline bool operator<=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less_equal()); + } + + template + inline bool operator>(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater()); + } + + template + inline bool operator>=(const xbuffer_adaptor& lhs, + const xbuffer_adaptor& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater_equal()); + } + + template + inline void swap(xbuffer_adaptor& lhs, + xbuffer_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xbuilder.hpp b/vendor/xtensor/include/xtensor/xbuilder.hpp new file mode 100644 index 0000000000..c3e34b8ac3 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xbuilder.hpp @@ -0,0 +1,918 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +/** + * @brief standard mathematical functions for xexpressions + */ + +#ifndef XTENSOR_BUILDER_HPP +#define XTENSOR_BUILDER_HPP + +#include +#include +#include +#include +#include +#include +#ifdef X_OLD_CLANG + #include +#endif + +#include +#include + +#include "xbroadcast.hpp" +#include "xfunction.hpp" +#include "xgenerator.hpp" +#include "xoperation.hpp" + +namespace xt +{ + + /******** + * ones * + ********/ + + /** + * Returns an \ref xexpression containing ones of the specified shape. + * @tparam shape the shape of the returned expression. + */ + template + inline auto ones(S shape) noexcept + { + return broadcast(T(1), std::forward(shape)); + } + +#ifdef X_OLD_CLANG + template + inline auto ones(std::initializer_list shape) noexcept + { + return broadcast(T(1), shape); + } +#else + template + inline auto ones(const I (&shape)[L]) noexcept + { + return broadcast(T(1), shape); + } +#endif + + /********* + * zeros * + *********/ + + /** + * Returns an \ref xexpression containing zeros of the specified shape. + * @tparam shape the shape of the returned expression. + */ + template + inline auto zeros(S shape) noexcept + { + return broadcast(T(0), std::forward(shape)); + } + +#ifdef X_OLD_CLANG + template + inline auto zeros(std::initializer_list shape) noexcept + { + return broadcast(T(0), shape); + } +#else + template + inline auto zeros(const I (&shape)[L]) noexcept + { + return broadcast(T(0), shape); + } +#endif + + /** + * Create a xcontainer (xarray, xtensor or xtensor_fixed) with uninitialized values of + * with value_type T and shape. Selects the best container match automatically + * from the supplied shape. + * + * - ``std::vector`` → ``xarray`` + * - ``std::array`` or ``initializer_list`` → ``xtensor`` + * - ``xshape`` → ``xtensor_fixed>`` + * + * @param shape shape of the new xcontainer + */ + template + inline xarray empty(const S& shape) + { + return xarray::from_shape(shape); + } + + template + inline xtensor empty(const std::array& shape) + { + using shape_type = typename xtensor::shape_type; + return xtensor(xtl::forward_sequence(shape)); + } + +#ifndef X_OLD_CLANG + template + inline xtensor empty(const I(&shape)[N]) + { + using shape_type = typename xtensor::shape_type; + return xtensor(xtl::forward_sequence(shape)); + } +#endif + + template + inline xtensor_fixed, L> empty(const fixed_shape& /*shape*/) + { + return xtensor_fixed, L>(); + } + + /** + * Create a xcontainer (xarray, xtensor or xtensor_fixed) with uninitialized values of + * the same shape, value type and layout as the input xexpression *e*. + * + * @param e the xexpression from which to extract shape, value type and layout. + */ + template + inline typename E::temporary_type empty_like(const xexpression& e) + { + typename E::temporary_type res(e.derived_cast().shape()); + return res; + } + + /** + * Create a xcontainer (xarray, xtensor or xtensor_fixed), filled with *fill_value* and of + * the same shape, value type and layout as the input xexpression *e*. + * + * @param e the xexpression from which to extract shape, value type and layout. + * @param fill_value the value used to set each element of the returned xcontainer. + */ + template + inline typename E::temporary_type full_like(const xexpression& e, typename E::value_type fill_value) + { + typename E::temporary_type res(e.derived_cast().shape(), fill_value); + return res; + } + + /** + * Create a xcontainer (xarray, xtensor or xtensor_fixed), filled with zeros and of + * the same shape, value type and layout as the input xexpression *e*. + * + * Note: contrary to zeros(shape), this function returns a non-lazy, allocated container! + * Use ``xt::zeros(e.shape());` for a lazy version. + * + * @param e the xexpression from which to extract shape, value type and layout. + */ + template + inline typename E::temporary_type zeros_like(const xexpression& e) + { + return full_like(e, typename E::value_type(0)); + } + + /** + * Create a xcontainer (xarray, xtensor or xtensor_fixed), filled with ones and of + * the same shape, value type and layout as the input xexpression *e*. + * + * Note: contrary to ones(shape), this function returns a non-lazy, evaluated container! + * Use ``xt::ones(e.shape());`` for a lazy version. + * + * @param e the xexpression from which to extract shape, value type and layout. + */ + template + inline typename E::temporary_type ones_like(const xexpression& e) + { + return full_like(e, typename E::value_type(1)); + } + + namespace detail + { + template + class arange_impl + { + public: + + using value_type = T; + + arange_impl(T start, T stop, T step) + : m_start(start), m_stop(stop), m_step(step) + { + } + + template + inline T operator()(Args... args) const + { + return access_impl(args...); + } + + template + inline T element(It first, It) const + { + return m_start + m_step * T(*first); + } + + template + inline void assign_to(xexpression& e) const noexcept + { + auto& de = e.derived_cast(); + value_type value = m_start; + + for (auto& el : de.storage()) + { + el = value; + value += m_step; + } + } + + private: + + value_type m_start; + value_type m_stop; + value_type m_step; + + template + inline T access_impl(T1 t, Args...) const + { + return m_start + m_step * T(t); + } + + inline T access_impl() const + { + return m_start; + } + }; + + template + class fn_impl + { + public: + + using value_type = typename F::value_type; + using size_type = std::size_t; + + fn_impl(F&& f) + : m_ft(f) + { + } + + inline value_type operator()() const + { + size_type idx[1] = {0ul}; + return access_impl(std::begin(idx), std::end(idx)); + } + + template + inline value_type operator()(Args... args) const + { + size_type idx[sizeof...(Args)] = {static_cast(args)...}; + return access_impl(std::begin(idx), std::end(idx)); + } + + template + inline value_type element(It first, It last) const + { + return access_impl(first, last); + } + + private: + + F m_ft; + template + inline value_type access_impl(const It& begin, const It& end) const + { + return m_ft(begin, end); + } + }; + + template + class eye_fn + { + public: + + using value_type = T; + + eye_fn(int k) + : m_k(k) + { + } + + template + inline T operator()(const It& /*begin*/, const It& end) const + { + using lvalue_type = typename std::iterator_traits::value_type; + return *(end - 1) == *(end - 2) + static_cast(static_cast(m_k)) ? T(1) : T(0); + } + + private: + + int m_k; + }; + } + + /** + * Generates an array with ones on the diagonal. + * @param shape shape of the resulting expression + * @param k index of the diagonal. 0 (default) refers to the main diagonal, + * a positive value refers to an upper diagonal, and a negative + * value to a lower diagonal. + * @tparam T value_type of xexpression + * @return xgenerator that generates the values on access + */ + template + inline auto eye(const std::vector& shape, int k = 0) + { + return detail::make_xgenerator(detail::fn_impl>(detail::eye_fn(k)), shape); + } + + /** + * Generates a (n x n) array with ones on the diagonal. + * @param n length of the diagonal. + * @param k index of the diagonal. 0 (default) refers to the main diagonal, + * a positive value refers to an upper diagonal, and a negative + * value to a lower diagonal. + * @tparam T value_type of xexpression + * @return xgenerator that generates the values on access + */ + template + inline auto eye(std::size_t n, int k = 0) + { + return eye({n, n}, k); + } + + /** + * Generates numbers evenly spaced within given half-open interval [start, stop). + * @param start start of the interval + * @param stop stop of the interval + * @param step stepsize + * @tparam T value_type of xexpression + * @return xgenerator that generates the values on access + */ + template + inline auto arange(T start, T stop, T step = 1) noexcept + { + std::size_t shape = static_cast(std::ceil((stop - start) / step)); + return detail::make_xgenerator(detail::arange_impl(start, stop, step), {shape}); + } + + /** + * Generate numbers evenly spaced within given half-open interval [0, stop) + * with a step size of 1. + * @param stop stop of the interval + * @tparam T value_type of xexpression + * @return xgenerator that generates the values on access + */ + template + inline auto arange(T stop) noexcept + { + return arange(T(0), stop, T(1)); + } + + /** + * Generates @a num_samples evenly spaced numbers over given interval + * @param start start of interval + * @param stop stop of interval + * @param num_samples number of samples (defaults to 50) + * @param endpoint if true, include endpoint (defaults to true) + * @tparam T value_type of xexpression + * @return xgenerator that generates the values on access + */ + template + inline auto linspace(T start, T stop, std::size_t num_samples = 50, bool endpoint = true) noexcept + { + using fp_type = std::common_type_t; + fp_type step = fp_type(stop - start) / fp_type(num_samples - (endpoint ? 1 : 0)); + return cast(detail::make_xgenerator(detail::arange_impl(fp_type(start), fp_type(stop), step), {num_samples})); + } + + /** + * Generates @a num_samples numbers evenly spaced on a log scale over given interval + * @param start start of interval (pow(base, start) is the first value). + * @param stop stop of interval (pow(base, stop) is the final value, except if endpoint = false) + * @param num_samples number of samples (defaults to 50) + * @param base the base of the log space. + * @param endpoint if true, include endpoint (defaults to true) + * @tparam T value_type of xexpression + * @return xgenerator that generates the values on access + */ + template + inline auto logspace(T start, T stop, std::size_t num_samples, T base = 10, bool endpoint = true) noexcept + { + return cast(pow(std::move(base), linspace(start, stop, num_samples, endpoint))); + } + + namespace detail + { + template + class concatenate_impl + { + public: + + using size_type = std::size_t; + using value_type = promote_type_t::value_type...>; + + inline concatenate_impl(std::tuple&& t, size_type axis) + : m_t(t), m_axis(axis) + { + } + + template + inline value_type operator()(Args... args) const + { + // TODO: avoid memory allocation + return access_impl(xindex({static_cast(args)...})); + } + + template + inline value_type element(It first, It last) const + { + // TODO: avoid memory allocation + return access_impl(xindex(first, last)); + } + + private: + + inline value_type access_impl(xindex idx) const + { + auto match = [this, &idx](auto& arr) { + if (idx[this->m_axis] >= arr.shape()[this->m_axis]) + { + idx[this->m_axis] -= arr.shape()[this->m_axis]; + return false; + } + return true; + }; + + auto get = [&idx](auto& arr) { + return arr[idx]; + }; + + size_type i = 0; + for (; i < sizeof...(CT); ++i) + { + if (apply(i, match, m_t)) + { + break; + } + } + return apply(i, get, m_t); + } + + std::tuple m_t; + size_type m_axis; + }; + + template + class stack_impl + { + public: + + using size_type = std::size_t; + using value_type = promote_type_t::value_type...>; + + inline stack_impl(std::tuple&& t, size_type axis) + : m_t(t), m_axis(axis) + { + } + + template + inline value_type operator()(Args... args) const + { + // TODO: avoid memory allocation + return access_impl(xindex({static_cast(args)...})); + } + + template + inline value_type element(It first, It last) const + { + // TODO: avoid memory allocation + return access_impl(xindex(first, last)); + } + + private: + + inline value_type access_impl(xindex idx) const + { + auto get_item = [&idx](auto& arr) { + return arr[idx]; + }; + size_type i = idx[m_axis]; + idx.erase(idx.begin() + std::ptrdiff_t(m_axis)); + return apply(i, get_item, m_t); + } + + const std::tuple m_t; + const size_type m_axis; + }; + + template + class repeat_impl + { + public: + + using xexpression_type = std::decay_t; + using size_type = typename xexpression_type::size_type; + using value_type = typename xexpression_type::value_type; + + template + repeat_impl(CTA&& source, size_type axis) + : m_source(std::forward(source)), m_axis(axis) + { + } + + template + value_type operator()(Args... args) const + { + std::array args_arr = {static_cast(args)...}; + return m_source(args_arr[m_axis]); + } + + template + inline value_type element(It first, It) const + { + return m_source(*(first + static_cast(m_axis))); + } + + private: + + CT m_source; + size_type m_axis; + }; + } + + /** + * @brief Creates tuples from arguments for \ref concatenate and \ref stack. + * Very similar to std::make_tuple. + */ + template + inline auto xtuple(Types&&... args) + { + return std::tuple...>(std::forward(args)...); + } + + /** + * @brief Concatenates xexpressions along \em axis. + * + * @param t \ref xtuple of xexpressions to concatenate + * @param axis axis along which elements are concatenated + * @returns xgenerator evaluating to concatenated elements + * + * \code{.cpp} + * xt::xarray a = {{1, 2, 3}}; + * xt::xarray b = {{2, 3, 4}}; + * xt::xarray c = xt::concatenate(xt::xtuple(a, b)); // => {{1, 2, 3}, + * {2, 3, 4}} + * xt::xarray d = xt::concatenate(xt::xtuple(a, b), 1); // => {{1, 2, 3, 2, 3, 4}} + * \endcode + */ + template + inline auto concatenate(std::tuple&& t, std::size_t axis = 0) + { + using shape_type = promote_shape_t::shape_type...>; + shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + auto shape_at_axis = [&axis](std::size_t prev, auto& arr) -> std::size_t { + return prev + arr.shape()[axis]; + }; + new_shape[axis] += accumulate(shape_at_axis, std::size_t(0), t) - new_shape[axis]; + return detail::make_xgenerator(detail::concatenate_impl(std::forward>(t), axis), new_shape); + } + + namespace detail + { + template + inline std::array add_axis(std::array arr, std::size_t axis, std::size_t value) + { + std::array temp; + std::copy(arr.begin(), arr.begin() + axis, temp.begin()); + temp[axis] = value; + std::copy(arr.begin() + axis, arr.end(), temp.begin() + axis + 1); + return temp; + } + + template + inline T add_axis(T arr, std::size_t axis, std::size_t value) + { + T temp(arr); + temp.insert(temp.begin() + std::ptrdiff_t(axis), value); + return temp; + } + } + + /** + * @brief Stack xexpressions along \em axis. + * Stacking always creates a new dimension along which elements are stacked. + * + * @param t \ref xtuple of xexpressions to concatenate + * @param axis axis along which elements are stacked + * @returns xgenerator evaluating to stacked elements + * + * \code{.cpp} + * xt::xarray a = {1, 2, 3}; + * xt::xarray b = {5, 6, 7}; + * xt::xarray s = xt::stack(xt::xtuple(a, b)); // => {{1, 2, 3}, + * {5, 6, 7}} + * xt::xarray t = xt::stack(xt::xtuple(a, b), 1); // => {{1, 5}, + * {2, 6}, + * {3, 7}} + * \endcode + */ + template + inline auto stack(std::tuple&& t, std::size_t axis = 0) + { + using shape_type = promote_shape_t::shape_type...>; + auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); + return detail::make_xgenerator(detail::stack_impl(std::forward>(t), axis), new_shape); + } + + namespace detail + { + + template + inline auto meshgrid_impl(std::index_sequence, E&&... e) noexcept + { +#if defined X_OLD_CLANG || defined _MSC_VER + const std::array shape = {e.shape()[0]...}; + return std::make_tuple( + detail::make_xgenerator( + detail::repeat_impl>(std::forward(e), I), + shape + )... + ); +#else + return std::make_tuple( + detail::make_xgenerator( + detail::repeat_impl>(std::forward(e), I), + {e.shape()[0]...} + )... + ); +#endif + } + } + + /** + * @brief Return coordinate tensors from coordinate vectors. + * Make N-D coordinate tensor expressions for vectorized evaluations of N-D scalar/vector + * fields over N-D grids, given one-dimensional coordinate arrays x1, x2,..., xn. + * + * @param e xexpressions to concatenate + * @returns tuple of xgenerator expressions. + */ + template + inline auto meshgrid(E&&... e) noexcept + { + return detail::meshgrid_impl(std::make_index_sequence(), std::forward(e)...); + } + + namespace detail + { + template + class diagonal_fn + { + public: + + using xexpression_type = std::decay_t; + using value_type = typename xexpression_type::value_type; + + template + diagonal_fn(CTA&& source, int offset, std::size_t axis_1, std::size_t axis_2) + : m_source(std::forward(source)), m_offset(offset), m_axis_1(axis_1), m_axis_2(axis_2) + { + } + + template + inline value_type operator()(It begin, It) const + { + xindex idx(m_source.shape().size()); + + for (std::size_t i = 0; i < idx.size(); i++) + { + if (i != m_axis_1 && i != m_axis_2) + { + idx[i] = *begin++; + } + } + using it_vtype = typename std::iterator_traits::value_type; + it_vtype uoffset = static_cast(m_offset); + if (m_offset >= 0) + { + idx[m_axis_1] = *(begin); + idx[m_axis_2] = *(begin) + uoffset; + } + else + { + idx[m_axis_1] = *(begin) - uoffset; + idx[m_axis_2] = *(begin); + } + return m_source[idx]; + } + + private: + + CT m_source; + const int m_offset; + const std::size_t m_axis_1; + const std::size_t m_axis_2; + }; + + template + class diag_fn + { + public: + + using xexpression_type = std::decay_t; + using value_type = typename xexpression_type::value_type; + + template + diag_fn(CTA&& source, int k) + : m_source(std::forward(source)), m_k(k) + { + } + + template + inline value_type operator()(It begin, It) const + { + using it_vtype = typename std::iterator_traits::value_type; + it_vtype umk = static_cast(m_k); + if (m_k > 0) + { + return *begin + umk == *(begin + 1) ? m_source(*begin) : value_type(0); + } + else + { + return *begin + umk == *(begin + 1) ? m_source(*begin + umk) : value_type(0); + } + } + + private: + + CT m_source; + const int m_k; + }; + + template + class trilu_fn + { + public: + + using xexpression_type = std::decay_t; + using value_type = typename xexpression_type::value_type; + using signed_idx_type = long int; + + template + trilu_fn(CTA&& source, int k, Comp comp) + : m_source(std::forward(source)), m_k(k), m_comp(comp) + { + } + + template + inline value_type operator()(It begin, It end) const + { + // have to cast to signed int otherwise -1 can lead to overflow + return m_comp(signed_idx_type(*begin) + m_k, signed_idx_type(*(begin + 1))) ? m_source.element(begin, end) : value_type(0); + } + + private: + + CT m_source; + const signed_idx_type m_k; + const Comp m_comp; + }; + } + + namespace detail + { + // meta-function returning the shape type for a diagonal + template + struct diagonal_shape_type + { + using type = ST; + }; + + template + struct diagonal_shape_type> + { + using type = std::array; + }; + } + + /** + * @brief Returns the elements on the diagonal of arr + * If arr has more than two dimensions, then the axes specified by + * axis_1 and axis_2 are used to determine the 2-D sub-array whose + * diagonal is returned. The shape of the resulting array can be + * determined by removing axis1 and axis2 and appending an index + * to the right equal to the size of the resulting diagonals. + * + * @param arr the input array + * @param offset offset of the diagonal from the main diagonal. Can + * be positive or negative. + * @param axis_1 Axis to be used as the first axis of the 2-D sub-arrays + * from which the diagonals should be taken. + * @param axis_2 Axis to be used as the second axis of the 2-D sub-arrays + * from which the diagonals should be taken. + * @returns xexpression with values of the diagonal + * + * \code{.cpp} + * xt::xarray a = {{1, 2, 3}, + * {4, 5, 6} + * {7, 8, 9}}; + * auto b = xt::diagonal(a); // => {1, 5, 9} + * \endcode + */ + template + inline auto diagonal(E&& arr, int offset = 0, std::size_t axis_1 = 0, std::size_t axis_2 = 1) + { + using CT = xclosure_t; + using shape_type = typename detail::diagonal_shape_type::shape_type>::type; + + auto shape = arr.shape(); + auto dimension = arr.dimension(); + + // The following shape calculation code is an almost verbatim adaptation of numpy: + // https://github.com/numpy/numpy/blob/2aabeafb97bea4e1bfa29d946fbf31e1104e7ae0/numpy/core/src/multiarray/item_selection.c#L1799 + auto ret_shape = xtl::make_sequence(dimension - 1, 0); + int dim_1 = static_cast(shape[axis_1]); + int dim_2 = static_cast(shape[axis_2]); + + offset >= 0 ? dim_2 -= offset : dim_1 += offset; + + auto diag_size = std::size_t(dim_2 < dim_1 ? dim_2 : dim_1); + + std::size_t i = 0; + for (std::size_t idim = 0; idim < dimension; ++idim) + { + if (idim != axis_1 && idim != axis_2) + { + ret_shape[i++] = shape[idim]; + } + } + + ret_shape.back() = diag_size; + + return detail::make_xgenerator(detail::fn_impl>(detail::diagonal_fn(std::forward(arr), offset, axis_1, axis_2)), + ret_shape); + } + + /** + * @brief xexpression with values of arr on the diagonal, zeroes otherwise + * + * @param arr the 1D input array of length n + * @param k the offset of the considered diagonal + * @returns xexpression function with shape n x n and arr on the diagonal + * + * \code{.cpp} + * xt::xarray a = {1, 5, 9}; + * auto b = xt::diag(a); // => {{1, 0, 0}, + * // {0, 5, 0}, + * // {0, 0, 9}} + * \endcode + */ + template + inline auto diag(E&& arr, int k = 0) + { + using CT = xclosure_t; + std::size_t sk = std::size_t(std::abs(k)); + std::size_t s = arr.shape()[0] + sk; + return detail::make_xgenerator(detail::fn_impl>(detail::diag_fn(std::forward(arr), k)), + {s, s}); + } + + /** + * @brief Extract lower triangular matrix from xexpression. The parameter k selects the + * offset of the diagonal. + * + * @param arr the input array + * @param k the diagonal above which to zero elements. 0 (default) selects the main diagonal, + * k < 0 is below the main diagonal, k > 0 above. + * @returns xexpression containing lower triangle from arr, 0 otherwise + */ + template + inline auto tril(E&& arr, int k = 0) + { + using CT = xclosure_t; + auto shape = arr.shape(); + return detail::make_xgenerator(detail::fn_impl>>( + detail::trilu_fn>(std::forward(arr), k, std::greater_equal())), + shape); + } + + /** + * @brief Extract upper triangular matrix from xexpression. The parameter k selects the + * offset of the diagonal. + * + * @param arr the input array + * @param k the diagonal below which to zero elements. 0 (default) selects the main diagonal, + * k < 0 is below the main diagonal, k > 0 above. + * @returns xexpression containing lower triangle from arr, 0 otherwise + */ + template + inline auto triu(E&& arr, int k = 0) + { + using CT = xclosure_t; + auto shape = arr.shape(); + return detail::make_xgenerator(detail::fn_impl>>( + detail::trilu_fn>(std::forward(arr), k, std::less_equal())), + shape); + } +} +#endif diff --git a/vendor/xtensor/include/xtensor/xcomplex.hpp b/vendor/xtensor/include/xtensor/xcomplex.hpp new file mode 100644 index 0000000000..e47842aa11 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xcomplex.hpp @@ -0,0 +1,251 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_COMPLEX_HPP +#define XTENSOR_COMPLEX_HPP + +#include +#include + +#include + +#include "xtensor/xbuilder.hpp" +#include "xtensor/xexpression.hpp" +#include "xtensor/xoffset_view.hpp" + +namespace xt +{ + + /****************************** + * real and imag declarations * + ******************************/ + + template + decltype(auto) real(E&& e) noexcept; + + template + decltype(auto) imag(E&& e) noexcept; + + /******************************** + * real and imag implementation * + ********************************/ + + namespace detail + { + template + struct complex_helper + { + template + static inline auto real(E&& e) noexcept + { + using real_type = typename std::decay_t::value_type::value_type; + return xoffset_view, real_type, 0>(std::forward(e)); + } + + template + static inline auto imag(E&& e) noexcept + { + using real_type = typename std::decay_t::value_type::value_type; + return xoffset_view, real_type, sizeof(real_type)>(std::forward(e)); + } + }; + + template <> + struct complex_helper + { + template + static inline decltype(auto) real(E&& e) noexcept + { + return e; + } + + template + static inline auto imag(E&& e) noexcept + { + return zeros::value_type>(e.shape()); + } + }; + + template + struct complex_expression_helper + { + template + static inline auto real(E&& e) noexcept + { + return detail::complex_helper::value_type>::value>::real(e); + } + + template + static inline auto imag(E&& e) noexcept + { + return detail::complex_helper::value_type>::value>::imag(e); + } + }; + + template <> + struct complex_expression_helper + { + template + static inline decltype(auto) real(E&& e) noexcept + { + return xtl::forward_real(std::forward(e)); + } + + template + static inline decltype(auto) imag(E&& e) noexcept + { + return xtl::forward_imag(std::forward(e)); + } + }; + } + + /** + * @brief Returns an \ref xexpression representing the real part of the given expression. + * + * @tparam e the \ref xexpression + * + * The returned expression either hold a const reference to \p e or a copy + * depending on whether \p e is an lvalue or an rvalue. + */ + template + inline decltype(auto) real(E&& e) noexcept + { + return detail::complex_expression_helper>::value>::real(std::forward(e)); + } + + /** + * @brief Returns an \ref xexpression representing the imaginary part of the given expression. + * + * @tparam e the \ref xexpression + * + * The returned expression either hold a const reference to \p e or a copy + * depending on whether \p e is an lvalue or an rvalue. + */ + template + inline decltype(auto) imag(E&& e) noexcept + { + return detail::complex_expression_helper>::value>::imag(std::forward(e)); + } + +#define UNARY_COMPLEX_FUNCTOR(NAME) \ + template \ + struct NAME##_fun \ + { \ + using argument_type = T; \ + using result_type = decltype(std::NAME(std::declval())); \ + constexpr result_type operator()(const T& t) const \ + { \ + using std::NAME; \ + return NAME(t); \ + } \ + } + + namespace math + { + UNARY_COMPLEX_FUNCTOR(norm); + UNARY_COMPLEX_FUNCTOR(arg); + + namespace detail + { + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + template + constexpr T conj(const T& c) + { + return c; + } + + template + constexpr std::complex conj(const std::complex& c) + { + return std::complex(c.real(), -c.imag()); + } + } + + template + struct conj_fun + { + using argument_type = T; + using result_type = decltype(detail::conj(std::declval())); + using simd_value_type = xsimd::simd_type; + constexpr result_type operator()(const T& t) const + { + return detail::conj(t); + } + constexpr simd_value_type simd_apply(const simd_value_type& t) const + { + return detail::conj(t); + } + }; + } + +#undef UNARY_COMPLEX_FUNCTOR + + /** + * @brief Returns an \ref xfunction evaluating to the complex conjugate of the given expression. + * + * @param e the \ref xexpression + */ + template + inline auto conj(E&& e) noexcept + { + using value_type = typename std::decay_t::value_type; + using functor = math::conj_fun; + using result_type = typename functor::result_type; + using type = xfunction>; + return type(functor(), std::forward(e)); + } + + /** + * @brief Calculates the phase angle (in radians) elementwise for the complex numbers in e. + * @param e the \ref xexpression + */ + template + inline auto arg(E&& e) noexcept + { + using value_type = typename std::decay_t::value_type; + using functor = math::arg_fun; + using result_type = typename functor::result_type; + using type = xfunction>; + return type(functor(), std::forward(e)); + } + + /** + * @brief Calculates the phase angle elementwise for the complex numbers in e. + * Note that this function might be slightly less perfomant than \ref arg. + * @param e the \ref xexpression + * @param deg calculate angle in degrees instead of radians + */ + template + inline auto angle(E&& e, bool deg = false) noexcept + { + using value_type = xtl::complex_value_type_t::value_type>; + value_type multiplier = 1.0; + if (deg) + { + multiplier = value_type(180) / numeric_constants::PI; + } + return arg(std::forward(e)) * std::move(multiplier); + } + + /** + * Calculates the squared magnitude elementwise for the complex numbers in e. + * Equivalent to pow(real(e), 2) + pow(imag(e), 2). + * @param e the \ref xexpression + */ + template + inline auto norm(E&& e) noexcept + { + using value_type = typename std::decay_t::value_type; + using functor = math::norm_fun; + using result_type = typename functor::result_type; + using type = xfunction>; + return type(functor(), std::forward(e)); + } +} +#endif diff --git a/vendor/xtensor/include/xtensor/xconcepts.hpp b/vendor/xtensor/include/xtensor/xconcepts.hpp new file mode 100644 index 0000000000..1845c6b033 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xconcepts.hpp @@ -0,0 +1,113 @@ +/*************************************************************************** +* Copyright (c) 2017, Ullrich Koethe * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_CONCEPTS_HPP +#define XTENSOR_CONCEPTS_HPP + +#include + +/***************************************************** + * concept checking and type inference functionality * + *****************************************************/ + +namespace xt +{ + + /****************************************** + * XTENSOR_REQUIRE concept checking macro * + ******************************************/ + + struct concept_check_successful + { + }; + + template + using concept_check = typename std::enable_if::type; + + /** @brief Concept checking macro (more readable than sfinae). + + The macro is used as the last argument in a template declaration. + It must be followed by a static boolean expression in angle brackets. + The template will only be included in overload resolution when + this expression evaluates to 'true'. + + Example: + \code + template ::value>> + T foo(T t) + {...} + \endcode + */ + #define XTENSOR_REQUIRE typename = concept_check + + /******************** + * iterator_concept * + ********************/ + + /** @brief Traits class to check if a type is an iterator. + + This is useful in concept checking to make sure that a given template + is only instantiated when the argument is an iterator. + Currently, we apply the simple rule that class @tparam T + is either a pointer or a C-array or has an embedded typedef + 'iterator_category'. More sophisticated checks can easily + be added when needed. + + If @tparam T is indeed an iterator, the class' value member + is true: + \code + template ::value>> + T foo(T t) + {...} + \endcode + */ + template + struct iterator_concept + { + using V = std::decay_t; + + static char test(...); + + template + static int test(U*, typename U::iterator_category* = 0); + + static const bool value = + std::is_array::value || + std::is_pointer::value || + std::is_same())), int>::value; + }; + + /** @brief Check if a conversion may loose information. + + @tparam FROM source type + @tparam TO target type + + When data is converted from a big type (e.g. int64_t or double) + to a smaller type (e.g. int32_t), most compilers issue a 'possible loss of data' + warning. This metafunction allows you to detect these situations and take appropriate + actions. + + If loss of data may occur, member is_narrowing_conversion::value is true. Currently, + the check is only implemented for built-in types, i.e. types where std::is_arithmetic + is true. + */ + template + struct is_narrowing_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_arithmetic::value && + (sizeof(result_type) < sizeof(argument_type) || + (std::is_integral::value && std::is_floating_point::value)); + }; +} // namespace xt + +#endif // XCONCEPTS_HPP diff --git a/vendor/xtensor/include/xtensor/xcontainer.hpp b/vendor/xtensor/include/xtensor/xcontainer.hpp new file mode 100644 index 0000000000..80df1907f9 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xcontainer.hpp @@ -0,0 +1,1418 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_CONTAINER_HPP +#define XTENSOR_CONTAINER_HPP + +#include +#include +#include +#include +#include + +#include +#include + +#include "xiterable.hpp" +#include "xiterator.hpp" +#include "xmath.hpp" +#include "xoperation.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + template + struct xcontainer_iterable_types + { + using inner_shape_type = typename xcontainer_inner_types::inner_shape_type; + using storage_type = typename xcontainer_inner_types::storage_type; + using stepper = xstepper; + using const_stepper = xstepper; + }; + +#define DL XTENSOR_DEFAULT_LAYOUT + + namespace detail + { + template + struct allocator_type_impl + { + using type = typename T::allocator_type; + }; + + template + struct allocator_type_impl> + { + using type = std::allocator; // fake allocator for testing + }; + } + + template + using allocator_type_t = typename detail::allocator_type_impl::type; + + + /** + * @class xcontainer + * @brief Base class for dense multidimensional containers. + * + * The xcontainer class defines the interface for dense multidimensional + * container classes. It does not embed any data container, this responsibility + * is delegated to the inheriting classes. + * + * @tparam D The derived type, i.e. the inheriting class for which xcontainer + * provides the interface. + */ + template + class xcontainer : private xiterable + { + public: + + using derived_type = D; + + using inner_types = xcontainer_inner_types; + using storage_type = typename inner_types::storage_type; + using allocator_type = allocator_type_t>; + using value_type = typename storage_type::value_type; + using reference = std::conditional_t::value, + typename storage_type::const_reference, + typename storage_type::reference>; + using const_reference = typename storage_type::const_reference; + using pointer = typename storage_type::pointer; + using const_pointer = typename storage_type::const_pointer; + using size_type = typename storage_type::size_type; + using difference_type = typename storage_type::difference_type; + using simd_value_type = xsimd::simd_type; + + using shape_type = typename inner_types::shape_type; + using strides_type = typename inner_types::strides_type; + using backstrides_type = typename inner_types::backstrides_type; + + using inner_shape_type = typename inner_types::inner_shape_type; + using inner_strides_type = typename inner_types::inner_strides_type; + using inner_backstrides_type = typename inner_types::inner_backstrides_type; + + using iterable_base = xiterable; + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + static constexpr layout_type static_layout = inner_types::layout; + static constexpr bool contiguous_layout = static_layout != layout_type::dynamic; + using data_alignment = xsimd::container_alignment_t; + using simd_type = xsimd::simd_type; + + static_assert(static_layout != layout_type::any, "Container layout can never be layout_type::any!"); + + size_type size() const noexcept; + + constexpr size_type dimension() const noexcept; + + constexpr const inner_shape_type& shape() const noexcept; + constexpr const inner_strides_type& strides() const noexcept; + constexpr const inner_backstrides_type& backstrides() const noexcept; + + template + void fill(const T& value); + + template + reference operator()(Args... args); + + template + const_reference operator()(Args... args) const; + + template + reference at(Args... args); + + template + const_reference at(Args... args) const; + + template + reference unchecked(Args... args); + + template + const_reference unchecked(Args... args) const; + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + reference element(It first, It last); + template + const_reference element(It first, It last) const; + + storage_type& storage() noexcept; + const storage_type& storage() const noexcept; + + value_type* data() noexcept; + const value_type* data() const noexcept; + const size_type data_offset() const noexcept; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const noexcept; + + template + stepper stepper_begin(const S& shape) noexcept; + template + stepper stepper_end(const S& shape, layout_type l) noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + reference data_element(size_type i); + const_reference data_element(size_type i) const; + + template + using simd_return_type = xsimd::simd_return_type; + + template + void store_simd(size_type i, const simd& e); + template + simd_return_type load_simd(size_type i) const; + +#if defined(_MSC_VER) && _MSC_VER >= 1910 + // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type parameters. + template + using layout_iterator = xiterator; + template + using const_layout_iterator = xiterator; + template + using reverse_layout_iterator = std::reverse_iterator>; + template + using const_reverse_layout_iterator = std::reverse_iterator>; +#else + template + using layout_iterator = typename iterable_base::template layout_iterator; + template + using const_layout_iterator = typename iterable_base::template const_layout_iterator; + template + using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; + template + using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; +#endif + + template + using broadcast_iterator = typename iterable_base::template broadcast_iterator; + template + using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; + template + using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; + template + using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; + + using storage_iterator = typename storage_type::iterator; + using const_storage_iterator = typename storage_type::const_iterator; + using reverse_storage_iterator = typename storage_type::reverse_iterator; + using const_reverse_storage_iterator = typename storage_type::const_reverse_iterator; + + template + using select_iterator_impl = std::conditional_t; + + template + using select_iterator = select_iterator_impl>; + template + using select_const_iterator = select_iterator_impl>; + template + using select_reverse_iterator = select_iterator_impl>; + template + using select_const_reverse_iterator = select_iterator_impl>; + + using iterator = select_iterator

; + using const_iterator = select_const_iterator
; + using reverse_iterator = select_reverse_iterator
; + using const_reverse_iterator = select_const_reverse_iterator
; + + template + select_iterator begin() noexcept; + template + select_iterator end() noexcept; + + template + select_const_iterator begin() const noexcept; + template + select_const_iterator end() const noexcept; + template + select_const_iterator cbegin() const noexcept; + template + select_const_iterator cend() const noexcept; + + template + select_reverse_iterator rbegin() noexcept; + template + select_reverse_iterator rend() noexcept; + + template + select_const_reverse_iterator rbegin() const noexcept; + template + select_const_reverse_iterator rend() const noexcept; + template + select_const_reverse_iterator crbegin() const noexcept; + template + select_const_reverse_iterator crend() const noexcept; + + template + broadcast_iterator begin(const S& shape) noexcept; + template + broadcast_iterator end(const S& shape) noexcept; + + template + const_broadcast_iterator begin(const S& shape) const noexcept; + template + const_broadcast_iterator end(const S& shape) const noexcept; + template + const_broadcast_iterator cbegin(const S& shape) const noexcept; + template + const_broadcast_iterator cend(const S& shape) const noexcept; + + + template + reverse_broadcast_iterator rbegin(const S& shape) noexcept; + template + reverse_broadcast_iterator rend(const S& shape) noexcept; + + template + const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator rend(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crend(const S& shape) const noexcept; + + template + storage_iterator storage_begin() noexcept; + template + storage_iterator storage_end() noexcept; + + template + const_storage_iterator storage_begin() const noexcept; + template + const_storage_iterator storage_end() const noexcept; + template + const_storage_iterator storage_cbegin() const noexcept; + template + const_storage_iterator storage_cend() const noexcept; + + template + reverse_storage_iterator storage_rbegin() noexcept; + template + reverse_storage_iterator storage_rend() noexcept; + + template + const_reverse_storage_iterator storage_rbegin() const noexcept; + template + const_reverse_storage_iterator storage_rend() const noexcept; + template + const_reverse_storage_iterator storage_crbegin() const noexcept; + template + const_reverse_storage_iterator storage_crend() const noexcept; + + using container_iterator = storage_iterator; + using const_container_iterator = const_storage_iterator; + + protected: + + xcontainer() = default; + ~xcontainer() = default; + + xcontainer(const xcontainer&) = default; + xcontainer& operator=(const xcontainer&) = default; + + xcontainer(xcontainer&&) = default; + xcontainer& operator=(xcontainer&&) = default; + + container_iterator data_xbegin() noexcept; + const_container_iterator data_xbegin() const noexcept; + container_iterator data_xend(layout_type l) noexcept; + const_container_iterator data_xend(layout_type l) const noexcept; + + protected: + + derived_type& derived_cast() & noexcept; + const derived_type& derived_cast() const & noexcept; + derived_type derived_cast() && noexcept; + + private: + + friend class xiterable; + friend class xconst_iterable; + + template + friend class xstepper; + + template + It data_xend_impl(It end, layout_type l) const noexcept; + + inner_shape_type& mutable_shape(); + inner_strides_type& mutable_strides(); + inner_backstrides_type& mutable_backstrides(); + }; + +#undef DL + + /** + * @class xstrided_container + * @brief Partial implementation of xcontainer that embeds the strides and the shape + * + * The xstrided_container class is a partial implementation of the xcontainer interface + * that embed the strides and the shape of the multidimensional container. It does + * not embed the data container, this responsibility is delegated to the inheriting + * classes. + * + * @tparam D The derived type, i.e. the inheriting class for which xstrided_container + * provides the partial imlpementation of xcontainer. + */ + template + class xstrided_container : public xcontainer + { + public: + + using base_type = xcontainer; + using storage_type = typename base_type::storage_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using size_type = typename base_type::size_type; + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using inner_shape_type = typename base_type::inner_shape_type; + using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + + template + void resize(S&& shape, bool force = false); + template + void resize(S&& shape, layout_type l); + template + void resize(S&& shape, const strides_type& strides); + + template + void reshape(S&& shape, layout_type layout = base_type::static_layout); + + layout_type layout() const noexcept; + + protected: + + xstrided_container() noexcept; + ~xstrided_container() = default; + + xstrided_container(const xstrided_container&) = default; + xstrided_container& operator=(const xstrided_container&) = default; + + xstrided_container(xstrided_container&&) = default; + xstrided_container& operator=(xstrided_container&&) = default; + + explicit xstrided_container(inner_shape_type&&, inner_strides_type&&) noexcept; + + inner_shape_type& shape_impl() noexcept; + const inner_shape_type& shape_impl() const noexcept; + + inner_strides_type& strides_impl() noexcept; + const inner_strides_type& strides_impl() const noexcept; + + inner_backstrides_type& backstrides_impl() noexcept; + const inner_backstrides_type& backstrides_impl() const noexcept; + + private: + + inner_shape_type m_shape; + inner_strides_type m_strides; + inner_backstrides_type m_backstrides; + layout_type m_layout = base_type::static_layout; + }; + + /****************************** + * xcontainer implementation * + ******************************/ + + template + template + inline It xcontainer::data_xend_impl(It end, layout_type l) const noexcept + { + return strided_data_end(*this, end, l); + } + + template + inline auto xcontainer::mutable_shape() -> inner_shape_type& + { + return derived_cast().shape_impl(); + } + + template + inline auto xcontainer::mutable_strides() -> inner_strides_type& + { + return derived_cast().strides_impl(); + } + + template + inline auto xcontainer::mutable_backstrides() -> inner_backstrides_type& + { + return derived_cast().backstrides_impl(); + } + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the number of element in the container. + */ + template + inline auto xcontainer::size() const noexcept -> size_type + { + return contiguous_layout ? storage().size() : compute_size(shape()); + } + + /** + * Returns the number of dimensions of the container. + */ + template + inline constexpr auto xcontainer::dimension() const noexcept -> size_type + { + return shape().size(); + } + + /** + * Returns the shape of the container. + */ + template + constexpr inline auto xcontainer::shape() const noexcept -> const inner_shape_type& + { + return derived_cast().shape_impl(); + } + + /** + * Returns the strides of the container. + */ + template + constexpr inline auto xcontainer::strides() const noexcept -> const inner_strides_type& + { + return derived_cast().strides_impl(); + } + + /** + * Returns the backstrides of the container. + */ + template + constexpr inline auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + { + return derived_cast().backstrides_impl(); + } + //@} + + /** + * @name Data + */ + //@{ + + /** + * Fills the container with the given value. + * @param value the value to fill the container with. + */ + template + template + inline void xcontainer::fill(const T& value) + { + std::fill(storage_begin(), storage_end(), value); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + size_type index = xt::data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + size_type index = xt::data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a reference to the element at the specified position in the container, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the container. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xcontainer::at(Args... args) -> reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the container, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the container. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xcontainer::at(Args... args) const -> const_reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the container, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xcontainer::unchecked(Args... args) -> reference + { + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param args a list of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the container, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xcontainer::unchecked(Args... args) const -> const_reference + { + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + return storage()[index]; + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator[](const S& index) + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xcontainer::operator[](std::initializer_list index) -> reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xcontainer::operator[](size_type i) -> reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xcontainer::operator[](const S& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xcontainer::operator[](std::initializer_list index) const -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xcontainer::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xcontainer::element(It first, It last) -> reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return storage()[element_offset(strides(), first, last)]; + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xcontainer::element(It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return storage()[element_offset(strides(), first, last)]; + } + + /** + * Returns a reference to the buffer containing the elements of the container. + */ + template + inline auto xcontainer::storage() noexcept -> storage_type& + { + return derived_cast().storage_impl(); + } + + /** + * Returns a constant reference to the buffer containing the elements of the + * container. + */ + template + inline auto xcontainer::storage() const noexcept -> const storage_type& + { + return derived_cast().storage_impl(); + } + + /** + * Returns a pointer to the underlying array serving as element storage. The pointer + * is such that range [data(); data() + size()] is always a valid range, even if the + * container is empty (data() is not is not dereferenceable in that case) + */ + template + inline auto xcontainer::data() noexcept -> value_type* + { + return storage().data(); + } + + /** + * Returns a constant pointer to the underlying array serving as element storage. The pointer + * is such that range [data(); data() + size()] is always a valid range, even if the + * container is empty (data() is not is not dereferenceable in that case) + */ + template + inline auto xcontainer::data() const noexcept -> const value_type* + { + return storage().data(); + } + + /** + * Returns the offset to the first element in the container. + */ + template + inline auto xcontainer::data_offset() const noexcept -> const size_type + { + return size_type(0); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the container to the specified parameter. + * @param shape the result shape + * @param reuse_cache parameter for internal optimization + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xcontainer::broadcast_shape(S& shape, bool) const + { + return xt::broadcast_shape(this->shape(), shape); + } + + /** + * Compares the specified strides with those of the container to see whether + * the broadcasting is trivial. + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xcontainer::is_trivial_broadcast(const S& str) const noexcept + { + return str.size() == strides().size() && + std::equal(str.cbegin(), str.cend(), strides().begin()); + } + //@} + + /**************** + * Iterator api * + ****************/ + + template + template + inline auto xcontainer::begin() noexcept -> select_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_begin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template begin(); + }); + } + + template + template + inline auto xcontainer::end() noexcept -> select_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_end(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template end(); + }); + } + + template + template + inline auto xcontainer::begin() const noexcept -> select_const_iterator + { + return this->template cbegin(); + } + + template + template + inline auto xcontainer::end() const noexcept -> select_const_iterator + { + return this->template cend(); + } + + template + template + inline auto xcontainer::cbegin() const noexcept -> select_const_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_cbegin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template cbegin(); + }); + } + + template + template + inline auto xcontainer::cend() const noexcept -> select_const_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_cend(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template cend(); + }); + } + + template + template + inline auto xcontainer::rbegin() noexcept -> select_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_rbegin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template rbegin(); + }); + } + + template + template + inline auto xcontainer::rend() noexcept -> select_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_rend(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template rend(); + }); + } + + template + template + inline auto xcontainer::rbegin() const noexcept -> select_const_reverse_iterator + { + return this->template crbegin(); + } + + template + template + inline auto xcontainer::rend() const noexcept -> select_const_reverse_iterator + { + return this->template crend(); + } + + template + template + inline auto xcontainer::crbegin() const noexcept -> select_const_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_crbegin(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template crbegin(); + }); + } + + template + template + inline auto xcontainer::crend() const noexcept -> select_const_reverse_iterator + { + return xtl::mpl::static_if([&](auto self) + { + return self(*this).template storage_crend(); + }, /*else*/ [&](auto self) + { + return self(*this).iterable_base::template crend(); + }); + } + + /***************************** + * Broadcasting iterator api * + *****************************/ + + template + template + inline auto xcontainer::begin(const S& shape) noexcept -> broadcast_iterator + { + return iterable_base::template begin(shape); + } + + template + template + inline auto xcontainer::end(const S& shape) noexcept -> broadcast_iterator + { + return iterable_base::template end(shape); + } + + template + template + inline auto xcontainer::begin(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template begin(shape); + } + + template + template + inline auto xcontainer::end(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template end(shape); + } + + template + template + inline auto xcontainer::cbegin(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template cbegin(shape); + } + + template + template + inline auto xcontainer::cend(const S& shape) const noexcept -> const_broadcast_iterator + { + return iterable_base::template cend(shape); + } + + template + template + inline auto xcontainer::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator + { + return iterable_base::template rbegin(shape); + } + + template + template + inline auto xcontainer::rend(const S& shape) noexcept -> reverse_broadcast_iterator + { + return iterable_base::template rend(shape); + } + + template + template + inline auto xcontainer::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template rbegin(shape); + } + + template + template + inline auto xcontainer::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template rend(shape); + } + + template + template + inline auto xcontainer::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template crbegin(shape); + } + + template + template + inline auto xcontainer::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return iterable_base::template crend(shape); + } + + /*********************** + * Linear iterator api * + ***********************/ + + template + template + inline auto xcontainer::storage_begin() noexcept -> storage_iterator + { + return storage().begin(); + } + + template + template + inline auto xcontainer::storage_end() noexcept -> storage_iterator + { + return storage().end(); + } + + template + template + inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator + { + return storage().begin(); + } + + template + template + inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator + { + return storage().end(); + } + + template + template + inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator + { + return storage().cbegin(); + } + + template + template + inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + template + inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator + { + return storage().rbegin(); + } + + template + template + inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator + { + return storage().rend(); + } + + template + template + inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().rbegin(); + } + + template + template + inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage().rend(); + } + + template + template + inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().crbegin(); + } + + template + template + inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return storage().crend(); + } + + /*************** + * stepper api * + ***************/ + + template + template + inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xend(l), offset); + } + + template + template + inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xend(l), offset); + } + + template + inline auto xcontainer::data_xbegin() noexcept -> container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xend(layout_type l) noexcept -> container_iterator + { + return data_xend_impl(storage().end(), l); + } + + template + inline auto xcontainer::data_xend(layout_type l) const noexcept -> const_container_iterator + { + return data_xend_impl(storage().end(), l); + } + + template + inline auto xcontainer::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); + } + + template + inline auto xcontainer::derived_cast() const & noexcept -> const derived_type& + { + return *static_cast(this); + } + + template + inline auto xcontainer::derived_cast() && noexcept -> derived_type + { + return *static_cast(this); + } + + template + inline auto xcontainer::data_element(size_type i) -> reference + { + return storage()[i]; + } + + template + inline auto xcontainer::data_element(size_type i) const -> const_reference + { + return storage()[i]; + } + + template + template + inline void xcontainer::store_simd(size_type i, const simd& e) + { + using align_mode = driven_align_mode_t; + xsimd::store_simd(&(storage()[i]), e, align_mode()); + } + + template + template + inline auto xcontainer::load_simd(size_type i) const -> simd_return_type + { + using align_mode = driven_align_mode_t; + return xsimd::load_simd(&(storage()[i]), align_mode()); + } + + /************************************* + * xstrided_container implementation * + *************************************/ + + template + inline xstrided_container::xstrided_container() noexcept + : base_type() + { + m_shape = xtl::make_sequence(base_type::dimension(), 1); + m_strides = xtl::make_sequence(base_type::dimension(), 0); + m_backstrides = xtl::make_sequence(base_type::dimension(), 0); + } + + template + inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides) noexcept + : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)) + { + m_backstrides = xtl::make_sequence(m_shape.size(), 0); + adapt_strides(m_shape, m_strides, m_backstrides); + } + + template + inline auto xstrided_container::shape_impl() noexcept -> inner_shape_type& + { + return m_shape; + } + + template + inline auto xstrided_container::shape_impl() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + inline auto xstrided_container::strides_impl() noexcept -> inner_strides_type& + { + return m_strides; + } + + template + inline auto xstrided_container::strides_impl() const noexcept -> const inner_strides_type& + { + return m_strides; + } + + template + inline auto xstrided_container::backstrides_impl() noexcept -> inner_backstrides_type& + { + return m_backstrides; + } + + template + inline auto xstrided_container::backstrides_impl() const noexcept -> const inner_backstrides_type& + { + return m_backstrides; + } + + /** + * Return the layout_type of the container + * @return layout_type of the container + */ + template + layout_type xstrided_container::layout() const noexcept + { + return m_layout; + } + + namespace detail + { + template + inline void resize_data_container(C& c, S size) + { + xt::resize_container(c, size); + } + + template + inline void resize_data_container(const C& c, S size) + { + (void) c; // remove unused parameter warning + (void) size; + XTENSOR_ASSERT_MSG(c.size() == size, "Trying to resize const data container with wrong size."); + } + } + + /** + * resizes the container. + * @param shape the new shape + * @param force force reshaping, even if the shape stays the same (default: false) + */ + template + template + inline void xstrided_container::resize(S&& shape, bool force) + { + if (m_shape.size() != shape.size() || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) + { + if (m_layout == layout_type::dynamic || m_layout == layout_type::any) + { + m_layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout + } + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); + detail::resize_data_container(this->storage(), data_size); + } + } + + /** + * resizes the container. + * @param shape the new shape + * @param l the new layout_type + */ + template + template + inline void xstrided_container::resize(S&& shape, layout_type l) + { + if (base_type::static_layout != layout_type::dynamic && l != base_type::static_layout) + { + throw std::runtime_error("Cannot change layout_type if template parameter not layout_type::dynamic."); + } + m_layout = l; + resize(std::forward(shape), true); + } + + /** + * Resizes the container. + * @param shape the new shape + * @param strides the new strides + */ + template + template + inline void xstrided_container::resize(S&& shape, const strides_type& strides) + { + if (base_type::static_layout != layout_type::dynamic) + { + throw std::runtime_error("Cannot resize with custom strides when layout() is != layout_type::dynamic."); + } + m_shape = xtl::forward_sequence(shape); + m_strides = strides; + resize_container(m_backstrides, m_strides.size()); + adapt_strides(m_shape, m_strides, m_backstrides); + m_layout = layout_type::dynamic; + detail::resize_data_container(this->storage(), compute_size(m_shape)); + } + + /** + * Reshapes the container and keeps old elements + * @param shape the new shape (has to have same number of elements as the original container) + * @param layout the layout to compute the strides (defaults to static layout of the container, + * or for a container with dynamic layout to XTENSOR_DEFAULT_LAYOUT) + */ + template + template + inline void xstrided_container::reshape(S&& shape, layout_type layout) + { + if (compute_size(shape) != this->size()) + { + throw std::runtime_error("Cannot reshape with incorrect number of elements. Do you mean to resize?"); + } + if (layout == layout_type::dynamic || layout == layout_type::any) + { + layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout + } + if (layout != base_type::static_layout && base_type::static_layout != layout_type::dynamic) + { + throw std::runtime_error("Cannot reshape with different layout if static layout != dynamic."); + } + m_layout = layout; + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xcsv.hpp b/vendor/xtensor/include/xtensor/xcsv.hpp new file mode 100644 index 0000000000..4a2716d400 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xcsv.hpp @@ -0,0 +1,169 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_CSV_HPP +#define XTENSOR_CSV_HPP + +#include +#include +#include +#include +#include +#include + +#include "xtensor.hpp" + +namespace xt +{ + + /************************************** + * load_csv and dump_csv declarations * + **************************************/ + + template > + using xcsv_tensor = xtensor_container, 2, layout_type::row_major>; + + template > + xcsv_tensor load_csv(std::istream& stream); + + template + void dump_csv(std::ostream& stream, const xexpression& e); + + /***************************************** + * load_csv and dump_csv implementations * + *****************************************/ + + namespace detail + { + template + inline T lexical_cast(const std::string& cell) + { + T res; + std::istringstream iss(cell); + iss >> res; + return res; + } + + template <> + inline float lexical_cast(const std::string& cell) { return std::stof(cell); } + + template <> + inline double lexical_cast(const std::string& cell) { return std::stod(cell); } + + template <> + inline long double lexical_cast(const std::string& cell) { return std::stold(cell); } + + template <> + inline int lexical_cast(const std::string& cell) { return std::stoi(cell); } + + template <> + inline long lexical_cast(const std::string& cell) { return std::stol(cell); } + + template <> + inline long long lexical_cast(const std::string& cell) { return std::stoll(cell); } + + template <> + inline unsigned int lexical_cast(const std::string& cell) { return static_cast(std::stoul(cell)); } + + template <> + inline unsigned long lexical_cast(const std::string& cell) { return std::stoul(cell); } + + template <> + inline unsigned long long lexical_cast(const std::string& cell) { return std::stoull(cell); } + + template + ST load_csv_row(std::istream& row_stream, OI output, std::string cell) + { + ST length = 0; + while (std::getline(row_stream, cell, ',')) + { + *output++ = lexical_cast(cell); + ++length; + } + return length; + } + } + + /** + * @brief Load tensor from CSV. + * + * Returns an \ref xexpression for the parsed CSV + * @param stream the input stream containing the CSV encoded values + */ + template + xcsv_tensor load_csv(std::istream& stream) + { + using tensor_type = xcsv_tensor; + using storage_type = typename tensor_type::storage_type; + using size_type = typename tensor_type::size_type; + using inner_shape_type = typename tensor_type::inner_shape_type; + using inner_strides_type = typename tensor_type::inner_strides_type; + using output_iterator = std::back_insert_iterator; + + storage_type data; + size_type nbrow = 0, nbcol = 0; + { + output_iterator output(data); + std::string row, cell; + while (std::getline(stream, row)) + { + std::stringstream row_stream(row); + nbcol = detail::load_csv_row(row_stream, output, cell); + ++nbrow; + } + } + inner_shape_type shape = {nbrow, nbcol}; + inner_strides_type strides; // no need for initializer list for stack-allocated strides_type + size_type data_size = compute_strides(shape, layout_type::row_major, strides); + // Sanity check for data size. + if (data.size() != data_size) + { + throw std::runtime_error("Inconsistent row lengths in CSV"); + } + return tensor_type(std::move(data), std::move(shape), std::move(strides)); + } + + /** + * @brief Dump tensor to CSV. + * + * @param stream the output stream to write the CSV encoded values + * @param e the tensor expression to serialize + */ + template + void dump_csv(std::ostream& stream, const xexpression& e) + { + using size_type = typename E::size_type; + const E& ex = e.derived_cast(); + if (ex.dimension() != 2) + { + throw std::runtime_error("Only 2-D expressions can be serialized to CSV"); + } + size_type nbrows = ex.shape()[0], nbcols = ex.shape()[1]; + auto st = ex.stepper_begin(ex.shape()); + for (size_type r = 0; r != nbrows; ++r) + { + for (size_type c = 0; c != nbcols; ++c) + { + stream << *st; + if (c != nbcols - 1) + { + st.step(1); + stream << ','; + } + else + { + st.reset(1); + st.step(0); + stream << std::endl; + } + } + } + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xeval.hpp b/vendor/xtensor/include/xtensor/xeval.hpp new file mode 100644 index 0000000000..18d53beea6 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xeval.hpp @@ -0,0 +1,57 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_EVAL_HPP +#define XTENSOR_EVAL_HPP + +#include "xtensor_forward.hpp" + +namespace xt +{ + + namespace detail + { + template + using is_container = std::is_base_of>, T>; + } + + /** + * Force evaluation of xexpression. + * @return xarray or xtensor depending on shape type + * + * \code{.cpp} + * xarray a = {1,2,3,4}; + * auto&& b = xt::eval(a); // b is a reference to a, no copy! + * auto&& c = xt::eval(a + b); // c is xarray, not an xexpression + * \endcode + */ + template + inline auto eval(T&& t) + -> std::enable_if_t>::value, T&&> + { + return std::forward(t); + } + + /// @cond DOXYGEN_INCLUDE_SFINAE + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> + { + return xtensor::value>(std::forward(t)); + } + + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && !detail::is_array::value, xt::xarray> + { + return xarray(std::forward(t)); + } + /// @endcond +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xexception.hpp b/vendor/xtensor/include/xtensor/xexception.hpp new file mode 100644 index 0000000000..689ce31e09 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xexception.hpp @@ -0,0 +1,219 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_EXCEPTION_HPP +#define XTENSOR_EXCEPTION_HPP + +#include +#include +#include +#include + +namespace xt +{ + + /******************* + * broadcast_error * + *******************/ + + class broadcast_error : public std::runtime_error + { + public: + + explicit broadcast_error(const char* msg) + : std::runtime_error(msg) + { + } + }; + + template + [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs); + + /********************************** + * broadcast_error implementation * + **********************************/ + +#ifdef NDEBUG + // Do not inline this function + template + [[noreturn]] void throw_broadcast_error(const S1&, const S2&) + { + throw broadcast_error("Incompatible dimension of arrays, compile in DEBUG for more info"); + } +#else + template + [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs) + { + std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + + buf << "\n LHS shape = ("; + using size_type1 = typename S1::value_type; + std::ostream_iterator iter1(buf, ", "); + std::copy(lhs.cbegin(), lhs.cend(), iter1); + + buf << ")\n RHS shape = ("; + using size_type2 = typename S2::value_type; + std::ostream_iterator iter2(buf, ", "); + std::copy(rhs.cbegin(), rhs.cend(), iter2); + buf << ")"; + + throw broadcast_error(buf.str().c_str()); + } +#endif + + /******************* + * transpose_error * + *******************/ + + class transpose_error : public std::runtime_error + { + public: + + explicit transpose_error(const char* msg) + : std::runtime_error(msg) + { + } + }; + + /*************** + * check_index * + ***************/ + + template + void check_index(const S& shape, Args... args); + + template + void check_element_index(const S& shape, It first, It last); + + namespace detail + { + template + inline void check_index_impl(const S&) + { + } + + template + inline void check_index_impl(const S& shape, std::size_t arg, Args... args) + { + if (sizeof...(Args) + 1 > shape.size()) + { + check_index_impl(shape, args...); + } + else + { + if (arg >= std::size_t(shape[dim]) && shape[dim] != 1) + { + throw std::out_of_range("index " + std::to_string(arg) + " is out of bounds for axis " + + std::to_string(dim) + " with size " + std::to_string(shape[dim])); + } + check_index_impl(shape, args...); + } + } + } + + template + inline void check_index(const S& shape, Args... args) + { + using value_type = typename S::value_type; + detail::check_index_impl(shape, static_cast(args)...); + } + + template + inline void check_element_index(const S& shape, It first, It last) + { + using value_type = typename std::iterator_traits::value_type; + auto dst = static_cast(last - first); + It efirst = last - static_cast((std::min)(shape.size(), dst)); + std::size_t axis = 0; + while (efirst != last) + { + if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + { + throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " + + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + } + ++efirst, ++axis; + } + } + + /******************* + * check_dimension * + *******************/ + + template + inline void check_dimension(const S& shape, Args...) + { + if (sizeof...(Args) > shape.size()) + { + throw std::out_of_range("Number of arguments (" + std::to_string(sizeof...(Args)) + ") us greater " + + "than the number of dimensions (" + std::to_string(shape.size()) + ")"); + } + } + + /**************** + * check_access * + ****************/ + + template + inline void check_access(const S& shape, Args... args) + { + check_dimension(shape, args...); + check_index(shape, args...); + } + +#ifdef XTENSOR_ENABLE_ASSERT +#define XTENSOR_TRY(expr) XTENSOR_TRY_IMPL(expr, __FILE__, __LINE__) +#define XTENSOR_TRY_IMPL(expr, file, line) \ + try \ + { \ + expr; \ + } \ + catch (std::exception& e) \ + { \ + throw std::runtime_error(std::string(file) + ':' + std::to_string(line) + ": check failed\n\t" + std::string(e.what())); \ + } +#else +#define XTENSOR_TRY(expr) +#endif + +#ifdef XTENSOR_ENABLE_ASSERT +#define XTENSOR_ASSERT(expr) XTENSOR_ASSERT_IMPL(expr, __FILE__, __LINE__) +#define XTENSOR_ASSERT_IMPL(expr, file, line) \ + if (!(expr)) \ + { \ + throw std::runtime_error(std::string(file) + ':' + std::to_string(line) + ": assertion failed (" #expr ") \n\t"); \ + } +#else +#define XTENSOR_ASSERT(expr) +#endif + +#ifdef XTENSOR_ENABLE_CHECK_DIMENSION +#define XTENSOR_CHECK_DIMENSION(S, ARGS) XTENSOR_TRY(check_dimension(S, ARGS)) +#else +#define XTENSOR_CHECK_DIMENSION(S, ARGS) +#endif + +#ifdef XTENSOR_ENABLE_ASSERT +#define XTENSOR_ASSERT_MSG(expr, msg) \ + if (!(expr)) \ + { \ + throw std::runtime_error(std::string("Assertion error!\n") + msg + \ + "\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n"); \ + } +#else +#define XTENSOR_ASSERT_MSG(expr, msg) +#endif + +#define XTENSOR_PRECONDITION(expr, msg) \ + if (!(expr)) \ + { \ + throw std::runtime_error(std::string("Precondition violation!\n") + msg + \ + "\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n"); \ + } +} +#endif // XEXCEPTION_HPP diff --git a/vendor/xtensor/include/xtensor/xexpression.hpp b/vendor/xtensor/include/xtensor/xexpression.hpp new file mode 100644 index 0000000000..a83ea0c582 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xexpression.hpp @@ -0,0 +1,307 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_EXPRESSION_HPP +#define XTENSOR_EXPRESSION_HPP + +#include +#include +#include + +#include +#include + +#include "xshape.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /*************************** + * xexpression declaration * + ***************************/ + + /** + * @class xexpression + * @brief Base class for xexpressions + * + * The xexpression class is the base class for all classes representing an expression + * that can be evaluated to a multidimensional container with tensor semantic. + * Functions that can apply to any xexpression regardless of its specific type should take a + * xexpression argument. + * + * \tparam E The derived type. + * + */ + template + class xexpression + { + public: + + using derived_type = D; + + derived_type& derived_cast() & noexcept; + const derived_type& derived_cast() const & noexcept; + derived_type derived_cast() && noexcept; + + protected: + + xexpression() = default; + ~xexpression() = default; + + xexpression(const xexpression&) = default; + xexpression& operator=(const xexpression&) = default; + + xexpression(xexpression&&) = default; + xexpression& operator=(xexpression&&) = default; + }; + + /****************************** + * xexpression implementation * + ******************************/ + + /** + * @name Downcast functions + */ + //@{ + /** + * Returns a reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); + } + + /** + * Returns a constant reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() const & noexcept -> const derived_type& + { + return *static_cast(this); + } + + /** + * Returns a constant reference to the actual derived type of the xexpression. + */ + template + inline auto xexpression::derived_cast() && noexcept -> derived_type + { + return *static_cast(this); + } + //@} + + namespace detail + { + template + struct is_xexpression_impl : std::is_base_of>, std::decay_t> + { + }; + + template + struct is_xexpression_impl> : std::true_type + { + }; + } + + template + using is_xexpression = detail::is_xexpression_impl; + + template + using enable_xexpression = typename std::enable_if::value, R>::type; + + template + using disable_xexpression = typename std::enable_if::value, R>::type; + + template + using has_xexpression = xtl::disjunction...>; + + /************ + * xclosure * + ************/ + + template + class xscalar; + + template + struct xclosure + { + using type = xtl::closure_type_t; + }; + + template + struct xclosure>> + { + using type = xscalar>; + }; + + template + using xclosure_t = typename xclosure::type; + + template + struct const_xclosure + { + using type = xtl::const_closure_type_t; + }; + + template + struct const_xclosure>> + { + using type = xscalar>; + }; + + template + using const_xclosure_t = typename const_xclosure::type; + + /*************** + * xvalue_type * + ***************/ + + namespace detail + { + template + struct xvalue_type_impl + { + using type = E; + }; + + template + struct xvalue_type_impl::value>> + { + using type = typename E::value_type; + }; + } + + template + using xvalue_type = detail::xvalue_type_impl; + + template + using xvalue_type_t = typename xvalue_type::type; + + /************************* + * expression tag system * + *************************/ + + struct xscalar_expression_tag + { + }; + + struct xtensor_expression_tag + { + }; + + struct xoptional_expression_tag + { + }; + + namespace detail + { + template > + struct get_expression_tag + { + using type = xtensor_expression_tag; + }; + + template + struct get_expression_tag::expression_tag>> + { + using type = typename std::decay_t::expression_tag; + }; + + template + using get_expression_tag_t = typename get_expression_tag::type; + + template + struct expression_tag_and; + + template + struct expression_tag_and + { + using type = T; + }; + + template + struct expression_tag_and + { + using type = T; + }; + + template <> + struct expression_tag_and + { + using type = xscalar_expression_tag; + }; + + template + struct expression_tag_and + { + using type = T; + }; + + template + struct expression_tag_and + : expression_tag_and + { + }; + + template <> + struct expression_tag_and + { + using type = xoptional_expression_tag; + }; + + template <> + struct expression_tag_and + : expression_tag_and + { + }; + + template + struct expression_tag_and + : expression_tag_and::type> + { + }; + + template + using expression_tag_and_t = typename expression_tag_and::type; + } + + template + struct xexpression_tag + { + using type = detail::expression_tag_and_t>>...>; + }; + + template + using xexpression_tag_t = typename xexpression_tag::type; + + template + struct is_xtensor_expression : std::is_same, xtensor_expression_tag> + { + }; + + template + struct is_xoptional_expression : std::is_same, xoptional_expression_tag> + { + }; + + /******************************** + * xoptional_comparable concept * + ********************************/ + + template + struct xoptional_comparable : xtl::conjunction, + is_xoptional_expression + >... + > + { + }; +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xfixed.hpp b/vendor/xtensor/include/xtensor/xfixed.hpp new file mode 100644 index 0000000000..4438825975 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xfixed.hpp @@ -0,0 +1,818 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_FIXED_HPP +#define XTENSOR_FIXED_HPP + +#include +#include +#include +#include +#include + +#include "xcontainer.hpp" +#include "xstrides.hpp" +#include "xstorage.hpp" +#include "xsemantic.hpp" + +#ifdef _MSC_VER + #define XTENSOR_CONSTEXPR_ENHANCED const + #define XTENSOR_CONSTEXPR_ENHANCED_STATIC const + #define XTENSOR_CONSTEXPR_RETURN +#else + #define XTENSOR_CONSTEXPR_ENHANCED constexpr + #define XTENSOR_CONSTEXPR_RETURN constexpr + #define XTENSOR_CONSTEXPR_ENHANCED_STATIC constexpr static + #define XTENSOR_HAS_CONSTEXPR_ENHANCED +#endif + +namespace xt +{ + /** + * @class fixed_shape + * Fixed shape implementation for compile time defined arrays. + * @sa xshape + */ + template + class fixed_shape + { + public: + + using cast_type = const_array; + + constexpr static std::size_t size() + { + return sizeof...(X); + } + + constexpr fixed_shape() + { + } + + constexpr operator cast_type() const + { + return {{X...}}; + } + }; +} + +namespace std +{ + template + class tuple_size> : + public integral_constant + { + }; +} + +namespace xtl +{ + namespace detail + { + template + struct sequence_builder> + { + using sequence_type = xt::const_array; + using value_type = typename sequence_type::value_type; + using size_type = typename sequence_type::size_type; + + inline static sequence_type make(size_type /*size*/, value_type /*v*/) + { + return sequence_type(); + } + }; + } +} + +namespace xt +{ + + /********************** + * xfixed declaration * + **********************/ + + template + class xfixed_container; + + namespace detail + { + /************************************************************************************** + The following is something we can currently only dream about -- for when we drop + support for a lot of the old compilers (e.g. GCC 4.9, MSVC 2017 ;) + + template + constexpr std::size_t calculate_stride(T& shape, std::size_t idx, layout_type L) + { + if (shape[idx] == 1) + { + return std::size_t(0); + } + + std::size_t data_size = 1; + std::size_t stride = 1; + if (L == layout_type::row_major) + { + // because we have a integer sequence that counts + // from 0 to sz - 1, we need to "invert" idx here + idx = shape.size() - idx; + for (std::size_t i = idx; i != 0; --i) + { + stride = data_size; + data_size = stride * shape[i - 1]; + } + } + else + { + for (std::size_t i = 0; i < idx + 1; ++i) + { + stride = data_size; + data_size = stride * shape[i]; + } + } + return stride; + } + + *****************************************************************************************/ + + template + struct at + { + constexpr static std::size_t arr[sizeof...(X)] = {X...}; + constexpr static std::size_t value = arr[IDX]; + }; + + template + struct calculate_stride; + + template + struct calculate_stride + { + constexpr static std::size_t value = Y * calculate_stride::value; + }; + + template + struct calculate_stride + { + constexpr static std::size_t value = 1; + }; + + template + struct calculate_stride_row_major + { + constexpr static std::size_t value = at::value * calculate_stride_row_major::value; + }; + + template + struct calculate_stride_row_major<0, X...> + { + constexpr static std::size_t value = 1; + }; + + template + struct calculate_stride + { + constexpr static std::size_t value = calculate_stride_row_major::value; + }; + + template + constexpr const_array + get_strides_impl(const xt::fixed_shape& /*shape*/, std::index_sequence) + { + static_assert((L == layout_type::row_major) || (L == layout_type::column_major), + "Layout not supported for fixed array"); + return {{at::value == 1 ? 0 : calculate_stride::value...}}; + } + + template + constexpr T get_backstrides_impl(const T& shape, const T& strides, std::index_sequence) + { + return {{(strides[I] * (shape[I] - 1))...}}; + } + + template + struct compute_size_impl; + + template + struct compute_size_impl + { + constexpr static std::size_t value = Y * compute_size_impl::value; + }; + + template + struct compute_size_impl + { + constexpr static std::size_t value = X; + }; + + template <> + struct compute_size_impl<> + { + // support for 0D xtensor fixed (empty shape = xshape<>) + constexpr static std::size_t value = 1; + }; + + // TODO unify with constexpr compute_size when dropping MSVC 2015 + template + struct fixed_compute_size; + + template + struct fixed_compute_size> + { + constexpr static std::size_t value = compute_size_impl::value; + }; + + template + struct get_init_type_impl; + + template + struct get_init_type_impl + { + using type = V[Y]; + }; + + template + struct get_init_type_impl + { + using type = V[1]; + }; + + template + struct get_init_type_impl + { + using tmp_type = typename get_init_type_impl::type; + using type = tmp_type[Y]; + }; + } + + template + constexpr const_array get_strides(const fixed_shape& shape) noexcept + { + return detail::get_strides_impl(shape, std::make_index_sequence{}); + } + + template + constexpr T get_backstrides(const T& shape, const T& strides) noexcept + { + return detail::get_backstrides_impl(shape, strides, + std::make_index_sequence::value>{}); + } + + template + struct get_init_type; + + template + struct get_init_type> + { + using type = typename detail::get_init_type_impl::type; + }; + + template + using get_init_type_t = typename get_init_type::type; + + template + struct xcontainer_inner_types> + { + using inner_shape_type = typename S::cast_type; + using inner_strides_type = inner_shape_type; + using backstrides_type = inner_shape_type; + using inner_backstrides_type = backstrides_type; + using shape_type = std::array::value>; + using strides_type = shape_type; + using storage_type = aligned_array::value>; + using temporary_type = xfixed_container; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xfixed_container + * @brief Dense multidimensional container with tensor semantic and fixed + * dimension. + * + * The xfixed_container class implements a dense multidimensional container + * with tensor semantic and fixed dimension + * + * @tparam ET The type of the elements. + * @tparam S The xshape template paramter of the container. + * @tparam L The layout_type of the tensor. + * @tparam Tag The expression tag. + * @sa xtensor_fixed + */ + template + class xfixed_container : public xcontainer>, + public xcontainer_semantic> + { + public: + + using self_type = xfixed_container; + using base_type = xcontainer; + using semantic_base = xcontainer_semantic; + + using storage_type = typename base_type::storage_type; + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using shape_type = typename base_type::shape_type; + using inner_shape_type = typename base_type::inner_shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + using inner_strides_type = typename base_type::inner_strides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + + constexpr static std::size_t N = std::tuple_size::value; + + xfixed_container(); +#if defined(_MSC_VER) && _MSC_VER < 1910 + explicit xfixed_container(value_type v); +#else + [[deprecated]] explicit xfixed_container(value_type v); +#endif + explicit xfixed_container(const inner_shape_type& shape, layout_type l = L); + explicit xfixed_container(const inner_shape_type& shape, value_type v, layout_type l = L); + +#ifndef X_OLD_CLANG + xfixed_container(const get_init_type_t& init); +#else + // remove this enable_if when removing the other value_type constructor + template , class EN = std::enable_if_t> + xfixed_container(nested_initializer_list_t t); +#endif + + ~xfixed_container() = default; + + xfixed_container(const xfixed_container&) = default; + xfixed_container& operator=(const xfixed_container&) = default; + + xfixed_container(xfixed_container&&) = default; + xfixed_container& operator=(xfixed_container&&) = default; + + template + xfixed_container(const xexpression& e); + + template + xfixed_container& operator=(const xexpression& e); + + template + void resize(ST&& shape, bool force = false) const; + + template + void reshape(ST&& shape, layout_type layout = L) const; + + template + bool broadcast_shape(ST& s, bool reuse_cache = false) const; + + constexpr layout_type layout() const noexcept; + + private: + + storage_type m_storage; + + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S(); + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides(S()); + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides); + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; + + friend class xcontainer>; + }; + +#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED + // Out of line definitions to prevent linker errors prior to C++17 + template + constexpr typename xfixed_container::inner_shape_type xfixed_container::m_shape; + + template + constexpr typename xfixed_container::inner_strides_type xfixed_container::m_strides; + + template + constexpr typename xfixed_container::inner_backstrides_type xfixed_container::m_backstrides; +#endif + + /**************************************** + * xfixed_container_adaptor declaration * + ****************************************/ + + template + class xfixed_adaptor; + + template + struct xcontainer_inner_types> + { + using storage_type = std::remove_reference_t; + using inner_shape_type = typename S::cast_type; + using inner_strides_type = inner_shape_type; + using backstrides_type = inner_shape_type; + using inner_backstrides_type = backstrides_type; + using shape_type = std::array::value>; + using strides_type = shape_type; + using temporary_type = xfixed_container; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + : xcontainer_iterable_types> + { + }; + + /** + * @class xfixed_adaptor + * @brief Dense multidimensional container adaptor with tensor semantic + * and fixed dimension. + * + * The xfixed_adaptor class implements a dense multidimensional + * container adaptor with tensor semantic and fixed dimension. It + * is used to provide a multidimensional container semantic and a + * tensor semantic to stl-like containers. + * + * @tparam EC The closure for the container type to adapt. + * @tparam S The xshape template parameter for the fixed shape of the adaptor + * @tparam L The layout_type of the adaptor. + * @tparam Tag The expression tag. + */ + template + class xfixed_adaptor : public xcontainer>, + public xcontainer_semantic> + { + public: + + using container_closure_type = EC; + + using self_type = xfixed_adaptor; + using base_type = xcontainer; + using semantic_base = xcontainer_semantic; + using storage_type = typename base_type::storage_type; + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + using inner_shape_type = typename base_type::inner_shape_type; + using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + using temporary_type = typename semantic_base::temporary_type; + using expression_tag = Tag; + + xfixed_adaptor(storage_type&& data); + xfixed_adaptor(const storage_type& data); + + template + xfixed_adaptor(D&& data); + + ~xfixed_adaptor() = default; + + xfixed_adaptor(const xfixed_adaptor&) = default; + xfixed_adaptor& operator=(const xfixed_adaptor&); + + xfixed_adaptor(xfixed_adaptor&&) = default; + xfixed_adaptor& operator=(xfixed_adaptor&&); + xfixed_adaptor& operator=(temporary_type&&); + + template + xfixed_adaptor& operator=(const xexpression& e); + + constexpr layout_type layout() const noexcept; + + private: + + container_closure_type m_storage; + + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S(); + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides(S()); + XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides); + + storage_type& storage_impl() noexcept; + const storage_type& storage_impl() const noexcept; + + XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept; + + friend class xcontainer>; + }; + +#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED + // Out of line definitions to prevent linker errors prior to C++17 + template + constexpr typename xfixed_adaptor::inner_shape_type xfixed_adaptor::m_shape; + + template + constexpr typename xfixed_adaptor::inner_strides_type xfixed_adaptor::m_strides; + + template + constexpr typename xfixed_adaptor::inner_backstrides_type xfixed_adaptor::m_backstrides; +#endif + + /************************************ + * xfixed_container implementation * + ************************************/ + + /** + * @name Constructors + */ + //@{ + /** + * Create an uninitialized xfixed_container according to the shape template parameter. + */ + template + inline xfixed_container::xfixed_container() + { + } + + /** + * Create an xfixed_container, and initialize with the value of v. + * + * @param v the fill value + */ + template + inline xfixed_container::xfixed_container(value_type v) + { + std::fill(this->begin(), this->end(), v); + } + + /** + * Create an uninitialized xfixed_container. + * Note this function is only provided for homogenity, and the shape & layout argument is + * disregarded (the template shape is always used). + * + * @param shape the shape of the xfixed_container (unused!) + * @param l the layout_type of the xfixed_container (unused!) + */ + template + inline xfixed_container::xfixed_container(const inner_shape_type& /*shape*/, layout_type /*l*/) + { + } + + /** + * Create an xfixed_container, and initialize with the value of v. + * Note, the shape argument to this function is only provided for homogenity, + * and the shape argument is disregarded (the template shape is always used). + * + * @param shape the shape of the xfixed_container (unused!) + * @param v the fill value + * @param l the layout_type of the xfixed_container (unused!) + */ + template + inline xfixed_container::xfixed_container(const inner_shape_type& /*shape*/, value_type v, layout_type /*l*/) + : xfixed_container(v) + { + } + + /** + * Allocates an xfixed_container with shape S with values from a C array. + * The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for ``xt::xshape``. + * C arrays can be initialized with the initializer list syntax, but the size is checked at compile + * time to prevent errors. + * Note: for clang < 3.8 this is an initializer_list and the size is not checked at compile-or runtime. + */ +#ifndef X_OLD_CLANG + template + inline xfixed_container::xfixed_container(const get_init_type_t& init) + { + std::copy(reinterpret_cast(&init), reinterpret_cast(&init) + this->size(), + this->template begin()); + } +#else + template + template + inline xfixed_container::xfixed_container(nested_initializer_list_t t) + { + L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin(), t); + } +#endif + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended copy constructor. + */ + template + template + inline xfixed_container::xfixed_container(const xexpression& e) + { + semantic_base::assign(e); + } + + /** + * The extended assignment operator. + */ + template + template + inline auto xfixed_container::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + /** + * Note that the xfixed_container **cannot** be resized. Attempting to resize with a different + * size throws an assert in debug mode. + */ + template + template + inline void xfixed_container::resize(ST&& shape, bool) const + { + (void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined + XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size()); + } + + /** + * Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``. + */ + template + template + inline void xfixed_container::reshape(ST&& shape, layout_type layout) const + { + if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L)) + { + throw std::runtime_error("Trying to reshape xtensor_fixed with different shape or layout."); + } + } + + template + template + inline bool xfixed_container::broadcast_shape(ST& shape, bool) const + { + return xt::broadcast_shape(m_shape, shape); + } + + template + constexpr layout_type xfixed_container::layout() const noexcept + { + return base_type::static_layout; + } + + template + inline auto xfixed_container::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xfixed_container::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_container::shape_impl() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_container::strides_impl() const noexcept -> const inner_strides_type& + { + return m_strides; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_container::backstrides_impl() const noexcept -> const inner_backstrides_type& + { + return m_backstrides; + } + + /******************* + * xfixed_adaptor * + *******************/ + + /** + * @name Constructors + */ + //@{ + /** + * Constructs an xfixed_adaptor of the given stl-like container. + * @param data the container to adapt + */ + template + inline xfixed_adaptor::xfixed_adaptor(storage_type&& data) + : base_type(), m_storage(std::move(data)) + { + } + + /** + * Constructs an xfixed_adaptor of the given stl-like container. + * @param data the container to adapt + */ + template + inline xfixed_adaptor::xfixed_adaptor(const storage_type& data) + : base_type(), m_storage(data) + { + } + + /** + * Constructs an xfixed_adaptor of the given stl-like container, + * with the specified shape and layout_type. + * @param data the container to adapt + */ + template + template + inline xfixed_adaptor::xfixed_adaptor(D&& data) + : base_type(), m_storage(std::forward(data)) + { + } + //@} + + template + inline auto xfixed_adaptor::operator=(const xfixed_adaptor& rhs) -> self_type& + { + base_type::operator=(rhs); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xfixed_adaptor::operator=(xfixed_adaptor&& rhs) -> self_type& + { + base_type::operator=(std::move(rhs)); + m_storage = rhs.m_storage; + return *this; + } + + template + inline auto xfixed_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + m_storage = xtl::forward_sequence(std::move(rhs.storage())); + return *this; + } + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xfixed_adaptor::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + inline auto xfixed_adaptor::storage_impl() noexcept -> storage_type& + { + return m_storage; + } + + template + inline auto xfixed_adaptor::storage_impl() const noexcept -> const storage_type& + { + return m_storage; + } + + template + constexpr layout_type xfixed_adaptor::layout() const noexcept + { + return base_type::static_layout; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::shape_impl() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::strides_impl() const noexcept -> const inner_strides_type& + { + return m_strides; + } + + template + XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor::backstrides_impl() const noexcept -> const inner_backstrides_type& + { + return m_backstrides; + } +} + +#undef XTENSOR_CONSTEXPR_ENHANCED +#undef XTENSOR_CONSTEXPR_RETURN +#undef XTENSOR_CONSTEXPR_ENHANCED_STATIC +#undef XTENSOR_HAS_CONSTEXPR_ENHANCED + +#endif diff --git a/vendor/xtensor/include/xtensor/xfunction.hpp b/vendor/xtensor/include/xtensor/xfunction.hpp new file mode 100644 index 0000000000..91fe86f365 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xfunction.hpp @@ -0,0 +1,1184 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_FUNCTION_HPP +#define XTENSOR_FUNCTION_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xlayout.hpp" +#include "xscalar.hpp" +#include "xstrides.hpp" +#include "xtensor_simd.hpp" +#include "xutils.hpp" + +namespace xt +{ + + namespace detail + { + + /******************** + * common_size_type * + ********************/ + + template + struct common_size_type + { + using type = std::common_type_t; + }; + + template <> + struct common_size_type<> + { + using type = std::size_t; + }; + + template + using common_size_type_t = typename common_size_type::type; + + template + using conjunction_c = xtl::conjunction...>; + + /************************** + * common_difference type * + **************************/ + + template + struct common_difference_type + { + using type = std::common_type_t; + }; + + template <> + struct common_difference_type<> + { + using type = std::ptrdiff_t; + }; + + template + using common_difference_type_t = typename common_difference_type::type; + + /********************* + * common_value_type * + *********************/ + + template + struct common_value_type + { + using type = promote_type_t...>; + }; + + template + using common_value_type_t = typename common_value_type::type; + + template > + struct simd_return_type + { + }; + + template + struct simd_return_type)>> + { + using type = xsimd::simd_type>; + }; + + template + using simd_return_type_t = typename simd_return_type::type; + + template + struct functor_return_type + { + using type = R; + using simd_type = xsimd::simd_type; + }; + + template + struct functor_return_type> + { + using type = std::complex; + using simd_type = xsimd::simd_type>; + }; + + template + struct functor_return_type + { + using type = bool; + using simd_type = xsimd::simd_bool_type; + }; + + template <> + struct functor_return_type + { + using type = bool; + using simd_type = bool; + }; + } + + template + class xfunction_iterator; + + template + class xfunction_stepper; + + template + class xfunction_base; + + template + struct xiterable_inner_types> + { + using inner_shape_type = promote_shape_t::shape_type...>; + using const_stepper = xfunction_stepper; + using stepper = const_stepper; + }; + + /****************** + * xfunction_base * + ******************/ + +#define DL XTENSOR_DEFAULT_LAYOUT + + /** + * @class xfunction_base + * @brief Base class for multidimensional function operating on + * xexpression. + * + * The xfunction_base class implements a multidimensional function + * operating on xexpression. Inheriting classes specify which + * kind of xexpression the xfunction_base operates on. + * + * @tparam F the function type + * @tparam R the return type of the function + * @tparam CT the closure types for arguments of the function + */ + template + class xfunction_base : private xconst_iterable> + { + public: + + using self_type = xfunction_base; + using only_scalar = all_xscalar; + using functor_type = typename std::remove_reference::type; + using tuple_type = std::tuple; + + using value_type = R; + using reference = value_type; + using const_reference = value_type; + using pointer = value_type*; + using const_pointer = const value_type*; + using size_type = detail::common_size_type_t...>; + using difference_type = detail::common_difference_type_t...>; + using simd_value_type = typename detail::functor_return_type...>, R>::simd_type; + using simd_argument_type = xsimd::simd_type...>>; + using iterable_base = xconst_iterable>; + using inner_shape_type = typename iterable_base::inner_shape_type; + using shape_type = inner_shape_type; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + static constexpr layout_type static_layout = compute_layout(std::decay_t::static_layout...); + static constexpr bool contiguous_layout = detail::conjunction_c::contiguous_layout...>::value; + + template + using layout_iterator = typename iterable_base::template layout_iterator; + template + using const_layout_iterator = typename iterable_base::template const_layout_iterator; + template + using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; + template + using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; + + template + using broadcast_iterator = typename iterable_base::template broadcast_iterator; + template + using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; + template + using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; + template + using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; + + using const_storage_iterator = xfunction_iterator; + using storage_iterator = const_storage_iterator; + using const_reverse_storage_iterator = std::reverse_iterator; + using reverse_storage_iterator = std::reverse_iterator; + + using iterator = typename iterable_base::iterator; + using const_iterator = typename iterable_base::const_iterator; + using reverse_iterator = typename iterable_base::reverse_iterator; + using const_reverse_iterator = typename iterable_base::const_reverse_iterator; + + size_type size() const noexcept; + size_type dimension() const noexcept; + const shape_type& shape() const; + layout_type layout() const noexcept; + + template + const_reference operator()(Args... args) const; + + template + const_reference at(Args... args) const; + + template + const_reference unchecked(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const noexcept; + + using iterable_base::begin; + using iterable_base::end; + using iterable_base::cbegin; + using iterable_base::cend; + using iterable_base::rbegin; + using iterable_base::rend; + using iterable_base::crbegin; + using iterable_base::crend; + + template + const_storage_iterator storage_begin() const noexcept; + template + const_storage_iterator storage_end() const noexcept; + template + const_storage_iterator storage_cbegin() const noexcept; + template + const_storage_iterator storage_cend() const noexcept; + + template + const_reverse_storage_iterator storage_rbegin() const noexcept; + template + const_reverse_storage_iterator storage_rend() const noexcept; + template + const_reverse_storage_iterator storage_crbegin() const noexcept; + template + const_reverse_storage_iterator storage_crend() const noexcept; + + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + const_reference data_element(size_type i) const; + + template ::type> + operator value_type() const; + + template + detail::simd_return_type_t load_simd(size_type i) const; + + const tuple_type& arguments() const noexcept; + + protected: + + template , self_type>::value>> + xfunction_base(Func&& f, CTA&&... e) noexcept; + + ~xfunction_base() = default; + + xfunction_base(const xfunction_base&) = default; + xfunction_base& operator=(const xfunction_base&) = default; + + xfunction_base(xfunction_base&&) = default; + xfunction_base& operator=(xfunction_base&&) = default; + + private: + + template + layout_type layout_impl(std::index_sequence) const noexcept; + + template + const_reference access_impl(std::index_sequence, Args... args) const; + + template + const_reference unchecked_impl(std::index_sequence, Args... args) const; + + template + const_reference element_access_impl(std::index_sequence, It first, It last) const; + + template + const_reference data_element_impl(std::index_sequence, size_type i) const; + + template + auto load_simd_impl(std::index_sequence, size_type i) const; + + template + const_stepper build_stepper(Func&& f, std::index_sequence) const noexcept; + + template + const_storage_iterator build_iterator(Func&& f, std::index_sequence) const noexcept; + + size_type compute_dimension() const noexcept; + + tuple_type m_e; + functor_type m_f; + mutable shape_type m_shape; + mutable bool m_shape_trivial; + mutable bool m_shape_computed; + + friend class xfunction_iterator; + friend class xfunction_stepper; + friend class xconst_iterable; + }; + +#undef DL + + /********************** + * xfunction_iterator * + **********************/ + + template + class xscalar; + + namespace detail + { + template + struct get_iterator_impl + { + using type = typename C::storage_iterator; + }; + + template + struct get_iterator_impl + { + using type = typename C::const_storage_iterator; + }; + + template + struct get_iterator_impl> + { + using type = typename xscalar::dummy_iterator; + }; + + template + struct get_iterator_impl> + { + using type = typename xscalar::const_dummy_iterator; + }; + } + + template + using get_iterator = typename detail::get_iterator_impl::type; + + template + class xfunction_iterator : public xtl::xrandom_access_iterator_base, + typename xfunction_base::value_type, + typename xfunction_base::difference_type, + typename xfunction_base::pointer, + typename xfunction_base::reference> + { + public: + + using self_type = xfunction_iterator; + using functor_type = typename std::remove_reference::type; + using xfunction_type = xfunction_base; + + using value_type = typename xfunction_type::value_type; + using reference = typename xfunction_type::value_type; + using pointer = typename xfunction_type::const_pointer; + using difference_type = typename xfunction_type::difference_type; + using iterator_category = std::random_access_iterator_tag; + + template + xfunction_iterator(const xfunction_type* func, It&&... it) noexcept; + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(const self_type& rhs) const; + + reference operator*() const; + + bool equal(const self_type& rhs) const; + bool less_than(const self_type& rhs) const; + + private: + + using data_type = std::tuple>...>; + + template + reference deref_impl(std::index_sequence) const; + + template + difference_type tuple_max_diff(std::index_sequence, + const data_type& lhs, + const data_type& rhs) const; + + const xfunction_type* p_f; + data_type m_it; + }; + + template + bool operator==(const xfunction_iterator& it1, + const xfunction_iterator& it2); + + template + bool operator<(const xfunction_iterator& it1, + const xfunction_iterator& it2); + + /********************* + * xfunction_stepper * + *********************/ + + template + class xfunction_stepper + { + public: + + using self_type = xfunction_stepper; + using functor_type = typename std::remove_reference::type; + using xfunction_type = xfunction_base; + + using value_type = typename xfunction_type::value_type; + using reference = typename xfunction_type::value_type; + using pointer = typename xfunction_type::const_pointer; + using size_type = typename xfunction_type::size_type; + using difference_type = typename xfunction_type::difference_type; + + using shape_type = typename xfunction_type::shape_type; + + template + xfunction_stepper(const xfunction_type* func, It&&... it) noexcept; + + void step(size_type dim); + void step_back(size_type dim); + void step(size_type dim, size_type n); + void step_back(size_type dim, size_type n); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type l); + + reference operator*() const; + + template + ST step_simd(); + + value_type step_leading(); + + private: + + template + reference deref_impl(std::index_sequence) const; + + template + ST step_simd_impl(std::index_sequence); + + template + value_type step_leading_impl(std::index_sequence); + + const xfunction_type* p_f; + std::tuple::const_stepper...> m_it; + }; + + /************* + * xfunction * + *************/ + + /** + * @class xfunction + * @brief Multidimensional function operating on + * xtensor expressions. + * + * The xfunction class implements a multidimensional function + * operating on xtensor expressions. + * + * @tparam F the function type + * @tparam R the return type of the function + * @tparam CT the closure types for arguments of the function + */ + template + class xfunction : public xfunction_base, + public xexpression> + { + public: + + using self_type = xfunction; + using base_type = xfunction_base; + + template , self_type>::value>> + xfunction(Func&& f, CTA&&... e) noexcept; + + ~xfunction() = default; + + xfunction(const xfunction&) = default; + xfunction& operator=(const xfunction&) = default; + + xfunction(xfunction&&) = default; + xfunction& operator=(xfunction&&) = default; + }; + + /********************************* + * xfunction_base implementation * + *********************************/ + + /** + * @name Constructor + */ + //@{ + /** + * Constructs an xfunction_base applying the specified function to the given + * arguments. + * @param f the function to apply + * @param e the \ref xexpression arguments + */ + template + template + inline xfunction_base::xfunction_base(Func&& f, CTA&&... e) noexcept + : m_e(std::forward(e)...), m_f(std::forward(f)), m_shape(xtl::make_sequence(0, size_type(0))), + m_shape_computed(false) + { + } + //@} + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the size of the expression. + */ + template + inline auto xfunction_base::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the function. + */ + template + inline auto xfunction_base::dimension() const noexcept -> size_type + { + size_type dimension = m_shape_computed ? m_shape.size() : compute_dimension(); + return dimension; + } + + /** + * Returns the shape of the xfunction. + */ + template + inline auto xfunction_base::shape() const -> const shape_type& + { + if (!m_shape_computed) + { + m_shape = xtl::make_sequence(compute_dimension(), size_type(0)); + m_shape_trivial = broadcast_shape(m_shape, false); + m_shape_computed = true; + } + return m_shape; + } + + /** + * Returns the layout_type of the xfunction. + */ + template + inline layout_type xfunction_base::layout() const noexcept + { + return layout_impl(std::make_index_sequence()); + } + //@} + + /** + * @name Data + */ + /** + * Returns a constant reference to the element at the specified position in the function. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the function. + */ + template + template + inline auto xfunction_base::operator()(Args... args) const -> const_reference + { + // The static cast prevents the compiler from instantiating the template methods with signed integers, + // leading to warning about signed/unsigned conversions in the deeper layers of the access methods + return access_impl(std::make_index_sequence(), static_cast(args)...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xfunction_base::at(Args... args) const -> const_reference + { + check_access(shape(), static_cast(args)...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the expression, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xfunction_base::unchecked(Args... args) const -> const_reference + { + // The static cast prevents the compiler from instantiating the template methods with signed integers, + // leading to warning about signed/unsigned conversions in the deeper layers of the access methods + return unchecked_impl(std::make_index_sequence(), static_cast(args)...); + } + + template + template + inline auto xfunction_base::operator[](const S& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xfunction_base::operator[](std::initializer_list index) const -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xfunction_base::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the function. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xfunction_base::element(It first, It last) const -> const_reference + { + return element_access_impl(std::make_index_sequence(), first, last); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the function to the specified parameter. + * @param shape the result shape + * @param reuse_cache boolean for reusing a previously computed shape + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xfunction_base::broadcast_shape(S& shape, bool reuse_cache) const + { + if (reuse_cache && m_shape_computed) + { + std::copy(m_shape.cbegin(), m_shape.cend(), shape.begin()); + return m_shape_trivial; + } + else + { + // e.broadcast_shape must be evaluated even if b is false + auto func = [&shape](bool b, auto&& e) { return e.broadcast_shape(shape) && b; }; + return accumulate(func, true, m_e); + } + } + + /** + * Compares the specified strides with those of the container to see whether + * the broadcasting is trivial. + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xfunction_base::is_trivial_broadcast(const S& strides) const noexcept + { + auto func = [&strides](bool b, auto&& e) { return b && e.is_trivial_broadcast(strides); }; + return accumulate(func, true, m_e); + } + //@} + + template + template + inline auto xfunction_base::storage_begin() const noexcept -> const_storage_iterator + { + return storage_cbegin(); + } + + template + template + inline auto xfunction_base::storage_end() const noexcept -> const_storage_iterator + { + return storage_cend(); + } + + template + template + inline auto xfunction_base::storage_cbegin() const noexcept -> const_storage_iterator + { + auto f = [](const auto& e) noexcept { return detail::trivial_begin(e); }; + return build_iterator(f, std::make_index_sequence()); + } + + template + template + inline auto xfunction_base::storage_cend() const noexcept -> const_storage_iterator + { + auto f = [](const auto& e) noexcept { return detail::trivial_end(e); }; + return build_iterator(f, std::make_index_sequence()); + } + + template + template + inline auto xfunction_base::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage_crbegin(); + } + + template + template + inline auto xfunction_base::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage_crend(); + } + + template + template + inline auto xfunction_base::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(storage_cend()); + } + + template + template + inline auto xfunction_base::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(storage_cbegin()); + } + + template + template + inline auto xfunction_base::stepper_begin(const S& shape) const noexcept -> const_stepper + { + auto f = [&shape](const auto& e) noexcept { return e.stepper_begin(shape); }; + return build_stepper(f, std::make_index_sequence()); + } + + template + template + inline auto xfunction_base::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + auto f = [&shape, l](const auto& e) noexcept { return e.stepper_end(shape, l); }; + return build_stepper(f, std::make_index_sequence()); + } + + template + inline auto xfunction_base::data_element(size_type i) const -> const_reference + { + return data_element_impl(std::make_index_sequence(), i); + } + + template + template + inline xfunction_base::operator value_type() const + { + return operator()(); + } + + template + template + inline auto xfunction_base::load_simd(size_type i) const -> detail::simd_return_type_t + { + return load_simd_impl(std::make_index_sequence(), i); + } + + template + inline auto xfunction_base::arguments() const noexcept -> const tuple_type& + { + return m_e; + } + + template + template + inline layout_type xfunction_base::layout_impl(std::index_sequence) const noexcept + { + return compute_layout(std::get(m_e).layout()...); + } + + template + template + inline auto xfunction_base::access_impl(std::index_sequence, Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + return m_f(std::get(m_e)(args...)...); + } + + template + template + inline auto xfunction_base::unchecked_impl(std::index_sequence, Args... args) const -> const_reference + { + return m_f(std::get(m_e).unchecked(args...)...); + } + + template + template + inline auto xfunction_base::element_access_impl(std::index_sequence, It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_f((std::get(m_e).element(first, last))...); + } + + template + template + inline auto xfunction_base::data_element_impl(std::index_sequence, size_type i) const -> const_reference + { + return m_f((std::get(m_e).data_element(i))...); + } + + namespace detail + { +// TODO: add traits for batch_bool in xsimd and remove this ugly hack + + template + struct is_batch_bool + { + static constexpr bool value = false; + }; + +#ifdef XTENSOR_USE_XSIMD + template + struct is_batch_bool> + { + static constexpr bool value = true; + }; +#endif + + // This metafunction avoids loading boolean values as batches of floating points and + // reciprocally. However, we cannot always load data as batches of their scalar type + // since this prevents mixed arithmetic. + template + struct get_simd_type + { + using simd_value_type = typename std::decay_t::simd_value_type; + static constexpr bool is_arg_bool = is_batch_bool::value; + static constexpr bool is_res_bool = is_batch_bool::value; + using type = std::conditional_t>; + }; + + template + using get_simd_type_t = typename get_simd_type::type; + } + + template + template + inline auto xfunction_base::load_simd_impl(std::index_sequence, size_type i) const + { + return m_f.simd_apply((std::get(m_e) + .template load_simd, simd, simd_argument_type>>(i))...); + } + + template + template + inline auto xfunction_base::build_stepper(Func&& f, std::index_sequence) const noexcept -> const_stepper + { + return const_stepper(this, f(std::get(m_e))...); + } + + template + template + inline auto xfunction_base::build_iterator(Func&& f, std::index_sequence) const noexcept -> const_storage_iterator + { + return const_storage_iterator(this, f(std::get(m_e))...); + } + + template + inline auto xfunction_base::compute_dimension() const noexcept -> size_type + { + auto func = [](size_type d, auto&& e) noexcept { return (std::max)(d, e.dimension()); }; + return accumulate(func, size_type(0), m_e); + } + + /************************************* + * xfunction_iterator implementation * + *************************************/ + + template + template + inline xfunction_iterator::xfunction_iterator(const xfunction_type* func, It&&... it) noexcept + : p_f(func), m_it(std::forward(it)...) + { + } + + template + inline auto xfunction_iterator::operator++() -> self_type& + { + auto f = [](auto& it) { ++it; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator--() -> self_type& + { + auto f = [](auto& it) { return --it; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator+=(difference_type n) -> self_type& + { + auto f = [n](auto& it) { it += n; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator-=(difference_type n) -> self_type& + { + auto f = [n](auto& it) { it -= n; }; + for_each(f, m_it); + return *this; + } + + template + inline auto xfunction_iterator::operator-(const self_type& rhs) const -> difference_type + { + return tuple_max_diff(std::make_index_sequence(), m_it, rhs.m_it); + } + + template + inline auto xfunction_iterator::operator*() const -> reference + { + return deref_impl(std::make_index_sequence()); + } + + template + inline bool xfunction_iterator::equal(const self_type& rhs) const + { + return p_f == rhs.p_f && m_it == rhs.m_it; + } + + template + inline bool xfunction_iterator::less_than(const self_type& rhs) const + { + return p_f == rhs.p_f && m_it < rhs.m_it; + } + + template + template + inline auto xfunction_iterator::deref_impl(std::index_sequence) const -> reference + { + return (p_f->m_f)(*std::get(m_it)...); + } + + template + template + inline auto xfunction_iterator::tuple_max_diff(std::index_sequence, + const data_type& lhs, + const data_type& rhs) const -> difference_type + { + auto diff = std::make_tuple((std::get(lhs) - std::get(rhs))...); + auto func = [](difference_type n, auto&& v) { return (std::max)(n, v); }; + return accumulate(func, difference_type(0), diff); + } + + template + inline bool operator==(const xfunction_iterator& it1, + const xfunction_iterator& it2) + { + return it1.equal(it2); + } + + template + inline bool operator<(const xfunction_iterator& it1, + const xfunction_iterator& it2) + { + return it1.less_than(it2); + } + + /************************************ + * xfunction_stepper implementation * + ************************************/ + + template + template + inline xfunction_stepper::xfunction_stepper(const xfunction_type* func, It&&... it) noexcept + : p_f(func), m_it(std::forward(it)...) + { + } + + template + inline void xfunction_stepper::step(size_type dim) + { + auto f = [dim](auto& it) { it.step(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::step_back(size_type dim) + { + auto f = [dim](auto& it) { it.step_back(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::step(size_type dim, size_type n) + { + auto f = [dim, n](auto& it) { it.step(dim, n); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::step_back(size_type dim, size_type n) + { + auto f = [dim, n](auto& it) { it.step_back(dim, n); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::reset(size_type dim) + { + auto f = [dim](auto& it) { it.reset(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::reset_back(size_type dim) + { + auto f = [dim](auto& it) { it.reset_back(dim); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::to_begin() + { + auto f = [](auto& it) { it.to_begin(); }; + for_each(f, m_it); + } + + template + inline void xfunction_stepper::to_end(layout_type l) + { + auto f = [l](auto& it) { it.to_end(l); }; + for_each(f, m_it); + } + + template + inline auto xfunction_stepper::operator*() const -> reference + { + return deref_impl(std::make_index_sequence()); + } + + template + template + inline auto xfunction_stepper::deref_impl(std::index_sequence) const -> reference + { + return (p_f->m_f)(*std::get(m_it)...); + } + + template + template + inline ST xfunction_stepper::step_simd_impl(std::index_sequence) + { + return (p_f->m_f.simd_apply)(std::get(m_it).template + step_simd, ST, typename xfunction_type::simd_argument_type>>()...); + } + + template + template + inline ST xfunction_stepper::step_simd() + { + return step_simd_impl(std::make_index_sequence()); + } + + template + template + inline auto xfunction_stepper::step_leading_impl(std::index_sequence) + -> value_type + { + return (p_f->m_f)(std::get(m_it).step_leading()...); + } + + template + inline auto xfunction_stepper::step_leading() + -> value_type + { + return step_leading_impl(std::make_index_sequence()); + } + + /**************************** + * xfunction implementation * + ****************************/ + + /** + * Constructs an xfunction applying the specified function to the given + * arguments. + * @param f the function to apply + * @param e the \ref xexpression arguments + */ + template + template + xfunction::xfunction(Func&& f, CTA&&... e) noexcept + : base_type(std::forward(f), std::forward(e)...) + { + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xfunctor_view.hpp b/vendor/xtensor/include/xtensor/xfunctor_view.hpp new file mode 100644 index 0000000000..6cba79575a --- /dev/null +++ b/vendor/xtensor/include/xtensor/xfunctor_view.hpp @@ -0,0 +1,1349 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_FUNCTOR_VIEW_HPP +#define XTENSOR_FUNCTOR_VIEW_HPP + +#include +#include +#include +#include +#include + +#include + +#include "xtensor/xexpression.hpp" +#include "xtensor/xiterator.hpp" +#include "xtensor/xsemantic.hpp" +#include "xtensor/xutils.hpp" + +#include "xtensor/xarray.hpp" +#include "xtensor/xtensor.hpp" + +namespace xt +{ + + /***************************** + * xfunctor_view declaration * + *****************************/ + + template + class xfunctor_iterator; + + template + class xfunctor_stepper; + + template + class xfunctor_view; + + /******************************** + * xfunctor_view_temporary_type * + ********************************/ + + namespace detail + { + template + struct functorview_temporary_type_impl + { + using type = xarray; + }; + + template + struct functorview_temporary_type_impl, L> + { + using type = xtensor; + }; + } + + template + struct xfunctor_view_temporary_type + { + using type = typename detail::functorview_temporary_type_impl::type; + }; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using temporary_type = typename xfunctor_view_temporary_type::type; + }; + +#define DL XTENSOR_DEFAULT_LAYOUT + /** + * @class xfunctor_view + * @brief View of an xexpression . + * + * The xfunctor_view class is an expression addressing its elements by applying a functor to the + * corresponding element of an underlying expression. Unlike e.g. xgenerator, an xfunctor_view is + * an lvalue. It is used e.g. to access real and imaginary parts of complex expressions. + * + * xfunctor_view is not meant to be used directly, but through helper functions such + * as \ref real or \ref imag. + * + * @tparam F the functor type to be applied to the elements of specified expression. + * @tparam CT the closure type of the \ref xexpression type underlying this view + * + * @sa real, imag + */ + template + class xfunctor_view : public xview_semantic> + { + public: + + using self_type = xfunctor_view; + using xexpression_type = std::decay_t; + using semantic_base = xview_semantic; + using functor_type = typename std::decay_t; + + using value_type = typename functor_type::value_type; + using reference = typename functor_type::reference; + using const_reference = typename functor_type::const_reference; + using pointer = typename functor_type::pointer; + using const_pointer = typename functor_type::const_pointer; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + + using shape_type = typename xexpression_type::shape_type; + + static constexpr layout_type static_layout = xexpression_type::static_layout; + static constexpr bool contiguous_layout = false; + + using stepper = xfunctor_stepper; + using const_stepper = xfunctor_stepper; + + template + using layout_iterator = xfunctor_iterator>; + template + using const_layout_iterator = xfunctor_iterator>; + + template + using reverse_layout_iterator = xfunctor_iterator>; + template + using const_reverse_layout_iterator = xfunctor_iterator>; + + template + using broadcast_iterator = xfunctor_iterator>; + template + using const_broadcast_iterator = xfunctor_iterator>; + + template + using reverse_broadcast_iterator = xfunctor_iterator>; + template + using const_reverse_broadcast_iterator = xfunctor_iterator>; + + using storage_iterator = xfunctor_iterator; + using const_storage_iterator = xfunctor_iterator; + using reverse_storage_iterator = xfunctor_iterator; + using const_reverse_storage_iterator = xfunctor_iterator; + + using iterator = xfunctor_iterator; + using const_iterator = xfunctor_iterator; + using reverse_iterator = xfunctor_iterator; + using const_reverse_iterator = xfunctor_iterator; + + explicit xfunctor_view(CT) noexcept; + + template + xfunctor_view(Func&&, E&&) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + size_type size() const noexcept; + size_type dimension() const noexcept; + const shape_type& shape() const noexcept; + layout_type layout() const noexcept; + + template + reference operator()(Args... args); + + template + reference at(Args... args); + + template + reference unchecked(Args... args); + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference element(IT first, IT last); + + template + const_reference operator()(Args... args) const; + + template + const_reference unchecked(Args... args) const; + + template + const_reference at(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(IT first, IT last) const; + + template + bool broadcast_shape(S& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const S& strides) const; + + template + auto begin() noexcept; + template + auto end() noexcept; + + template + auto begin() const noexcept; + template + auto end() const noexcept; + template + auto cbegin() const noexcept; + template + auto cend() const noexcept; + + template + auto rbegin() noexcept; + template + auto rend() noexcept; + + template + auto rbegin() const noexcept; + template + auto rend() const noexcept; + template + auto crbegin() const noexcept; + template + auto crend() const noexcept; + + template + broadcast_iterator begin(const S& shape) noexcept; + template + broadcast_iterator end(const S& shape) noexcept; + + template + const_broadcast_iterator begin(const S& shape) const noexcept; + template + const_broadcast_iterator end(const S& shape) const noexcept; + template + const_broadcast_iterator cbegin(const S& shape) const noexcept; + template + const_broadcast_iterator cend(const S& shape) const noexcept; + + template + reverse_broadcast_iterator rbegin(const S& shape) noexcept; + template + reverse_broadcast_iterator rend(const S& shape) noexcept; + + template + const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator rend(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crend(const S& shape) const noexcept; + + template + storage_iterator storage_begin() noexcept; + template + storage_iterator storage_end() noexcept; + + template + const_storage_iterator storage_begin() const noexcept; + template + const_storage_iterator storage_end() const noexcept; + template + const_storage_iterator storage_cbegin() const noexcept; + template + const_storage_iterator storage_cend() const noexcept; + + template + reverse_storage_iterator storage_rbegin() noexcept; + template + reverse_storage_iterator storage_rend() noexcept; + + template + const_reverse_storage_iterator storage_rbegin() const noexcept; + template + const_reverse_storage_iterator storage_rend() const noexcept; + template + const_reverse_storage_iterator storage_crbegin() const noexcept; + template + const_reverse_storage_iterator storage_crend() const noexcept; + + template + stepper stepper_begin(const S& shape) noexcept; + template + stepper stepper_end(const S& shape, layout_type l) noexcept; + template + const_stepper stepper_begin(const S& shape) const noexcept; + template + const_stepper stepper_end(const S& shape, layout_type l) const noexcept; + + private: + + CT m_e; + functor_type m_functor; + + using temporary_type = typename xcontainer_inner_types::temporary_type; + void assign_temporary_impl(temporary_type&& tmp); + friend class xview_semantic>; + }; + +#undef DL + + /********************************* + * xfunctor_iterator declaration * + *********************************/ + + template + class xfunctor_iterator : public xtl::xrandom_access_iterator_base, + typename F::value_type, + typename std::iterator_traits::difference_type, + typename xtl::xproxy_wrapper()(*(IT())))>::pointer, + xtl::xproxy_wrapper()(*(IT())))>> + { + public: + + using functor_type = std::decay_t; + using subiterator_traits = std::iterator_traits; + + using value_type = typename functor_type::value_type; + using reference = xtl::xproxy_wrapper()(*(IT())))>; + using pointer = typename reference::pointer; + using difference_type = typename subiterator_traits::difference_type; + using iterator_category = typename subiterator_traits::iterator_category; + + using self_type = xfunctor_iterator; + + xfunctor_iterator(const IT&, const functor_type*); + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(xfunctor_iterator rhs) const; + + reference operator*() const; + pointer operator->() const; + + bool equal(const xfunctor_iterator& rhs) const; + bool less_than(const xfunctor_iterator& rhs) const; + + private: + + IT m_it; + const functor_type* p_functor; + }; + + template + bool operator==(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs); + + template + bool operator<(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs); + + /******************************** + * xfunctor_stepper declaration * + ********************************/ + + template + class xfunctor_stepper + { + public: + + using functor_type = std::decay_t; + + using value_type = typename functor_type::value_type; + using reference = apply_cv_t; + using pointer = std::remove_reference_t*; + using size_type = typename ST::size_type; + using difference_type = typename ST::difference_type; + + xfunctor_stepper() = default; + xfunctor_stepper(const ST&, const functor_type*); + + reference operator*() const; + + void step(size_type dim); + void step_back(size_type dim); + void step(size_type dim, size_type n); + void step_back(size_type dim, size_type n); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type); + + private: + + ST m_stepper; + const functor_type* p_functor; + }; + + /******************************** + * xfunctor_view implementation * + ********************************/ + + /** + * @name Constructors + */ + //@{ + + /** + * Constructs an xfunctor_view expression wrappering the specified \ref xexpression. + * + * @param e the underlying expression + */ + template + inline xfunctor_view::xfunctor_view(CT e) noexcept + : m_e(e), m_functor(functor_type()) + { + } + + /** + * Constructs an xfunctor_view expression wrappering the specified \ref xexpression. + * + * @param func the functor to be applied to the elements of the underlying expression. + * @param e the underlying expression + */ + template + template + inline xfunctor_view::xfunctor_view(Func&& func, E&& e) noexcept + : m_e(std::forward(e)), m_functor(std::forward(func)) + { + } + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xfunctor_view::operator=(const xexpression& e) -> self_type& + { + bool cond = (e.derived_cast().shape().size() == dimension()) && std::equal(shape().begin(), shape().end(), e.derived_cast().shape().begin()); + if (!cond) + { + semantic_base::operator=(broadcast(e.derived_cast(), shape())); + } + else + { + semantic_base::operator=(e); + } + return *this; + } + //@} + + template + template + inline auto xfunctor_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(begin(), end(), e); + return *this; + } + + template + inline void xfunctor_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), begin()); + } + + /** + * @name Size and shape + */ + /** + * Returns the size of the expression. + */ + template + inline auto xfunctor_view::size() const noexcept -> size_type + { + return m_e.size(); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xfunctor_view::dimension() const noexcept -> size_type + { + return m_e.dimension(); + } + + /** + * Returns the shape of the expression. + */ + template + inline auto xfunctor_view::shape() const noexcept -> const shape_type& + { + return m_e.shape(); + } + + /** + * Returns the layout_type of the expression. + */ + template + inline layout_type xfunctor_view::layout() const noexcept + { + return m_e.layout(); + } + //@} + + /** + * @name Data + */ + /** + * Returns a reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the expression. + */ + template + template + inline auto xfunctor_view::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + return m_functor(m_e(args...)); + } + + /** + * Returns a reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xfunctor_view::at(Args... args) -> reference + { + check_access(shape(), args...); + return this->operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the expression, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xfunctor_view::unchecked(Args... args) -> reference + { + return m_functor(m_e.unchecked(args...)); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices in the sequence should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xfunctor_view::operator[](const S& index) + -> disable_integral_t + { + return m_functor(m_e[index]); + } + + template + template + inline auto xfunctor_view::operator[](std::initializer_list index) + -> reference + { + return m_functor(m_e[index]); + } + + template + inline auto xfunctor_view::operator[](size_type i) -> reference + { + return operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the function. + */ + template + template + inline auto xfunctor_view::element(IT first, IT last) -> reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_functor(m_e.element(first, last)); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the expression. + */ + template + template + inline auto xfunctor_view::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + XTENSOR_CHECK_DIMENSION(shape(), args...); + return m_functor(m_e(args...)); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xfunctor_view::at(Args... args) const -> const_reference + { + check_access(shape(), args...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the expression, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xfunctor_view::unchecked(Args... args) const -> const_reference + { + return m_functor(m_e.unchecked(args...)); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices in the sequence should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xfunctor_view::operator[](const S& index) const + -> disable_integral_t + { + return m_functor(m_e[index]); + } + + template + template + inline auto xfunctor_view::operator[](std::initializer_list index) const + -> const_reference + { + return m_functor(m_e[index]); + } + + template + inline auto xfunctor_view::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the function. + */ + template + template + inline auto xfunctor_view::element(IT first, IT last) const -> const_reference + { + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_functor(m_e.element(first, last)); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the function to the specified parameter. + * @param shape the result shape + * @param reuse_cache boolean for reusing a previously computed shape + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xfunctor_view::broadcast_shape(S& shape, bool reuse_cache) const + { + return m_e.broadcast_shape(shape, reuse_cache); + } + + /** + * Compares the specified strides with those of the container to see whether + * the broadcasting is trivial. + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xfunctor_view::is_trivial_broadcast(const S& strides) const + { + return m_e.is_trivial_broadcast(strides); + } + //@} + + /** + * @name Iterators + */ + //@{ + /** + * Returns an iterator to the first element of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::begin() noexcept + { + return xfunctor_iterator())> + (m_e.template begin(), &m_functor); + } + + /** + * Returns an iterator to the element following the last element + * of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::end() noexcept + { + return xfunctor_iterator())> + (m_e.template end(), &m_functor); + } + + /** + * Returns a constant iterator to the first element of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::begin() const noexcept + { + return this->template cbegin(); + } + + /** + * Returns a constant iterator to the element following the last element + * of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::end() const noexcept + { + return this->template cend(); + } + + /** + * Returns a constant iterator to the first element of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::cbegin() const noexcept + { + return xfunctor_iterator())> + (m_e.template cbegin(), &m_functor); + } + + /** + * Returns a constant iterator to the element following the last element + * of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::cend() const noexcept + { + return xfunctor_iterator())> + (m_e.template cend(), &m_functor); + } + //@} + + /** + * @name Broadcast iterators + */ + //@{ + /** + * Returns a constant iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::begin(const S& shape) noexcept -> broadcast_iterator + { + return broadcast_iterator(m_e.template begin(shape), &m_functor); + } + + /** + * Returns a constant iterator to the element following the last element of the + * expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::end(const S& shape) noexcept -> broadcast_iterator + { + return broadcast_iterator(m_e.template end(shape), &m_functor); + } + + /** + * Returns a constant iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::begin(const S& shape) const noexcept -> const_broadcast_iterator + { + return cbegin(shape); + } + + /** + * Returns a constant iterator to the element following the last element of the + * expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::end(const S& shape) const noexcept -> const_broadcast_iterator + { + return cend(shape); + } + + /** + * Returns a constant iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::cbegin(const S& shape) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(m_e.template cbegin(shape), &m_functor); + } + + /** + * Returns a constant iterator to the element following the last element of the + * expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::cend(const S& shape) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(m_e.template cend(shape), &m_functor); + } + //@} + + /** + * @name Reverse iterators + */ + //@{ + /** + * Returns an iterator to the first element of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rbegin() noexcept + { + return xfunctor_iterator())> + (m_e.template rbegin(), &m_functor); + } + + /** + * Returns an iterator to the element following the last element + * of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rend() noexcept + { + return xfunctor_iterator())> + (m_e.template rend(), &m_functor); + } + + /** + * Returns a constant iterator to the first element of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rbegin() const noexcept + { + return this->template crbegin(); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rend() const noexcept + { + return this->template crend(); + } + + /** + * Returns a constant iterator to the first element of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::crbegin() const noexcept + { + return xfunctor_iterator())> + (m_e.template rbegin(), &m_functor); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::crend() const noexcept + { + return xfunctor_iterator())> + (m_e.template rend(), &m_functor); + } + //@} + + /** + * @name Reverse broadcast iterators + */ + /** + * Returns an iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(m_e.template rbegin(shape), &m_functor); + } + + /** + * Returns an iterator to the element following the last element of the + * reversed expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rend(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(m_e.template rend(shape), &m_functor); + } + + /** + * Returns a constant iterator to the first element of the reversed expression. + * The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return crbegin(shape); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::rend(const S& /*shape*/) const noexcept -> const_reverse_broadcast_iterator + { + return crend(); + } + + /** + * Returns a constant iterator to the first element of the reversed expression. + * The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::crbegin(const S& /*shape*/) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(m_e.template crbegin(), &m_functor); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xfunctor_view::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(m_e.template crend(shape), &m_functor); + } + //@} + + template + template + inline auto xfunctor_view::storage_begin() noexcept -> storage_iterator + { + return storage_iterator(m_e.template storage_begin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_end() noexcept -> storage_iterator + { + return storage_iterator(m_e.template storage_end(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_begin() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_begin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_end() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_end(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_cbegin() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_cbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_cend() const noexcept -> const_storage_iterator + { + return const_storage_iterator(m_e.template storage_cend(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rbegin() noexcept -> reverse_storage_iterator + { + return reverse_storage_iterator(m_e.template storage_rbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rend() noexcept -> reverse_storage_iterator + { + return reverse_storage_iterator(m_e.template storage_rend(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_rbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_rend(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_crbegin(), &m_functor); + } + + template + template + inline auto xfunctor_view::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return const_reverse_storage_iterator(m_e.template storage_crend(), &m_functor); + } + + /*************** + * stepper api * + ***************/ + + template + template + inline auto xfunctor_view::stepper_begin(const S& shape) noexcept -> stepper + { + return stepper(m_e.stepper_begin(shape), &m_functor); + } + + template + template + inline auto xfunctor_view::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + return stepper(m_e.stepper_end(shape, l), &m_functor); + } + + template + template + inline auto xfunctor_view::stepper_begin(const S& shape) const noexcept -> const_stepper + { + const xexpression_type& const_m_e = m_e; + return const_stepper(const_m_e.stepper_begin(shape), &m_functor); + } + + template + template + inline auto xfunctor_view::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + const xexpression_type& const_m_e = m_e; + return const_stepper(const_m_e.stepper_end(shape, l), &m_functor); + } + + /************************************ + * xfunctor_iterator implementation * + ************************************/ + + template + xfunctor_iterator::xfunctor_iterator(const IT& it, const functor_type* pf) + : m_it(it), p_functor(pf) + { + } + + template + inline auto xfunctor_iterator::operator++() -> self_type& + { + ++m_it; + return *this; + } + + template + inline auto xfunctor_iterator::operator--() -> self_type& + { + --m_it; + return *this; + } + + template + inline auto xfunctor_iterator::operator+=(difference_type n) -> self_type& + { + m_it += n; + return *this; + } + + template + inline auto xfunctor_iterator::operator-=(difference_type n) -> self_type& + { + m_it -= n; + return *this; + } + + template + inline auto xfunctor_iterator::operator-(xfunctor_iterator rhs) const -> difference_type + { + return m_it - rhs.m_it; + } + + template + auto xfunctor_iterator::operator*() const -> reference + { + return xtl::proxy_wrapper((*p_functor)(*m_it)); + } + + template + auto xfunctor_iterator::operator->() const -> pointer + { + return &(operator*()); + } + + template + auto xfunctor_iterator::equal(const xfunctor_iterator& rhs) const -> bool + { + return m_it == rhs.m_it; + } + + template + auto xfunctor_iterator::less_than(const xfunctor_iterator& rhs) const -> bool + { + return m_it < rhs.m_it; + } + + template + bool operator==(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs) + { + return lhs.equal(rhs); + } + + template + bool operator<(const xfunctor_iterator& lhs, + const xfunctor_iterator& rhs) + { + return !lhs.less_than(rhs); + } + + /*********************************** + * xfunctor_stepper implementation * + ***********************************/ + + template + xfunctor_stepper::xfunctor_stepper(const ST& stepper, const functor_type* pf) + : m_stepper(stepper), p_functor(pf) + { + } + + template + auto xfunctor_stepper::operator*() const -> reference + { + return (*p_functor)(*m_stepper); + } + + template + void xfunctor_stepper::step(size_type dim) + { + m_stepper.step(dim); + } + + template + void xfunctor_stepper::step_back(size_type dim) + { + m_stepper.step_back(dim); + } + + template + void xfunctor_stepper::step(size_type dim, size_type n) + { + m_stepper.step(dim, n); + } + + template + void xfunctor_stepper::step_back(size_type dim, size_type n) + { + m_stepper.step_back(dim, n); + } + + template + void xfunctor_stepper::reset(size_type dim) + { + m_stepper.reset(dim); + } + + template + void xfunctor_stepper::reset_back(size_type dim) + { + m_stepper.reset_back(dim); + } + + template + void xfunctor_stepper::to_begin() + { + m_stepper.to_begin(); + } + + template + void xfunctor_stepper::to_end(layout_type l) + { + m_stepper.to_end(l); + } +} +#endif diff --git a/vendor/xtensor/include/xtensor/xgenerator.hpp b/vendor/xtensor/include/xtensor/xgenerator.hpp new file mode 100644 index 0000000000..f1118fe439 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xgenerator.hpp @@ -0,0 +1,401 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_GENERATOR_HPP +#define XTENSOR_GENERATOR_HPP + +#include +#include +#include +#include +#include +#include + +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xstrides.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /************** + * xgenerator * + **************/ + + template + class xgenerator; + + template + struct xiterable_inner_types> + { + using inner_shape_type = S; + using const_stepper = xindexed_stepper, true>; + using stepper = const_stepper; + }; + + /** + * @class xgenerator + * @brief Multidimensional function operating on indices. + * + * The xgenerator class implements a multidimensional function, + * generating a value from the supplied indices. + * + * @tparam F the function type + * @tparam R the return type of the function + * @tparam S the shape type of the generator + */ + template + class xgenerator : public xexpression>, + public xconst_iterable> + { + public: + + using self_type = xgenerator; + using functor_type = typename std::remove_reference::type; + + using value_type = R; + using reference = value_type; + using const_reference = value_type; + using pointer = value_type*; + using const_pointer = const value_type*; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterable_base = xconst_iterable; + using inner_shape_type = typename iterable_base::inner_shape_type; + using shape_type = inner_shape_type; + using strides_type = S; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + static constexpr layout_type static_layout = layout_type::any; + static constexpr bool contiguous_layout = false; + + template + xgenerator(Func&& f, const S& shape) noexcept; + + size_type size() const noexcept; + size_type dimension() const noexcept; + const inner_shape_type& shape() const noexcept; + layout_type layout() const noexcept; + + template + const_reference operator()(Args... args) const; + template + const_reference at(Args... args) const; + template + const_reference unchecked(Args... args) const; + template + disable_integral_t operator[](const OS& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(O& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const O& /*strides*/) const noexcept; + + template + const_stepper stepper_begin(const O& shape) const noexcept; + template + const_stepper stepper_end(const O& shape, layout_type) const noexcept; + + template ::value>> + void assign_to(xexpression& e) const noexcept; + + private: + + template + void adapt_index() const; + + template + void adapt_index(I& arg, Args&... args) const; + + functor_type m_f; + inner_shape_type m_shape; + }; + + /***************************** + * xgenerator implementation * + *****************************/ + + /** + * @name Constructor + */ + //@{ + /** + * Constructs an xgenerator applying the specified function over the + * given shape. + * @param f the function to apply + * @param shape the shape of the xgenerator + */ + template + template + inline xgenerator::xgenerator(Func&& f, const S& shape) noexcept + : m_f(std::forward(f)), m_shape(shape) + { + } + //@} + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the size of the expression. + */ + template + inline auto xgenerator::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the function. + */ + template + inline auto xgenerator::dimension() const noexcept -> size_type + { + return m_shape.size(); + } + + /** + * Returns the shape of the xgenerator. + */ + template + inline auto xgenerator::shape() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + inline layout_type xgenerator::layout() const noexcept + { + return static_layout; + } + + //@} + + /** + * @name Data + */ + /** + * Returns the evaluated element at the specified position in the function. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal or greater than + * the number of dimensions of the function. + */ + template + template + inline auto xgenerator::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(shape(), args...)); + adapt_index<0>(args...); + return m_f(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the function. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xgenerator::at(Args... args) const -> const_reference + { + check_access(shape(), args...); + return this->operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices must be equal to the number of + * dimensions of the expression, else the behavior is undefined. + * + * @warning This method is meant for performance, for expressions with a dynamic + * number of dimensions (i.e. not known at compile time). Since it may have + * undefined behavior (see parameters), operator() should be prefered whenever + * it is possible. + * @warning This method is NOT compatible with broadcasting, meaning the following + * code has undefined behavior: + * \code{.cpp} + * xt::xarray a = {{0, 1}, {2, 3}}; + * xt::xarray b = {0, 1}; + * auto fd = a + b; + * double res = fd.uncheked(0, 1); + * \endcode + */ + template + template + inline auto xgenerator::unchecked(Args... args) const -> const_reference + { + return m_f(args...); + } + + template + template + inline auto xgenerator::operator[](const OS& index) const + -> disable_integral_t + { + return element(index.cbegin(), index.cend()); + } + + template + template + inline auto xgenerator::operator[](std::initializer_list index) const + -> const_reference + { + return element(index.begin(), index.end()); + } + + template + inline auto xgenerator::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the function. + * @param first iterator starting the sequence of indices + * @param last iterator ending the sequence of indices + * The number of indices in the sequence should be equal to or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xgenerator::element(It first, It last) const -> const_reference + { + using bounded_iterator = xbounded_iterator; + XTENSOR_TRY(check_element_index(shape(), first, last)); + return m_f.element(bounded_iterator(first, shape().cbegin()), bounded_iterator(last, shape().cend())); + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the function to the specified parameter. + * @param shape the result shape + * @param reuse_cache parameter for internal optimization + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xgenerator::broadcast_shape(O& shape, bool) const + { + return xt::broadcast_shape(m_shape, shape); + } + + /** + * Compares the specified strides with those of the container to see whether + * the broadcasting is trivial. + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xgenerator::is_trivial_broadcast(const O& /*strides*/) const noexcept + { + return false; + } + //@} + + template + template + inline auto xgenerator::stepper_begin(const O& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xgenerator::stepper_end(const O& shape, layout_type) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset, true); + } + + template + template + inline void xgenerator::assign_to(xexpression& e) const noexcept + { + e.derived_cast().resize(m_shape); + m_f.assign_to(e); + } + + template + template + inline void xgenerator::adapt_index() const + { + } + + template + template + inline void xgenerator::adapt_index(I& arg, Args&... args) const + { + using value_type = typename decltype(m_shape)::value_type; + if (sizeof...(Args) + 1 > m_shape.size()) + { + adapt_index(args...); + } + else + { + if (static_cast(arg) >= m_shape[dim] && m_shape[dim] == 1) + { + arg = 0; + } + adapt_index(args...); + } + } + + namespace detail + { +#ifdef X_OLD_CLANG + template + inline auto make_xgenerator(Functor&& f, std::initializer_list shape) noexcept + { + using shape_type = std::vector; + using type = xgenerator; + return type(std::forward(f), xtl::forward_sequence(shape)); + } +#else + template + inline auto make_xgenerator(Functor&& f, const I (&shape)[L]) noexcept + { + using shape_type = std::array; + using type = xgenerator; + return type(std::forward(f), xtl::forward_sequence(shape)); + } +#endif + + template + inline auto make_xgenerator(Functor&& f, S&& shape) noexcept + { + using type = xgenerator>; + return type(std::forward(f), std::forward(shape)); + } + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xindex_view.hpp b/vendor/xtensor/include/xtensor/xindex_view.hpp new file mode 100644 index 0000000000..ef46c1bbbd --- /dev/null +++ b/vendor/xtensor/include/xtensor/xindex_view.hpp @@ -0,0 +1,745 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_INDEX_VIEW_HPP +#define XTENSOR_INDEX_VIEW_HPP + +#include +#include +#include +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xstrides.hpp" +#include "xutils.hpp" + +namespace xt +{ + + template + class xindex_view; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using temporary_type = xarray; + }; + + template + struct xiterable_inner_types> + { + using inner_shape_type = std::array; + using const_stepper = xindexed_stepper, true>; + using stepper = xindexed_stepper, false>; + }; + + /*************** + * xindex_view * + ***************/ + + /** + * @class xindex_view + * @brief View of an xexpression from vector of indices. + * + * The xindex_view class implements a flat (1D) view into a multidimensional + * xexpression yielding the values at the indices of the index array. + * xindex_view is not meant to be used directly, but only with the \ref index_view + * and \ref filter helper functions. + * + * @tparam CT the closure type of the \ref xexpression type underlying this view + * @tparam I the index array type of the view + * + * @sa index_view, filter + */ + template + class xindex_view : public xview_semantic>, + public xiterable> + { + public: + + using self_type = xindex_view; + using xexpression_type = std::decay_t; + using semantic_base = xview_semantic; + + using value_type = typename xexpression_type::value_type; + using reference = typename xexpression_type::reference; + using const_reference = typename xexpression_type::const_reference; + using pointer = typename xexpression_type::pointer; + using const_pointer = typename xexpression_type::const_pointer; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + + using iterable_base = xiterable; + using inner_shape_type = typename iterable_base::inner_shape_type; + using shape_type = inner_shape_type; + using strides_type = shape_type; + + using indices_type = I; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + using temporary_type = typename xcontainer_inner_types::temporary_type; + using base_index_type = xindex_type_t; + + static constexpr layout_type static_layout = layout_type::dynamic; + static constexpr bool contiguous_layout = false; + + template + xindex_view(CTA&& e, I2&& indices) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + size_type size() const noexcept; + size_type dimension() const noexcept; + const inner_shape_type& shape() const noexcept; + layout_type layout() const noexcept; + + template + void fill(const T& value); + + reference operator()(size_type idx = size_type(0)); + template + reference operator()(size_type idx0, size_type idx1, Args... args); + reference unchecked(size_type idx); + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference element(It first, It last); + + const_reference operator()(size_type idx = size_type(0)) const; + template + const_reference operator()(size_type idx0, size_type idx1, Args... args) const; + const_reference unchecked(size_type idx) const; + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference element(It first, It last) const; + + template + bool broadcast_shape(O& shape, bool reuse_cache = false) const; + + template + bool is_trivial_broadcast(const O& /*strides*/) const noexcept; + + template + stepper stepper_begin(const ST& shape); + template + stepper stepper_end(const ST& shape, layout_type); + + template + const_stepper stepper_begin(const ST& shape) const; + template + const_stepper stepper_end(const ST& shape, layout_type) const; + + private: + + CT m_e; + const indices_type m_indices; + const inner_shape_type m_shape; + + void assign_temporary_impl(temporary_type&& tmp); + + friend class xview_semantic>; + }; + + /*************** + * xfiltration * + ***************/ + + /** + * @class xfiltration + * @brief Filter of a xexpression for fast scalar assign. + * + * The xfiltration class implements a lazy filtration of a multidimentional + * \ref xexpression, optimized for scalar and computed scalar assignments. + * Actually, the \ref xfiltration class IS NOT an \ref xexpression and the + * scalar and computed scalar assignments are the only method it provides. + * The filtering condition is not evaluated until the filtration is assigned. + * + * xfiltration is not meant to be used directly, but only with the \ref filtration + * helper function. + * + * @tparam ECT the closure type of the \ref xexpression type underlying this filtration + * @tparam CCR the closure type of the filtering \ref xexpression type + * + * @sa filtration + */ + template + class xfiltration + { + public: + + using self_type = xfiltration; + using xexpression_type = std::decay_t; + using const_reference = typename xexpression_type::const_reference; + + template + xfiltration(ECTA&& e, CCTA&& condition); + + template + disable_xexpression operator=(const E&); + + template + disable_xexpression operator+=(const E&); + + template + disable_xexpression operator-=(const E&); + + template + disable_xexpression operator*=(const E&); + + template + disable_xexpression operator/=(const E&); + + template + disable_xexpression operator%=(const E&); + + private: + + template + self_type& apply(F&& func); + + ECT m_e; + CCT m_condition; + }; + + /****************************** + * xindex_view implementation * + ******************************/ + + /** + * @name Constructor + */ + //@{ + /** + * Constructs an xindex_view, selecting the indices specified by \a indices. + * The resulting xexpression has a 1D shape with a length of n for n indices. + * + * @param e the underlying xexpression for this view + * @param indices the indices to select + */ + template + template + inline xindex_view::xindex_view(CTA&& e, I2&& indices) noexcept + : m_e(std::forward(e)), m_indices(std::forward(indices)), m_shape({ m_indices.size() }) + { + } + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * The extended assignment operator. + */ + template + template + inline auto xindex_view::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + //@} + + template + template + inline auto xindex_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(this->begin(), this->end(), e); + return *this; + } + + template + inline void xindex_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); + } + + /** + * @name Size and shape + */ + //@{ + /** + * Returns the size of the xindex_view. + */ + template + inline auto xindex_view::size() const noexcept -> size_type + { + return compute_size(shape()); + } + + /** + * Returns the number of dimensions of the xindex_view. + */ + template + inline auto xindex_view::dimension() const noexcept -> size_type + { + return 1; + } + + /** + * Returns the shape of the xindex_view. + */ + template + inline auto xindex_view::shape() const noexcept -> const inner_shape_type& + { + return m_shape; + } + + template + inline layout_type xindex_view::layout() const noexcept + { + return static_layout; + } + + //@} + + /** + * @name Data + */ + //@{ + + /** + * Fills the view with the given value. + * @param value the value to fill the view with. + */ + template + template + inline void xindex_view::fill(const T& value) + { + std::fill(this->storage_begin(), this->storage_end(), value); + } + + /** + * Returns a reference to the element at the specified position in the xindex_view. + * @param idx index specifying the position in the index_view. More indices may be provided, + * only the last one will be used. + */ + template + inline auto xindex_view::operator()(size_type idx) -> reference + { + return m_e[m_indices[idx]]; + } + + template + template + inline auto xindex_view::operator()(size_type, size_type idx1, Args... args) -> reference + { + return this->operator()(idx1, static_cast(args)...); + } + + /** + * Returns a reference to the element at the specified position in the xindex_view. + * @param idx index specifying the position in the index_view. + */ + template + inline auto xindex_view::unchecked(size_type idx) -> reference + { + return this->operator()(idx); + } + + /** + * Returns a constant reference to the element at the specified position in the xindex_view. + * @param idx index specifying the position in the index_view. More indices may be provided, + * only the last one will be used. + */ + template + inline auto xindex_view::operator()(size_type idx) const -> const_reference + { + return m_e[m_indices[idx]]; + } + + template + template + inline auto xindex_view::operator()(size_type, size_type idx1, Args... args) const -> const_reference + { + return this->operator()(idx1, args...); + } + + /** + * Returns a constant reference to the element at the specified position in the xindex_view. + * @param idx index specifying the position in the index_view. + */ + template + inline auto xindex_view::unchecked(size_type idx) const -> const_reference + { + return this->operator()(idx); + } + + /** + * Returns a reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xindex_view::operator[](const S& index) + -> disable_integral_t + { + return m_e[m_indices[index[0]]]; + } + + template + template + inline auto xindex_view::operator[](std::initializer_list index) + -> reference + { + return m_e[m_indices[*(index.begin())]]; + } + + template + inline auto xindex_view::operator[](size_type i) -> reference + { + return operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the container. + * @param index a sequence of indices specifying the position in the container. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the container. + */ + template + template + inline auto xindex_view::operator[](const S& index) const + -> disable_integral_t + { + return m_e[m_indices[index[0]]]; + } + + template + template + inline auto xindex_view::operator[](std::initializer_list index) const + -> const_reference + { + return m_e[m_indices[*(index.begin())]]; + } + + template + inline auto xindex_view::operator[](size_type i) const -> const_reference + { + return operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the xindex_view. + * @param first iterator starting the sequence of indices + * The number of indices in the sequence should be equal to or greater 1. + */ + template + template + inline auto xindex_view::element(It first, It /*last*/) -> reference + { + return m_e[m_indices[(*first)]]; + } + + /** + * Returns a reference to the element at the specified position in the xindex_view. + * @param first iterator starting the sequence of indices + * The number of indices in the sequence should be equal to or greater 1. + */ + template + template + inline auto xindex_view::element(It first, It /*last*/) const -> const_reference + { + return m_e[m_indices[(*first)]]; + } + //@} + + /** + * @name Broadcasting + */ + //@{ + /** + * Broadcast the shape of the xindex_view to the specified parameter. + * @param shape the result shape + * @param reuse_cache parameter for internal optimization + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xindex_view::broadcast_shape(O& shape, bool) const + { + return xt::broadcast_shape(m_shape, shape); + } + + /** + * Compares the specified strides with those of the container to see whether + * the broadcasting is trivial. + * @return a boolean indicating whether the broadcasting is trivial + */ + template + template + inline bool xindex_view::is_trivial_broadcast(const O& /*strides*/) const noexcept + { + return false; + } + //@} + + /*************** + * stepper api * + ***************/ + + template + template + inline auto xindex_view::stepper_begin(const ST& shape) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset); + } + + template + template + inline auto xindex_view::stepper_end(const ST& shape, layout_type) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset, true); + } + + template + template + inline auto xindex_view::stepper_begin(const ST& shape) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xindex_view::stepper_end(const ST& shape, layout_type) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset, true); + } + + /****************************** + * xfiltration implementation * + ******************************/ + + /** + * @name Constructor + */ + //@{ + /** + * Constructs a xfiltration on the given expression \c e, selecting + * the elements matching the specified \c condition. + * + * @param e the \ref xexpression to filter. + * @param condition the filtering \ref xexpression to apply. + */ + template + template + inline xfiltration::xfiltration(ECTA&& e, CCTA&& condition) + : m_e(std::forward(e)), m_condition(std::forward(condition)) + { + } + //@} + + /** + * @name Extended copy semantic + */ + //@{ + /** + * Assigns the scalar \c e to \c *this. + * @param e the scalar to assign. + * @return a reference to \ *this. + */ + template + template + inline auto xfiltration::operator=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? e : v; }); + } + //@} + + /** + * @name Computed assignement + */ + //@{ + /** + * Adds the scalar \c e to \c *this. + * @param e the scalar to add. + * @return a reference to \c *this. + */ + template + template + inline auto xfiltration::operator+=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? v + e : v; }); + } + + /** + * Subtracts the scalar \c e from \c *this. + * @param e the scalar to subtract. + * @return a reference to \c *this. + */ + template + template + inline auto xfiltration::operator-=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? v - e : v; }); + } + + /** + * Multiplies \c *this with the scalar \c e. + * @param e the scalar involved in the operation. + * @return a reference to \c *this. + */ + template + template + inline auto xfiltration::operator*=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? v * e : v; }); + } + + /** + * Divides \c *this by the scalar \c e. + * @param e the scalar involved in the operation. + * @return a reference to \c *this. + */ + template + template + inline auto xfiltration::operator/=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? v / e : v; }); + } + + /** + * Computes the remainder of \c *this after division by the scalar \c e. + * @param e the scalar involved in the operation. + * @return a reference to \c *this. + */ + template + template + inline auto xfiltration::operator%=(const E& e) -> disable_xexpression + { + return apply([this, &e](const_reference v, bool cond) { return cond ? v % e : v; }); + } + + template + template + inline auto xfiltration::apply(F&& func) -> self_type& + { + std::transform(m_e.cbegin(), m_e.cend(), m_condition.cbegin(), m_e.begin(), func); + return *this; + } + + /** + * @brief creates an indexview from a container of indices. + * + * Returns a 1D view with the elements at \a indices selected. + * + * @param e the underlying xexpression + * @param indices the indices to select + * + * \code{.cpp} + * xarray a = {{1,5,3}, {4,5,6}}; + * b = index_view(a, {{0, 0}, {1, 0}, {1, 1}}); + * std::cout << b << std::endl; // {1, 4, 5} + * b += 100; + * std::cout << a << std::endl; // {{101, 5, 3}, {104, 105, 6}} + * \endcode + */ + template + inline auto index_view(E&& e, I&& indices) noexcept + { + using view_type = xindex_view, std::decay_t>; + return view_type(std::forward(e), std::forward(indices)); + } +#ifdef X_OLD_CLANG + template + inline auto index_view(E&& e, std::initializer_list> indices) noexcept + { + std::vector idx; + for (auto it = indices.begin(); it != indices.end(); ++it) + { + idx.emplace_back(xindex(it->begin(), it->end())); + } + using view_type = xindex_view, std::vector>; + return view_type(std::forward(e), std::move(idx)); + } +#else + template + inline auto index_view(E&& e, const xindex (&indices)[L]) noexcept + { + using view_type = xindex_view, std::array>; + return view_type(std::forward(e), to_array(indices)); + } +#endif + + /** + * @brief creates a view into \a e filtered by \a condition. + * + * Returns a 1D view with the elements selected where \a condition evaluates to \em true. + * This is equivalent to \verbatim{index_view(e, where(condition));}\endverbatim + * The returned view is not optimal if you just want to assign a scalar to the filtered + * elements. In that case, you should consider using the \ref filtration function + * instead. + * + * @param e the underlying xexpression + * @param condition xexpression with shape of \a e which selects indices + * + * \code{.cpp} + * xarray a = {{1,5,3}, {4,5,6}}; + * b = filter(a, a >= 5); + * std::cout << b << std::endl; // {5, 5, 6} + * \endcode + * + * \sa filtration + */ + template + inline auto filter(E&& e, O&& condition) noexcept + { + auto indices = where(std::forward(condition)); + using view_type = xindex_view, decltype(indices)>; + return view_type(std::forward(e), std::move(indices)); + } + + /** + * @brief creates a filtration of \c e filtered by \a condition. + * + * Returns a lazy filtration optimized for scalar assignment. + * Actually, scalar assignment and computed scalar assignments + * are the only available methods of the filtration, the filtration + * IS NOT an \ref xexpression. + * + * @param e the \ref xexpression to filter + * @param condition the filtering \ref xexpression + * + * \code{.cpp} + * xarray a = {{1,5,3}, {4,5,6}}; + * filtration(a, a >= 5) += 2; + * std::cout << a << std::endl; // {{1, 7, 3}, {4, 7, 8}} + * \endcode + */ + template + inline auto filtration(E&& e, C&& condition) noexcept + { + using filtration_type = xfiltration, xclosure_t>; + return filtration_type(std::forward(e), std::forward(condition)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xinfo.hpp b/vendor/xtensor/include/xtensor/xinfo.hpp new file mode 100644 index 0000000000..50da4f6cd4 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xinfo.hpp @@ -0,0 +1,139 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_INFO_HPP +#define XTENSOR_INFO_HPP + +#include + +#ifndef _MSC_VER +# if __cplusplus < 201103 +# define CONSTEXPR11_TN +# define CONSTEXPR14_TN +# define NOEXCEPT_TN +# elif __cplusplus < 201402 +# define CONSTEXPR11_TN constexpr +# define CONSTEXPR14_TN +# define NOEXCEPT_TN noexcept +# else +# define CONSTEXPR11_TN constexpr +# define CONSTEXPR14_TN constexpr +# define NOEXCEPT_TN noexcept +# endif +#else // _MSC_VER +# if _MSC_VER < 1900 +# define CONSTEXPR11_TN +# define CONSTEXPR14_TN +# define NOEXCEPT_TN +# elif _MSC_VER < 2000 +# define CONSTEXPR11_TN constexpr +# define CONSTEXPR14_TN +# define NOEXCEPT_TN noexcept +# else +# define CONSTEXPR11_TN constexpr +# define CONSTEXPR14_TN constexpr +# define NOEXCEPT_TN noexcept +# endif +#endif + +namespace xt +{ + // see http://stackoverflow.com/a/20170989 + struct static_string + { + template + explicit CONSTEXPR11_TN static_string(const char (&a)[N]) NOEXCEPT_TN + : data(a), size(N - 1) + { + } + + CONSTEXPR11_TN static_string(const char* a, const std::size_t sz) NOEXCEPT_TN + : data(a), size(sz) + { + } + + const char* const data; + const std::size_t size; + }; + + template + CONSTEXPR14_TN static_string type_name() + { +#ifdef __clang__ + static_string p(__PRETTY_FUNCTION__); + return static_string(p.data + 39, p.size - 39 - 1); +#elif defined(__GNUC__) + static_string p(__PRETTY_FUNCTION__); +#if __cplusplus < 201402 + return static_string(p.data + 36, p.size - 36 - 1); +#else + return static_string(p.data + 54, p.size - 54 - 1); +#endif +#elif defined(_MSC_VER) + static const static_string p(__FUNCSIG__); + return static_string(p.data + 47, p.size - 47 - 7); +#endif + } + + template + std::string type_to_string() + { + static_string static_name = type_name(); + return std::string(static_name.data, static_name.size); + } + + template + std::string info(const T& t) + { + std::string s; + s += "\nValue type: " + type_to_string(); + s += "\nLayout: "; + if (t.layout() == layout_type::row_major) + { + s += "row_major"; + } + else if (t.layout() == layout_type::column_major) + { + s += "column_major"; + } + else if (t.layout() == layout_type::dynamic) + { + s += "dynamic"; + } + else + { + s += "any"; + } + s += "\nShape: ("; + bool first = true; + for (const auto& el : t.shape()) + { + if (!first) + { + s += ", "; + } + first = false; + s += std::to_string(el); + } + s += ")\nStrides: ("; + first = true; + for (const auto& el : t.strides()) + { + if (!first) + { + s += ", "; + } + first = false; + s += std::to_string(el); + } + s += ")\nSize: " + std::to_string(t.size()) + "\n"; + return s; + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xio.hpp b/vendor/xtensor/include/xtensor/xio.hpp new file mode 100644 index 0000000000..fa778996da --- /dev/null +++ b/vendor/xtensor/include/xtensor/xio.hpp @@ -0,0 +1,634 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_IO_HPP +#define XTENSOR_IO_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include "xexpression.hpp" +#include "xmath.hpp" +#include "xstrided_view.hpp" + +namespace xt +{ + + template + inline std::ostream& operator<<(std::ostream& out, const xexpression& e); + + namespace print_options + { + struct print_options_impl + { + std::size_t edgeitems = 3; + std::size_t line_width = 75; + std::size_t threshold = 1000; + std::streamsize precision = -1; // default precision + }; + + inline print_options_impl& print_options() + { + static print_options_impl po; + return po; + } + + /** + * @brief Sets the line width. After \a line_width chars, + * a new line is added. + * + * @param line_width The line width + */ + inline void set_line_width(std::size_t line_width) + { + print_options().line_width = line_width; + } + + /** + * @brief Sets the threshold after which summarization is triggered (default: 1000). + * + * @param threshold The number of elements in the xexpression that triggers + * summarization in the output + */ + inline void set_threshold(std::size_t threshold) + { + print_options().threshold = threshold; + } + + /** + * @brief Sets the number of edge items. If the summarization is + * triggered, this value defines how many items of each dimension + * are printed. + * + * @param edgeitems The number of edge items + */ + inline void set_edgeitems(std::size_t edgeitems) + { + print_options().edgeitems = edgeitems; + } + + /** + * @brief Sets the precision for printing floating point values. + * + * @param precision The number of digits for floating point output + */ + inline void set_precision(std::streamsize precision) + { + print_options().precision = precision; + } + } + + /************************************** + * xexpression ostream implementation * + **************************************/ + + namespace detail + { + template + std::ostream& xoutput(std::ostream& out, const E& e, + xstrided_slice_vector& slices, F& printer, std::size_t blanks, + std::streamsize element_width, std::size_t edgeitems, std::size_t line_width) + { + using size_type = typename E::size_type; + + const auto view = xt::strided_view(e, slices); + if (view.dimension() == 0) + { + printer.print_next(out); + } + else + { + std::string indents(blanks, ' '); + + size_type i = 0; + size_type elems_on_line = 0; + size_type ewp2 = static_cast(element_width) + size_type(2); + size_type line_lim = static_cast(std::floor(line_width / ewp2)); + + out << '{'; + for (; i != size_type(view.shape()[0] - 1); ++i) + { + if (edgeitems && size_type(view.shape()[0]) > (edgeitems * 2) && i == edgeitems) + { + out << "..., "; + if (view.dimension() > 1) + { + elems_on_line = 0; + out << std::endl + << indents; + } + i = size_type(view.shape()[0]) - edgeitems; + } + if (view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim) + { + out << std::endl + << indents; + elems_on_line = 0; + } + slices.push_back(static_cast(i)); + xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems, line_width) << ','; + slices.pop_back(); + elems_on_line++; + + if (view.dimension() == 1) + { + out << ' '; + } + else + { + out << std::endl + << indents; + } + } + if (view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim) + { + out << std::endl + << indents; + } + slices.push_back(static_cast(i)); + xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems, line_width) << '}'; + slices.pop_back(); + } + return out; + } + + template + static void recurser_run(F& fn, const E& e, xstrided_slice_vector& slices, std::size_t lim = 0) + { + using size_type = typename E::size_type; + const auto view = strided_view(e, slices); + if (view.dimension() == 0) + { + fn.update(view()); + } + else + { + size_type i = 0; + for (; i != static_cast(view.shape()[0] - 1); ++i) + { + if (lim && size_type(view.shape()[0]) > (lim * 2) && i == lim) + { + i = static_cast(view.shape()[0]) - lim; + } + slices.push_back(static_cast(i)); + recurser_run(fn, e, slices, lim); + slices.pop_back(); + } + slices.push_back(static_cast(i)); + recurser_run(fn, e, slices, lim); + slices.pop_back(); + } + } + + template + struct printer; + + template + struct printer::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + using cache_iterator = typename cache_type::const_iterator; + + explicit printer(std::streamsize precision) + : m_precision(precision) + { + } + + void init() + { + m_precision = m_required_precision < m_precision ? m_required_precision : m_precision; + m_it = m_cache.cbegin(); + if (m_scientific) + { + // 3 = sign, number and dot and 4 = "e+00" + m_width = m_precision + 7; + if (m_large_exponent) + { + // = e+000 (additional number) + m_width += 1; + } + } + else + { + std::streamsize decimals = 1; // print a leading 0 + if (std::floor(m_max) != 0) + { + decimals += std::streamsize(std::log10(std::floor(m_max))); + } + // 2 => sign and dot + m_width = 2 + decimals + m_precision; + } + if (!m_required_precision) + { + --m_width; + } + } + + std::ostream& print_next(std::ostream& out) + { + if (!m_scientific) + { + std::stringstream buf; + buf.width(m_width); + buf << std::fixed; + buf.precision(m_precision); + buf << (*m_it); + if (!m_required_precision) + { + buf << '.'; + } + std::string res = buf.str(); + auto sit = res.rbegin(); + while (*sit == '0') + { + *sit = ' '; + ++sit; + } + out << res; + } + else + { + if (!m_large_exponent) + { + out << std::scientific; + out.width(m_width); + out << (*m_it); + } + else + { + std::stringstream buf; + buf.width(m_width); + buf << std::scientific; + buf.precision(m_precision); + buf << (*m_it); + std::string res = buf.str(); + + if (res[res.size() - 4] == 'e') + { + res.erase(0, 1); + res.insert(res.size() - 2, "0"); + } + out << res; + } + } + ++m_it; + return out; + } + + void update(const value_type& val) + { + if (val != 0 && !std::isinf(val) && !std::isnan(val)) + { + if (!m_scientific || !m_large_exponent) + { + int exponent = 1 + int(std::log10(math::abs(val))); + if (exponent <= -5 || exponent > 7) + { + m_scientific = true; + m_required_precision = m_precision; + if (exponent <= -100 || exponent >= 100) + { + m_large_exponent = true; + } + } + } + if (math::abs(val) > m_max) + { + m_max = math::abs(val); + } + if (m_required_precision < m_precision) + { + while (std::floor(val * std::pow(10, m_required_precision)) != val * std::pow(10, m_required_precision)) + { + m_required_precision++; + } + } + } + m_cache.push_back(val); + } + + std::streamsize width() + { + return m_width; + } + + private: + + bool m_large_exponent = false; + bool m_scientific = false; + std::streamsize m_width = 9; + std::streamsize m_precision; + std::streamsize m_required_precision = 0; + value_type m_max = 0; + + cache_type m_cache; + cache_iterator m_it; + }; + + template + struct printer::value && !std::is_same::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + using cache_iterator = typename cache_type::const_iterator; + + explicit printer(std::streamsize) + { + } + + void init() + { + m_it = m_cache.cbegin(); + m_width = 1 + std::streamsize(std::log10(m_max)) + m_sign; + } + + std::ostream& print_next(std::ostream& out) + { + // + enables printing of chars etc. as numbers + // TODO should chars be printed as numbers? + out.width(m_width); + out << +(*m_it); + ++m_it; + return out; + } + + void update(const value_type& val) + { + if (math::abs(val) > m_max) + { + m_max = math::abs(val); + } + if (std::is_signed::value && val < 0) + { + m_sign = true; + } + m_cache.push_back(val); + } + + std::streamsize width() + { + return m_width; + } + + private: + + std::streamsize m_width; + bool m_sign = false; + value_type m_max = 0; + + cache_type m_cache; + cache_iterator m_it; + }; + + template + struct printer::value>> + { + using value_type = bool; + using cache_type = std::vector; + using cache_iterator = typename cache_type::const_iterator; + + explicit printer(std::streamsize) + { + } + + void init() + { + m_it = m_cache.cbegin(); + } + + std::ostream& print_next(std::ostream& out) + { + if (*m_it) + { + out << " true"; + } + else + { + out << "false"; + } + // TODO: the following std::setw(5) isn't working correctly on OSX. + //out << std::boolalpha << std::setw(m_width) << (*m_it); + ++m_it; + return out; + } + + void update(const value_type& val) + { + m_cache.push_back(val); + } + + std::streamsize width() + { + return m_width; + } + + private: + + std::streamsize m_width = 5; + + cache_type m_cache; + cache_iterator m_it; + }; + + template + struct printer::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + using cache_iterator = typename cache_type::const_iterator; + + explicit printer(std::streamsize precision) + : real_printer(precision), imag_printer(precision) + { + } + + void init() + { + real_printer.init(); + imag_printer.init(); + m_it = m_signs.cbegin(); + } + + std::ostream& print_next(std::ostream& out) + { + real_printer.print_next(out); + if (*m_it) + { + out << "-"; + } + else + { + out << "+"; + } + std::stringstream buf; + imag_printer.print_next(buf); + std::string s = buf.str(); + if (s[0] == ' ') + { + s.erase(0, 1); // erase space for +/- + } + // insert j at end of number + std::size_t idx = s.find_last_not_of(" "); + s.insert(idx + 1, "i"); + out << s; + ++m_it; + return out; + } + + void update(const value_type& val) + { + real_printer.update(val.real()); + imag_printer.update(std::abs(val.imag())); + m_signs.push_back(std::signbit(val.imag())); + } + + std::streamsize width() + { + return real_printer.width() + imag_printer.width() + 2; + } + + private: + + printer real_printer, imag_printer; + cache_type m_signs; + cache_iterator m_it; + }; + + template + struct printer::value && !xtl::is_complex::value>> + { + using value_type = std::decay_t; + using cache_type = std::vector; + using cache_iterator = typename cache_type::const_iterator; + + explicit printer(std::streamsize) + { + } + + void init() + { + m_it = m_cache.cbegin(); + if (m_width > 20) + { + m_width = 0; + } + } + + std::ostream& print_next(std::ostream& out) + { + out.width(m_width); + out << *m_it; + ++m_it; + return out; + } + + void update(const value_type& val) + { + std::stringstream buf; + buf << val; + std::string s = buf.str(); + if (int(s.size()) > m_width) + { + m_width = std::streamsize(s.size()); + } + m_cache.push_back(s); + } + + std::streamsize width() + { + return m_width; + } + + private: + + std::streamsize m_width = 0; + cache_type m_cache; + cache_iterator m_it; + }; + + template + struct custom_formatter + { + using value_type = std::decay_t; + + template + custom_formatter(F&& func) + : m_func(func) + { + } + + std::string operator()(const value_type& val) const + { + return m_func(val); + } + + private: + + std::function m_func; + }; + } + + template + std::ostream& pretty_print(const xexpression& e, F&& func, std::ostream& out = std::cout) + { + xfunction, std::string, const_xclosure_t> print_fun(detail::custom_formatter(std::forward(func)), e); + return pretty_print(print_fun, out); + } + + template + std::ostream& pretty_print(const xexpression& e, std::ostream& out = std::cout) + { + const E& d = e.derived_cast(); + + size_t lim = 0; + std::size_t sz = compute_size(d.shape()); + if (sz > print_options::print_options().threshold) + { + lim = print_options::print_options().edgeitems; + } + if (sz == 0) + { + out << "{}"; + return out; + } + + auto temp_precision = out.precision(); + auto precision = temp_precision; + if (print_options::print_options().precision != -1) + { + out.precision(print_options::print_options().precision); + precision = print_options::print_options().precision; + } + + detail::printer p(precision); + + xstrided_slice_vector sv; + detail::recurser_run(p, d, sv, lim); + p.init(); + sv.clear(); + xoutput(out, d, sv, p, 1, p.width(), lim, print_options::print_options().line_width); + + out.precision(temp_precision); // restore precision + + return out; + } + + template + inline std::ostream& operator<<(std::ostream& out, const xexpression& e) + { + return pretty_print(e, out); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xiterable.hpp b/vendor/xtensor/include/xtensor/xiterable.hpp new file mode 100644 index 0000000000..9eb4a55f28 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xiterable.hpp @@ -0,0 +1,824 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ITERABLE_HPP +#define XTENSOR_ITERABLE_HPP + +#include "xiterator.hpp" + +namespace xt +{ + + /******************* + * xconst_iterable * + *******************/ + + template + struct xiterable_inner_types; + +#define DL XTENSOR_DEFAULT_LAYOUT + + /** + * @class xconst_iterable + * @brief Base class for multidimensional iterable constant expressions + * + * The xconst_iterable class defines the interface for multidimensional + * constant expressions that can be iterated. + * + * @tparam D The derived type, i.e. the inheriting class for which xconst_iterable + * provides the interface. + */ + template + class xconst_iterable + { + public: + + using derived_type = D; + + using iterable_types = xiterable_inner_types; + using inner_shape_type = typename iterable_types::inner_shape_type; + + using stepper = typename iterable_types::stepper; + using const_stepper = typename iterable_types::const_stepper; + + template + using layout_iterator = xiterator; + template + using const_layout_iterator = xiterator; + template + using reverse_layout_iterator = std::reverse_iterator>; + template + using const_reverse_layout_iterator = std::reverse_iterator>; + + template + using broadcast_iterator = xiterator; + template + using const_broadcast_iterator = xiterator; + template + using reverse_broadcast_iterator = std::reverse_iterator>; + template + using const_reverse_broadcast_iterator = std::reverse_iterator>; + + using storage_iterator = layout_iterator
; + using const_storage_iterator = const_layout_iterator
; + using reverse_storage_iterator = reverse_layout_iterator
; + using const_reverse_storage_iterator = const_reverse_layout_iterator
; + + using iterator = layout_iterator
; + using const_iterator = const_layout_iterator
; + using reverse_iterator = reverse_layout_iterator
; + using const_reverse_iterator = const_reverse_layout_iterator
; + + template + const_layout_iterator begin() const noexcept; + template + const_layout_iterator end() const noexcept; + template + const_layout_iterator cbegin() const noexcept; + template + const_layout_iterator cend() const noexcept; + + template + const_reverse_layout_iterator rbegin() const noexcept; + template + const_reverse_layout_iterator rend() const noexcept; + template + const_reverse_layout_iterator crbegin() const noexcept; + template + const_reverse_layout_iterator crend() const noexcept; + + template + const_broadcast_iterator begin(const S& shape) const noexcept; + template + const_broadcast_iterator end(const S& shape) const noexcept; + template + const_broadcast_iterator cbegin(const S& shape) const noexcept; + template + const_broadcast_iterator cend(const S& shape) const noexcept; + + template + const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator rend(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; + template + const_reverse_broadcast_iterator crend(const S& shape) const noexcept; + + template + const_layout_iterator storage_begin() const noexcept; + template + const_layout_iterator storage_end() const noexcept; + template + const_layout_iterator storage_cbegin() const noexcept; + template + const_layout_iterator storage_cend() const noexcept; + + template + const_reverse_layout_iterator storage_rbegin() const noexcept; + template + const_reverse_layout_iterator storage_rend() const noexcept; + template + const_reverse_layout_iterator storage_crbegin() const noexcept; + template + const_reverse_layout_iterator storage_crend() const noexcept; + + protected: + + const inner_shape_type& get_shape() const; + + private: + + template + const_layout_iterator get_cbegin(bool end_index) const noexcept; + template + const_layout_iterator get_cend(bool end_index) const noexcept; + + template + const_broadcast_iterator get_cbegin(const S& shape, bool end_index) const noexcept; + template + const_broadcast_iterator get_cend(const S& shape, bool end_index) const noexcept; + + template + const_stepper get_stepper_begin(const S& shape) const noexcept; + template + const_stepper get_stepper_end(const S& shape, layout_type l) const noexcept; + + const derived_type& derived_cast() const; + }; + + /************* + * xiterable * + *************/ + + /** + * @class xiterable + * @brief Base class for multidimensional iterable expressions + * + * The xiterable class defines the interface for multidimensional + * expressions that can be iterated. + * + * @tparam D The derived type, i.e. the inheriting class for which xiterable + * provides the interface. + */ + template + class xiterable : public xconst_iterable + { + public: + + using derived_type = D; + + using base_type = xconst_iterable; + using inner_shape_type = typename base_type::inner_shape_type; + + using stepper = typename base_type::stepper; + using const_stepper = typename base_type::const_stepper; + + template + using layout_iterator = typename base_type::template layout_iterator; + template + using const_layout_iterator = typename base_type::template const_layout_iterator; + template + using reverse_layout_iterator = typename base_type::template reverse_layout_iterator; + template + using const_reverse_layout_iterator = typename base_type::template const_reverse_layout_iterator; + + template + using broadcast_iterator = typename base_type::template broadcast_iterator; + template + using const_broadcast_iterator = typename base_type::template const_broadcast_iterator; + template + using reverse_broadcast_iterator = typename base_type::template reverse_broadcast_iterator; + template + using const_reverse_broadcast_iterator = typename base_type::template const_reverse_broadcast_iterator; + + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using reverse_iterator = typename base_type::reverse_iterator; + using const_reverse_iterator = typename base_type::const_reverse_iterator; + + using base_type::begin; + using base_type::end; + using base_type::rbegin; + using base_type::rend; + using base_type::storage_begin; + using base_type::storage_end; + + template + layout_iterator begin() noexcept; + template + layout_iterator end() noexcept; + + template + reverse_layout_iterator rbegin() noexcept; + template + reverse_layout_iterator rend() noexcept; + + template + broadcast_iterator begin(const S& shape) noexcept; + template + broadcast_iterator end(const S& shape) noexcept; + + template + reverse_broadcast_iterator rbegin(const S& shape) noexcept; + template + reverse_broadcast_iterator rend(const S& shape) noexcept; + + template + layout_iterator storage_begin() noexcept; + template + layout_iterator storage_end() noexcept; + + template + reverse_layout_iterator storage_rbegin() noexcept; + template + reverse_layout_iterator storage_rend() noexcept; + + private: + + template + layout_iterator get_begin(bool end_index) noexcept; + template + layout_iterator get_end(bool end_index) noexcept; + + template + broadcast_iterator get_begin(const S& shape, bool end_index) noexcept; + template + broadcast_iterator get_end(const S& shape, bool end_index) noexcept; + + template + stepper get_stepper_begin(const S& shape) noexcept; + template + stepper get_stepper_end(const S& shape, layout_type l) noexcept; + + template + const_stepper get_stepper_begin(const S& shape) const noexcept; + template + const_stepper get_stepper_end(const S& shape, layout_type l) const noexcept; + + derived_type& derived_cast(); + }; + +#undef DL + + /********************************** + * xconst_iterable implementation * + **********************************/ + + /** + * @name Constant iterators + */ + //@{ + /** + * Returns a constant iterator to the first element of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::begin() const noexcept -> const_layout_iterator + { + return this->template cbegin(); + } + + /** + * Returns a constant iterator to the element following the last element + * of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::end() const noexcept -> const_layout_iterator + { + return this->template cend(); + } + + /** + * Returns a constant iterator to the first element of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::cbegin() const noexcept -> const_layout_iterator + { + return this->template get_cbegin(false); + } + + /** + * Returns a constant iterator to the element following the last element + * of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::cend() const noexcept -> const_layout_iterator + { + return this->template get_cend(true); + } + //@} + + /** + * @name Constant reverse iterators + */ + //@{ + /** + * Returns a constant iterator to the first element of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::rbegin() const noexcept -> const_reverse_layout_iterator + { + return this->template crbegin(); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::rend() const noexcept -> const_reverse_layout_iterator + { + return this->template crend(); + } + + /** + * Returns a constant iterator to the first element of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::crbegin() const noexcept -> const_reverse_layout_iterator + { + return const_reverse_layout_iterator(get_cend(true)); + } + + /** + * Returns a constant iterator to the element following the last element + * of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::crend() const noexcept -> const_reverse_layout_iterator + { + return const_reverse_layout_iterator(get_cbegin(false)); + } + //@} + + /** + * @name Constant broadcast iterators + */ + //@{ + /** + * Returns a constant iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::begin(const S& shape) const noexcept -> const_broadcast_iterator + { + return cbegin(shape); + } + + /** + * Returns a constant iterator to the element following the last element of the + * expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::end(const S& shape) const noexcept -> const_broadcast_iterator + { + return cend(shape); + } + + /** + * Returns a constant iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::cbegin(const S& shape) const noexcept -> const_broadcast_iterator + { + return get_cbegin(shape, false); + } + + /** + * Returns a constant iterator to the element following the last element of the + * expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::cend(const S& shape) const noexcept -> const_broadcast_iterator + { + return get_cend(shape, true); + } + //@} + + /** + * @name Constant reverse broadcast iterators + */ + //@{ + /** + * Returns a constant iterator to the first element of the reversed expression. + * The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return crbegin(shape); + } + + /** + * Returns a constant iterator to the element following the last element of the + * reversed expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return crend(shape); + } + + /** + * Returns a constant iterator to the first element of the reversed expression. + * The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(get_cend(shape, true)); + } + + /** + * Returns a constant iterator to the element following the last element of the + * reversed expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xconst_iterable::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator + { + return const_reverse_broadcast_iterator(get_cbegin(shape, false)); + } + //@} + + template + template + inline auto xconst_iterable::storage_begin() const noexcept -> const_layout_iterator + { + return this->template cbegin(); + } + + template + template + inline auto xconst_iterable::storage_end() const noexcept -> const_layout_iterator + { + return this->template cend(); + } + + template + template + inline auto xconst_iterable::storage_cbegin() const noexcept -> const_layout_iterator + { + return this->template cbegin(); + } + + template + template + inline auto xconst_iterable::storage_cend() const noexcept -> const_layout_iterator + { + return this->template cend(); + } + + template + template + inline auto xconst_iterable::storage_rbegin() const noexcept -> const_reverse_layout_iterator + { + return this->template crbegin(); + } + + template + template + inline auto xconst_iterable::storage_rend() const noexcept -> const_reverse_layout_iterator + { + return this->template crend(); + } + + template + template + inline auto xconst_iterable::storage_crbegin() const noexcept -> const_reverse_layout_iterator + { + return this->template crbegin(); + } + + template + template + inline auto xconst_iterable::storage_crend() const noexcept -> const_reverse_layout_iterator + { + return this->template crend(); + } + + template + template + inline auto xconst_iterable::get_cbegin(bool end_index) const noexcept -> const_layout_iterator + { + return const_layout_iterator(get_stepper_begin(get_shape()), &get_shape(), end_index); + } + + template + template + inline auto xconst_iterable::get_cend(bool end_index) const noexcept -> const_layout_iterator + { + return const_layout_iterator(get_stepper_end(get_shape(), L), &get_shape(), end_index); + } + + template + template + inline auto xconst_iterable::get_cbegin(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(get_stepper_begin(shape), shape, end_index); + } + + template + template + inline auto xconst_iterable::get_cend(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator + { + return const_broadcast_iterator(get_stepper_end(shape, L), shape, end_index); + } + + template + template + inline auto xconst_iterable::get_stepper_begin(const S& shape) const noexcept -> const_stepper + { + return derived_cast().stepper_begin(shape); + } + + template + template + inline auto xconst_iterable::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + return derived_cast().stepper_end(shape, l); + } + + template + inline auto xconst_iterable::get_shape() const -> const inner_shape_type& + { + return derived_cast().shape(); + } + + template + inline auto xconst_iterable::derived_cast() const -> const derived_type& + { + return *static_cast(this); + } + + /**************************** + * xiterable implementation * + ****************************/ + + /** + * @name Iterators + */ + //@{ + /** + * Returns an iterator to the first element of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::begin() noexcept -> layout_iterator + { + return get_begin(false); + } + + /** + * Returns an iterator to the element following the last element + * of the expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::end() noexcept -> layout_iterator + { + return get_end(true); + } + //@} + + /** + * @name Reverse iterators + */ + //@{ + /** + * Returns an iterator to the first element of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::rbegin() noexcept -> reverse_layout_iterator + { + return reverse_layout_iterator(get_end(true)); + } + + /** + * Returns an iterator to the element following the last element + * of the reversed expression. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::rend() noexcept -> reverse_layout_iterator + { + return reverse_layout_iterator(get_begin(false)); + } + //@} + + /** + * @name Broadcast iterators + */ + //@{ + /** + * Returns an iterator to the first element of the expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::begin(const S& shape) noexcept -> broadcast_iterator + { + return get_begin(shape, false); + } + + /** + * Returns an iterator to the element following the last element of the + * expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::end(const S& shape) noexcept -> broadcast_iterator + { + return get_end(shape, true); + } + //@} + + /** + * @name Reverse broadcast iterators + */ + //@{ + /** + * Returns an iterator to the first element of the reversed expression. The + * iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(get_end(shape, true)); + } + + /** + * Returns an iterator to the element following the last element of the + * reversed expression. The iteration is broadcasted to the specified shape. + * @param shape the shape used for broadcasting + * @tparam S type of the \c shape parameter. + * @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT. + */ + template + template + inline auto xiterable::rend(const S& shape) noexcept -> reverse_broadcast_iterator + { + return reverse_broadcast_iterator(get_begin(shape, false)); + } + //@} + + template + template + inline auto xiterable::storage_begin() noexcept -> layout_iterator + { + return this->template begin(); + } + + template + template + inline auto xiterable::storage_end() noexcept -> layout_iterator + { + return this->template end(); + } + + template + template + inline auto xiterable::storage_rbegin() noexcept -> reverse_layout_iterator + { + return this->template rbegin(); + } + + template + template + inline auto xiterable::storage_rend() noexcept -> reverse_layout_iterator + { + return this->template rend(); + } + + template + template + inline auto xiterable::get_begin(bool end_index) noexcept -> layout_iterator + { + return layout_iterator(get_stepper_begin(this->get_shape()), &(this->get_shape()), end_index); + } + + template + template + inline auto xiterable::get_end(bool end_index) noexcept -> layout_iterator + { + return layout_iterator(get_stepper_end(this->get_shape(), L), &(this->get_shape()), end_index); + } + + template + template + inline auto xiterable::get_begin(const S& shape, bool end_index) noexcept -> broadcast_iterator + { + return broadcast_iterator(get_stepper_begin(shape), shape, end_index); + } + + template + template + inline auto xiterable::get_end(const S& shape, bool end_index) noexcept -> broadcast_iterator + { + return broadcast_iterator(get_stepper_end(shape, L), shape, end_index); + } + + template + template + inline auto xiterable::get_stepper_begin(const S& shape) noexcept -> stepper + { + return derived_cast().stepper_begin(shape); + } + + template + template + inline auto xiterable::get_stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + return derived_cast().stepper_end(shape, l); + } + + template + template + inline auto xiterable::get_stepper_begin(const S& shape) const noexcept -> const_stepper + { + return derived_cast().stepper_begin(shape); + } + + template + template + inline auto xiterable::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + return derived_cast().stepper_end(shape, l); + } + + template + inline auto xiterable::derived_cast() -> derived_type& + { + return *static_cast(this); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xiterator.hpp b/vendor/xtensor/include/xtensor/xiterator.hpp new file mode 100644 index 0000000000..01b7950515 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xiterator.hpp @@ -0,0 +1,1123 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ITERATOR_HPP +#define XTENSOR_ITERATOR_HPP + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "xexception.hpp" +#include "xlayout.hpp" +#include "xshape.hpp" +#include "xutils.hpp" + +namespace xt +{ + + /*********************** + * iterator meta utils * + ***********************/ + + template + class xscalar; + + namespace detail + { + template + struct get_stepper_iterator_impl + { + using type = typename C::container_iterator; + }; + + template + struct get_stepper_iterator_impl + { + using type = typename C::const_container_iterator; + }; + + template + struct get_stepper_iterator_impl> + { + using type = typename xscalar::dummy_iterator; + }; + + template + struct get_stepper_iterator_impl> + { + using type = typename xscalar::const_dummy_iterator; + }; + } + + template + using get_stepper_iterator = typename detail::get_stepper_iterator_impl::type; + + namespace detail + { + template + struct index_type_impl + { + using type = dynamic_shape; + }; + + template + struct index_type_impl> + { + using type = std::array; + }; + } + + template + using xindex_type_t = typename detail::index_type_impl::type; + + /************ + * xstepper * + ************/ + + template + class xstepper + { + public: + + using storage_type = C; + using subiterator_type = get_stepper_iterator; + using subiterator_traits = std::iterator_traits; + using value_type = typename subiterator_traits::value_type; + using reference = typename subiterator_traits::reference; + using pointer = typename subiterator_traits::pointer; + using difference_type = typename subiterator_traits::difference_type; + using size_type = typename storage_type::size_type; + using shape_type = typename storage_type::shape_type; + using simd_type = xsimd::simd_type; + + xstepper() = default; + xstepper(storage_type* c, subiterator_type it, size_type offset) noexcept; + + reference operator*() const; + + void step(size_type dim, size_type n = 1); + void step_back(size_type dim, size_type n = 1); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type l); + + template + R step_simd(); + + value_type step_leading(); + + template + void store_simd(const R& vec); + + private: + + storage_type* p_c; + subiterator_type m_it; + size_type m_offset; + }; + + template + struct stepper_tools + { + // For performance reasons, increment_stepper and decrement_stepper are + // specialized for the case where n=1, which underlies operator++ and + // operator-- on xiterators. + + template + static void increment_stepper(S& stepper, + IT& index, + const ST& shape); + + template + static void decrement_stepper(S& stepper, + IT& index, + const ST& shape); + + template + static void increment_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n); + + template + static void decrement_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n); + }; + + /******************** + * xindexed_stepper * + ********************/ + + template + class xindexed_stepper + { + public: + + using self_type = xindexed_stepper; + using xexpression_type = std::conditional_t; + + using value_type = typename xexpression_type::value_type; + using reference = std::conditional_t; + using pointer = std::conditional_t; + using size_type = typename xexpression_type::size_type; + using difference_type = typename xexpression_type::difference_type; + + using shape_type = typename xexpression_type::shape_type; + using index_type = xindex_type_t; + + xindexed_stepper() = default; + xindexed_stepper(xexpression_type* e, size_type offset, bool end = false) noexcept; + + reference operator*() const; + + void step(size_type dim, size_type n = 1); + void step_back(size_type dim, size_type n = 1); + void reset(size_type dim); + void reset_back(size_type dim); + + void to_begin(); + void to_end(layout_type l); + + private: + + xexpression_type* p_e; + index_type m_index; + size_type m_offset; + }; + + template + struct is_indexed_stepper + { + static const bool value = false; + }; + + template + struct is_indexed_stepper> + { + static const bool value = true; + }; + + /************* + * xiterator * + *************/ + + namespace detail + { + template + class shape_storage + { + public: + + using shape_type = S; + using param_type = const S&; + + shape_storage() = default; + shape_storage(param_type shape); + const S& shape() const; + + private: + + S m_shape; + }; + + template + class shape_storage + { + public: + + using shape_type = S; + using param_type = const S*; + + shape_storage(param_type shape = 0); + const S& shape() const; + + private: + + const S* p_shape; + }; + + template + struct LAYOUT_FORBIDEN_FOR_XITERATOR; + } + + template + class xiterator : public xtl::xrandom_access_iterator_base, + typename It::value_type, + typename It::difference_type, + typename It::pointer, + typename It::reference>, + private detail::shape_storage + { + public: + + using self_type = xiterator; + + using subiterator_type = It; + using value_type = typename subiterator_type::value_type; + using reference = typename subiterator_type::reference; + using pointer = typename subiterator_type::pointer; + using difference_type = typename subiterator_type::difference_type; + using size_type = typename subiterator_type::size_type; + using iterator_category = std::random_access_iterator_tag; + + using private_base = detail::shape_storage; + using shape_type = typename private_base::shape_type; + using shape_param_type = typename private_base::param_type; + using index_type = xindex_type_t; + + xiterator() = default; + // end_index means either reverse_iterator && !end or !reverse_iterator && end + xiterator(It it, shape_param_type shape, bool end_index); + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(const self_type& rhs) const; + + reference operator*() const; + pointer operator->() const; + + bool equal(const xiterator& rhs) const; + bool less_than(const xiterator& rhs) const; + + private: + + subiterator_type m_it; + index_type m_index; + difference_type m_linear_index; + + using checking_type = typename detail::LAYOUT_FORBIDEN_FOR_XITERATOR::type; + }; + + template + bool operator==(const xiterator& lhs, + const xiterator& rhs); + + template + bool operator<(const xiterator& lhs, + const xiterator& rhs); + + /********************* + * xbounded_iterator * + *********************/ + + template + class xbounded_iterator : public xtl::xrandom_access_iterator_base, + typename std::iterator_traits::value_type, + typename std::iterator_traits::difference_type, + typename std::iterator_traits::pointer, + typename std::iterator_traits::reference> + { + public: + + using self_type = xbounded_iterator; + + using subiterator_type = It; + using bound_iterator_type = BIt; + using value_type = typename std::iterator_traits::value_type; + using reference = typename std::iterator_traits::reference; + using pointer = typename std::iterator_traits::pointer; + using difference_type = typename std::iterator_traits::difference_type; + using iterator_category = std::random_access_iterator_tag; + + xbounded_iterator() = default; + xbounded_iterator(It it, BIt bound_it); + + self_type& operator++(); + self_type& operator--(); + + self_type& operator+=(difference_type n); + self_type& operator-=(difference_type n); + + difference_type operator-(const self_type& rhs) const; + + value_type operator*() const; + + bool equal(const self_type& rhs) const; + bool less_than(const self_type& rhs) const; + + private: + + subiterator_type m_it; + bound_iterator_type m_bound_it; + }; + + template + bool operator==(const xbounded_iterator& lhs, + const xbounded_iterator& rhs); + + template + bool operator<(const xbounded_iterator& lhs, + const xbounded_iterator& rhs); + + /******************************* + * trivial_begin / trivial_end * + *******************************/ + + namespace detail + { + template + constexpr auto trivial_begin(C& c) noexcept + { + return c.storage_begin(); + } + + template + constexpr auto trivial_end(C& c) noexcept + { + return c.storage_end(); + } + + template + constexpr auto trivial_begin(const C& c) noexcept + { + return c.storage_begin(); + } + + template + constexpr auto trivial_end(const C& c) noexcept + { + return c.storage_end(); + } + } + + /*************************** + * xstepper implementation * + ***************************/ + + template + inline xstepper::xstepper(storage_type* c, subiterator_type it, size_type offset) noexcept + : p_c(c), m_it(it), m_offset(offset) + { + } + + template + inline auto xstepper::operator*() const -> reference + { + return *m_it; + } + + template + inline void xstepper::step(size_type dim, size_type n) + { + if (dim >= m_offset) + { + using strides_value_type = decltype(p_c->strides()[0]); + m_it += difference_type(static_cast(n) * p_c->strides()[dim - m_offset]); + } + } + + template + inline void xstepper::step_back(size_type dim, size_type n) + { + if (dim >= m_offset) + { + using strides_value_type = decltype(p_c->strides()[0]); + m_it -= difference_type(static_cast(n) * p_c->strides()[dim - m_offset]); + } + } + + template + inline void xstepper::reset(size_type dim) + { + if (dim >= m_offset) + { + m_it -= difference_type(p_c->backstrides()[dim - m_offset]); + } + } + + template + inline void xstepper::reset_back(size_type dim) + { + if (dim >= m_offset) + { + m_it += difference_type(p_c->backstrides()[dim - m_offset]); + } + } + + template + inline void xstepper::to_begin() + { + m_it = p_c->data_xbegin(); + } + + template + inline void xstepper::to_end(layout_type l) + { + m_it = p_c->data_xend(l); + } + + template + template + inline R xstepper::step_simd() + { + R reg; + reg.load_unaligned(&(*m_it)); + m_it += xsimd::revert_simd_traits::size; + return reg; + } + + template + template + inline void xstepper::store_simd(const R& vec) + { + vec.store_unaligned(&(*m_it)); + m_it += xsimd::revert_simd_traits::size;; + } + + template + auto xstepper::step_leading() -> value_type + { + ++m_it; + return *m_it; + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type i = index.size(); + while (i != 0) + { + --i; + if (index[i] != shape[i] - 1) + { + ++index[i]; + stepper.step(i); + return; + } + else + { + index[i] = 0; + if (i != 0) + { + stepper.reset(i); + } + } + } + if (i == 0) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::row_major); + } + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type i = index.size(); + size_type leading_i = index.size() - 1; + while (i != 0 && n != 0) + { + --i; + size_type inc = (i == leading_i) ? n : 1; + if (index[i] + inc < shape[i]) + { + index[i] += inc; + stepper.step(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = index.size(); + } + } + else + { + if (i == leading_i) + { + size_type off = shape[i] - index[i] - 1; + stepper.step(i, off); + n -= off; + } + index[i] = 0; + if (i != 0) + { + stepper.reset(i); + } + } + } + if (i == 0) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::row_major); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type i = index.size(); + while (i != 0) + { + --i; + if (index[i] != 0) + { + --index[i]; + stepper.step_back(i); + return; + } + else + { + index[i] = shape[i] - 1; + if (i != 0) + { + stepper.reset_back(i); + } + } + } + if (i == 0) + { + stepper.to_begin(); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type i = index.size(); + size_type leading_i = index.size() - 1; + while (i != 0 && n != 0) + { + --i; + size_type inc = (i == leading_i) ? n : 1; + if (index[i] >= inc) + { + index[i] -= inc; + stepper.step_back(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = index.size(); + } + } + else + { + if (i == leading_i) + { + size_type off = index[i]; + stepper.step_back(i, off); + n -= off; + } + index[i] = shape[i] - 1; + if (i != 0) + { + stepper.reset_back(i); + } + } + } + if (i == 0) + { + stepper.to_begin(); + } + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + while (i != size) + { + if (index[i] != shape[i] - 1) + { + ++index[i]; + stepper.step(i); + return; + } + else + { + index[i] = 0; + if (i != size - 1) + { + stepper.reset(i); + } + } + ++i; + } + if (i == size) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::column_major); + } + } + + template <> + template + void stepper_tools::increment_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + size_type leading_i = 0; + while (i != size && n != 0) + { + size_type inc = (i == leading_i) ? n : 1; + if (index[i] + inc < shape[i]) + { + index[i] += inc; + stepper.step(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = 0; + continue; + } + } + else + { + if (i == leading_i) + { + size_type off = shape[i] - index[i] - 1; + stepper.step(i, off); + n -= off; + } + index[i] = 0; + if (i != size - 1) + { + stepper.reset(i); + } + } + ++i; + } + if (i == size) + { + std::copy(shape.cbegin(), shape.cend(), index.begin()); + stepper.to_end(layout_type::column_major); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + while (i != size) + { + if (index[i] != 0) + { + --index[i]; + stepper.step_back(i); + return; + } + else + { + index[i] = shape[i] - 1; + if (i != size - 1) + { + stepper.reset_back(i); + } + } + ++i; + } + if (i == size) + { + stepper.to_begin(); + } + } + + template <> + template + void stepper_tools::decrement_stepper(S& stepper, + IT& index, + const ST& shape, + typename S::size_type n) + { + using size_type = typename S::size_type; + size_type size = index.size(); + size_type i = 0; + size_type leading_i = 0; + while (i != size && n != 0) + { + size_type inc = (i == leading_i) ? n : 1; + if (index[i] >= inc) + { + index[i] -= inc; + stepper.step_back(i, inc); + n -= inc; + if (i != leading_i || index.size() == 1) + { + i = 0; + continue; + } + } + else + { + if (i == leading_i) + { + size_type off = index[i]; + stepper.step_back(i, off); + n -= off; + } + index[i] = shape[i] - 1; + if (i != size - 1) + { + stepper.reset_back(i); + } + } + ++i; + } + if (i == size) + { + stepper.to_begin(); + } + } + + /*********************************** + * xindexed_stepper implementation * + ***********************************/ + + template + inline xindexed_stepper::xindexed_stepper(xexpression_type* e, size_type offset, bool end) noexcept + : p_e(e), m_index(xtl::make_sequence(e->shape().size(), size_type(0))), m_offset(offset) + { + if (end) + { + // Note: the layout here doesn't matter (unused) but using default layout looks more "correct" + to_end(XTENSOR_DEFAULT_LAYOUT); + } + } + + template + inline auto xindexed_stepper::operator*() const -> reference + { + return p_e->element(m_index.cbegin(), m_index.cend()); + } + + template + inline void xindexed_stepper::step(size_type dim, size_type n) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] += static_cast(n); + } + } + + template + inline void xindexed_stepper::step_back(size_type dim, size_type n) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] -= static_cast(n); + } + } + + template + inline void xindexed_stepper::reset(size_type dim) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] = 0; + } + } + + template + inline void xindexed_stepper::reset_back(size_type dim) + { + if (dim >= m_offset) + { + m_index[dim - m_offset] = p_e->shape()[dim - m_offset] - 1; + } + } + + template + inline void xindexed_stepper::to_begin() + { + std::fill(m_index.begin(), m_index.end(), size_type(0)); + } + + template + inline void xindexed_stepper::to_end(layout_type) + { + std::copy(p_e->shape().begin(), p_e->shape().end(), m_index.begin()); + } + + /**************************** + * xiterator implementation * + ****************************/ + + namespace detail + { + template + inline shape_storage::shape_storage(param_type shape) + : m_shape(shape) + { + } + + template + inline const S& shape_storage::shape() const + { + return m_shape; + } + + template + inline shape_storage::shape_storage(param_type shape) + : p_shape(shape) + { + } + + template + inline const S& shape_storage::shape() const + { + return *p_shape; + } + + template <> + struct LAYOUT_FORBIDEN_FOR_XITERATOR + { + using type = int; + }; + + template <> + struct LAYOUT_FORBIDEN_FOR_XITERATOR + { + using type = int; + }; + } + + template + inline xiterator::xiterator(It it, shape_param_type shape, bool end_index) + : private_base(shape), m_it(it), + m_index(end_index ? xtl::forward_sequence(this->shape()) + : xtl::make_sequence(this->shape().size(), size_type(0))), + m_linear_index(0) + { + // end_index means either reverse_iterator && !end or !reverse_iterator && end + if (end_index) + { + if (m_index.size() != size_type(0)) + { + auto iter_begin = (L == layout_type::row_major) ? m_index.begin() : m_index.begin() + 1; + auto iter_end = (L == layout_type::row_major) ? m_index.end() - 1 : m_index.end(); + std::transform(iter_begin, iter_end, iter_begin, [](const auto& v) { return v - 1; }); + } + m_linear_index = difference_type(std::accumulate(this->shape().cbegin(), this->shape().cend(), + size_type(1), std::multiplies())); + } + } + + template + inline auto xiterator::operator++() -> self_type& + { + stepper_tools::increment_stepper(m_it, m_index, this->shape()); + ++m_linear_index; + return *this; + } + + template + inline auto xiterator::operator--() -> self_type& + { + stepper_tools::decrement_stepper(m_it, m_index, this->shape()); + --m_linear_index; + return *this; + } + + template + inline auto xiterator::operator+=(difference_type n) -> self_type& + { + if (n >= 0) + { + stepper_tools::increment_stepper(m_it, m_index, this->shape(), static_cast(n)); + } + else + { + stepper_tools::decrement_stepper(m_it, m_index, this->shape(), static_cast(-n)); + } + m_linear_index += n; + return *this; + } + + template + inline auto xiterator::operator-=(difference_type n) -> self_type& + { + if (n >= 0) + { + stepper_tools::decrement_stepper(m_it, m_index, this->shape(), static_cast(n)); + } + else + { + stepper_tools::increment_stepper(m_it, m_index, this->shape(), static_cast(-n)); + } + m_linear_index -= n; + return *this; + } + + template + inline auto xiterator::operator-(const self_type& rhs) const -> difference_type + { + return m_linear_index - rhs.m_linear_index; + } + + template + inline auto xiterator::operator*() const -> reference + { + return *m_it; + } + + template + inline auto xiterator::operator->() const -> pointer + { + return &(*m_it); + } + + template + inline bool xiterator::equal(const xiterator& rhs) const + { + XTENSOR_ASSERT(this->shape() == rhs.shape()); + return m_linear_index == rhs.m_linear_index; + } + + template + inline bool xiterator::less_than(const xiterator& rhs) const + { + XTENSOR_ASSERT(this->shape() == rhs.shape()); + return m_linear_index < rhs.m_linear_index; + } + + template + inline bool operator==(const xiterator& lhs, + const xiterator& rhs) + { + return lhs.equal(rhs); + } + + template + bool operator<(const xiterator& lhs, + const xiterator& rhs) + { + return lhs.less_than(rhs); + } + + /************************************ + * xbounded_iterator implementation * + ************************************/ + + template + xbounded_iterator::xbounded_iterator(It it, BIt bound_it) + : m_it(it), m_bound_it(bound_it) + { + } + + template + inline auto xbounded_iterator::operator++() -> self_type& + { + ++m_it; + ++m_bound_it; + return *this; + } + + template + inline auto xbounded_iterator::operator--() -> self_type& + { + --m_it; + --m_bound_it; + return *this; + } + + template + inline auto xbounded_iterator::operator+=(difference_type n) -> self_type& + { + m_it += n; + m_bound_it += n; + return *this; + } + + template + inline auto xbounded_iterator::operator-=(difference_type n) -> self_type& + { + m_it -= n; + m_bound_it -= n; + return *this; + } + + template + inline auto xbounded_iterator::operator-(const self_type& rhs) const -> difference_type + { + return m_it - rhs.m_it; + } + + template + inline auto xbounded_iterator::operator*() const -> value_type + { + using type = decltype(*m_bound_it); + return (static_cast(*m_it) < *m_bound_it) ? *m_it : static_cast((*m_bound_it) - 1); + } + + template + inline bool xbounded_iterator::equal(const self_type& rhs) const + { + return m_it == rhs.m_it && m_bound_it == rhs.m_bound_it; + } + + template + inline bool xbounded_iterator::less_than(const self_type& rhs) const + { + return m_it < rhs.m_it; + } + + template + inline bool operator==(const xbounded_iterator& lhs, + const xbounded_iterator& rhs) + { + return lhs.equal(rhs); + } + + template + inline bool operator<(const xbounded_iterator& lhs, + const xbounded_iterator& rhs) + { + return lhs.less_than(rhs); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xjson.hpp b/vendor/xtensor/include/xtensor/xjson.hpp new file mode 100644 index 0000000000..b0d33ed8a8 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xjson.hpp @@ -0,0 +1,183 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_JSON_HPP +#define XTENSOR_JSON_HPP + +#include +#include +#include + +#include + +#include "xstrided_view.hpp" + +namespace xt +{ + /************************************* + * to_json and from_json declaration * + *************************************/ + + template + enable_xexpression to_json(nlohmann::json&, const E&); + + template + enable_xcontainer_semantics from_json(const nlohmann::json&, E&); + + /// @cond DOXYGEN_INCLUDE_SFINAE + template + enable_xview_semantics from_json(const nlohmann::json&, E&); + /// @endcond + + /**************************************** + * to_json and from_json implementation * + ****************************************/ + + namespace detail + { + template + void to_json_impl(nlohmann::json& j, const xexpression& e, xstrided_slice_vector& slices) + { + const auto view = strided_view(e.derived_cast(), slices); + if (view.dimension() == 0) + { + j = view(); + } + else + { + j = nlohmann::json::array(); + using size_type = typename D::size_type; + size_type nrows = view.shape()[0]; + for (size_type i = 0; i != nrows; ++i) + { + slices.push_back(i); + nlohmann::json k; + to_json_impl(k, e, slices); + j.push_back(std::move(k)); + slices.pop_back(); + } + } + } + + template + inline void from_json_impl(const nlohmann::json& j, xexpression& e, xstrided_slice_vector& slices) + { + auto view = strided_view(e.derived_cast(), slices); + + if (view.dimension() == 0) + { + view() = j; + } + else + { + using size_type = typename D::size_type; + size_type nrows = view.shape()[0]; + for (size_type i = 0; i != nrows; ++i) + { + slices.push_back(i); + const nlohmann::json& k = j[i]; + from_json_impl(k, e, slices); + slices.pop_back(); + } + } + } + + inline unsigned int json_dimension(const nlohmann::json& j) + { + if (j.is_array() && j.size()) + { + return 1 + json_dimension(j[0]); + } + else + { + return 0; + } + } + + template + inline void json_shape(const nlohmann::json& j, S& s, std::size_t pos = 0) + { + if (j.is_array()) + { + auto size = j.size(); + s[pos] = size; + if (size) + { + json_shape(j[0], s, pos + 1); + } + } + } + } + + /** + * @brief JSON serialization of an xtensor expression. + * + * The to_json method is used by the nlohmann_json package for automatic + * serialization of user-defined types. The method is picked up by + * argument-dependent lookup. + * + * @param j a JSON object + * @param e a const \ref xexpression + */ + template + inline enable_xexpression to_json(nlohmann::json& j, const E& e) + { + auto sv = xstrided_slice_vector(); + detail::to_json_impl(j, e, sv); + } + + /** + * @brief JSON deserialization of a xtensor expression with a container or + * a view semantics. + * + * The from_json method is used by the nlohmann_json library for automatic + * serialization of user-defined types. The method is picked up by + * argument-dependent lookup. + * + * Note: for converting a JSON object to a value, nlohmann_json requiress + * the value type to be default constructible, which is typically not the + * case for expressions with a view semantics. In this case, from_json can + * be called directly. + * + * @param j a const JSON object + * @param e an \ref xexpression + */ + template + inline enable_xcontainer_semantics from_json(const nlohmann::json& j, E& e) + { + auto dimension = detail::json_dimension(j); + auto s = xtl::make_sequence(dimension); + detail::json_shape(j, s); + + // In the case of a container, we resize the container. + e.resize(s); + + auto sv = xstrided_slice_vector(); + detail::from_json_impl(j, e, sv); + } + + /// @cond DOXYGEN_INCLUDE_SFINAE + template + inline enable_xview_semantics from_json(const nlohmann::json& j, E& e) + { + typename E::shape_type s; + detail::json_shape(j, s); + + // In the case of a view, we check the size of the container. + if (!std::equal(s.cbegin(), s.cend(), e.shape().cbegin())) + { + throw std::runtime_error("Shape mismatch when deserializing JSON to view"); + } + + auto sv = xstrided_slice_vector(); + detail::from_json_impl(j, e, sv); + } + /// @endcond +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xlayout.hpp b/vendor/xtensor/include/xtensor/xlayout.hpp new file mode 100644 index 0000000000..5ec8a340c5 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xlayout.hpp @@ -0,0 +1,93 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_LAYOUT_HPP +#define XTENSOR_LAYOUT_HPP + +#include "xtensor_config.hpp" + +namespace xt +{ + /*! layout_type enum for xcontainer based xexpressions */ + enum class layout_type + { + /*! dynamic layout_type: you can resize to row major, column major, or use custom strides */ + dynamic = 0x00, + /*! layout_type compatible with all others */ + any = 0xFF, + /*! row major layout_type */ + row_major = 0x01, + /*! column major layout_type */ + column_major = 0x02 + }; + + /** + * Implementation of the following logical table: + * + * @verbatim + | d | a | r | c | + --+---+---+---+---+ + d | d | d | d | d | + a | d | a | r | c | + r | d | r | r | d | + c | d | c | d | c | + d = dynamic, a = any, r = row_major, c = column_major. + @endverbatim + * Using bitmasks to avoid nested if-else statements. + * + * @param args the input layouts. + * @return the output layout, computed with the previous logical table. + */ + template + constexpr layout_type compute_layout(Args... args) noexcept; + + constexpr layout_type default_assignable_layout(layout_type l) noexcept; + + /****************** + * Implementation * + ******************/ + + namespace detail + { + constexpr layout_type compute_layout_impl() noexcept + { + return layout_type::any; + } + + constexpr layout_type compute_layout_impl(layout_type l) noexcept + { + return l; + } + + constexpr layout_type compute_layout_impl(layout_type lhs, layout_type rhs) noexcept + { + using type = std::underlying_type_t; + return layout_type(static_cast(lhs) & static_cast(rhs)); + } + + template + constexpr layout_type compute_layout_impl(layout_type lhs, Args... args) noexcept + { + return compute_layout_impl(lhs, compute_layout_impl(args...)); + } + } + + template + constexpr layout_type compute_layout(Args... args) noexcept + { + return detail::compute_layout_impl(args...); + } + + constexpr layout_type default_assignable_layout(layout_type l) noexcept + { + return (l == layout_type::row_major || l == layout_type::column_major) ? + l : XTENSOR_DEFAULT_LAYOUT; + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xmath.hpp b/vendor/xtensor/include/xtensor/xmath.hpp new file mode 100644 index 0000000000..41332b180b --- /dev/null +++ b/vendor/xtensor/include/xtensor/xmath.hpp @@ -0,0 +1,2146 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +/** + * @brief standard mathematical functions for xexpressions + */ + +#ifndef XTENSOR_MATH_HPP +#define XTENSOR_MATH_HPP + +#include +#include +#include +#include + +#include + +#include "xaccumulator.hpp" +#include "xoperation.hpp" +#include "xreducer.hpp" +#include "xslice.hpp" +#include "xstrided_view.hpp" +#include "xeval.hpp" + +namespace xt +{ + template + struct numeric_constants + { + static constexpr T PI = 3.141592653589793238463; + static constexpr T PI_2 = 1.57079632679489661923; + static constexpr T PI_4 = 0.785398163397448309616; + static constexpr T D_1_PI = 0.318309886183790671538; + static constexpr T D_2_PI = 0.636619772367581343076; + static constexpr T D_2_SQRTPI = 1.12837916709551257390; + static constexpr T SQRT2 = 1.41421356237309504880; + static constexpr T SQRT1_2 = 0.707106781186547524401; + static constexpr T E = 2.71828182845904523536; + static constexpr T LOG2E = 1.44269504088896340736; + static constexpr T LOG10E = 0.434294481903251827651; + static constexpr T LN2 = 0.693147180559945309417; + }; + + /*********** + * Helpers * + ***********/ + +#define XTENSOR_UNSIGNED_ABS_FUNC(T) \ +constexpr inline T abs(const T& x) \ +{ \ + return x; \ +} \ + +#define XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, T) \ +constexpr inline bool FUNC_NAME(const T& /*x*/) noexcept \ +{ \ + return RETURN_VAL; \ +} \ + +#define XTENSOR_INT_SPECIALIZATION(FUNC_NAME, RETURN_VAL) \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, char); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, short); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, int); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long long); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned char); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned short); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned int); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long); \ +XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long long); \ + + +#define XTENSOR_UNARY_MATH_FUNCTOR_IMPL(NAME, R) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg) \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + using frt = xt::detail::functor_return_type; \ + using return_type = frt; \ + using argument_type = T; \ + using result_type = decltype(exec(std::declval())); \ + using simd_value_type = xsimd::simd_type; \ + using simd_result_type = typename return_type::simd_type; \ + constexpr result_type operator()(const T& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + constexpr typename frt, R>::simd_type \ + simd_apply(const B& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_UNARY_MATH_FUNCTOR(NAME) XTENSOR_UNARY_MATH_FUNCTOR_IMPL(NAME, T) +#define XTENSOR_UNARY_BOOL_FUNCTOR(NAME) XTENSOR_UNARY_MATH_FUNCTOR_IMPL(NAME, bool) + +#define XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(NAME) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg) \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + using argument_type = T; \ + using result_type = decltype(exec(std::declval())); \ + using simd_value_type = argument_type; \ + using simd_result_type = result_type; \ + constexpr result_type operator()(const T& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + constexpr simd_result_type simd_apply(const B& arg) const \ + { \ + using math::NAME; \ + return NAME(arg); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_BINARY_MATH_FUNCTOR_IMPL(NAME, R) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg1, const T& arg2) \ + { \ + using math::NAME; \ + return NAME(arg1, arg2); \ + } \ + template \ + using frt = xt::detail::functor_return_type; \ + using return_type = xt::detail::functor_return_type; \ + using first_argument_type = T; \ + using second_argument_type = T; \ + using result_type = decltype(exec(std::declval(), std::declval())); \ + using simd_value_type = xsimd::simd_type; \ + using simd_result_type = typename return_type::simd_type; \ + constexpr result_type operator()(const T& arg1, const T& arg2) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2); \ + } \ + template \ + constexpr typename frt, R>::simd_type \ + simd_apply(const B& arg1, const B& arg2) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_BINARY_MATH_FUNCTOR(NAME) XTENSOR_BINARY_MATH_FUNCTOR_IMPL(NAME, T) +#define XTENSOR_BINARY_BOOL_FUNCTOR(NAME) XTENSOR_BINARY_MATH_FUNCTOR_IMPL(NAME, bool) + +#define XTENSOR_TERNARY_MATH_FUNCTOR_IMPL(NAME, R) \ + template \ + struct NAME##_fun \ + { \ + static auto exec(const T& arg1, const T& arg2, const T& arg3) \ + { \ + using math::NAME; \ + return NAME(arg1, arg2, arg3); \ + } \ + template \ + using frt = xt::detail::functor_return_type; \ + using return_type = xt::detail::functor_return_type; \ + using first_argument_type = T; \ + using second_argument_type = T; \ + using third_argument_type = T; \ + using result_type = decltype(exec(std::declval(), std::declval(), \ + std::declval())); \ + using simd_value_type = xsimd::simd_type; \ + using simd_result_type = typename return_type::simd_type; \ + constexpr result_type operator()(const T& arg1, \ + const T& arg2, \ + const T& arg3) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2, arg3); \ + } \ + template \ + constexpr typename frt, R>::simd_type \ + simd_apply(const B& arg1, const B& arg2, const B& arg3) const \ + { \ + using math::NAME; \ + return NAME(arg1, arg2, arg3); \ + } \ + template \ + struct rebind \ + { \ + using type = NAME##_fun; \ + }; \ + } + +#define XTENSOR_TERNARY_MATH_FUNCTOR(NAME) XTENSOR_TERNARY_MATH_FUNCTOR_IMPL(NAME, T) +#define XTENSOR_TERNARY_BOOL_FUNCTOR(NAME) XTENSOR_TERNARY_MATH_FUNCTOR_IMPL(NAME, bool) + + namespace math + { + using std::abs; + using std::fabs; + + using std::cos; + using std::sin; + using std::tan; + using std::acos; + using std::asin; + using std::atan; + + using std::cosh; + using std::sinh; + using std::tanh; + using std::acosh; + using std::asinh; + using std::atanh; + + using std::sqrt; + using std::cbrt; + + using std::exp; + using std::exp2; + using std::expm1; + using std::log; + using std::log2; + using std::log10; + using std::log1p; + using std::logb; + using std::ilogb; + + using std::floor; + using std::ceil; + using std::trunc; + using std::round; + using std::lround; + using std::llround; + using std::rint; + using std::nearbyint; + using std::remainder; + + using std::erf; + using std::erfc; + using std::erfc; + using std::tgamma; + using std::lgamma; + + using std::conj; + using std::real; + using std::imag; + using std::arg; + + using std::atan2; + using std::copysign; + using std::fdim; + using std::fmax; + using std::fmin; + using std::fmod; + using std::hypot; + using std::pow; + + using std::fma; + + using std::isnan; + using std::isinf; + using std::isfinite; + using std::fpclassify; + + // Overload isinf, isnan and isfinite for complex datatypes, + // following the Python specification: + template + inline bool isinf(const std::complex& c) + { + return std::isinf(std::real(c)) || std::isinf(std::imag(c)); + } + + template + inline bool isnan(const std::complex& c) + { + return std::isnan(std::real(c)) || std::isnan(std::imag(c)); + } + + template + inline bool isfinite(const std::complex& c) + { + return !isinf(c) && !isnan(c); + } + + // The following specializations are needed to avoid 'ambiguous overload' errors, + // whereas 'unsigned char' and 'unsigned short' are automatically converted to 'int'. + // we're still adding those functions to silence warnings + XTENSOR_UNSIGNED_ABS_FUNC(unsigned char); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned short); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned int); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned long); + XTENSOR_UNSIGNED_ABS_FUNC(unsigned long long); + +#ifdef _WIN32 + XTENSOR_INT_SPECIALIZATION(isinf, false); + XTENSOR_INT_SPECIALIZATION(isnan, false); + XTENSOR_INT_SPECIALIZATION(isfinite, true); +#endif + + XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(abs); + + XTENSOR_UNARY_MATH_FUNCTOR(fabs); + XTENSOR_BINARY_MATH_FUNCTOR(fmod); + XTENSOR_BINARY_MATH_FUNCTOR(remainder); + XTENSOR_TERNARY_MATH_FUNCTOR(fma); + XTENSOR_BINARY_MATH_FUNCTOR(fmax); + XTENSOR_BINARY_MATH_FUNCTOR(fmin); + XTENSOR_BINARY_MATH_FUNCTOR(fdim); + XTENSOR_UNARY_MATH_FUNCTOR(exp); + XTENSOR_UNARY_MATH_FUNCTOR(exp2); + XTENSOR_UNARY_MATH_FUNCTOR(expm1); + XTENSOR_UNARY_MATH_FUNCTOR(log); + XTENSOR_UNARY_MATH_FUNCTOR(log10); + XTENSOR_UNARY_MATH_FUNCTOR(log2); + XTENSOR_UNARY_MATH_FUNCTOR(log1p); + XTENSOR_BINARY_MATH_FUNCTOR(pow); + XTENSOR_UNARY_MATH_FUNCTOR(sqrt); + XTENSOR_UNARY_MATH_FUNCTOR(cbrt); + XTENSOR_BINARY_MATH_FUNCTOR(hypot); + XTENSOR_UNARY_MATH_FUNCTOR(sin); + XTENSOR_UNARY_MATH_FUNCTOR(cos); + XTENSOR_UNARY_MATH_FUNCTOR(tan); + XTENSOR_UNARY_MATH_FUNCTOR(asin); + XTENSOR_UNARY_MATH_FUNCTOR(acos); + XTENSOR_UNARY_MATH_FUNCTOR(atan); + XTENSOR_BINARY_MATH_FUNCTOR(atan2); + XTENSOR_UNARY_MATH_FUNCTOR(sinh); + XTENSOR_UNARY_MATH_FUNCTOR(cosh); + XTENSOR_UNARY_MATH_FUNCTOR(tanh); + XTENSOR_UNARY_MATH_FUNCTOR(asinh); + XTENSOR_UNARY_MATH_FUNCTOR(acosh); + XTENSOR_UNARY_MATH_FUNCTOR(atanh); + XTENSOR_UNARY_MATH_FUNCTOR(erf); + XTENSOR_UNARY_MATH_FUNCTOR(erfc); + XTENSOR_UNARY_MATH_FUNCTOR(tgamma); + XTENSOR_UNARY_MATH_FUNCTOR(lgamma); + XTENSOR_UNARY_MATH_FUNCTOR(ceil); + XTENSOR_UNARY_MATH_FUNCTOR(floor); + XTENSOR_UNARY_MATH_FUNCTOR(trunc); + XTENSOR_UNARY_MATH_FUNCTOR(round); + XTENSOR_UNARY_MATH_FUNCTOR(nearbyint); + XTENSOR_UNARY_MATH_FUNCTOR(rint); + XTENSOR_UNARY_BOOL_FUNCTOR(isfinite); + XTENSOR_UNARY_BOOL_FUNCTOR(isinf); + XTENSOR_UNARY_BOOL_FUNCTOR(isnan); + } + +#undef XTENSOR_UNARY_MATH_FUNCTOR +#undef XTENSOR_UNARY_BOOL_FUNCTOR +#undef XTENSOR_UNARY_MATH_FUNCTOR_IMPL +#undef XTENSOR_BINARY_MATH_FUNCTOR +#undef XTENSOR_BINARY_BOOL_FUNCTOR +#undef XTENSOR_BINARY_MATH_FUNCTOR_IMPL +#undef XTENSOR_TERNARY_MATH_FUNCTOR +#undef XTENSOR_TERNARY_BOOL_FUNCTOR +#undef XTENSOR_TERNARY_MATH_FUNCTOR_IMPL +#undef XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING +#undef XTENSOR_UNSIGNED_ABS_FUNC + +#define XTENSOR_REDUCER_FUNCTION(NAME, FUNCTOR, RESULT_TYPE) \ + template >::value, int>> \ + inline auto NAME(E&& e, X&& axes, EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), \ + std::forward(axes), es); \ + } \ + \ + template ::value, int>> \ + inline auto NAME(E&& e, EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), es); \ + } + +#define XTENSOR_OLD_CLANG_REDUCER(NAME, FUNCTOR, RESULT_TYPE) \ + template \ + inline auto NAME(E&& e, std::initializer_list axes, EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), axes, es); \ + } \ + +#define XTENSOR_MODERN_CLANG_REDUCER(NAME, FUNCTOR, RESULT_TYPE) \ + template \ + inline auto NAME(E&& e, const I (&axes)[N], EVS es = EVS()) \ + { \ + using result_type = RESULT_TYPE; \ + using functor_type = FUNCTOR; \ + return reduce(make_xreducer_functor(functor_type()), std::forward(e), axes, es); \ + } + + /******************* + * basic functions * + *******************/ + + /** + * @defgroup basic_functions Basic functions + */ + + /** + * @ingroup basic_functions + * @brief Absolute value function. + * + * Returns an \ref xfunction for the element-wise absolute value + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto abs(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup basic_functions + * @brief Absolute value function. + * + * Returns an \ref xfunction for the element-wise absolute value + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto fabs(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup basic_functions + * @brief Remainder of the floating point division operation. + * + * Returns an \ref xfunction for the element-wise remainder of + * the floating point division operation e1 / e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fmod(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Signed remainder of the division operation. + * + * Returns an \ref xfunction for the element-wise signed remainder + * of the floating point division operation e1 / e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto remainder(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Fused multiply-add operation. + * + * Returns an \ref xfunction for e1 * e2 + e3 as if + * to infinite precision and rounded only once to fit the result type. + * @param e1 an \ref xfunction or a scalar + * @param e2 an \ref xfunction or a scalar + * @param e3 an \ref xfunction or a scalar + * @return an \ref xfunction + * @note e1, e2 and e3 can't be scalars every three. + */ + template + inline auto fma(E1&& e1, E2&& e2, E3&& e3) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2), std::forward(e3)); + } + + /** + * @ingroup basic_functions + * @brief Maximum function. + * + * Returns an \ref xfunction for the element-wise maximum + * of \a e1 and \a e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fmax(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Minimum function. + * + * Returns an \ref xfunction for the element-wise minimum + * of \a e1 and \a e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fmin(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Positive difference function. + * + * Returns an \ref xfunction for the element-wise positive + * difference of \a e1 and \a e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto fdim(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + namespace math + { + template + struct minimum + { + using result_type = T; + using simd_value_type = xsimd::simd_type; + + constexpr result_type operator()(const T& t1, const T& t2) const noexcept + { + return (t1 < t2) ? t1 : t2; + } + + constexpr simd_value_type simd_apply(const simd_value_type& t1, const simd_value_type& t2) const noexcept + { + return xsimd::select(t1 < t2, t1, t2); + } + }; + + template + struct maximum + { + using result_type = T; + using simd_value_type = xsimd::simd_type; + + constexpr result_type operator()(const T& t1, const T& t2) const noexcept + { + return (t1 > t2) ? t1 : t2; + } + + constexpr simd_value_type simd_apply(const simd_value_type& t1, const simd_value_type& t2) const noexcept + { + return xsimd::select(t1 > t2, t1, t2); + } + }; + + template + struct clamp_fun + { + using first_argument_type = T; + using second_argument_type = T; + using third_argument_type = T; + using result_type = T; + using simd_value_type = xsimd::simd_type; + + constexpr T operator()(const T& v, const T& lo, const T& hi) const + { + return v < lo ? lo : hi < v ? hi : v; + } + + constexpr simd_value_type simd_apply(const simd_value_type& v, + const simd_value_type& lo, + const simd_value_type& hi) const + { + return xsimd::select(v < lo, lo, xsimd::select(hi < v, hi, v)); + } + }; + } + + /** + * @ingroup basic_functions + * @brief Elementwise maximum + * + * Returns an \ref xfunction for the element-wise + * maximum between e1 and e2. + * @param e1 an \ref xexpression + * @param e2 an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto maximum(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Elementwise minimum + * + * Returns an \ref xfunction for the element-wise + * minimum between e1 and e2. + * @param e1 an \ref xexpression + * @param e2 an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto minimum(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup basic_functions + * @brief Maximum element along given axis. + * + * Returns an \ref xreducer for the maximum of elements over given + * \em axes. + * @param e an \ref xexpression + * @param axes the axes along which the maximum is found (optional) + * @param es evaluation strategy of the reducer + * @return an \ref xreducer + */ + XTENSOR_REDUCER_FUNCTION(amax, math::maximum, typename std::decay_t::value_type); +#ifdef X_OLD_CLANG + XTENSOR_OLD_CLANG_REDUCER(amax, math::maximum, typename std::decay_t::value_type); +#else + XTENSOR_MODERN_CLANG_REDUCER(amax, math::maximum, typename std::decay_t::value_type); +#endif + + /** + * @ingroup basic_functions + * @brief Minimum element along given axis. + * + * Returns an \ref xreducer for the minimum of elements over given + * \em axes. + * @param e an \ref xexpression + * @param axes the axes along which the minimum is found (optional) + * @param es evaluation strategy of the reducer + * @return an \ref xreducer + */ + XTENSOR_REDUCER_FUNCTION(amin, math::minimum, typename std::decay_t::value_type); +#ifdef X_OLD_CLANG + XTENSOR_OLD_CLANG_REDUCER(amin, math::minimum, typename std::decay_t::value_type); +#else + XTENSOR_MODERN_CLANG_REDUCER(amin, math::minimum, typename std::decay_t::value_type); +#endif + + /** + * @ingroup basic_functions + * @brief Clip values between hi and lo + * + * Returns an \ref xfunction for the element-wise clipped + * values between lo and hi + * @param e1 an \ref xexpression or a scalar + * @param lo a scalar + * @param hi a scalar + * + * @return a \ref xfunction + */ + template + inline auto clip(E1&& e1, E2&& lo, E3&& hi) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(lo), std::forward(hi)); + } + + namespace math + { + namespace detail + { + template + constexpr std::enable_if_t::value, T> + sign_impl(T x) + { + return std::isnan(x) ? std::numeric_limits::quiet_NaN() : x == 0 ? T(copysign(T(0), x)) : T(copysign(T(1), x)); + } + + template + inline std::enable_if_t::value, T> + sign_impl(T x) + { + typename T::value_type e = (x.real() != T(0)) ? x.real() : x.imag(); + return T(sign_impl(e), 0); + } + + template + constexpr std::enable_if_t::value, T> + sign_impl(T x) + { + return T(x > T(0)); + } + } + + template + struct sign_fun + { + using argument_type = T; + using result_type = T; + + constexpr T operator()(const T& x) const + { + return detail::sign_impl(x); + } + }; + } + + /** + * @ingroup basic_functions + * @brief Returns an element-wise indication of the sign of a number + * + * If the number is positive, returns +1. If negative, -1. If the number + * is zero, returns 0. + * + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sign(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /************************* + * exponential functions * + *************************/ + + /** + * @defgroup exp_functions Exponential functions + */ + + /** + * @ingroup exp_functions + * @brief Natural exponential function. + * + * Returns an \ref xfunction for the element-wise natural + * exponential of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto exp(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Base 2 exponential function. + * + * Returns an \ref xfunction for the element-wise base 2 + * exponential of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto exp2(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Natural exponential minus one function. + * + * Returns an \ref xfunction for the element-wise natural + * exponential of \em e, minus 1. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto expm1(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Natural logarithm function. + * + * Returns an \ref xfunction for the element-wise natural + * logarithm of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Base 10 logarithm function. + * + * Returns an \ref xfunction for the element-wise base 10 + * logarithm of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log10(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Base 2 logarithm function. + * + * Returns an \ref xfunction for the element-wise base 2 + * logarithm of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log2(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup exp_functions + * @brief Natural logarithm of one plus function. + * + * Returns an \ref xfunction for the element-wise natural + * logarithm of \em e, plus 1. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto log1p(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /******************* + * power functions * + *******************/ + + /** + * @defgroup pow_functions Power functions + */ + + /** + * @ingroup pow_functions + * @brief Power function. + * + * Returns an \ref xfunction for the element-wise value of + * of \em e1 raised to the power \em e2. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto pow(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /** + * @ingroup pow_functions + * @brief Square root function. + * + * Returns an \ref xfunction for the element-wise square + * root of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sqrt(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup pow_functions + * @brief Cubic root function. + * + * Returns an \ref xfunction for the element-wise cubic + * root of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto cbrt(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup pow_functions + * @brief Hypotenuse function. + * + * Returns an \ref xfunction for the element-wise square + * root of the sum of the square of \em e1 and \em e2, avoiding + * overflow and underflow at intermediate stages of computation. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto hypot(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /*************************** + * trigonometric functions * + ***************************/ + + /** + * @defgroup trigo_functions Trigonometric function + */ + + /** + * @ingroup trigo_functions + * @brief Sine function. + * + * Returns an \ref xfunction for the element-wise sine + * of \em e (measured in radians). + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sin(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Cosine function. + * + * Returns an \ref xfunction for the element-wise cosine + * of \em e (measured in radians). + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto cos(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Tangent function. + * + * Returns an \ref xfunction for the element-wise tangent + * of \em e (measured in radians). + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto tan(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Arcsine function. + * + * Returns an \ref xfunction for the element-wise arcsine + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto asin(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Arccosine function. + * + * Returns an \ref xfunction for the element-wise arccosine + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto acos(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Arctangent function. + * + * Returns an \ref xfunction for the element-wise arctangent + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto atan(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup trigo_functions + * @brief Artangent function, using signs to determine quadrants. + * + * Returns an \ref xfunction for the element-wise arctangent + * of e1 / e2, using the signs of arguments to determine the + * correct quadrant. + * @param e1 an \ref xexpression or a scalar + * @param e2 an \ref xexpression or a scalar + * @return an \ref xfunction + * @note e1 and e2 can't be both scalars. + */ + template + inline auto atan2(E1&& e1, E2&& e2) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e1), std::forward(e2)); + } + + /************************ + * hyperbolic functions * + ************************/ + + /** + * @defgroup hyper_functions Hyperbolic functions + */ + + /** + * @ingroup hyper_functions + * @brief Hyperbolic sine function. + * + * Returns an \ref xfunction for the element-wise hyperbolic + * sine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto sinh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Hyperbolic cosine function. + * + * Returns an \ref xfunction for the element-wise hyperbolic + * cosine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto cosh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Hyperbolic tangent function. + * + * Returns an \ref xfunction for the element-wise hyperbolic + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto tanh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Inverse hyperbolic sine function. + * + * Returns an \ref xfunction for the element-wise inverse hyperbolic + * sine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto asinh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Inverse hyperbolic cosine function. + * + * Returns an \ref xfunction for the element-wise inverse hyperbolic + * cosine of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto acosh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup hyper_functions + * @brief Inverse hyperbolic tangent function. + * + * Returns an \ref xfunction for the element-wise inverse hyperbolic + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto atanh(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /***************************** + * error and gamma functions * + *****************************/ + + /** + * @defgroup err_functions Error and gamma functions + */ + + /** + * @ingroup err_functions + * @brief Error function. + * + * Returns an \ref xfunction for the element-wise error function + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto erf(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup err_functions + * @brief Complementary error function. + * + * Returns an \ref xfunction for the element-wise complementary + * error function of \em e, whithout loss of precision for large argument. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto erfc(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup err_functions + * @brief Gamma function. + * + * Returns an \ref xfunction for the element-wise gamma function + * of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto tgamma(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup err_functions + * @brief Natural logarithm of the gamma function. + * + * Returns an \ref xfunction for the element-wise logarithm of + * the asbolute value fo the gamma function of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto lgamma(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /********************************************* + * nearest integer floating point operations * + *********************************************/ + + /** + * @defgroup nearint_functions Nearest integer floating point operations + */ + + /** + * @ingroup nearint_functions + * @brief ceil function. + * + * Returns an \ref xfunction for the element-wise smallest integer value + * not less than \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto ceil(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief floor function. + * + * Returns an \ref xfunction for the element-wise smallest integer value + * not greater than \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto floor(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief trunc function. + * + * Returns an \ref xfunction for the element-wise nearest integer not greater + * in magnitude than \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto trunc(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief round function. + * + * Returns an \ref xfunction for the element-wise nearest integer value + * to \em e, rounding halfway cases away from zero, regardless of the + * current rounding mode. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto round(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief nearbyint function. + * + * Returns an \ref xfunction for the element-wise rounding of \em e to integer + * values in floating point format, using the current rounding mode. nearbyint + * never raises FE_INEXACT error. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto nearbyint(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup nearint_functions + * @brief rint function. + * + * Returns an \ref xfunction for the element-wise rounding of \em e to integer + * values in floating point format, using the current rounding mode. Contrary + * to nearbyint, rint may raise FE_INEXACT error. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto rint(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /**************************** + * classification functions * + ****************************/ + + /** + * @defgroup classif_functions Classification functions + */ + + /** + * @ingroup classif_functions + * @brief finite value check + * + * Returns an \ref xfunction for the element-wise finite value check + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto isfinite(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup classif_functions + * @brief infinity check + * + * Returns an \ref xfunction for the element-wise infinity check + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto isinf(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + /** + * @ingroup classif_functions + * @brief NaN check + * + * Returns an \ref xfunction for the element-wise NaN check + * tangent of \em e. + * @param e an \ref xexpression + * @return an \ref xfunction + */ + template + inline auto isnan(E&& e) noexcept + -> detail::xfunction_type_t + { + return detail::make_xfunction(std::forward(e)); + } + + namespace detail + { + template + inline auto get_functor(T&& args, std::index_sequence) + { + return FUNCTOR(std::get(args)...); + } + + template