From e9cf857af98b02ac15fc2f6100bd81323c500a0e Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Fri, 28 Jul 2017 14:08:00 +0200 Subject: [PATCH 01/27] added FIXME --- include/xtensor/xassign.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/xtensor/xassign.hpp b/include/xtensor/xassign.hpp index 137b55090..fbb7223ca 100644 --- a/include/xtensor/xassign.hpp +++ b/include/xtensor/xassign.hpp @@ -157,6 +157,7 @@ namespace xt shape_type shape = make_sequence(dim, size_type(1)); bool trivial_broadcast = de2.broadcast_shape(shape); + // FIXME: The second comparison is lexicographic. Comment why this is correct. if (dim > de1.dimension() || shape > de1.shape()) { typename E1::temporary_type tmp(shape); From 802c6ec4ca3d7e97db7e8c0a96f8955dc322fbc4 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Fri, 28 Jul 2017 18:56:20 +0200 Subject: [PATCH 02/27] first running version of TinyArray and tests (needs clean-up) --- include/xtensor/xconcepts.hpp | 78 + include/xtensor/xexception.hpp | 16 + include/xtensor/xtiny.hpp | 3838 ++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/test_xtiny.cpp | 602 +++++ 5 files changed, 4535 insertions(+) create mode 100644 include/xtensor/xconcepts.hpp create mode 100644 include/xtensor/xtiny.hpp create mode 100644 test/test_xtiny.cpp diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp new file mode 100644 index 000000000..21ec48a02 --- /dev/null +++ b/include/xtensor/xconcepts.hpp @@ -0,0 +1,78 @@ +/*************************************************************************** +* 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 XCONCEPTS_HPP +#define XCONCEPTS_HPP + +#include + +namespace xt +{ + +/**********************************************************/ +/* */ +/* XTENSOR_REQUIRE concept checking macro */ +/* */ +/**********************************************************/ + +struct require_ok {}; + +template +using ConceptCheck = typename std::enable_if::type; + +#define XTENSOR_REQUIRE typename Require = ConceptCheck + +/**********************************************************/ +/* */ +/* TinyArrayConcept */ +/* */ +/**********************************************************/ + +struct TinyArrayTag {}; + + // TinyArrayConcept refers to TinyArrayBase and TinyArray. + // By default, 'ARRAY' fulfills the TinyArrayConcept if it is derived + // from TinyArrayTag. + // + // Alternatively, one can partially specialize TinyArrayConcept. +template +struct TinyArrayConcept +{ + static const bool value = std::is_base_of::value; +}; + + +/**********************************************************/ +/* */ +/* IteratorConcept */ +/* */ +/**********************************************************/ + + // currently, we apply only the simple rule that class T + // must be a pointer or array or has an embedded typedef + // 'iterator_category'. More sophisticated checks should + // be added when needed. +template +struct IteratorConcept +{ + typedef typename std::decay::type V; + + 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::value; +}; + +} // namespace xt + +#endif // XCONCEPTS_HPP diff --git a/include/xtensor/xexception.hpp b/include/xtensor/xexception.hpp index 983b4bcd6..39e2c0aec 100644 --- a/include/xtensor/xexception.hpp +++ b/include/xtensor/xexception.hpp @@ -167,4 +167,20 @@ namespace xt #define XTENSOR_ASSERT(expr) #endif } + +#ifdef XTENSOR_ENABLE_ASSERT +#define XTENSOR_ASSERT_MSG(PREDICATE, MESSAGE) \ + if((PREDICATE)) {} else { \ + throw std::runtime_error(std::string("Assertion error!\n") + MESSAGE + \ + "\n(" + __FILE__ + ':' + std::to_string(__LINE__) + ")\n"); } + +#else +#define XTENSOR_ASSERT_MSG(PREDICATE, MESSAGE) #endif + +#define xtensor_precondition(PREDICATE, MESSAGE) \ + if((PREDICATE)) {} else { \ + throw std::runtime_error(std::string("Precondition violation!\n") + MESSAGE + \ + "\n(" + __FILE__ + ':' + std::to_string(__LINE__) + ")\n"); } + +#endif // XEXCEPTION_HPP diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp new file mode 100644 index 000000000..b66ae715e --- /dev/null +++ b/include/xtensor/xtiny.hpp @@ -0,0 +1,3838 @@ +/*************************************************************************** +* 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_XTINY_HPP +#define XTENSOR_XTINY_HPP + +#include "xconcepts.hpp" +#include "xexception.hpp" +#include // ostream +#include +#include +#include +#include +#include +#include +#include + +#ifdef XTENSOR_CHECK_BOUNDS + #define XTENSOR_ASSERT_INSIDE(array, diff) \ + xtensor_precondition(diff >= 0 && diff < array.size(), "Index out of bounds") +#else + #define XTENSOR_ASSERT_INSIDE(array, diff) +#endif + +namespace xt { + +// FIXME: move these to the appropriate places + +using std::swap; +using std::sqrt; +using std::abs; + +using ArrayIndex = std::ptrdiff_t; +static const int runtime_size = -1; +enum SkipInitialization { DontInit }; +enum ReverseCopyTag { ReverseCopy }; + +/////////////////////////////////////////////////////////////// +// UninitializedMemoryTraits + +template +struct UninitializedMemoryTraits +{ + static const bool value = std::is_scalar::value || std::is_pod::value; +}; + +template +class TinyArray; + +template +class TinyArrayView; + +/**********************************************************/ +/* */ +/* abs() */ +/* */ +/**********************************************************/ + +// define the missing variants of abs() to avoid 'ambiguous overload' +// errors in template functions +#define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ + inline T abs(T t) { return t; } + +XTENSOR_DEFINE_UNSIGNED_ABS(bool) +XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) +XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) +XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) +XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) +XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) + +#undef XTENSOR_DEFINE_UNSIGNED_ABS + +#define XTENSOR_DEFINE_MISSING_ABS(T) \ + inline T abs(T t) { return t < 0 ? static_cast(-t) : t; } + +XTENSOR_DEFINE_MISSING_ABS(signed char) +XTENSOR_DEFINE_MISSING_ABS(signed short) + +#if defined(_MSC_VER) && _MSC_VER < 1600 +XTENSOR_DEFINE_MISSING_ABS(signed long long) +#endif + +#undef XTENSOR_DEFINE_MISSING_ABS + + +template +using PromoteType = decltype((*((T1*)0)) * (*((T2*)0))); + +/////////////////////////////////////////////////////////////// +// BoolPromote + + // replace 'bool' with 'unsigned char' +template +using BoolPromote = typename std::conditional::value, unsigned char, T>::type; + +template +using RealPromoteType = decltype(sqrt(*((T*)0))); + +/////////////////////////////////////////////////////////////// +// NormTraits + +template +struct NormTraits; + +namespace detail { + +template ::value> +struct NormOfScalarImpl; + +template +struct NormOfScalarImpl +{ + static const bool value = false; + typedef void * NormType; + typedef void * SquaredNormType; +}; + +template +struct NormOfScalarImpl +{ + static const bool value = true; + typedef T NormType; + typedef typename + std::conditional::value, + typename std::conditional= 4, + uint64_t, + uint32_t>::type, + T>::type + SquaredNormType; +}; + +template ::value, + bool floating = std::is_floating_point::value> +struct NormOfArrayElementsImpl; + +template <> +struct NormOfArrayElementsImpl +{ + typedef void * NormType; + typedef void * SquaredNormType; +}; + +template +struct NormOfArrayElementsImpl +{ + typedef typename NormTraits::NormType NormType; + typedef typename NormTraits::SquaredNormType SquaredNormType; +}; + +template +struct NormOfArrayElementsImpl +{ + static_assert(!std::is_same::value, + "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); + + typedef double NormType; + typedef unsigned long long SquaredNormType; +}; + +template +struct NormOfArrayElementsImpl +{ + typedef double NormType; + typedef double SquaredNormType; +}; + +template <> +struct NormOfArrayElementsImpl +{ + typedef long double NormType; + typedef long double SquaredNormType; +}; + +template +struct NormOfVectorImpl +{ + static void * test(...); + + template + static typename U::value_type test(U*, typename U::value_type * = 0); + + typedef decltype(test((ARRAY*)0)) T; + + static const bool value = !std::is_same::value; + + typedef typename NormOfArrayElementsImpl::NormType NormType; + typedef typename NormOfArrayElementsImpl::SquaredNormType SquaredNormType; +}; + + +} // namespace detail + + /* NormTraits implement the following default rules, which are + designed to minimize the possibility of overflow: + * T is a 32-bit integer type: + NormType is T itself, + SquaredNormType is 'unsigned long long' + * T is another built-in arithmetic type: + NormType is T itself, + SquaredNormType is the NumericTraits::UnsignedPromote + * T is a container of 'long double': + NormType and SquaredNormType are 'long double' + * T is a container of another built-in arithmetic type: + NormType is 'double', + SquaredNormType is 'unsigned long long' + * T is a container of some other type: + NormType is the element's norm type, + SquaredNormType is the element's squared norm type + Containers are recognized by having an embedded typedef 'value_type'. + + To change the behavior for a particular case or extend it to cases + not covered here, simply specialize the NormTraits template. + */ +template +struct NormTraits +{ + static_assert(!std::is_same::value, + "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); + + typedef detail::NormOfScalarImpl NormOfScalar; + typedef detail::NormOfVectorImpl NormOfVector; + + static const bool value = NormOfScalar::value || NormOfVector::value; + + static_assert(value, "NormTraits are undefined for type T."); + + typedef typename std::conditional::type + NormType; + + typedef typename std::conditional::type + SquaredNormType; +}; + +template +using SquaredNormType = typename NormTraits::SquaredNormType; + +template +using NormType = typename NormTraits::NormType; + +namespace mathfunctions { + +using std::abs; +using std::fabs; + +using std::cos; +using std::sin; +using std::tan; +// using std::sin_pi; +// using std::cos_pi; +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::sqrti; +// using std::sq; +// using std::elementwiseNorm; +// using std::elementwiseSquaredNorm; + +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::ceil; +using std::floor; +using std::trunc; +using std::round; +using std::lround; +using std::llround; +// using std::roundi; +// using std::even; +// using std::odd; +// using std::sign; +// using std::signi; + +using std::erf; +using std::erfc; +using std::erfc; +using std::tgamma; +using std::lgamma; +// using std::loggamma; + +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; + +template +inline +std::enable_if_t >::value, bool> +isclose(V1 v1, V2 v2, double rtol = 1e-05, double atol = 1e-08) +{ + using P = PromoteType; + return abs(v1-v2) <= (atol + rtol * std::max(abs(static_cast

(v1)), abs(static_cast

(v2)))); +} + + /** \brief The square function. + + sq(x) = x*x is needed so often that it makes sense to define it as a function. + + \#include \
+ Namespace: vigra + */ +template ::value> > +inline PromoteType +sq(T t) +{ + return t*t; +} + +/**********************************************************/ +/* */ +/* min() */ +/* */ +/**********************************************************/ + + /** \brief A proper minimum function. + + The std::min template matches everything -- this is way too + greedy to be useful. VIGRA implements the basic min function + only for arithmetic types and provides explicit overloads for everything + else. Moreover, VIGRA's min function also computes the minimum + between two different types, as long as they have a std::common_type. + + \#include \
+ Namespace: vigra + */ +template ::value && std::is_arithmetic::value> > +inline std::common_type_t +min(T1 const & t1, T2 const & t2) +{ + using T = std::common_type_t; + return std::min(static_cast(t1), static_cast(t2)); +} + +template ::value> > +inline T const & +min(T const & t1, T const & t2) +{ + return std::min(t1, t2); +} + +/**********************************************************/ +/* */ +/* max() */ +/* */ +/**********************************************************/ + + /** \brief A proper maximum function. + + The std::max template matches everything -- this is way too + greedy to be useful. VIGRA implements the basic max function + only for arithmetic types and provides explicit overloads for everything + else. Moreover, VIGRA's max function also computes the maximum + between two different types, as long as they have a std::common_type. + + \#include \
+ Namespace: vigra + */ +template ::value && std::is_arithmetic::value> > +inline std::common_type_t +max(T1 const & t1, T2 const & t2) +{ + using T = std::common_type_t; + return std::max(static_cast(t1), static_cast(t2)); +} + +template ::value> > +inline T const & +max(T const & t1, T const & t2) +{ + return std::max(t1, t2); +} + +/**********************************************************/ +/* */ +/* floor(), ceil() */ +/* */ +/**********************************************************/ + + // add missing floor() and ceil() overloads for integral types + +#define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ + inline T floor(signed T t) { return t; } \ + inline T floor(unsigned T t) { return t; } \ + inline T ceil(signed T t) { return t; } \ + inline T ceil(unsigned T t) { return t; } + +XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) +XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) +XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) +XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) +XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) + +#undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL + +/**********************************************************/ +/* */ +/* dot() */ +/* */ +/**********************************************************/ + +// scalar dot is needed for generic functions that should work with +// scalars and vectors alike + +#define XTENSOR_DEFINE_SCALAR_DOT(T) \ + inline PromoteType dot(T l, T r) { return l*r; } + +XTENSOR_DEFINE_SCALAR_DOT(unsigned char) +XTENSOR_DEFINE_SCALAR_DOT(unsigned short) +XTENSOR_DEFINE_SCALAR_DOT(unsigned int) +XTENSOR_DEFINE_SCALAR_DOT(unsigned long) +XTENSOR_DEFINE_SCALAR_DOT(unsigned long long) +XTENSOR_DEFINE_SCALAR_DOT(signed char) +XTENSOR_DEFINE_SCALAR_DOT(signed short) +XTENSOR_DEFINE_SCALAR_DOT(signed int) +XTENSOR_DEFINE_SCALAR_DOT(signed long) +XTENSOR_DEFINE_SCALAR_DOT(signed long long) +XTENSOR_DEFINE_SCALAR_DOT(float) +XTENSOR_DEFINE_SCALAR_DOT(double) +XTENSOR_DEFINE_SCALAR_DOT(long double) + +#undef XTENSOR_DEFINE_SCALAR_DOT + +/**********************************************************/ +/* */ +/* pow() */ +/* */ +/**********************************************************/ + +// support 'double' exponents for all floating point versions of pow() +inline float pow(float v, double e) +{ + return std::pow(v, (float)e); +} + +inline long double pow(long double v, double e) +{ + return std::pow(v, (long double)e); +} + +/**********************************************************/ +/* */ +/* roundi() */ +/* */ +/**********************************************************/ + + // round and cast to nearest long int +inline long int roundi(double t) +{ + return lround(t); +} + +/**********************************************************/ +/* */ +/* even(), odd() */ +/* */ +/**********************************************************/ + +template ::value> > +inline bool +even(T const t) +{ + return (t&1) == 0; +} + +template ::value> > +inline bool +odd(T const t) +{ + return (t&1) != 0; +} + +/**********************************************************/ +/* */ +/* sin_pi(), cos_pi() */ +/* */ +/**********************************************************/ + + /** \brief sin(pi*x). + + Essentially calls std::sin(M_PI*x) but uses a more accurate implementation + to make sure that sin_pi(1.0) == 0.0 (which does not hold for + std::sin(M_PI) due to round-off error), and sin_pi(0.5) == 1.0. + + \#include \
+ Namespace: vigra + */ +template ::value> > +REAL sin_pi(REAL x) +{ + if(x < 0.0) + return -sin_pi(-x); + if(x < 0.5) + return std::sin(numeric_constants::PI * x); + + bool invert = false; + if(x < 1.0) + { + invert = true; + x = -x; + } + + REAL rem = std::floor(x); + if(odd((int)rem)) + invert = !invert; + rem = x - rem; + if(rem > 0.5) + rem = 1.0 - rem; + if(rem == 0.5) + rem = REAL(1); + else + rem = std::sin(numeric_constants::PI * rem); + return invert + ? -rem + : rem; +} + + /** \brief cos(pi*x). + + Essentially calls std::cos(M_PI*x) but uses a more accurate implementation + to make sure that cos_pi(1.0) == -1.0 and cos_pi(0.5) == 0.0. + + \#include \
+ Namespace: vigra + */ +template ::value> > +REAL cos_pi(REAL x) +{ + return sin_pi(x+0.5); +} + +/**********************************************************/ +/* */ +/* gamma(), loggamma() */ +/* */ +/**********************************************************/ + +inline double gamma(double x) +{ + xtensor_precondition(x <= 171.0, + "gamma(): argument cannot exceed 171.0."); + + xtensor_precondition(x > 0.0 || fmod(x, 1.0) != 0, + "gamma(): gamma function is undefined for 0 and negative integers."); + + return tgamma(x); +} + +inline double loggamma(double x) +{ + xtensor_precondition(x > 0.0, + "loggamma(): argument must be positive."); + + xtensor_precondition(x <= 1.0e307, + "loggamma(): argument must not exceed 1e307."); + + return lgamma(x); +} + +} // namespace mathfunctions + +using mathfunctions::sq; + +/**********************************************************/ +/* */ +/* squaredNorm() */ +/* */ +/**********************************************************/ + +template +inline SquaredNormType > +squaredNorm(std::complex const & t) +{ + return sq(t.real()) + sq(t.imag()); +} + +/**********************************************************/ +/* */ +/* norm() */ +/* */ +/**********************************************************/ + + /** \brief The norm of a numerical object. + + For scalar types: implemented as abs(t)
+ otherwise: implemented as sqrt(squaredNorm(t)). + + \#include \
+ Namespace: vigra + */ +template +inline auto +norm(T const & t) -> decltype(sqrt(squaredNorm(t))) +{ + return sqrt(squaredNorm(t)); +} + +#define XTENSOR_DEFINE_NORM(T) \ + inline SquaredNormType squaredNorm(T t) { return sq(t); } \ + inline NormType norm(T t) { return abs(t); } \ + inline SquaredNormType sizeDividedSquaredNorm(T t) { return sq(t); } \ + inline NormType sizeDividedNorm(T t) { return abs(t); } + +XTENSOR_DEFINE_NORM(signed char) +XTENSOR_DEFINE_NORM(unsigned char) +XTENSOR_DEFINE_NORM(short) +XTENSOR_DEFINE_NORM(unsigned short) +XTENSOR_DEFINE_NORM(int) +XTENSOR_DEFINE_NORM(unsigned int) +XTENSOR_DEFINE_NORM(long) +XTENSOR_DEFINE_NORM(unsigned long) +XTENSOR_DEFINE_NORM(long long) +XTENSOR_DEFINE_NORM(unsigned long long) +XTENSOR_DEFINE_NORM(float) +XTENSOR_DEFINE_NORM(double) +XTENSOR_DEFINE_NORM(long double) + +#undef XTENSOR_DEFINE_NORM + +namespace tags { + +/********************************************************/ +/* */ +/* tags::size */ +/* */ +/********************************************************/ + + // Support for tags::size keyword argument + // to disambiguate array sizes from initial values. +struct SizeProxy +{ + ArrayIndex value; +}; + +struct SizeTag +{ + SizeProxy operator=(ArrayIndex s) const + { + return {s}; + } + + SizeProxy operator()(ArrayIndex s) const + { + return {s}; + } +}; + +namespace { + +SizeTag size; + +} + +} // namespace tags + +// mask cl.exe shortcomings [begin] +// #if defined(_MSC_VER) +// #pragma warning( push ) +// #pragma warning( disable : 4503 ) +// #endif + + +// FIXME: document this +template +struct TinyShapeImpl; + +template +struct TinyShapeImpl +{ + static_assert(N >= 0, "TinyArrayBase(): array must have non-negative shape."); + using NextType = TinyShapeImpl; + + static const ArrayIndex level = LEVEL; + static const ArrayIndex stride = NextType::total_size; + static const ArrayIndex total_size = N * stride; + static const ArrayIndex alloc_size = total_size; + + static ArrayIndex offset(ArrayIndex const * coord) + { + return stride*coord[level] + NextType::offset(coord); + } + + template + static ArrayIndex offset(ArrayIndex i, V...rest) + { + return stride*i + NextType::offset(rest...); + } +}; + +template +struct TinyShapeImpl +{ + static_assert(N >= 0, "TinyArrayBase(): array must have non-negative shape."); + static const ArrayIndex level = LEVEL; + static const ArrayIndex stride = 1; + static const ArrayIndex total_size = N; + static const ArrayIndex alloc_size = total_size; + + static ArrayIndex offset(ArrayIndex const * coord) + { + return coord[level]; + } + + static ArrayIndex offset(ArrayIndex i) + { + return i; + } +}; + +template +struct TinyShapeImpl +{ + static const ArrayIndex level = LEVEL; + static const ArrayIndex stride = 1; + static const ArrayIndex total_size = 0; + static const ArrayIndex alloc_size = 1; + + static ArrayIndex offset(ArrayIndex const * coord) + { + return coord[level]; + } + + static ArrayIndex offset(ArrayIndex i) + { + return i; + } +}; + +template +struct TinySize +{ + static const ArrayIndex value = TinyShapeImpl<0, N...>::total_size; + static const ArrayIndex ndim = sizeof...(N); +}; + +namespace detail { + +template +struct TinyArrayIsStatic +{ + static const int ndim = sizeof...(N)+1; + static const bool value = ndim > 1 || N0 != runtime_size; +}; + +} // namespace detail + +#define XTENSOR_ASSERT_RUNTIME_SIZE(SHAPE, PREDICATE, MESSAGE) \ + if(detail::TinyArrayIsStatic::value) {} else \ + xtensor_precondition(PREDICATE, MESSAGE) + + +/********************************************************/ +/* */ +/* TinyArrayBase */ +/* */ +/********************************************************/ + +/** \brief Base class for fixed size vectors and matrices. + + This class contains functionality shared by + \ref TinyArray and \ref TinyArrayView, and enables these classes + to be freely mixed within expressions. It is typically not used directly. + + \#include \
+ Namespace: vigra +**/ +template +class TinyArrayBase +: public TinyArrayTag +{ + protected: + using ShapeHelper = TinyShapeImpl<0, N...>; + + static const bool derived_is_array = std::is_same >::value; + using data_array_type = typename std::conditional::type; + + template + void initImpl(VALUETYPE v1, V2... v2) + { + data_[LEVEL] = v1; + initImpl(v2...); + } + + template + void initImpl(VALUETYPE v1) + { + data_[LEVEL] = v1; + } + + public: + + template + using AsType = TinyArray; + + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = value_type &; + using const_reference = const_value_type &; + using pointer = value_type *; + using const_pointer = const_value_type *; + using iterator = value_type *; + using const_iterator = const_value_type *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = TinyArray; + + static constexpr ArrayIndex static_ndim = sizeof...(N); + static constexpr ArrayIndex static_size = ShapeHelper::total_size; + static const bool may_use_uninitialized_memory = + UninitializedMemoryTraits::value; + + // constructors + + constexpr TinyArrayBase(TinyArrayBase const &) = default; + + protected: + + TinyArrayBase(SkipInitialization) + {} + + // constructors to be used by TinyArray + + template + TinyArrayBase(TinyArrayBase const & other) + { + xtensor_precondition(size() == other.size(), + "TinyArrayBase(): shape mismatch."); + for(int i=0; i(other[i]); + } + + // constructor for zero or one argument + // activate 'constexpr' in C++ 14 + explicit /* constexpr */ TinyArrayBase(value_type v = value_type()) + { + for(int i=0; i + constexpr TinyArrayBase(value_type v0, value_type v1, V ... v) + : data_{VALUETYPE(v0), VALUETYPE(v1), VALUETYPE(v)...} + { + static_assert(sizeof...(V)+2 == static_size, + "TinyArrayBase(): number of constructor arguments contradicts size()."); + } + + // // constructor for two or more arguments + // constexpr TinyArrayBase(std::initializer_list const & init) + // : data_(init) + // { + // static_assert(init.size() == static_size, + // "TinyArrayBase(): wrong number of arguments."); + // } + + constexpr TinyArrayBase(value_type const (&v)[static_ndim]) + : data_{v} + {} + + template + explicit TinyArrayBase(U const * u) + { + for(int i=0; i(u[i]); + } + + template + TinyArrayBase(U const * u, ReverseCopyTag) + { + for(int i=0; i(u[static_size-1-i]); + } + + // for compatibility with TinyArrayBase<..., runtime_size> + template + TinyArrayBase(U const * u, U const * /* end */, ReverseCopyTag) + : TinyArrayBase(u, ReverseCopy) + {} + + public: + + // assignment + + TinyArrayBase & operator=(TinyArrayBase const &) = default; + + TinyArrayBase & operator=(value_type v) + { + for(int i=0; i + TinyArrayBase & operator=(TinyArrayBase const & other) + { + for(int i=0; i(other[i]); + return *this; + } + + template + TinyArrayBase & operator=(TinyArrayBase const & other) + { + xtensor_precondition(size() == other.size(), + "TinyArrayBase::operator=(): size mismatch."); + for(int i=0; i(other[i]); + return *this; + } + + template + constexpr bool + sameShape(TinyArrayBase const & other) const + { + return false; + } + + template + constexpr bool + sameShape(TinyArrayBase const & other) const + { + return true; + } + + template + bool + sameShape(TinyArrayBase const & other) const + { + return sizeof...(N) == 1 && size() == other.size(); + } + + DERIVED & init(value_type v = value_type()) + { + for(int i=0; i(*this); + } + + template + DERIVED & init(value_type v0, value_type v1, V... v) + { + static_assert(sizeof...(V)+2 == static_size, + "TinyArrayBase::init(): wrong number of arguments."); + initImpl<0>(v0, v1, v...); + return static_cast(*this); + } + + template + DERIVED & init(Iterator first, Iterator end) + { + ArrayIndex range = std::distance(first, end); + if(static_size < range) + range = static_size; + for(ArrayIndex i=0; i(*first); + return static_cast(*this); + } + + // index access + + reference operator[](ArrayIndex i) + { + return data_[i]; + } + + constexpr const_reference operator[](ArrayIndex i) const + { + return data_[i]; + } + + reference at(ArrayIndex i) + { + if(i < 0 || i >= static_size) + throw std::out_of_range("TinyArrayBase::at()"); + return data_[i]; + } + + const_reference at(ArrayIndex i) const + { + if(i < 0 || i >= static_size) + throw std::out_of_range("TinyArrayBase::at()"); + return data_[i]; + } + + reference operator[](ArrayIndex const (&i)[static_ndim]) + { + return data_[ShapeHelper::offset(i)]; + } + + constexpr const_reference operator[](ArrayIndex const (&i)[static_ndim]) const + { + return data_[ShapeHelper::offset(i)]; + } + + reference at(ArrayIndex const (&i)[static_ndim]) + { + return at(ShapeHelper::offset(i)); + } + + const_reference at(ArrayIndex const (&i)[static_ndim]) const + { + return at(ShapeHelper::offset(i)); + } + + reference operator[](index_type const & i) + { + return data_[ShapeHelper::offset(i.data())]; + } + + constexpr const_reference operator[](index_type const & i) const + { + return data_[ShapeHelper::offset(i.data())]; + } + + reference at(index_type const & i) + { + return at(ShapeHelper::offset(i.data())); + } + + const_reference at(index_type const & i) const + { + return at(ShapeHelper::offset(i.data())); + } + + template + reference operator()(V...v) + { + static_assert(sizeof...(V) == static_ndim, + "TinyArrayBase::operator(): wrong number of arguments."); + return data_[ShapeHelper::offset(v...)]; + } + + template + constexpr const_reference operator()(V...v) const + { + static_assert(sizeof...(V) == static_ndim, + "TinyArrayBase::operator(): wrong number of arguments."); + return data_[ShapeHelper::offset(v...)]; + } + + /** Get a view to the subarray with length (TO-FROM) starting at FROM. + The bounds must fullfill 0 <= FROM < TO <= static_size. + Only available if static_ndim == 1. + */ + template + TinyArrayView + subarray() const + { + static_assert(sizeof...(N) == 1, + "TinyArrayBase::subarray(): array must be 1-dimensional."); + static_assert(FROM >= 0 && FROM < TO && TO <= static_size, + "TinyArrayBase::subarray(): range out of bounds."); + return TinyArrayView(const_cast(data_)+FROM); + } + + TinyArrayView + subarray(ArrayIndex FROM, ArrayIndex TO) const + { + xtensor_precondition(FROM >= 0 && FROM < TO && TO <= static_size, + "TinyArrayBase::subarray(): range out of bounds."); + return TinyArrayView(TO-FROM, const_cast(data_)+FROM); + } + + template + TinyArray + erase(ArrayIndex m) const + { + static_assert(sizeof...(N) == 1, + "TinyArrayBase::erase(): array must be 1-dimensional."); + xtensor_precondition(m >= 0 && m < static_size, "TinyArray::erase(): " + "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); + TinyArray res(static_size-1, DontInit); + for(int k=0; k + TinyArray + pop_front() const + { + static_assert(sizeof...(N) == 1, + "TinyArrayBase::pop_front(): array must be 1-dimensional."); + return erase(0); + } + + template + TinyArray + pop_back() const + { + static_assert(sizeof...(N) == 1, + "TinyArrayBase::pop_back(): array must be 1-dimensional."); + return erase(size()-1); + } + + template + TinyArray + insert(ArrayIndex m, value_type v) const + { + static_assert(sizeof...(N) == 1, + "TinyArrayBase::insert(): array must be 1-dimensional."); + xtensor_precondition(m >= 0 && m <= static_size, "TinyArray::insert(): " + "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); + TinyArray res(DontInit); + for(int k=0; k + inline + TinyArray + transpose(TinyArrayBase const & permutation) const + { + static_assert(sizeof...(N) == 1, + "TinyArray::transpose(): only allowed for 1-dimensional arrays."); + static_assert(M == static_size || M == runtime_size, + "TinyArray::transpose(): size mismatch."); + XTENSOR_ASSERT_RUNTIME_SIZE(M, size() == 0 || size() == permutation.size(), + "TinyArray::transpose(): size mismatch."); + TinyArray res(DontInit); + for(int k=0; k < size(); ++k) + { + XTENSOR_ASSERT_MSG(permutation[k] >= 0 && permutation[k] < size(), + "transpose(): Permutation index out of bounds"); + res[k] = (*this)[permutation[k]]; + } + return res; + } + + // boiler plate + + iterator begin() { return data_; } + iterator end() { return data_ + static_size; } + const_iterator begin() const { return data_; } + const_iterator end() const { return data_ + static_size; } + const_iterator cbegin() const { return data_; } + const_iterator cend() const { return data_ + static_size; } + + reverse_iterator rbegin() { return reverse_iterator(data_ + static_size); } + reverse_iterator rend() { return reverse_iterator(data_); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(data_ + static_size); } + const_reverse_iterator rend() const { return const_reverse_iterator(data_); } + const_reverse_iterator crbegin() const { return const_reverse_iterator(data_ + static_size); } + const_reverse_iterator crend() const { return const_reverse_iterator(data_); } + + pointer data() { return data_; } + const_pointer data() const { return data_; } + + reference front() { return data_[0]; } + reference back() { return data_[static_size-1]; } + constexpr const_reference front() const { return data_[0]; } + constexpr const_reference back() const { return data_[static_size-1]; } + + constexpr bool empty() const { return static_size == 0; } + constexpr ArrayIndex size() const { return static_size; } + constexpr ArrayIndex max_size() const { return static_size; } + constexpr index_type shape() const { return index_type{ N... }; } + constexpr ArrayIndex ndim() const { return static_ndim; } + + TinyArrayBase & reverse() + { + ArrayIndex i=0, j=size()-1; + while(i < j) + xt::swap(data_[i++], data_[j--]); + return *this; + } + + void swap(TinyArrayBase & other) + { + for(int k=0; k + void swap(TinyArrayBase & other) + { + for(int k=0; k t = data_[k]; + data_[k] = static_cast(other[k]); + other[k] = static_cast(t); + } + } + + /// factory function for fixed-size unit matrix + template + static inline + TinyArray + eye() + { + TinyArray res; + for(int k=0; k + static inline + TinyArray + unitVector(ArrayIndex k) + { + TinyArray res; + res(k) = 1; + return res; + } + + /// factory function for the k-th unit vector + // (for compatibility with TinyArray<..., runtime_size>) + static inline + TinyArray + unitVector(tags::SizeProxy const & size, ArrayIndex k) + { + XTENSOR_ASSERT_MSG(size.value == static_size, + "TinyArray::unitVector(): size mismatch."); + TinyArray res; + res(k) = 1; + return res; + } + + /// factory function for fixed-size linear sequence starting at start with stepsize step + static inline + TinyArray + linearSequence(value_type start = value_type(), value_type step = value_type(1)) + { + TinyArray res; + for(int k=0; k < static_size; ++k, start += step) + res[k] = start; + return res; + } + + /// factory function for fixed-size linear sequence ending at end-1 + static inline + TinyArray + range(value_type end) + { + value_type start = end - static_size; + TinyArray res; + for(int k=0; k < static_size; ++k, ++start) + res[k] = start; + return res; + } + + protected: + data_array_type data_; +}; + +/********************************************************/ +/* */ +/* TinyArrayBase output */ +/* */ +/********************************************************/ + +template +std::ostream & operator<<(std::ostream & o, TinyArrayBase const & v) +{ + o << "{"; + if(v.size() > 0) + o << PromoteType(v[0]); + for(int i=1; i < v.size(); ++i) + o << ", " << PromoteType(v[i]); + o << "}"; + return o; +} + +template +std::ostream & operator<<(std::ostream & o, TinyArrayBase const & v) +{ + o << "{"; + for(int i=0; N2>0 && i 0) + o << ",\n "; + o << PromoteType(v(i,0)); + for(int j=1; j(v(i, j)); + } + } + o << "}"; + return o; +} + +/********************************************************/ +/* */ +/* TinyArrayBase<..., runtime_size> */ +/* */ +/********************************************************/ + +/** \brief Specialization of TinyArrayBase for dynamic arrays. + + This class contains functionality shared by + \ref TinyArray and \ref TinyArrayView, and enables these classes + to be freely mixed within expressions. It is typically not used directly. + + \#include \
+ Namespace: vigra +**/ +template +class TinyArrayBase +: public TinyArrayTag +{ + public: + + template + using AsType = TinyArray; + + using value_type = VALUETYPE; + using const_value_type = typename std::add_const::type; + using reference = value_type &; + using const_reference = const_value_type &; + using pointer = value_type *; + using const_pointer = const_value_type *; + using iterator = value_type *; + using const_iterator = const_value_type *; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using index_type = ArrayIndex; + + static const ArrayIndex static_size = runtime_size; + static const ArrayIndex static_ndim = 1; + static const bool may_use_uninitialized_memory = + UninitializedMemoryTraits::value; + + protected: + + template + void initImpl(VALUETYPE v1, V2... v2) + { + data_[LEVEL] = v1; + initImpl(v2...); + } + + template + void initImpl(VALUETYPE v1) + { + data_[LEVEL] = v1; + } + + public: + + TinyArrayBase(ArrayIndex size=0, pointer data=0) + : size_(size) + , data_(data) + {} + + TinyArrayBase(TinyArrayBase const &) = default; + + // assignment + + TinyArrayBase & operator=(value_type v) + { + for(int i=0; i + TinyArrayBase & operator=(TinyArrayBase const & other) + { + xtensor_precondition(size_ == other.size(), + "TinyArrayBase::operator=(): size mismatch."); + for(int i=0; i(other[i]); + return *this; + } + + template + bool + sameShape(TinyArrayBase const & other) const + { + return sizeof...(M) == 1 && size() == other.size();; + } + + template + bool + sameShape(TinyArrayBase const & other) const + { + return size() == other.size(); + } + + DERIVED & init(value_type v = value_type()) + { + for(int i=0; i(*this); + } + + template + DERIVED & init(value_type v0, value_type v1, V... v) + { + xtensor_precondition(sizeof...(V)+2 == size_, + "TinyArrayBase::init(): wrong number of arguments."); + initImpl<0>(v0, v1, v...); + return static_cast(*this); + } + + template + DERIVED & init(Iterator first, Iterator end) + { + ArrayIndex range = std::distance(first, end); + if(size_ < range) + range = size_; + for(ArrayIndex i=0; i(*first); + return static_cast(*this); + } + + template + DERIVED & init(std::initializer_list l) + { + return init(l.begin(), l.end()); + } + + // index access + + reference operator[](ArrayIndex i) + { + return data_[i]; + } + + constexpr const_reference operator[](ArrayIndex i) const + { + return data_[i]; + } + + reference at(ArrayIndex i) + { + if(i < 0 || i >= size_) + throw std::out_of_range("TinyArrayBase::at()"); + return data_[i]; + } + + const_reference at(ArrayIndex i) const + { + if(i < 0 || i >= size_) + throw std::out_of_range("TinyArrayBase::at()"); + return data_[i]; + } + + /** Get a view to the subarray with length (TO-FROM) starting at FROM. + The bounds must fullfill 0 <= FROM < TO <= size_. + */ + template + TinyArrayView + subarray() const + { + static_assert(FROM >= 0 && FROM < TO, + "TinyArrayBase::subarray(): range out of bounds."); + xtensor_precondition(TO <= size_, + "TinyArrayBase::subarray(): range out of bounds."); + return TinyArrayView(data_+FROM); + } + + /** Get a view to the subarray with length (TO-FROM) starting at FROM. + The bounds must fullfill 0 <= FROM < TO <= size_. + */ + TinyArrayView + subarray(ArrayIndex FROM, ArrayIndex TO) const + { + xtensor_precondition(FROM >= 0 && FROM < TO && TO <= size_, + "TinyArrayBase::subarray(): range out of bounds."); + return TinyArrayView(TO-FROM, const_cast(data_)+FROM); + } + + + TinyArray + erase(ArrayIndex m) const + { + xtensor_precondition(m >= 0 && m < size(), "TinyArray::erase(): " + "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); + TinyArray res(size()-1, DontInit); + for(int k=0; k + pop_front() const + { + return erase(0); + } + + TinyArray + pop_back() const + { + return erase(size()-1); + } + + TinyArray + insert(ArrayIndex m, value_type v) const + { + xtensor_precondition(m >= 0 && m <= size(), "TinyArray::insert(): " + "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); + TinyArray res(size()+1, DontInit); + for(int k=0; k + inline + TinyArray + transpose(TinyArrayBase const & permutation) const + { + xtensor_precondition(size() == 0 || size() == permutation.size(), + "TinyArray::transpose(): size mismatch."); + TinyArray res(size(), DontInit); + for(ArrayIndex k=0; k < size(); ++k) + { + XTENSOR_ASSERT_MSG(permutation[k] >= 0 && permutation[k] < size(), + "transpose(): Permutation index out of bounds"); + res[k] = (*this)[permutation[k]]; + } + return res; + } + + // boiler plate + + iterator begin() { return data_; } + iterator end() { return data_ + size_; } + const_iterator begin() const { return data_; } + const_iterator end() const { return data_ + size_; } + const_iterator cbegin() const { return data_; } + const_iterator cend() const { return data_ + size_; } + + reverse_iterator rbegin() { return reverse_iterator(data_ + size_); } + reverse_iterator rend() { return reverse_iterator(data_); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(data_ + size_); } + const_reverse_iterator rend() const { return const_reverse_iterator(data_); } + const_reverse_iterator crbegin() const { return const_reverse_iterator(data_ + size_); } + const_reverse_iterator crend() const { return const_reverse_iterator(data_); } + + pointer data() { return data_; } + const_pointer data() const { return data_; } + + reference front() { return data_[0]; } + reference back() { return data_[size_-1]; } + const_reference front() const { return data_[0]; } + const_reference back() const { return data_[size_-1]; } + + bool empty() const { return size_ == 0; } + ArrayIndex size() const { return size_; } + ArrayIndex max_size() const { return size_; } + ArrayIndex ndim() const { return static_ndim; } + + TinyArrayBase & reverse() + { + ArrayIndex i=0, j=size_-1; + while(i < j) + xt::swap(data_[i++], data_[j--]); + return *this; + } + + void swap(TinyArrayBase & other) + { + xt::swap(size_, other.size_); + xt::swap(data_, other.data_); + } + + /// factory function for the fixed-size k-th unit vector + static inline + TinyArray + unitVector(tags::SizeProxy const & size, ArrayIndex k) + { + TinyArray res(size.value); + res[k] = 1; + return res; + } + + /// factory function for a linear sequence from begin to end + /// (exclusive) with stepsize step + static inline + TinyArray + range(value_type begin, + value_type end, + value_type step = value_type(1)) + { + xtensor_precondition(step != 0, + "TinyArray::range(): step must be non-zero."); + xtensor_precondition((step > 0 && begin <= end) || (step < 0 && begin >= end), + "TinyArray::range(): sign mismatch between step and (end-begin)."); + ArrayIndex size = mathfunctions::floor((abs(end-begin+step)-1)/abs(step)); + TinyArray res(size, DontInit); + for(ArrayIndex k=0; k < size; ++k, begin += step) + res[k] = begin; + return res; + } + + /// factory function for a linear sequence from 0 to end + /// (exclusive) with stepsize 1 + static inline + TinyArray + range(value_type end) + { + xtensor_precondition(end >= 0, + "TinyArray::range(): end must be non-negative."); + TinyArray res(end, DontInit); + auto begin = value_type(); + for(ArrayIndex k=0; k < res.size(); ++k, ++begin) + res[k] = begin; + return res; + } + + protected: + ArrayIndex size_; + pointer data_; +}; + +/********************************************************/ +/* */ +/* TinyArray */ +/* */ +/********************************************************/ + +/** \brief Class for fixed size arrays. + \ingroup RangesAndPoints + + This class contains an array of the specified VALUETYPE with + (possibly multi-dimensional) shape given by the sequence ArrayIndex ... N. + The interface conforms to STL vector, except that there are no functions + that change the size of a TinyArray. + + \ref TinyArrayOperators "Arithmetic operations" + on TinyArrays are defined as component-wise applications of these + operations. + + See also:
+

    +
  • \ref vigra::TinyArrayBase +
  • \ref vigra::TinyArrayView +
  • \ref TinyArrayOperators +
+ + \#include \
+ Namespace: vigra +**/ +template +class TinyArray +: public TinyArrayBase, M, N...> +{ + public: + using base_type = TinyArrayBase, M, N...>; + + typedef typename base_type::value_type value_type; + static const ArrayIndex static_ndim = base_type::static_ndim; + static const ArrayIndex static_size = base_type::static_size; + + explicit constexpr + TinyArray(value_type const & v = value_type()) + : base_type(v) + {} + + template + constexpr TinyArray(value_type v0, value_type v1, V... v) + : base_type(v0, v1, v...) + {} + + explicit + TinyArray(SkipInitialization) + : base_type(DontInit) + {} + + // /** Construction from lemon::Invalid. + // Initializes all vector elements with -1. + // */ + // constexpr TinyArray(lemon::Invalid const &) + // : base_type(-1) + // {} + + // for compatibility with TinyArray + explicit + TinyArray(tags::SizeProxy const & size, + value_type const & v = value_type()) + : base_type(v) + { + XTENSOR_ASSERT_MSG(size.value == static_size, + "TinyArray(size): size argument conflicts with array length."); + } + + // for compatibility with TinyArray + TinyArray(tags::SizeProxy const & size, SkipInitialization) + : base_type(DontInit) + { + XTENSOR_ASSERT_MSG(size.value == static_size, + "TinyArray(size): size argument conflicts with array length."); + } + + // for compatibility with TinyArray + TinyArray(ArrayIndex size, SkipInitialization) + : base_type(DontInit) + { + XTENSOR_ASSERT_MSG(size == static_size, + "TinyArray(size): size argument conflicts with array length."); + } + + constexpr TinyArray(TinyArray const &) = default; + + template + TinyArray(TinyArrayBase const & other) + : base_type(other) + {} + + template + TinyArray(TinyArrayBase const & other) + : base_type(DontInit) + { + if(other.size() == 0) + { + this->init(value_type()); + } + else if(this->size() != 0) + { + xtensor_precondition(this->size() == other.size(), + "TinyArray(): shape mismatch."); + this->init(other.begin(), other.end()); + } + } + + constexpr TinyArray(value_type const (&v)[static_ndim]) + : base_type(v) + {} + + template ::value> > + explicit TinyArray(U u, U end = U()) + : base_type(u) + {} + + template ::value> > + TinyArray(U u, ReverseCopyTag) + : base_type(u, ReverseCopy) + {} + + // for compatibility with TinyArray<..., runtime_size> + template ::value> > + TinyArray(U u, U end, ReverseCopyTag) + : base_type(u, ReverseCopy) + {} + + TinyArray & operator=(TinyArray const &) = default; + + TinyArray & operator=(value_type v) + { + base_type::operator=(v); + return *this; + } + + TinyArray & operator=(value_type const (&v)[static_size]) + { + base_type::operator=(v); + return *this; + } + + template + TinyArray & operator=(TinyArrayBase const & other) + { + base_type::operator=(other); + return *this; + } + + constexpr bool empty() const { return static_size == 0; } + constexpr ArrayIndex size() const { return static_size; } + constexpr ArrayIndex max_size() const { return static_size; } + constexpr typename base_type::index_type shape() const { return typename base_type::index_type{ M, N... }; } + constexpr ArrayIndex ndim() const { return static_ndim; } +}; + +template +struct UninitializedMemoryTraits> +{ + static const bool value = UninitializedMemoryTraits::value; +}; + +/********************************************************/ +/* */ +/* TinyArray<..., runtime_size> */ +/* */ +/********************************************************/ + +/** \brief Specialization of TinyArray for dynamic arrays. + \ingroup RangesAndPoints + + This class contains an array of the specified VALUETYPE with + size specified at runtim. + The interface conforms to STL vector, except that there are no functions + that change the size of a TinyArray. + + \ref TinyArrayOperators "Arithmetic operations" + on TinyArrays are defined as component-wise applications of these + operations. + + See also:
+
    +
  • \ref vigra::TinyArrayBase +
  • \ref vigra::TinyArrayView +
  • \ref TinyArrayOperators +
+ + \#include \
+ Namespace: vigra +**/ +template +class TinyArray +: public TinyArrayBase, runtime_size> +{ + public: + using base_type = TinyArrayBase, runtime_size>; + + using value_type = VALUETYPE; + + TinyArray() + : base_type() + {} + + explicit + TinyArray(ArrayIndex size, + value_type const & initial = value_type()) + : base_type(size) + { + this->data_ = alloc_.allocate(this->size_); + std::uninitialized_fill(this->begin(), this->end(), initial); + } + + explicit + TinyArray(tags::SizeProxy const & size, + value_type const & initial = value_type()) + : TinyArray(size.value, initial) + {} + + TinyArray(ArrayIndex size, SkipInitialization) + : base_type(size) + { + this->data_ = alloc_.allocate(this->size_); + if(!base_type::may_use_uninitialized_memory) + std::uninitialized_fill(this->begin(), this->end(), value_type()); + } + + // TinyArray(lemon::Invalid const &) + // : base_type() + // {} + + // TinyArray(ArrayIndex size, lemon::Invalid const &) + // : TinyArray(size, value_type(-1)) + // {} + + TinyArray(TinyArray const & rhs ) + : base_type(rhs.size()) + { + this->data_ = alloc_.allocate(this->size_); + std::uninitialized_copy(rhs.begin(), rhs.end(), this->begin()); + } + + TinyArray(TinyArray && rhs) + : base_type() + { + this->swap(rhs); + } + + template + TinyArray(TinyArrayBase const & other) + : TinyArray(other.begin(), other.end()) + {} + + template ::value> > + TinyArray(U begin, U end) + : base_type(std::distance(begin, end)) + { + this->data_ = alloc_.allocate(this->size_); + for(int i=0; isize_; ++i, ++begin) + new(this->data_+i) value_type(static_cast(*begin)); + } + + template ::value> > + TinyArray(U begin, U end, ReverseCopyTag) + : base_type(std::distance(begin, end)) + { + this->data_ = alloc_.allocate(this->size_); + for(int i=0; isize_; ++i, --end) + new(this->data_+i) value_type(static_cast(*(end-1))); + } + + template + TinyArray(std::initializer_list rhs) + : TinyArray(rhs.begin(), rhs.end()) + {} + + TinyArray & operator=(value_type const & v) + { + base_type::operator=(v); + return *this; + } + + TinyArray & operator=(TinyArray && rhs) + { + if(this->size_ != rhs.size()) + rhs.swap(*this); + else + base_type::operator=(rhs); + return *this; + } + + TinyArray & operator=(TinyArray const & rhs) + { + if(this == &rhs) + return *this; + if(this->size_ != rhs.size()) + TinyArray(rhs).swap(*this); + else + base_type::operator=(rhs); + return *this; + } + + template + TinyArray & operator=(TinyArrayBase const & rhs) + { + if(this->size_ == 0 || rhs.size() == 0) + TinyArray(rhs).swap(*this); + else + base_type::operator=(rhs); + return *this; + } + + ~TinyArray() + { + if(!base_type::may_use_uninitialized_memory) + { + for(ArrayIndex i=0; isize_; ++i) + (this->data_+i)->~value_type(); + } + alloc_.deallocate(this->data_, this->size_); + } + +#if 0 + // FIXME: hacks to use TinyArray as shape in xtensor + using base_type::erase; + + void erase(base_type::pointer p) + { + --this->size_; + for(; p < this->data_ + this->size_; ++p) + *p = p[1]; + } + + void resize(size_t s) + { + if(s > this->size_) + { + alloc_.deallocate(this->data_, this->size_); + this->data_ = alloc_.allocate(s); + } + this->size_ = s; + } + + template + TinyArray(std::vector const & rhs) + : TinyArray(rhs.cbegin(), rhs.cend()) + {} + + template + TinyArray & operator=(std::vector const & rhs) + { + resize(rhs.size()); + for(int k=0; k < this->size_; ++k) + this->data_[k] = rhs[k]; + return *this; + } + + template + bool operator==(std::vector const & rhs) const + { + if(this->size_ != (int)rhs.size()) + return false; + for(int k=0; k < this->size_; ++k) + if(this->data_[k] != rhs[k]) + return false; + return true; + } +#endif + + private: + // FIXME: implement an optimized allocator + // FIXME: (look at Alexandrescu's Loki library or Kolmogorov's code) + std::allocator alloc_; +}; + + +template +bool operator==(std::vector const & l, TinyArray const & r) +{ + if((int)l.size() != r.size()) + return false; + for(int k=0; k < (int)l.size(); ++k) + if(l[k] != r[k]) + return false; + return true; +} + + +template +struct UninitializedMemoryTraits> +{ + static const bool value = false; +}; + + + +/********************************************************/ +/* */ +/* TinyArrayView */ +/* */ +/********************************************************/ + +/** \brief Wrapper for fixed size arrays. + + This class wraps the memory of an array of the specified VALUETYPE + with (possibly multi-dimensional) shape given by ArrayIndex....N. + Thus, the array can be accessed with an interface similar to + that of std::vector (except that there are no functions + that change the size of a TinyArrayView). The TinyArrayView + does not assume ownership of the given memory. + + \ref TinyArrayOperators "Arithmetic operations" + on TinyArrayViews are defined as component-wise applications of these + operations. + + See also: +
    +
  • \ref vigra::TinyArrayBase +
  • \ref vigra::TinyArray +
  • \ref vigra::TinySymmetricView +
  • \ref TinyArrayOperators +
+ + \#include \
+ Namespace: vigra +**/ +template +class TinyArrayView +: public TinyArrayBase, M, N...> +{ + public: + using base_type = TinyArrayBase, M, N...>; + + typedef typename base_type::value_type value_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + static const ArrayIndex static_size = base_type::static_size; + static const ArrayIndex static_ndim = base_type::static_ndim; + + TinyArrayView() + : base_type(DontInit) + { + base_type::data_ = nullptr; + } + + /** Construct view for given data array + */ + TinyArrayView(const_pointer data) + : base_type(DontInit) + { + base_type::data_ = const_cast(data); + } + + /** Copy constructor (shallow copy). + */ + TinyArrayView(TinyArrayView const & other) + : base_type(DontInit) + { + base_type::data_ = const_cast(other.data()); + } + + /** Construct view from other TinyArray. + */ + template + TinyArrayView(TinyArrayBase const & other) + : base_type(DontInit) + { + base_type::data_ = const_cast(other.data()); + } + + /** Reset to the other array's pointer. + */ + template + void reset(TinyArrayBase const & other) + { + base_type::data_ = const_cast(other.data()); + } + + /** Copy the data (not the pointer) of the rhs. + */ + TinyArrayView & operator=(TinyArrayView const & r) + { + for(int k=0; k(r[k]); + return *this; + } + + /** Copy the data of the rhs with cast. + */ + template + TinyArrayView & operator=(TinyArrayBase const & r) + { + for(int k=0; k(r[k]); + return *this; + } + + constexpr bool empty() const { return static_size == 0; } + constexpr ArrayIndex size() const { return static_size; } + constexpr ArrayIndex max_size() const { return static_size; } + constexpr typename base_type::index_type shape() const { return typename base_type::index_type{ M, N... }; } + constexpr ArrayIndex ndim() const { return static_ndim; } +}; + +template +class TinyArrayView +: public TinyArrayBase, runtime_size> +{ + public: + using base_type = TinyArrayBase, runtime_size>; + + using base_type::base_type; + using base_type::operator=; +}; + +/********************************************************/ +/* */ +/* TinyArraySymmetricView */ +/* */ +/********************************************************/ + +/** \brief Wrapper for fixed size arrays. + + This class wraps the memory of an 1D array of the specified VALUETYPE + with size N*(N+1)/2 and interprets this array as a symmetric + matrix. Specifically, the data are interpreted as the row-wise + representation of the upper triangular part of the symmetric matrix. + All index access operations are overloaded such that the view appears + as if it were a full matrix. The TinySymmetricView + does not assume ownership of the given memory. + + \ref TinyArrayOperators "Arithmetic operations" + on TinySymmetricView are defined as component-wise applications of these + operations. + + See also: +
    +
  • \ref vigra::TinyArrayBase +
  • \ref vigra::TinyArray +
  • \ref vigra::TinyArrayView +
  • \ref TinyArrayOperators +
+ + \#include \
+ Namespace: vigra +**/ +template +class TinySymmetricView +: public TinyArrayBase, N*(N+1)/2> +{ + public: + using base_type = TinyArrayBase, N*(N+1)/2>; + + typedef typename base_type::value_type value_type; + typedef typename base_type::pointer pointer; + typedef typename base_type::const_pointer const_pointer; + typedef typename base_type::reference reference; + typedef typename base_type::const_reference const_reference; + using index_type = TinyArray; + + static const ArrayIndex static_size = base_type::static_size; + static const ArrayIndex static_ndim = 2; + + TinySymmetricView() + : base_type(DontInit) + { + base_type::data_ = nullptr; + } + + /** Construct view for given data array + */ + TinySymmetricView(const_pointer data) + : base_type(DontInit) + { + base_type::data_ = const_cast(data); + } + + /** Copy constructor (shallow copy). + */ + TinySymmetricView(TinySymmetricView const & other) + : base_type(DontInit) + { + base_type::data_ = const_cast(other.data()); + } + + /** Construct view from other TinyArray. + */ + template + TinySymmetricView(TinyArrayBase const & other) + : base_type(DontInit) + { + base_type::data_ = const_cast(other.data()); + } + + /** Reset to the other array's pointer. + */ + template + void reset(TinyArrayBase const & other) + { + base_type::data_ = const_cast(other.data()); + } + + /** Copy the data (not the pointer) of the rhs. + */ + TinySymmetricView & operator=(TinySymmetricView const & r) + { + for(int k=0; k(r[k]); + return *this; + } + + /** Copy the data of the rhs with cast. + */ + template + TinySymmetricView & operator=(TinyArrayBase const & r) + { + for(int k=0; k(r[k]); + return *this; + } + + // index access + + reference operator[](ArrayIndex i) + { + return base_type::operator[](i); + } + + constexpr const_reference operator[](ArrayIndex i) const + { + return base_type::operator[](i); + } + + reference at(ArrayIndex i) + { + return base_type::at(i); + } + + const_reference at(ArrayIndex i) const + { + return base_type::at(i); + } + + reference operator[](ArrayIndex const (&i)[2]) + { + return this->operator()(i[0], i[1]); + } + + constexpr const_reference operator[](ArrayIndex const (&i)[2]) const + { + return this->operator()(i[0], i[1]); + } + + reference at(ArrayIndex const (&i)[static_ndim]) + { + return this->at(i[0], i[1]); + } + + const_reference at(ArrayIndex const (&i)[static_ndim]) const + { + return this->at(i[0], i[1]); + } + + reference operator[](index_type const & i) + { + return this->operator()(i[0], i[1]); + } + + constexpr const_reference operator[](index_type const & i) const + { + return this->operator()(i[0], i[1]); + } + + reference at(index_type const & i) + { + return this->at(i[0], i[1]); + } + + const_reference at(index_type const & i) const + { + return this->at(i[0], i[1]); + } + + reference operator()(ArrayIndex i, ArrayIndex j) + { + return (i > j) + ? base_type::data_[i + N*j - (j*(j+1) >> 1)] + : base_type::data_[N*i + j - (i*(i+1) >> 1)]; + } + + constexpr const_reference operator()(ArrayIndex const i, ArrayIndex const j) const + { + return (i > j) + ? base_type::data_[i + (j*((2 * N - 1) - j) >> 1)] + : base_type::data_[j + (i*((2 * N - 1) - i) >> 1)]; + } + + reference at(ArrayIndex i, ArrayIndex j) + { + ArrayIndex k = (i > j) + ? i + (j*((2*N-1) - j) >> 1) + : j + (i*((2*N-1) - i) >> 1); + if(k < 0 || k >= static_size) + throw std::out_of_range("TinySymmetricView::at()"); + return base_type::data_[k]; + } + + const_reference at(ArrayIndex i, ArrayIndex j) const + { + ArrayIndex k = (i > j) + ? i + N*j - (j*(j+1) >> 1) + : N*i + j - (i*(i+1) >> 1); + if(k < 0 || k >= static_size) + throw std::out_of_range("TinySymmetricView::at()"); + return base_type::data_[k]; + } + + constexpr index_type shape() const { return index_type(N, N); } + constexpr ArrayIndex ndim () const { return static_ndim; } +}; + +/********************************************************/ +/* */ +/* TinyArraySymmetricView output */ +/* */ +/********************************************************/ + +template +std::ostream & operator<<(std::ostream & o, TinySymmetricView const & v) +{ + o << "{"; + for(int i=0; i 0) + o << ",\n "; + o << PromoteType(v(i,0)); + for(int j=1; j(v(i, j)); + } + } + o << "}"; + return o; +} + + +/********************************************************/ +/* */ +/* TinyArray Comparison */ +/* */ +/********************************************************/ + +/** \addtogroup TinyArrayOperators Functions for TinyArray + + \brief Implement basic arithmetic and equality for TinyArray. + + These functions fulfill the requirements of a Linear Space (vector space). + Return types are determined according to \ref PromoteType or \ref RealPromoteType. + + \#include \
+ Namespace: vigra +*/ +//@{ + + /// element-wise equal +template +inline bool +operator==(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + if(!l.sameShape(r)) + return false; + for(int k=0; k < l.size(); ++k) + if(l[k] != r[k]) + return false; + return true; +} + + /// element-wise equal to a constant +template ::value && + std::is_convertible::value> > +inline bool +operator==(TinyArrayBase const & l, + V2 const & r) +{ + for(int k=0; k < l.size(); ++k) + if(l[k] != r) + return false; + return true; +} + + /// element-wise equal to a constant +template ::value && + std::is_convertible::value> > +inline bool +operator==(V1 const & l, + TinyArrayBase const & r) +{ + for(int k=0; k < r.size(); ++k) + if(l != r[k]) + return false; + return true; +} + + /// element-wise not equal +template +inline bool +operator!=(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + if(!l.sameShape(r)) + return true; + for(int k=0; k < l.size(); ++k) + if(l[k] != r[k]) + return true; + return false; +} + + /// element-wise not equal to a constant +template ::value && + std::is_convertible::value> > +inline bool +operator!=(TinyArrayBase const & l, + V2 const & r) +{ + for(int k=0; k < l.size(); ++k) + if(l[k] != r) + return true; + return false; +} + + /// element-wise not equal to a constant +template ::value && + std::is_convertible::value> > +inline bool +operator!=(V1 const & l, + TinyArrayBase const & r) +{ + for(int k=0; k < r.size(); ++k) + if(l != r[k]) + return true; + return false; +} + + /// lexicographical comparison +template +inline bool +operator<(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "TinyArrayBase::operator<(): size mismatch."); + for(int k=0; k < l.size(); ++k) + { + if(l[k] < r[k]) + return true; + if(r[k] < l[k]) + return false; + } + return false; +} + + /// lexicographical comparison +template +inline bool +operator<(TinyArrayBase const & l, + std::vector const & r) +{ + ArrayIndex size = r.size(); + bool equal_res = false; + if(l.size() < size) + { + size = l.size(); + equal_res = true; + } + for(int k=0; k < size; ++k) + { + if(l[k] < r[k]) + return true; + if(r[k] < l[k]) + return false; + } + return equal_res; +} + +template +inline bool +operator<(std::vector const & l, + TinyArrayBase const & r) +{ + ArrayIndex size = r.size(); + bool equal_res = false; + if(l.size() < size) + { + size = l.size(); + equal_res = true; + } + for(int k=0; k < size; ++k) + { + if(l[k] < r[k]) + return true; + if(r[k] < l[k]) + return false; + } + return equal_res; +} + +template +inline bool +operator>(TinyArrayBase const & l, + std::vector const & r) +{ + return r < l; +} + +template +inline bool +operator>(std::vector const & l, + TinyArrayBase const & r) +{ + return r < l; +} + + /// check if all elements are non-zero (or 'true' if V is bool) +template +inline bool +all(TinyArrayBase const & t) +{ + for(int i=0; i +inline bool +any(TinyArrayBase const & t) +{ + for(int i=0; i +inline bool +allZero(TinyArrayBase const & t) +{ + for(int i=0; i +inline bool +allLess(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "TinyArrayBase::allLess(): size mismatch."); + for(int k=0; k < l.size(); ++k) + if (l[k] >= r[k]) + return false; + return true; +} + + /// pointwise less than a constant + /// (typically used to check negativity with `r = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allLess(TinyArrayBase const & l, + V2 const & r) +{ + for(int k=0; k < l.size(); ++k) + if (l[k] >= r) + return false; + return true; +} + + /// constant pointwise less than the vector + /// (typically used to check positivity with `l = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allLess(V1 const & l, + TinyArrayBase const & r) +{ + for(int k=0; k < r.size(); ++k) + if (l >= r[k]) + return false; + return true; +} + + /// pointwise less-equal +template +inline bool +allLessEqual(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "TinyArrayBase::allLessEqual(): size mismatch."); + for(int k=0; k < l.size(); ++k) + if (l[k] > r[k]) + return false; + return true; +} + + /// pointwise less-equal with a constant + /// (typically used to check non-positivity with `r = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allLessEqual(TinyArrayBase const & l, + V2 const & r) +{ + for(int k=0; k < l.size(); ++k) + if (l[k] > r) + return false; + return true; +} + + /// pointwise less-equal with a constant + /// (typically used to check non-negativity with `l = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allLessEqual(V1 const & l, + TinyArrayBase const & r) +{ + for(int k=0; k < r.size(); ++k) + if (l > r[k]) + return false; + return true; +} + + /// pointwise greater-than +template +inline bool +allGreater(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "TinyArrayBase::allGreater(): size mismatch."); + for(int k=0; k < l.size(); ++k) + if (l[k] <= r[k]) + return false; + return true; +} + + /// pointwise greater-than with a constant + /// (typically used to check positivity with `r = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allGreater(TinyArrayBase const & l, + V2 const & r) +{ + for(int k=0; k < l.size(); ++k) + if (l[k] <= r) + return false; + return true; +} + + /// constant pointwise greater-than a vector + /// (typically used to check negativity with `l = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allGreater(V1 const & l, + TinyArrayBase const & r) +{ + for(int k=0; k < r.size(); ++k) + if (l <= r[k]) + return false; + return true; +} + + /// pointwise greater-equal +template +inline bool +allGreaterEqual(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "TinyArrayBase::allGreaterEqual(): size mismatch."); + for(int k=0; k < l.size(); ++k) + if (l[k] < r[k]) + return false; + return true; +} + + /// pointwise greater-equal with a constant + /// (typically used to check non-negativity with `r = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allGreaterEqual(TinyArrayBase const & l, + V2 const & r) +{ + for(int k=0; k < l.size(); ++k) + if (l[k] < r) + return false; + return true; +} + + /// pointwise greater-equal with a constant + /// (typically used to check non-positivity with `l = 0`) +template ::value && + std::is_convertible::value> > +inline bool +allGreaterEqual(V1 const & l, + TinyArrayBase const & r) +{ + for(int k=0; k < r.size(); ++k) + if (l < r[k]) + return false; + return true; +} + +template +inline bool +isclose(TinyArrayBase const & l, + TinyArrayBase const & r, + PromoteType epsilon = 2.0*std::numeric_limits >::epsilon()) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "TinyArrayBase::isclose(): size mismatch."); + for(int k=0; k < l.size(); ++k) + if(!mathfunctions::isclose(l[k], r[k], epsilon, epsilon)) + return false; + return true; +} + +// template +// inline bool +// operator==(TinyArrayBase const & l, + // lemon::Invalid const &) +// { + // for(int k=0; k < l.size(); ++k) + // if(l[k] != -1) + // return false; + // return true; +// } + +// template +// inline bool +// operator==(lemon::Invalid const &, + // TinyArrayBase const & r) +// { + // return r == lemon::INVALID; +// } + +// template +// inline bool +// operator!=(TinyArrayBase const & l, + // lemon::Invalid const &) +// { + // return !(l == lemon::INVALID); +// } + +// template +// inline bool +// operator!=(lemon::Invalid const &, + // TinyArrayBase const & r) +// { + // return !(r == lemon::INVALID); +// } + + + +/********************************************************/ +/* */ +/* TinyArray-Arithmetic */ +/* */ +/********************************************************/ + +/** \addtogroup TinyArrayOperators + */ +//@{ + +#ifdef DOXYGEN +// Declare arithmetic functions for documentation, +// the implementations are provided by a macro below. + + /// scalar add-assignment +template ::value> > +DERIVED & +operator+=(TinyArrayBase & l, + V2 r); + + /// element-wise add-assignment +template +DERIVED & +operator+=(TinyArrayBase & l, + TinyArrayBase const & r); + + /// element-wise addition +template +TinyArray, N...> +operator+(TinyArrayBase const & l, + TinyArrayBase const & r); + + /// element-wise scalar addition +template +TinyArray, N...> +operator+(TinyArrayBase const & l, + V2 r); + + /// element-wise left scalar addition +template +TinyArray, N...> +operator+(V1 l, + TinyArrayBase const & r); + + /// scalar subtract-assignment +template ::value> > +DERIVED & +operator-=(TinyArrayBase & l, + V2 r); + + /// element-wise subtract-assignment +template +DERIVED & +operator-=(TinyArrayBase & l, + TinyArrayBase const & r); + + /// element-wise subtraction +template +TinyArray, N...> +operator-(TinyArrayBase const & l, + TinyArrayBase const & r); + + /// element-wise scalar subtraction +template +TinyArray, N...> +operator-(TinyArrayBase const & l, + V2 r); + + /// element-wise left scalar subtraction +template +TinyArray, N...> +operator-(V1 l, + TinyArrayBase const & r); + + /// scalar multiply-assignment +template ::value> > +DERIVED & +operator*=(TinyArrayBase & l, + V2 r); + + /// element-wise multiply-assignment +template +DERIVED & +operator*=(TinyArrayBase & l, + TinyArrayBase const & r); + + /// element-wise multiplication +template +TinyArray, N...> +operator*(TinyArrayBase const & l, + TinyArrayBase const & r); + + /// element-wise scalar multiplication +template +TinyArray, N...> +operator*(TinyArrayBase const & l, + V2 r); + + /// element-wise left scalar multiplication +template +TinyArray, N...> +operator*(V1 l, + TinyArrayBase const & r); + + /// scalar divide-assignment +template ::value> > +DERIVED & +operator/=(TinyArrayBase & l, + V2 r); + + /// element-wise divide-assignment +template +DERIVED & +operator/=(TinyArrayBase & l, + TinyArrayBase const & r); + + /// element-wise division +template +TinyArray, N...> +operator/(TinyArrayBase const & l, + TinyArrayBase const & r); + + /// element-wise scalar division +template +TinyArray, N...> +operator/(TinyArrayBase const & l, + V2 r); + + /// element-wise left scalar division +template +TinyArray, N...> +operator/(V1 l, + TinyArrayBase const & r); + + /// scalar modulo-assignment +template ::value> > +DERIVED & +operator%=(TinyArrayBase & l, + V2 r); + + /// element-wise modulo-assignment +template +DERIVED & +operator%=(TinyArrayBase & l, + TinyArrayBase const & r); + + /// element-wise modulo +template +TinyArray, N...> +operator%(TinyArrayBase const & l, + TinyArrayBase const & r); + + /// element-wise scalar modulo +template +TinyArray, N...> +operator%(TinyArrayBase const & l, + V2 r); + + /// element-wise left scalar modulo +template +TinyArray, N...> +operator%(V1 l, + TinyArrayBase const & r); + +#else + +#define XTENSOR_TINYARRAY_OPERATORS(OP) \ +template ::value && \ + std::is_convertible::value> > \ +DERIVED & \ +operator OP##=(TinyArrayBase & l, \ + V2 r) \ +{ \ + for(int i=0; i(l); \ +} \ + \ +template \ +inline DERIVED & \ +operator OP##=(TinyArrayBase & l, \ + TinyArrayBase const & r) \ +{ \ + XTENSOR_ASSERT_MSG(l.size() == r.size(), \ + "TinyArrayBase::operator" #OP "=(): size mismatch."); \ + for(int i=0; i(l); \ +} \ +template \ +inline \ +TinyArray \ +operator OP(TinyArrayBase const & l, \ + TinyArrayBase const & r) \ +{ \ + TinyArray res(l); \ + return res OP##= r; \ +} \ + \ +template ::value> >\ +inline \ +TinyArray \ +operator OP(TinyArrayBase const & l, \ + V2 r) \ +{ \ + TinyArray res(l); \ + return res OP##= r; \ +} \ + \ +template ::value && \ + !std::is_base_of::value> >\ +inline \ +TinyArray \ +operator OP(V1 l, \ + TinyArrayBase const & r) \ +{ \ + TinyArray res(l); \ + return res OP##= r; \ +} \ + \ +template ::value && \ + !std::is_base_of::value> >\ +inline \ +TinyArray \ +operator OP(V1 l, \ + TinyArrayBase const & r) \ +{ \ + TinyArray res(tags::size=r.size(), l); \ + return res OP##= r; \ +} + +XTENSOR_TINYARRAY_OPERATORS(+) +XTENSOR_TINYARRAY_OPERATORS(-) +XTENSOR_TINYARRAY_OPERATORS(*) +XTENSOR_TINYARRAY_OPERATORS(/) +XTENSOR_TINYARRAY_OPERATORS(%) +XTENSOR_TINYARRAY_OPERATORS(&) +XTENSOR_TINYARRAY_OPERATORS(|) +XTENSOR_TINYARRAY_OPERATORS(^) +XTENSOR_TINYARRAY_OPERATORS(<<) +XTENSOR_TINYARRAY_OPERATORS(>>) + +#undef XTENSOR_TINYARRAY_OPERATORS + +#endif // DOXYGEN + +#define XTENSOR_TINYARRAY_UNARY_FUNCTION(FCT) \ +template \ +inline \ +TinyArray, N...> \ +FCT(TinyArrayBase const & v) \ +{ \ + TinyArray, N...> res(v.size(), DontInit); \ + for(int k=0; k < v.size(); ++k) \ + res[k] = mathfunctions::FCT(v[k]); \ + return res; \ +} + +XTENSOR_TINYARRAY_UNARY_FUNCTION(abs) +XTENSOR_TINYARRAY_UNARY_FUNCTION(fabs) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(cos) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sin) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tan) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sin_pi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(cos_pi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(acos) +XTENSOR_TINYARRAY_UNARY_FUNCTION(asin) +XTENSOR_TINYARRAY_UNARY_FUNCTION(atan) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(cosh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sinh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tanh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(acosh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(asinh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(atanh) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrt) +XTENSOR_TINYARRAY_UNARY_FUNCTION(cbrt) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrti) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sq) +XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseNorm) +XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseSquaredNorm) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(exp) +XTENSOR_TINYARRAY_UNARY_FUNCTION(exp2) +XTENSOR_TINYARRAY_UNARY_FUNCTION(expm1) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log2) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log10) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log1p) +XTENSOR_TINYARRAY_UNARY_FUNCTION(logb) +XTENSOR_TINYARRAY_UNARY_FUNCTION(ilogb) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(ceil) +XTENSOR_TINYARRAY_UNARY_FUNCTION(floor) +XTENSOR_TINYARRAY_UNARY_FUNCTION(trunc) +XTENSOR_TINYARRAY_UNARY_FUNCTION(round) +XTENSOR_TINYARRAY_UNARY_FUNCTION(lround) +XTENSOR_TINYARRAY_UNARY_FUNCTION(llround) +XTENSOR_TINYARRAY_UNARY_FUNCTION(roundi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(even) +XTENSOR_TINYARRAY_UNARY_FUNCTION(odd) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sign) +XTENSOR_TINYARRAY_UNARY_FUNCTION(signi) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(erf) +XTENSOR_TINYARRAY_UNARY_FUNCTION(erfc) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tgamma) +XTENSOR_TINYARRAY_UNARY_FUNCTION(lgamma) +XTENSOR_TINYARRAY_UNARY_FUNCTION(loggamma) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(conj) +XTENSOR_TINYARRAY_UNARY_FUNCTION(real) +XTENSOR_TINYARRAY_UNARY_FUNCTION(imag) +XTENSOR_TINYARRAY_UNARY_FUNCTION(arg) + +#undef XTENSOR_TINYARRAY_UNARY_FUNCTION + + /// Arithmetic negation +template +inline +TinyArray +operator-(TinyArrayBase const & v) +{ + TinyArray res(v.size(), DontInit); + for(int k=0; k < v.size(); ++k) + res[k] = -v[k]; + return res; +} + + /// Boolean negation +template +inline +TinyArray +operator!(TinyArrayBase const & v) +{ + TinyArray res(v.size(), DontInit); + for(int k=0; k < v.size(); ++k) + res[k] = !v[k]; + return res; +} + + /// Bitwise negation +template +inline +TinyArray +operator~(TinyArrayBase const & v) +{ + TinyArray res(v.size(), DontInit); + for(int k=0; k < v.size(); ++k) + res[k] = ~v[k]; + return res; +} + +#define XTENSOR_TINYARRAY_BINARY_FUNCTION(FCT) \ +template \ +inline \ +TinyArray \ +FCT(TinyArrayBase const & l, \ + TinyArrayBase const & r) \ +{ \ + XTENSOR_ASSERT_MSG(l.size() == r.size(), #FCT "(TinyArray, TinyArray): size mismatch."); \ + TinyArray res(l.size(), DontInit); \ + for(int k=0; k < l.size(); ++k) \ + res[k] = mathfunctions::FCT(l[k], r[k]); \ + return res; \ +} + +XTENSOR_TINYARRAY_BINARY_FUNCTION(atan2) +XTENSOR_TINYARRAY_BINARY_FUNCTION(copysign) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fdim) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmax) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmin) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmod) +XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot) + +#undef XTENSOR_TINYARRAY_BINARY_FUNCTION + + /** Apply pow() function to each vector component. + */ +template +inline auto +pow(TinyArrayBase const & v, E exponent) -> + TinyArray +{ + TinyArray res(v.size(), DontInit); + for(int k=0; k < v.size(); ++k) + res[k] = mathfunctions::pow(v[k], exponent); + return res; +} + + /// cross product +template > +inline +TinyArray, N> +cross(TinyArrayBase const & r1, + TinyArrayBase const & r2) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N, r1.size() == 3 && r2.size() == 3, + "cross(): cross product requires size() == 3."); + typedef TinyArray, N> Res; + return Res{r1[1]*r2[2] - r1[2]*r2[1], + r1[2]*r2[0] - r1[0]*r2[2], + r1[0]*r2[1] - r1[1]*r2[0]}; +} + + /// dot product of two vectors +template +inline +PromoteType +dot(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_MSG(l.size() == r.size(), "dot(): size mismatch."); + PromoteType res = PromoteType(); + for(int k=0; k < l.size(); ++k) + res += l[k] * r[k]; + return res; +} + + /// sum of the vector's elements +template +inline +PromoteType +sum(TinyArrayBase const & l) +{ + PromoteType res = PromoteType(); + for(int k=0; k < l.size(); ++k) + res += l[k]; + return res; +} + + /// mean of the vector's elements +template +inline RealPromoteType +mean(TinyArrayBase const & t) +{ + using Promote = RealPromoteType; + const Promote sumVal = static_cast(sum(t)); + if(t.size() > 0) + return sumVal / t.size(); + else + return sumVal; +} + + /// cumulative sum of the vector's elements +template +inline +TinyArray, N...> +cumsum(TinyArrayBase const & l) +{ + TinyArray, N...> res(l); + for(int k=1; k < l.size(); ++k) + res[k] += res[k-1]; + return res; +} + + /// product of the vector's elements +template +inline +PromoteType +prod(TinyArrayBase const & l) +{ + using Promote = PromoteType; + if(l.size() == 0) + return Promote(); + Promote res = Promote(1); + for(int k=0; k < l.size(); ++k) + res *= l[k]; + return res; +} + + /// cumulative product of the vector's elements +template +inline +TinyArray, N...> +cumprod(TinyArrayBase const & l) +{ + TinyArray, N...> res(l); + for(int k=1; k < l.size(); ++k) + res[k] *= res[k-1]; + return res; +} + + // /// \brief compute the F-order or C-order (default) stride of a given shape. + // /// Example: {200, 100, 50} => {5000, 50, 1} +// template +// inline +// TinyArray, N> +// shapeToStrides(TinyArrayBase const & shape, + // MemoryOrder order = C_ORDER) +// { + // TinyArray, N> res(shape.size(), DontInit); + + // if(order == C_ORDER) + // { + // res[shape.size()-1] = 1; + // for(int k=shape.size()-2; k >= 0; --k) + // res[k] = res[k+1] * shape[k+1]; + // } + // else + // { + // res[0] = 1; + // for(int k=1; k < shape.size(); ++k) + // res[k] = res[k-1] * shape[k-1]; + // } + // return res; +// } + + /// element-wise minimum +template +inline +TinyArray, N...> +min(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "min(): size mismatch."); + TinyArray, N...> res(l.size(), DontInit); + for(int k=0; k < l.size(); ++k) + res[k] = mathfunctions::min(l[k], r[k]); + return res; +} + + /// element-wise minimum with a constant +template ::value>> +inline +TinyArray, N...> +min(TinyArrayBase const & l, + V2 const & r) +{ + TinyArray, N...> res(l.size(), DontInit); + for(int k=0; k < l.size(); ++k) + res[k] = mathfunctions::min(l[k], r); + return res; +} + + /// element-wise minimum with a constant +template ::value>> +inline +TinyArray, N...> +min(V1 const & l, + TinyArrayBase const & r) +{ + TinyArray, N...> res(r.size(), DontInit); + for(int k=0; k < r.size(); ++k) + res[k] = mathfunctions::min(l, r[k]); + return res; +} + + /** Index of minimal element. + + Returns -1 for an empty array. + */ +template +inline int +min_element(TinyArrayBase const & l) +{ + if(l.size() == 0) + return -1; + int m = 0; + for(int i=1; i +inline +V const & +min(TinyArrayBase const & l) +{ + int m = min_element(l); + xtensor_precondition(m >= 0, "min() on empty TinyArray."); + return l[m]; +} + + /// element-wise maximum +template +inline +TinyArray, N...> +max(TinyArrayBase const & l, + TinyArrayBase const & r) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), + "max(): size mismatch."); + TinyArray, N...> res(l.size(), DontInit); + for(int k=0; k < l.size(); ++k) + res[k] = mathfunctions::max(l[k], r[k]); + return res; +} + + /// element-wise maximum with a constant +template ::value>> +inline +TinyArray, N...> +max(TinyArrayBase const & l, + V2 const & r) +{ + TinyArray, N...> res(l.size(), DontInit); + for(int k=0; k < l.size(); ++k) + res[k] = mathfunctions::max(l[k], r); + return res; +} + + /// element-wise maximum with a constant +template ::value>> +inline +TinyArray, N...> +max(V1 const & l, + TinyArrayBase const & r) +{ + TinyArray, N...> res(r.size(), DontInit); + for(int k=0; k < r.size(); ++k) + res[k] = mathfunctions::max(l, r[k]); + return res; +} + + /** Index of maximal element. + + Returns -1 for an empty array. + */ +template +inline int +max_element(TinyArrayBase const & l) +{ + if(l.size() == 0) + return -1; + int m = 0; + for(int i=1; i +inline V const & +max(TinyArrayBase const & l) +{ + int m = max_element(l); + xtensor_precondition(m >= 0, "max() on empty TinyArray."); + return l[m]; +} + +/// squared norm +template +inline SquaredNormType > +squaredNorm(TinyArrayBase const & t) +{ + using Type = SquaredNormType >; + Type result = Type(); + for(int i=0; i +inline SquaredNormType > +squaredNorm(TinySymmetricView const & t) +{ + using Type = SquaredNormType >; + Type result = Type(); + for (int i = 0; i < N; ++i) + { + result += squaredNorm(t(i, i)); + for (int j = i + 1; j < N; ++j) + { + auto c = squaredNorm(t(i, j)); + result += c + c; + } + } + + return result; +} + +template +inline +NormType +sizeDividedSquaredNorm(TinyArrayBase const & t) +{ + return NormType(squaredNorm(t)) / t.size(); +} + +template +inline +NormType +sizeDividedNorm(TinyArrayBase const & t) +{ + return NormType(norm(t)) / t.size(); +} + + /// reversed copy +template +inline +TinyArray +reversed(TinyArrayBase const & t) +{ + return TinyArray(t.begin(), t.end(), ReverseCopy); +} + + /** \brief transposed copy + + Elements are arranged such that res[k] = t[permutation[k]]. + */ +template +inline +TinyArray +transpose(TinyArrayBase const & v, + TinyArrayBase const & permutation) +{ + return v.transpose(permutation); +} + +template +inline +TinyArray +transpose(TinyArrayBase const & v) +{ + return reversed(v); +} + +template +inline +TinyArray +transpose(TinyArrayBase const & v) +{ + TinyArray res(DontInit); + for(int i=0; i < N1; ++i) + { + for(int j=0; j < N2; ++j) + { + res(j,i) = v(i,j); + } + } + return res; +} + +template +inline +TinySymmetricView +transpose(TinySymmetricView const & v) +{ + return v; +} + + /** \brief Clip negative values. + + All elements smaller than 0 are set to zero. + */ +template +inline +TinyArray +clipLower(TinyArrayBase const & t) +{ + return clipLower(t, V()); +} + + /** \brief Clip values below a threshold. + + All elements smaller than \a val are set to \a val. + */ +template +inline +TinyArray +clipLower(TinyArrayBase const & t, const V val) +{ + TinyArray res(t.size(), DontInit); + for(int k=0; k < t.size(); ++k) + { + res[k] = t[k] < val ? val : t[k]; + } + return res; +} + + /** \brief Clip values above a threshold. + + All elements bigger than \a val are set to \a val. + */ +template +inline +TinyArray +clipUpper(TinyArrayBase const & t, const V val) +{ + TinyArray res(t.size(), DontInit); + for(int k=0; k < t.size(); ++k) + { + res[k] = t[k] > val ? val : t[k]; + } + return res; +} + + /** \brief Clip values to an interval. + + All elements less than \a valLower are set to \a valLower, all elements + bigger than \a valUpper are set to \a valUpper. + */ +template +inline +TinyArray +clip(TinyArrayBase const & t, + const V valLower, const V valUpper) +{ + TinyArray res(t.size(), DontInit); + for(int k=0; k < t.size(); ++k) + { + res[k] = (t[k] < valLower) + ? valLower + : (t[k] > valUpper) + ? valUpper + : t[k]; + } + return res; +} + + /** \brief Clip values to a vector of intervals. + + All elements less than \a valLower are set to \a valLower, all elements + bigger than \a valUpper are set to \a valUpper. + */ +template +inline +TinyArray +clip(TinyArrayBase const & t, + TinyArrayBase const & valLower, + TinyArrayBase const & valUpper) +{ + XTENSOR_ASSERT_RUNTIME_SIZE(N..., t.size() == valLower.size() && t.size() == valUpper.size(), + "clip(): size mismatch."); + TinyArray res(t.size(), DontInit); + for(int k=0; k < t.size(); ++k) + { + res[k] = (t[k] < valLower[k]) + ? valLower[k] + : (t[k] > valUpper[k]) + ? valUpper[k] + : t[k]; + } + return res; +} + +template +inline void +swap(TinyArrayBase & l, + TinyArrayBase & r) +{ + l.swap(r); +} + +//@} + +#if 0 //##################################### +//////////////////////////////////////////////////////////// +// PromoteTraits specializations + +template +struct PromoteTraits, TinyArrayBase > +{ + static const bool value = PromoteTraits::value; + typedef TinyArray, N...> type; +}; + +template +struct PromoteTraits, TinyArray > +{ + static const bool value = PromoteTraits::value; + typedef TinyArray, N...> type; +}; + +template +struct PromoteTraits, TinyArrayView > +{ + static const bool value = PromoteTraits::value; + typedef TinyArray, N...> type; +}; + +template +struct PromoteTraits, TinySymmetricView > +{ + static const bool value = PromoteTraits::value; + typedef TinyArray, N*(N+1)/2> type; +}; + +//////////////////////////////////////////////////////////// +// NumericTraits specializations + +template +struct NumericTraits> +{ + typedef TinyArrayBase Type; + typedef T value_type; + typedef PromoteType Promote; + typedef RealPromoteType RealPromote; + typedef TinyArray::UnsignedPromote, N...> UnsignedPromote; + typedef TinyArray::ComplexPromote>, N...> ComplexPromote; + + static Type zero() { return {}; } + static Type one() { return {NumericTraits::one()}; } + static Type nonZero() { return {NumericTraits::one()}; } + static Type epsilon() { return {NumericTraits::epsilon()}; } + static Type smallestPositive() { return {NumericTraits::smallestPositive()}; } + + static const std::ptrdiff_t static_size = Type::static_size; + + static Promote toPromote(Type const & v) { return v; } + static Type fromPromote(Promote const & v) { return v; } + static Type fromRealPromote(RealPromote v) { return Type(v); } +}; + +template +struct NumericTraits> +: public NumericTraits::base_type> +{ + typedef TinyArray Type; +}; + +template +struct NumericTraits> +: public NumericTraits::base_type> +{ + typedef TinyArrayView Type; +}; + +template +struct NumericTraits> +: public NumericTraits::base_type> +{ + typedef TinySymmetricView Type; +}; + +// mask cl.exe shortcomings [end] +// #if defined(_MSC_VER) +// #pragma warning( pop ) +// #endif + +#endif // if 0 //##################################### + +} // namespace xt + +#undef XTENSOR_ASSERT_INSIDE + +#endif // XTENSOR_XTINY_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c67bfb7df..1fd112ea0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -119,6 +119,7 @@ set(XTENSOR_TESTS test_xoptional.cpp test_xstorage.cpp test_xcsv.cpp + test_xtiny.cpp ) set(XTENSOR_TARGET test_xtensor) diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp new file mode 100644 index 000000000..932545e5d --- /dev/null +++ b/test/test_xtiny.cpp @@ -0,0 +1,602 @@ +/*************************************************************************** +* 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_ENABLE_ASSERT +#define XTENSOR_ENABLE_ASSERT +#endif + +#include +#include +#include + +#include "gtest/gtest.h" +#include "xtensor/xtiny.hpp" + +template +bool equalValue(VECTOR const & v, VALUE const & vv) +{ + for (unsigned int i = 0; i +bool equalVector(VECTOR1 const & v1, VECTOR2 const & v2) +{ + for (unsigned int i = 0; i +bool equalIter(ITER1 i1, ITER1 i1end, ITER2 i2, xt::ArrayIndex size) +{ + if (i1end - i1 != size) + return false; + for (; i1; + using IV = TinyArray; + using FV = TinyArray; + + static float di[] = { 1, 2, 4, 5, 8, 10 }; + static float df[] = { 1.2f, 2.4f, 3.6f, 4.8f, 8.1f, 9.7f }; + BV bv0, bv1(1), bv3(di); + IV iv0, iv1(1), iv3(di); + FV fv0, fv1(1), fv3(df); + + TEST(xtiny, promote) + { + EXPECT_TRUE((std::is_same > >::value)); + EXPECT_TRUE((std::is_same, 1> > >::value)); + EXPECT_TRUE((std::is_same > >::value)); + EXPECT_TRUE((std::is_same, 1> > >::value)); + } + + TEST(xtiny, construct) + { + EXPECT_TRUE(BV::may_use_uninitialized_memory); + EXPECT_TRUE((TinyArray::may_use_uninitialized_memory == (SIZE != runtime_size))); + EXPECT_TRUE(UninitializedMemoryTraits::value == (SIZE != runtime_size)); + EXPECT_TRUE((UninitializedMemoryTraits, SIZE>>::value == false)); + //EXPECT_TRUE(ValueTypeTraits::value); + //EXPECT_TRUE((std::is_same::type>::value)); + + EXPECT_TRUE(bv0.size() == SIZE); + EXPECT_TRUE(iv0.size() == SIZE); + EXPECT_TRUE(fv0.size() == SIZE); + + EXPECT_TRUE(equalValue(bv0, 0)); + EXPECT_TRUE(equalValue(iv0, 0)); + EXPECT_TRUE(equalValue(fv0, 0.0f)); + + EXPECT_TRUE(equalValue(bv1, 1)); + EXPECT_TRUE(equalValue(iv1, 1)); + EXPECT_TRUE(equalValue(fv1, 1.0f)); + + EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), di, SIZE)); + EXPECT_TRUE(equalIter(iv3.begin(), iv3.end(), di, SIZE)); + EXPECT_TRUE(equalIter(fv3.begin(), fv3.end(), df, SIZE)); + + EXPECT_TRUE(!equalVector(bv3, fv3)); + EXPECT_TRUE(!equalVector(iv3, fv3)); + + BV bv(round(fv3)); + EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), bv.begin(), SIZE)); + EXPECT_TRUE(equalVector(bv3, bv)); + + BV bv4(bv3.begin()); + EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), bv4.begin(), SIZE)); + EXPECT_TRUE(equalVector(bv3, bv4)); + + BV bv5(bv3.begin(), ReverseCopy); + EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), + std::reverse_iterator(bv5.end()), SIZE)); + + FV fv(iv3); + EXPECT_TRUE(equalIter(iv3.begin(), iv3.end(), fv.begin(), SIZE)); + EXPECT_TRUE(equalVector(iv3, fv)); + + fv = fv3; + EXPECT_TRUE(equalIter(fv3.begin(), fv3.end(), fv.begin(), SIZE)); + EXPECT_TRUE(equalVector(fv3, fv)); + + fv = bv3; + EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), fv.begin(), SIZE)); + EXPECT_TRUE(equalVector(bv3, fv)); + + TinyArray fv5; + fv5.init(fv3.begin(), fv3.end()); + EXPECT_EQ(fv5[0], fv3[0]); + EXPECT_EQ(fv5[1], fv3[1]); + EXPECT_EQ(fv5[2], fv3[2]); + EXPECT_EQ(fv5[3], SIZE <= 3 ? 0.0 : fv3[3]); + EXPECT_EQ(fv5[4], SIZE <= 4 ? 0.0 : fv3[4]); + + EXPECT_EQ(iv3, (iv3.template subarray<0, SIZE>())); + EXPECT_EQ(2, (iv3.template subarray<0, 2>().size())); + EXPECT_EQ(iv3[0], (iv3.template subarray<0, 2>()[0])); + EXPECT_EQ(iv3[1], (iv3.template subarray<0, 2>()[1])); + EXPECT_EQ(2, (iv3.template subarray<1, 3>().size())); + EXPECT_EQ(iv3[1], (iv3.template subarray<1, 3>()[0])); + EXPECT_EQ(iv3[2], (iv3.template subarray<1, 3>()[1])); + EXPECT_EQ(1, (iv3.template subarray<1, 2>().size())); + EXPECT_EQ(iv3[1], (iv3.template subarray<1, 2>()[0])); + EXPECT_EQ(1, (iv3.subarray(1, 2).size())); + EXPECT_EQ(iv3[1], (iv3.subarray(1, 2)[0])); + + for (int k = 0; k FV1; + FV1 fv10(fv3.begin()); + EXPECT_EQ(fv10, fv3.erase(SIZE - 1)); + EXPECT_EQ(fv3, fv10.insert(SIZE - 1, fv3[SIZE - 1])); + FV1 fv11(fv3.begin() + 1); + EXPECT_EQ(fv11, fv3.erase(0)); + } + + TEST(xtiny, comparison) + { + EXPECT_TRUE(bv0 == bv0); + EXPECT_TRUE(bv0 == 0); + EXPECT_TRUE(0 == bv0); + EXPECT_TRUE(iv0 == iv0); + EXPECT_TRUE(fv0 == fv0); + EXPECT_TRUE(fv0 == 0); + EXPECT_TRUE(0 == fv0); + EXPECT_TRUE(iv0 == bv0); + EXPECT_TRUE(iv0 == fv0); + EXPECT_TRUE(fv0 == bv0); + + EXPECT_TRUE(bv3 == bv3); + EXPECT_TRUE(iv3 == iv3); + EXPECT_TRUE(fv3 == fv3); + EXPECT_TRUE(iv3 == bv3); + EXPECT_TRUE(iv3 != fv3); + EXPECT_TRUE(iv3 != 0); + EXPECT_TRUE(0 != iv3); + EXPECT_TRUE(fv3 != bv3); + EXPECT_TRUE(fv3 != 0); + EXPECT_TRUE(0 != fv3); + + EXPECT_TRUE(bv0 < bv1); + + EXPECT_TRUE(allLess(bv0, bv1)); + EXPECT_TRUE(!allLess(bv1, bv3)); + EXPECT_TRUE(allGreater(bv1, bv0)); + EXPECT_TRUE(!allGreater(bv3, bv1)); + EXPECT_TRUE(allLessEqual(bv0, bv1)); + EXPECT_TRUE(allLessEqual(0, bv0)); + EXPECT_TRUE(allLessEqual(bv0, 0)); + EXPECT_TRUE(allLessEqual(bv1, bv3)); + EXPECT_TRUE(!allLessEqual(bv3, bv1)); + EXPECT_TRUE(allGreaterEqual(bv1, bv0)); + EXPECT_TRUE(allGreaterEqual(bv3, bv1)); + EXPECT_TRUE(!allGreaterEqual(bv1, bv3)); + + EXPECT_TRUE(isclose(fv3, fv3)); + + EXPECT_TRUE(!any(bv0) && !all(bv0) && any(bv1) && all(bv1)); + EXPECT_TRUE(!any(iv0) && !all(iv0) && any(iv1) && all(iv1)); + EXPECT_TRUE(!any(fv0) && !all(fv0) && any(fv1) && all(fv1)); + IV iv; + iv = IV(); iv[0] = 1; + EXPECT_TRUE(any(iv) && !all(iv)); + iv = IV(); iv[1] = 1; + EXPECT_TRUE(any(iv) && !all(iv)); + iv = IV(); iv[SIZE - 1] = 1; + EXPECT_TRUE(any(iv) && !all(iv)); + iv = IV(1); iv[0] = 0; + EXPECT_TRUE(any(iv) && !all(iv)); + iv = IV(1); iv[1] = 0; + EXPECT_TRUE(any(iv) && !all(iv)); + iv = IV(1); iv[SIZE - 1] = 0; + EXPECT_TRUE(any(iv) && !all(iv)); + } + + TEST(xtiny, arithmetic) + { + EXPECT_TRUE((std::is_same>::value)); + EXPECT_TRUE((std::is_same, RealPromoteType>::value)); + EXPECT_TRUE((std::is_same, RealPromoteType>::value)); + + IV ivm3 = -iv3; + FV fvm3 = -fv3; + + int mi[] = { -1, -2, -4, -5, -8, -10 }; + float mf[] = { -1.2f, -2.4f, -3.6f, -4.8f, -8.1f, -9.7f }; + + EXPECT_TRUE(equalIter(ivm3.begin(), ivm3.end(), mi, SIZE)); + EXPECT_TRUE(equalIter(fvm3.begin(), fvm3.end(), mf, SIZE)); + + IV iva3 = abs(ivm3); + FV fva3 = abs(fvm3); + EXPECT_TRUE(equalVector(iv3, iva3)); + EXPECT_TRUE(equalVector(fv3, fva3)); + + int fmi[] = { -2, -3, -4, -5, -9, -10 }; + int fpi[] = { 1, 2, 3, 4, 8, 9 }; + int ri[] = { 1, 2, 4, 5, 8, 10 }; + IV ivi3 = floor(fvm3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), fmi, SIZE)); + ivi3 = -ceil(fv3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), fmi, SIZE)); + ivi3 = round(fv3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), ri, SIZE)); + ivi3 = floor(fv3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), fpi, SIZE)); + ivi3 = roundi(fv3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), ri, SIZE)); + ivi3 = -ceil(fvm3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), fpi, SIZE)); + ivi3 = -round(fvm3); + EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), ri, SIZE)); + + EXPECT_EQ(clipLower(iv3), iv3); + EXPECT_EQ(clipLower(iv3, 11), IV(11)); + EXPECT_EQ(clipUpper(iv3, 0), IV(0)); + EXPECT_EQ(clipUpper(iv3, 11), iv3); + EXPECT_EQ(clip(iv3, 0, 11), iv3); + EXPECT_EQ(clip(iv3, 11, 12), IV(11)); + EXPECT_EQ(clip(iv3, -1, 0), IV(0)); + EXPECT_EQ(clip(iv3, IV(0), IV(11)), iv3); + EXPECT_EQ(clip(iv3, IV(11), IV(12)), IV(11)); + EXPECT_EQ(clip(iv3, IV(-1), IV(0)), IV(0)); + + EXPECT_TRUE(squaredNorm(bv1) == SIZE); + EXPECT_TRUE(squaredNorm(iv1) == SIZE); + EXPECT_TRUE(squaredNorm(fv1) == (float)SIZE); + + float expectedSM = 1.2f*1.2f + 2.4f*2.4f + 3.6f*3.6f; + EXPECT_TRUE(mathfunctions::isclose(squaredNorm(fv3), expectedSM, 1e-7f)); + + EXPECT_EQ(dot(bv3, bv3), squaredNorm(bv3)); + EXPECT_EQ(dot(iv3, bv3), squaredNorm(iv3)); + EXPECT_TRUE(mathfunctions::isclose(dot(fv3, fv3), squaredNorm(fv3))); + + TinyArray ivv(iv3, iv3, iv3); + EXPECT_EQ(squaredNorm(ivv), 3 * squaredNorm(iv3)); + EXPECT_EQ(norm(ivv), sqrt(3.0*squaredNorm(iv3))); + + EXPECT_TRUE(mathfunctions::isclose(sqrt(dot(bv3, bv3)), norm(bv3), 0.0)); + EXPECT_TRUE(mathfunctions::isclose(sqrt(dot(iv3, bv3)), norm(iv3), 0.0)); + EXPECT_TRUE(mathfunctions::isclose(sqrt(dot(fv3, fv3)), norm(fv3), 0.0f)); + + BV bv = bv3; + bv[2] = 200; + int expectedSM2 = 40005; + if (SIZE == 6) + expectedSM2 += 189; + EXPECT_EQ(dot(bv, bv), expectedSM2); + EXPECT_EQ(squaredNorm(bv), expectedSM2); + + EXPECT_TRUE(equalVector(bv0 + 1.0, fv1)); + EXPECT_TRUE(equalVector(1.0 + bv0, fv1)); + EXPECT_TRUE(equalVector(bv1 - 1.0, fv0)); + EXPECT_TRUE(equalVector(1.0 - bv1, fv0)); + EXPECT_TRUE(equalVector(bv3 - iv3, bv0)); + EXPECT_TRUE(equalVector(fv3 - fv3, fv0)); + BV bvp = (bv3 + bv3)*0.5; + FV fvp = (fv3 + fv3)*0.5; + EXPECT_TRUE(equalVector(bvp, bv3)); + EXPECT_TRUE(equalVector(fvp, fv3)); + bvp = 2.0*bv3 - bv3; + fvp = 2.0*fv3 - fv3; + EXPECT_TRUE(equalVector(bvp, bv3)); + EXPECT_TRUE(equalVector(fvp, fv3)); + + IV ivp = bv + bv; + int ip1[] = { 2, 4, 400, 10, 16, 20 }; + EXPECT_TRUE(equalIter(ivp.begin(), ivp.end(), ip1, SIZE)); + EXPECT_TRUE(equalVector(bv0 - iv1, -iv1)); + + bvp = bv3 / 2.0; + fvp = bv3 / 2.0; + int ip[] = { 0, 1, 2, 3, 4, 5 }; + float fp[] = { 0.5, 1.0, 2.0, 2.5, 4.0, 5.0 }; + EXPECT_TRUE(equalIter(bvp.begin(), bvp.end(), ip, SIZE)); + EXPECT_TRUE(equalIter(fvp.begin(), fvp.end(), fp, SIZE)); + fvp = fv3 / 2.0; + float fp1[] = { 0.6f, 1.2f, 1.8f, 2.4f, 4.05f, 4.85f }; + EXPECT_TRUE(equalIter(fvp.begin(), fvp.end(), fp1, SIZE)); + EXPECT_EQ(2.0 / fv1, 2.0 * fv1); + float fp2[] = { 1.0f, 0.5f, 0.25f, 0.2f, 0.125f, 0.1f }; + fvp = 1.0 / bv3; + EXPECT_TRUE(equalIter(fvp.begin(), fvp.end(), fp2, SIZE)); + + int ivsq[] = { 1, 4, 16, 25, 64, 100 }; + ivp = iv3*iv3; + EXPECT_TRUE(equalIter(ivp.begin(), ivp.end(), ivsq, SIZE)); + EXPECT_EQ(iv3 * iv1, iv3); + EXPECT_EQ(iv0 * iv3, iv0); + EXPECT_EQ(iv3 / iv3, iv1); + EXPECT_EQ(iv3 % iv3, iv0); + EXPECT_EQ(iv3 % (iv3 + iv1), iv3); + + float minRef[] = { 1.0f, 2.0f, 3.6f, 4.8f, 8.0f, 9.7f }; + float minRefScalar[] = { 1.2f, 2.4f, 3.6f, 4.0f, 4.0f, 4.0f }; + auto minRes = min(iv3, fv3); + EXPECT_TRUE(equalIter(minRef, minRef + SIZE, minRes.cbegin(), SIZE)); + minRes = min(4.0f, fv3); + EXPECT_TRUE(equalIter(minRefScalar, minRefScalar + SIZE, minRes.cbegin(), SIZE)); + minRes = min(fv3, 4.0f); + EXPECT_TRUE(equalIter(minRefScalar, minRefScalar + SIZE, minRes.cbegin(), SIZE)); + IV ivmin = floor(fv3); + ivmin[1] = 3; + int minRef2[] = { 1, 2, 3, 4, 8, 9 }; + auto minRes2 = min(iv3, ivmin); + EXPECT_TRUE(equalIter(minRef2, minRef2 + SIZE, minRes2.cbegin(), SIZE)); + EXPECT_EQ(min(iv3), di[0]); + EXPECT_EQ(min(fv3), df[0]); + EXPECT_EQ(max(iv3), di[SIZE - 1]); + EXPECT_EQ(max(fv3), df[SIZE - 1]); + + float maxRef[] = { 1.2f, 2.4f, 4.0f, 5.0f, 8.1f, 10.0f }; + EXPECT_TRUE(equalIter(maxRef, maxRef + SIZE, max(iv3, fv3).begin(), SIZE)); + float maxRefScalar[] = { 4.0f, 4.0f, 4.0f, 4.8f, 8.1f, 9.7f }; + EXPECT_TRUE(equalIter(maxRefScalar, maxRefScalar + SIZE, max(4.0f, fv3).begin(), SIZE)); + EXPECT_TRUE(equalIter(maxRefScalar, maxRefScalar + SIZE, max(fv3, 4.0f).begin(), SIZE)); + IV ivmax = floor(fv3); + ivmax[1] = 3; + int maxRef2[] = { 1, 3, 4, 5, 8, 10 }; + EXPECT_TRUE(equalIter(maxRef2, maxRef2 + SIZE, max(iv3, ivmax).begin(), SIZE)); + + EXPECT_EQ(sqrt(iv3 * iv3), iv3); + EXPECT_EQ(sqrt(pow(iv3, 2)), iv3); + + EXPECT_EQ(sum(iv3), SIZE == 3 ? 7 : 30); + EXPECT_EQ(sum(fv3), SIZE == 3 ? 7.2f : 29.8f); + EXPECT_EQ(prod(iv3), SIZE == 3 ? 8 : 3200); + EXPECT_EQ(prod(fv3), SIZE == 3 ? 10.368f : 3910.15f); + EXPECT_TRUE(mathfunctions::isclose(mean(iv3), 7.0 / SIZE, 1e-15)); + + float cumsumRef[] = { 1.2f, 3.6f, 7.2f, 12.0f, 20.1f, 29.8f }; + FV cs = cumsum(fv3), csr(cumsumRef); + EXPECT_TRUE(isclose(cs, csr, 1e-6f)); + float cumprodRef[] = { 1.2f, 2.88f, 10.368f, 49.7664f, 403.108f, 3910.15f }; + FV cr = cumprod(fv3), crr(cumprodRef); + EXPECT_TRUE(isclose(cr, crr, 1e-6f)); + + TinyArray src{ 1, 2, -3, -4 }, signs{ 2, -3, 4, -5 }; + EXPECT_EQ(copysign(src, signs), (TinyArray{1, -2, 3, -4})); + + TinyArray left{ 3., 5., 8. }, right{ 4., 12., 15. }; + EXPECT_EQ(hypot(left, right), (TinyArray{5., 13., 17.})); + + int oddRef[] = { 1, 0, 0, 1, 0, 0 }; + EXPECT_TRUE(equalIter(oddRef, oddRef + SIZE, odd(iv3).begin(), SIZE)); + EXPECT_TRUE(equalIter(oddRef, oddRef + SIZE, (iv3 & 1).begin(), SIZE)); + } + + TEST(xtiny, cross_product) + { + EXPECT_EQ(cross(bv3, bv3), IV(0)); + EXPECT_EQ(cross(iv3, bv3), IV(0)); + EXPECT_TRUE(isclose(cross(fv3, fv3), FV(0.0), 1e-6f)); + + FV cr = cross(fv1, fv3), crr{ 1.2f, -2.4f, 1.2f }; + EXPECT_TRUE(isclose(cr, crr, 1e-6f)); + } + + TEST(xtiny, ostream) + { + std::ostringstream out; + out << iv3; + std::string expected("{1, 2, 4}"); + EXPECT_EQ(expected, out.str()); + out << "Testing.." << fv3 << 42; + out << bv3 << std::endl; + } + + TEST(xtiny, 2D) + { + using Array = TinyArray; + using Index = TinyArray; + + EXPECT_EQ(Array::static_ndim, 2); + EXPECT_EQ(Array::static_size, 6); + EXPECT_TRUE((std::is_same::value)); + + int adata[] = { 4,5,6,7,8,9 }; + Array a{ adata }; + EXPECT_EQ(a.ndim(), 2); + EXPECT_EQ(a.size(), 6); + EXPECT_EQ(a.shape(), Index(2, 3)); + + int count = 0, i, j; + Index idx; + for (i = 0, idx[0] = 0; i<2; ++i, ++idx[0]) + { + for (j = 0, idx[1] = 0; j<3; ++j, ++count, ++idx[1]) + { + EXPECT_EQ(a[count], adata[count]); + EXPECT_EQ((a[{i, j}]), adata[count]); + EXPECT_EQ(a[idx], adata[count]); + EXPECT_EQ(a(i, j), adata[count]); + } + } + { + std::string s = "{4, 5, 6,\n 7, 8, 9}"; + std::stringstream ss; + ss << a; + EXPECT_EQ(s, ss.str()); + } + + TinySymmetricView sym(a.data()); + EXPECT_EQ(sym.shape(), Index(3, 3)); + { + std::string s = "{4, 5, 6,\n 5, 7, 8,\n 6, 8, 9}"; + std::stringstream ss; + ss << sym; + EXPECT_EQ(s, ss.str()); + } + + Array::AsType b = a; + EXPECT_EQ(a, b); + + int adata2[] = { 0,1,2,3,4,5 }; + a = { 0,1,2,3,4,5 }; + EXPECT_TRUE(equalIter(a.begin(), a.end(), adata2, a.size())); + Array c = reversed(a); + EXPECT_TRUE(equalIter(c.rbegin(), c.rend(), adata2, c.size())); + + EXPECT_TRUE(a == a); + EXPECT_TRUE(a != b); + EXPECT_TRUE(a < b); + EXPECT_TRUE(any(a)); + EXPECT_TRUE(!all(a)); + EXPECT_TRUE(any(b)); + EXPECT_TRUE(all(b)); + EXPECT_TRUE(!allZero(a)); + EXPECT_TRUE(allLess(a, b)); + EXPECT_TRUE(allLessEqual(a, b)); + EXPECT_TRUE(!allGreater(a, b)); + EXPECT_TRUE(!allGreaterEqual(a, b)); + EXPECT_TRUE(isclose(a, b, 10.0f)); + + EXPECT_EQ(squaredNorm(a), 55); + EXPECT_TRUE(mathfunctions::isclose(norm(a), sqrt(55.0), 1e-15)); + EXPECT_EQ(min(a), 0); + EXPECT_EQ(max(a), 5); + EXPECT_EQ(max(a, b), b); + + swap(b, c); + EXPECT_TRUE(equalIter(c.cbegin(), c.cend(), adata, c.size())); + EXPECT_TRUE(equalIter(b.crbegin(), b.crend(), adata2, b.size())); + + int eyedata[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + auto eye = Array::eye<3>(); + EXPECT_TRUE(equalIter(eye.begin(), eye.end(), eyedata, eye.size())); + } + + TEST(xtiny, runtime_size) + { + using A = TinyArray; + + EXPECT_TRUE(typeid(A) == typeid(TinyArray)); + + A a{ 1,2,3 }, b{ 1,2,3 }, c = a, d = a + b, e(3); + EXPECT_EQ(a.size(), 3); + EXPECT_EQ(b.size(), 3); + EXPECT_EQ(c.size(), 3); + EXPECT_EQ(d.size(), 3); + EXPECT_EQ(e.size(), 3); + EXPECT_EQ(a, b); + EXPECT_EQ(a, c); + EXPECT_TRUE(a != d); + EXPECT_TRUE(a != e); + EXPECT_TRUE(a < d); + EXPECT_TRUE(e < a); + EXPECT_EQ(e, (A{ 0,0,0 })); + c.init(2, 4, 6); + EXPECT_EQ(d, c); + c.init({ 1,2,3 }); + EXPECT_EQ(a, c); + c = 2 * a; + EXPECT_EQ(d, c); + c.reverse(); + EXPECT_EQ(c, (A{ 6,4,2 })); + EXPECT_EQ(c, reversed(d)); + c = c - 2; + EXPECT_TRUE(all(d)); + EXPECT_TRUE(!all(c)); + EXPECT_TRUE(any(c)); + EXPECT_TRUE(!allZero(c)); + EXPECT_TRUE(!all(e)); + EXPECT_TRUE(!any(e)); + EXPECT_TRUE(allZero(e)); + + EXPECT_EQ(prod(a), 6); + EXPECT_EQ(prod(A()), 0); + + EXPECT_EQ(cross(a, a), e); + EXPECT_EQ(dot(a, a), 14); + EXPECT_EQ(squaredNorm(a), 14); + + EXPECT_EQ(a.erase(1), (A{ 1,3 })); + EXPECT_EQ(a.insert(3, 4), (A{ 1,2,3,4 })); + + // testing move constructor and assignment + EXPECT_EQ(std::move(A{ 1,2,3 }), (A{ 1,2,3 })); + EXPECT_EQ(A(a.insert(3, 4)), (A{ 1,2,3,4 })); + a = a.insert(3, 4); + EXPECT_EQ(a, (A{ 1,2,3,4 })); + + A r = A::range(2, 6); + EXPECT_EQ(r, (A{ 2,3,4,5 })); + EXPECT_EQ(r.subarray(1, 3).size(), 2); + EXPECT_EQ(r.subarray(1, 3), (A{ 3,4 })); + EXPECT_EQ((r.template subarray<1, 3>().size()), 2); + EXPECT_EQ((r.template subarray<1, 3>()), (A{ 3,4 })); + + EXPECT_EQ(A::range(0, 6, 3), (A{ 0,3 })); + EXPECT_EQ(A::range(0, 7, 3), (A{ 0,3,6 })); + EXPECT_EQ(A::range(0, 8, 3), (A{ 0,3,6 })); + EXPECT_EQ(A::range(0, 9, 3), (A{ 0,3,6 })); + EXPECT_EQ(A::range(10, 2, -2), (A{ 10, 8, 6, 4 })); + EXPECT_EQ(A::range(10, 1, -2), (A{ 10, 8, 6, 4, 2 })); + EXPECT_EQ(A::range(10, 0, -2), (A{ 10, 8, 6, 4, 2 })); + + EXPECT_EQ(transpose(A::range(1, 4)), (A{ 3,2,1 })); + EXPECT_EQ(transpose(A::range(1, 4), A{ 1,2,0 }), (A{ 2,3,1 })); + + EXPECT_THROW(A(3) / A(2), std::runtime_error); + + using TA = TinyArray; + TA s(A{ 1,2,3 }); + EXPECT_EQ(s, (TA{ 1,2,3 })); + s = A{ 3,4,5 }; + EXPECT_EQ(s, (TA{ 3,4,5 })); + + EXPECT_THROW({ TA(A{ 1,2,3,4 }); }, std::runtime_error); + + EXPECT_EQ((A{ 0,0,0 }), A(tags::size = 3)); + EXPECT_EQ((A{ 1,1,1 }), A(tags::size = 3, 1)); + + EXPECT_EQ(A::unitVector(tags::size = 3, 1), TA::unitVector(1)); + } + +} // namespace xt \ No newline at end of file From c764648d17859b5f22604b815875078e9187ff80 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Fri, 28 Jul 2017 19:22:20 +0200 Subject: [PATCH 03/27] fixed comment --- include/xtensor/xtiny.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index b66ae715e..32334cfbe 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -159,7 +159,7 @@ struct NormOfArrayElementsImpl "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); typedef double NormType; - typedef unsigned long long SquaredNormType; + typedef uint64_t SquaredNormType; }; template @@ -197,17 +197,18 @@ struct NormOfVectorImpl /* NormTraits implement the following default rules, which are designed to minimize the possibility of overflow: - * T is a 32-bit integer type: + * T is an integer type: NormType is T itself, - SquaredNormType is 'unsigned long long' - * T is another built-in arithmetic type: - NormType is T itself, - SquaredNormType is the NumericTraits::UnsignedPromote - * T is a container of 'long double': + SquaredNormType is 'uint32_t' (sizeof(T) < 4) or 'uint64_t' (otherwise) + * T is a floating-point type: + NormType and SquaredNormType are T itself, + * T is a container of 'long double' elements: NormType and SquaredNormType are 'long double' - * T is a container of another built-in arithmetic type: + * T is a container of another floating-point type: + NormType and SquaredNormType are 'double', + * T is a container of integer elements: NormType is 'double', - SquaredNormType is 'unsigned long long' + SquaredNormType is 'uint64_t' * T is a container of some other type: NormType is the element's norm type, SquaredNormType is the element's squared norm type From 73ba2e37f75bac3b5ed7f03c162f882e01920683 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sat, 29 Jul 2017 14:54:53 +0200 Subject: [PATCH 04/27] cleaned up constructors --- include/xtensor/xtiny.hpp | 110 ++++++++++++++++++++++---------------- test/test_xtiny.cpp | 109 +++++++++++++++++++++++-------------- 2 files changed, 133 insertions(+), 86 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 32334cfbe..1a45106b8 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -832,6 +832,14 @@ class TinyArrayBase data_[LEVEL] = v1; } + template ::value>> + void initImpl(ITERATOR i) + { + for(ArrayIndex k=0; k < static_size; ++k, ++i) + data_[k] = static_cast(*i); + } + public: template @@ -877,34 +885,21 @@ class TinyArrayBase } // constructor for zero or one argument - // activate 'constexpr' in C++ 14 - explicit /* constexpr */ TinyArrayBase(value_type v = value_type()) + explicit TinyArrayBase(value_type v = value_type()) { for(int i=0; i - constexpr TinyArrayBase(value_type v0, value_type v1, V ... v) - : data_{VALUETYPE(v0), VALUETYPE(v1), VALUETYPE(v)...} - { - static_assert(sizeof...(V)+2 == static_size, - "TinyArrayBase(): number of constructor arguments contradicts size()."); - } - // // constructor for two or more arguments - // constexpr TinyArrayBase(std::initializer_list const & init) - // : data_(init) + // template + // constexpr TinyArrayBase(value_type v0, value_type v1, V ... v) + // : data_{VALUETYPE(v0), VALUETYPE(v1), VALUETYPE(v)...} // { - // static_assert(init.size() == static_size, - // "TinyArrayBase(): wrong number of arguments."); + // static_assert(sizeof...(V)+2 == static_size, + // "TinyArrayBase(): number of constructor arguments contradicts size()."); // } - constexpr TinyArrayBase(value_type const (&v)[static_ndim]) - : data_{v} - {} - template explicit TinyArrayBase(U const * u) { @@ -1286,7 +1281,7 @@ class TinyArrayBase TinyArray linearSequence(value_type start = value_type(), value_type step = value_type(1)) { - TinyArray res; + TinyArray res(DontInit); for(int k=0; k < static_size; ++k, start += step) res[k] = start; return res; @@ -1298,7 +1293,7 @@ class TinyArrayBase range(value_type end) { value_type start = end - static_size; - TinyArray res; + TinyArray res(DontInit); for(int k=0; k < static_size; ++k, ++start) res[k] = start; return res; @@ -1726,13 +1721,8 @@ class TinyArray static const ArrayIndex static_size = base_type::static_size; explicit constexpr - TinyArray(value_type const & v = value_type()) - : base_type(v) - {} - - template - constexpr TinyArray(value_type v0, value_type v1, V... v) - : base_type(v0, v1, v...) + TinyArray() + : base_type(value_type()) {} explicit @@ -1740,13 +1730,33 @@ class TinyArray : base_type(DontInit) {} - // /** Construction from lemon::Invalid. - // Initializes all vector elements with -1. - // */ - // constexpr TinyArray(lemon::Invalid const &) - // : base_type(-1) + // This constructor would allow construction with round brackets, e.g.: + // TinyArray a(2); + // However, this may lead to bugs when fixed-size arrays are mixed with + // runtime_size arrays, where + // TinyArray a(2); + // constructs an array of length 2 with initial value 0. To avoid such bugs, + // construction is restricted to curly braces: + // TinyArray a{2}; + // + // template + // constexpr TinyArray(value_type v0, V... v) + // : base_type(v0, v...) // {} + template + TinyArray(std::initializer_list v) + : base_type(DontInit) + { + if(v.size() == 1) + base_type::init(static_cast(*v.begin())); + else if(v.size() == static_size) + base_type::initImpl(v.begin()); + else + xtensor_precondition(false, + "TinyArray(std::initializer_list): wrong initialization size."); + } + // for compatibility with TinyArray explicit TinyArray(tags::SizeProxy const & size, @@ -1792,12 +1802,23 @@ class TinyArray { xtensor_precondition(this->size() == other.size(), "TinyArray(): shape mismatch."); - this->init(other.begin(), other.end()); + this->initImpl(other.begin()); } } - constexpr TinyArray(value_type const (&v)[static_ndim]) - : base_type(v) + explicit TinyArray(value_type const (&u)[1]) + : base_type(*u) + {} + + template + explicit TinyArray(U const (&u)[1]) + : base_type(static_cast(*u)) + {} + + template > + explicit TinyArray(U const (&u)[static_size]) + : base_type(u) {} template std::uninitialized_fill(this->begin(), this->end(), value_type()); } - // TinyArray(lemon::Invalid const &) - // : base_type() - // {} - - // TinyArray(ArrayIndex size, lemon::Invalid const &) - // : TinyArray(size, value_type(-1)) - // {} - TinyArray(TinyArray const & rhs ) : base_type(rhs.size()) { @@ -1963,6 +1976,11 @@ class TinyArray new(this->data_+i) value_type(static_cast(*(end-1))); } + template + TinyArray(const U (&u)[SIZE]) + : TinyArray(u, u+SIZE) + {} + template TinyArray(std::initializer_list rhs) : TinyArray(rhs.begin(), rhs.end()) @@ -2409,7 +2427,7 @@ class TinySymmetricView return base_type::data_[k]; } - constexpr index_type shape() const { return index_type(N, N); } + constexpr index_type shape() const { return index_type{N, N}; } constexpr ArrayIndex ndim () const { return static_ndim; } }; @@ -3103,7 +3121,7 @@ TinyArray \ operator OP(V1 l, \ TinyArrayBase const & r) \ { \ - TinyArray res(l); \ + TinyArray res{l}; \ return res OP##= r; \ } \ \ diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 932545e5d..8343b76ee 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -54,14 +54,26 @@ namespace xt using IV = TinyArray; using FV = TinyArray; - static float di[] = { 1, 2, 4, 5, 8, 10 }; - static float df[] = { 1.2f, 2.4f, 3.6f, 4.8f, 8.1f, 9.7f }; - BV bv0, bv1(1), bv3(di); - IV iv0, iv1(1), iv3(di); - FV fv0, fv1(1), fv3(df); + static float di[] = { 1, 2, 4}; + static float df[] = { 1.2f, 2.4f, 3.6f}; + BV bv0, bv1{1}, bv3(di); + IV iv0, iv1{1}, iv3(di); + FV fv0, fv1{1.0f}, fv3(df); - TEST(xtiny, promote) + TEST(xtiny, traits) { + EXPECT_TRUE(BV::may_use_uninitialized_memory); + // FIXME: should be FALSE + EXPECT_TRUE((TinyArray::may_use_uninitialized_memory)); + EXPECT_TRUE(UninitializedMemoryTraits::value == (SIZE != runtime_size)); + EXPECT_TRUE((UninitializedMemoryTraits, SIZE>>::value == false)); + //EXPECT_TRUE(ValueTypeTraits::value); + //EXPECT_TRUE((std::is_same::type>::value)); + + EXPECT_TRUE((std::is_same>::value)); + EXPECT_TRUE((std::is_same, RealPromoteType>::value)); + EXPECT_TRUE((std::is_same, RealPromoteType>::value)); + EXPECT_TRUE((std::is_same > >::value)); EXPECT_TRUE((std::is_same, 1> > >::value)); EXPECT_TRUE((std::is_same > >::value)); @@ -70,13 +82,6 @@ namespace xt TEST(xtiny, construct) { - EXPECT_TRUE(BV::may_use_uninitialized_memory); - EXPECT_TRUE((TinyArray::may_use_uninitialized_memory == (SIZE != runtime_size))); - EXPECT_TRUE(UninitializedMemoryTraits::value == (SIZE != runtime_size)); - EXPECT_TRUE((UninitializedMemoryTraits, SIZE>>::value == false)); - //EXPECT_TRUE(ValueTypeTraits::value); - //EXPECT_TRUE((std::is_same::type>::value)); - EXPECT_TRUE(bv0.size() == SIZE); EXPECT_TRUE(iv0.size() == SIZE); EXPECT_TRUE(fv0.size() == SIZE); @@ -96,6 +101,19 @@ namespace xt EXPECT_TRUE(!equalVector(bv3, fv3)); EXPECT_TRUE(!equalVector(iv3, fv3)); + EXPECT_EQ(iv3, (IV{ 1, 2, 4 })); + EXPECT_EQ(iv3, (IV{ 1.1, 2.2, 4.4 })); + EXPECT_EQ(iv3, (IV({ 1, 2, 4 }))); + EXPECT_EQ(iv3, (IV({ 1.1, 2.2, 4.4 }))); + EXPECT_EQ(iv1, (IV{ 1 })); + EXPECT_EQ(iv1, (IV{ 1.1 })); + EXPECT_EQ(iv1, (IV({ 1 }))); + EXPECT_EQ(iv1, (IV({ 1.1 }))); + EXPECT_EQ(iv1, IV(tags::size = SIZE, 1)); + // these should not compile: + // EXPECT_EQ(iv1, IV(1)); + // EXPECT_EQ(iv3, IV(1, 2, 4)); + BV bv(round(fv3)); EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), bv.begin(), SIZE)); EXPECT_TRUE(equalVector(bv3, bv)); @@ -229,20 +247,16 @@ namespace xt EXPECT_TRUE(any(iv) && !all(iv)); iv = IV(); iv[SIZE - 1] = 1; EXPECT_TRUE(any(iv) && !all(iv)); - iv = IV(1); iv[0] = 0; + iv = IV{ 1 }; iv[0] = 0; EXPECT_TRUE(any(iv) && !all(iv)); - iv = IV(1); iv[1] = 0; + iv = IV{ 1 }; iv[1] = 0; EXPECT_TRUE(any(iv) && !all(iv)); - iv = IV(1); iv[SIZE - 1] = 0; + iv = IV{ 1 }; iv[SIZE - 1] = 0; EXPECT_TRUE(any(iv) && !all(iv)); } TEST(xtiny, arithmetic) { - EXPECT_TRUE((std::is_same>::value)); - EXPECT_TRUE((std::is_same, RealPromoteType>::value)); - EXPECT_TRUE((std::is_same, RealPromoteType>::value)); - IV ivm3 = -iv3; FV fvm3 = -fv3; @@ -276,15 +290,15 @@ namespace xt EXPECT_TRUE(equalIter(ivi3.begin(), ivi3.end(), ri, SIZE)); EXPECT_EQ(clipLower(iv3), iv3); - EXPECT_EQ(clipLower(iv3, 11), IV(11)); - EXPECT_EQ(clipUpper(iv3, 0), IV(0)); + EXPECT_EQ(clipLower(iv3, 11), IV{ 11 }); + EXPECT_EQ(clipUpper(iv3, 0), IV{ 0 }); EXPECT_EQ(clipUpper(iv3, 11), iv3); EXPECT_EQ(clip(iv3, 0, 11), iv3); - EXPECT_EQ(clip(iv3, 11, 12), IV(11)); - EXPECT_EQ(clip(iv3, -1, 0), IV(0)); - EXPECT_EQ(clip(iv3, IV(0), IV(11)), iv3); - EXPECT_EQ(clip(iv3, IV(11), IV(12)), IV(11)); - EXPECT_EQ(clip(iv3, IV(-1), IV(0)), IV(0)); + EXPECT_EQ(clip(iv3, 11, 12), IV{ 11 }); + EXPECT_EQ(clip(iv3, -1, 0), IV{ 0 }); + EXPECT_EQ(clip(iv3, IV{0 }, IV{11}), iv3); + EXPECT_EQ(clip(iv3, IV{11}, IV{12}), IV{11}); + EXPECT_EQ(clip(iv3, IV{-1}, IV{0 }), IV{0 }); EXPECT_TRUE(squaredNorm(bv1) == SIZE); EXPECT_TRUE(squaredNorm(iv1) == SIZE); @@ -297,7 +311,7 @@ namespace xt EXPECT_EQ(dot(iv3, bv3), squaredNorm(iv3)); EXPECT_TRUE(mathfunctions::isclose(dot(fv3, fv3), squaredNorm(fv3))); - TinyArray ivv(iv3, iv3, iv3); + TinyArray ivv{ iv3, iv3, iv3 }; EXPECT_EQ(squaredNorm(ivv), 3 * squaredNorm(iv3)); EXPECT_EQ(norm(ivv), sqrt(3.0*squaredNorm(iv3))); @@ -387,16 +401,16 @@ namespace xt EXPECT_EQ(sqrt(iv3 * iv3), iv3); EXPECT_EQ(sqrt(pow(iv3, 2)), iv3); - EXPECT_EQ(sum(iv3), SIZE == 3 ? 7 : 30); - EXPECT_EQ(sum(fv3), SIZE == 3 ? 7.2f : 29.8f); - EXPECT_EQ(prod(iv3), SIZE == 3 ? 8 : 3200); - EXPECT_EQ(prod(fv3), SIZE == 3 ? 10.368f : 3910.15f); + EXPECT_EQ(sum(iv3), 7); + EXPECT_EQ(sum(fv3), 7.2f); + EXPECT_EQ(prod(iv3), 8); + EXPECT_EQ(prod(fv3), 10.368f); EXPECT_TRUE(mathfunctions::isclose(mean(iv3), 7.0 / SIZE, 1e-15)); - float cumsumRef[] = { 1.2f, 3.6f, 7.2f, 12.0f, 20.1f, 29.8f }; + float cumsumRef[] = { 1.2f, 3.6f, 7.2f}; FV cs = cumsum(fv3), csr(cumsumRef); EXPECT_TRUE(isclose(cs, csr, 1e-6f)); - float cumprodRef[] = { 1.2f, 2.88f, 10.368f, 49.7664f, 403.108f, 3910.15f }; + float cumprodRef[] = { 1.2f, 2.88f, 10.368f}; FV cr = cumprod(fv3), crr(cumprodRef); EXPECT_TRUE(isclose(cr, crr, 1e-6f)); @@ -413,9 +427,9 @@ namespace xt TEST(xtiny, cross_product) { - EXPECT_EQ(cross(bv3, bv3), IV(0)); - EXPECT_EQ(cross(iv3, bv3), IV(0)); - EXPECT_TRUE(isclose(cross(fv3, fv3), FV(0.0), 1e-6f)); + EXPECT_EQ(cross(bv3, bv3), IV{0}); + EXPECT_EQ(cross(iv3, bv3), IV{0}); + EXPECT_TRUE(isclose(cross(fv3, fv3), FV{ 0.0f }, 1e-6f)); FV cr = cross(fv1, fv3), crr{ 1.2f, -2.4f, 1.2f }; EXPECT_TRUE(isclose(cr, crr, 1e-6f)); @@ -441,10 +455,10 @@ namespace xt EXPECT_TRUE((std::is_same::value)); int adata[] = { 4,5,6,7,8,9 }; - Array a{ adata }; + Array a(adata); EXPECT_EQ(a.ndim(), 2); EXPECT_EQ(a.size(), 6); - EXPECT_EQ(a.shape(), Index(2, 3)); + EXPECT_EQ(a.shape(), (Index{ 2, 3 })); int count = 0, i, j; Index idx; @@ -466,7 +480,7 @@ namespace xt } TinySymmetricView sym(a.data()); - EXPECT_EQ(sym.shape(), Index(3, 3)); + EXPECT_EQ(sym.shape(), (Index{ 3, 3 })); { std::string s = "{4, 5, 6,\n 5, 7, 8,\n 6, 8, 9}"; std::stringstream ss; @@ -515,6 +529,7 @@ namespace xt TEST(xtiny, runtime_size) { using A = TinyArray; + using V1 = TinyArray; EXPECT_TRUE(typeid(A) == typeid(TinyArray)); @@ -531,6 +546,20 @@ namespace xt EXPECT_TRUE(a < d); EXPECT_TRUE(e < a); EXPECT_EQ(e, (A{ 0,0,0 })); + + EXPECT_EQ(iv3, (A{ 1, 2, 4 })); + EXPECT_EQ(iv3, (A{ 1.1, 2.2, 4.4 })); + EXPECT_EQ(iv3, (A({ 1, 2, 4 }))); + EXPECT_EQ(iv3, (A({ 1.1, 2.2, 4.4 }))); + EXPECT_EQ(V1{1}, (A{ 1 })); + EXPECT_EQ(V1{1}, (A{ 1.1 })); + EXPECT_EQ(V1{1}, (A({ 1 }))); + EXPECT_EQ(V1{1}, (A({ 1.1 }))); + EXPECT_EQ(iv0, A(SIZE)); + EXPECT_EQ(iv0, A(tags::size = SIZE)); + EXPECT_EQ(iv1, A(SIZE, 1)); + EXPECT_EQ(iv1, A(tags::size = SIZE, 1)); + c.init(2, 4, 6); EXPECT_EQ(d, c); c.init({ 1,2,3 }); From 1ec55cad36cc5e7c42eb2ea246b31572393ccabc Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sat, 29 Jul 2017 15:33:51 +0200 Subject: [PATCH 05/27] switched to lower-case naming convention; refactored type inference --- include/xtensor/xconcepts.hpp | 204 +++++- include/xtensor/xtiny.hpp | 1284 +++++++++++++++------------------ test/test_xtiny.cpp | 54 +- 3 files changed, 779 insertions(+), 763 deletions(-) diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp index 21ec48a02..808ea5592 100644 --- a/include/xtensor/xconcepts.hpp +++ b/include/xtensor/xconcepts.hpp @@ -11,6 +11,12 @@ #include +/**********************************************************/ +/* */ +/* concept checking and type inference functionality */ +/* */ +/**********************************************************/ + namespace xt { @@ -23,42 +29,41 @@ namespace xt struct require_ok {}; template -using ConceptCheck = typename std::enable_if::type; +using concept_check = typename std::enable_if::type; -#define XTENSOR_REQUIRE typename Require = ConceptCheck +#define XTENSOR_REQUIRE typename Require = concept_check /**********************************************************/ /* */ -/* TinyArrayConcept */ +/* tiny_array_concept */ /* */ /**********************************************************/ -struct TinyArrayTag {}; +struct tiny_array_tag {}; - // TinyArrayConcept refers to TinyArrayBase and TinyArray. - // By default, 'ARRAY' fulfills the TinyArrayConcept if it is derived - // from TinyArrayTag. + // tiny_array_concept refers to tiny_array_base and tiny_array. + // By default, 'ARRAY' fulfills the tiny_array_concept if it is derived + // from tiny_array_tag. // - // Alternatively, one can partially specialize TinyArrayConcept. + // Alternatively, one can partially specialize tiny_array_concept. template -struct TinyArrayConcept +struct tiny_array_concept { - static const bool value = std::is_base_of::value; + static const bool value = std::is_base_of::value; }; - /**********************************************************/ /* */ -/* IteratorConcept */ +/* iterator_concept */ /* */ /**********************************************************/ // currently, we apply only the simple rule that class T - // must be a pointer or array or has an embedded typedef + // is either a pointer or array or has an embedded typedef // 'iterator_category'. More sophisticated checks should // be added when needed. template -struct IteratorConcept +struct iterator_concept { typedef typename std::decay::type V; @@ -73,6 +78,177 @@ struct IteratorConcept std::is_same::value; }; +/**********************************************************/ +/* */ +/* promote types */ +/* */ +/**********************************************************/ + + // result of arithmetic expressions + // (e.g. unsigned char * unsigned char => int) +template +using promote_t = decltype(*(typename std::decay::type*)0 * *(typename std::decay::type*)0); + + // result of algebraic expressions + // (e.g. sqrt(int) => double) +template +using real_promote_t = decltype(sqrt(*(typename std::decay::type*)0)); + + // replace 'bool' with 'uint8_t', keep everything else +template +using bool_promote_t = typename std::conditional::value, uint8_t, T>::type; + +/**********************************************************/ +/* */ +/* type inference for norm and squared norm */ +/* */ +/**********************************************************/ + +template +struct norm_traits; + +namespace detail { + +template ::value> +struct norm_of_scalar_impl; + +template +struct norm_of_scalar_impl +{ + static const bool value = false; + typedef void * norm_type; + typedef void * squared_norm_type; +}; + +template +struct norm_of_scalar_impl +{ + static const bool value = true; + typedef T norm_type; + typedef typename + std::conditional::value, + typename std::conditional= 4, + uint64_t, + uint32_t>::type, + T>::type + squared_norm_type; +}; + +template ::value, + bool floating = std::is_floating_point::value> +struct norm_of_array_elements_impl; + +template <> +struct norm_of_array_elements_impl +{ + typedef void * norm_type; + typedef void * squared_norm_type; +}; + +template +struct norm_of_array_elements_impl +{ + typedef typename norm_traits::norm_type norm_type; + typedef typename norm_traits::squared_norm_type squared_norm_type; +}; + +template +struct norm_of_array_elements_impl +{ + static_assert(!std::is_same::value, + "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); + + typedef double norm_type; + typedef uint64_t squared_norm_type; +}; + +template +struct norm_of_array_elements_impl +{ + typedef double norm_type; + typedef double squared_norm_type; +}; + +template <> +struct norm_of_array_elements_impl +{ + typedef long double norm_type; + typedef long double squared_norm_type; +}; + +template +struct norm_of_vector_impl +{ + static void * test(...); + + template + static typename U::value_type test(U*, typename U::value_type * = 0); + + typedef decltype(test((ARRAY*)0)) T; + + static const bool value = !std::is_same::value; + + typedef typename norm_of_array_elements_impl::norm_type norm_type; + typedef typename norm_of_array_elements_impl::squared_norm_type squared_norm_type; +}; + +} // namespace detail + + /* norm_traits implement the following default rules, which are + designed to minimize the possibility of overflow: + * T is an integer type: + norm_type is T itself, + squared_norm_type is 'uint32_t' (sizeof(T) < 4) or 'uint64_t' (otherwise) + * T is a floating-point type: + norm_type and squared_norm_type are T itself, + * T is a container of 'long double' elements: + norm_type and squared_norm_type are 'long double' + * T is a container of another floating-point type: + norm_type and squared_norm_type are 'double', + * T is a container of integer elements: + norm_type is 'double', + squared_norm_type is 'uint64_t' + * T is a container of some other type: + norm_type is the element's norm type, + squared_norm_type is the element's squared norm type + Containers are recognized by having an embedded typedef 'value_type'. + + To change the behavior for a particular case or extend it to cases + not covered here, simply specialize the norm_traits template. + */ +template +struct norm_traits +{ + using T = typename std::decay::type; + + static_assert(!std::is_same::value, + "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); + + typedef detail::norm_of_scalar_impl norm_of_scalar; + typedef detail::norm_of_vector_impl norm_of_vector; + + static const bool value = norm_of_scalar::value || norm_of_vector::value; + + static_assert(value, "norm_traits are undefined for type U."); + + typedef typename std::conditional::type + norm_type; + + typedef typename std::conditional::type + squared_norm_type; +}; + +template +using squared_norm_t = typename norm_traits::squared_norm_type; + +template +using norm_t = typename norm_traits::norm_type; + + } // namespace xt #endif // XCONCEPTS_HPP diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 1a45106b8..2e61dc9f2 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -50,10 +50,10 @@ struct UninitializedMemoryTraits }; template -class TinyArray; +class tiny_array; template -class TinyArrayView; +class tiny_array_view; /**********************************************************/ /* */ @@ -87,166 +87,6 @@ XTENSOR_DEFINE_MISSING_ABS(signed long long) #undef XTENSOR_DEFINE_MISSING_ABS - -template -using PromoteType = decltype((*((T1*)0)) * (*((T2*)0))); - -/////////////////////////////////////////////////////////////// -// BoolPromote - - // replace 'bool' with 'unsigned char' -template -using BoolPromote = typename std::conditional::value, unsigned char, T>::type; - -template -using RealPromoteType = decltype(sqrt(*((T*)0))); - -/////////////////////////////////////////////////////////////// -// NormTraits - -template -struct NormTraits; - -namespace detail { - -template ::value> -struct NormOfScalarImpl; - -template -struct NormOfScalarImpl -{ - static const bool value = false; - typedef void * NormType; - typedef void * SquaredNormType; -}; - -template -struct NormOfScalarImpl -{ - static const bool value = true; - typedef T NormType; - typedef typename - std::conditional::value, - typename std::conditional= 4, - uint64_t, - uint32_t>::type, - T>::type - SquaredNormType; -}; - -template ::value, - bool floating = std::is_floating_point::value> -struct NormOfArrayElementsImpl; - -template <> -struct NormOfArrayElementsImpl -{ - typedef void * NormType; - typedef void * SquaredNormType; -}; - -template -struct NormOfArrayElementsImpl -{ - typedef typename NormTraits::NormType NormType; - typedef typename NormTraits::SquaredNormType SquaredNormType; -}; - -template -struct NormOfArrayElementsImpl -{ - static_assert(!std::is_same::value, - "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); - - typedef double NormType; - typedef uint64_t SquaredNormType; -}; - -template -struct NormOfArrayElementsImpl -{ - typedef double NormType; - typedef double SquaredNormType; -}; - -template <> -struct NormOfArrayElementsImpl -{ - typedef long double NormType; - typedef long double SquaredNormType; -}; - -template -struct NormOfVectorImpl -{ - static void * test(...); - - template - static typename U::value_type test(U*, typename U::value_type * = 0); - - typedef decltype(test((ARRAY*)0)) T; - - static const bool value = !std::is_same::value; - - typedef typename NormOfArrayElementsImpl::NormType NormType; - typedef typename NormOfArrayElementsImpl::SquaredNormType SquaredNormType; -}; - - -} // namespace detail - - /* NormTraits implement the following default rules, which are - designed to minimize the possibility of overflow: - * T is an integer type: - NormType is T itself, - SquaredNormType is 'uint32_t' (sizeof(T) < 4) or 'uint64_t' (otherwise) - * T is a floating-point type: - NormType and SquaredNormType are T itself, - * T is a container of 'long double' elements: - NormType and SquaredNormType are 'long double' - * T is a container of another floating-point type: - NormType and SquaredNormType are 'double', - * T is a container of integer elements: - NormType is 'double', - SquaredNormType is 'uint64_t' - * T is a container of some other type: - NormType is the element's norm type, - SquaredNormType is the element's squared norm type - Containers are recognized by having an embedded typedef 'value_type'. - - To change the behavior for a particular case or extend it to cases - not covered here, simply specialize the NormTraits template. - */ -template -struct NormTraits -{ - static_assert(!std::is_same::value, - "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); - - typedef detail::NormOfScalarImpl NormOfScalar; - typedef detail::NormOfVectorImpl NormOfVector; - - static const bool value = NormOfScalar::value || NormOfVector::value; - - static_assert(value, "NormTraits are undefined for type T."); - - typedef typename std::conditional::type - NormType; - - typedef typename std::conditional::type - SquaredNormType; -}; - -template -using SquaredNormType = typename NormTraits::SquaredNormType; - -template -using NormType = typename NormTraits::NormType; - namespace mathfunctions { using std::abs; @@ -320,10 +160,10 @@ using std::pow; template inline -std::enable_if_t >::value, bool> +std::enable_if_t >::value, bool> isclose(V1 v1, V2 v2, double rtol = 1e-05, double atol = 1e-08) { - using P = PromoteType; + using P = promote_t; return abs(v1-v2) <= (atol + rtol * std::max(abs(static_cast

(v1)), abs(static_cast

(v2)))); } @@ -336,7 +176,7 @@ isclose(V1 v1, V2 v2, double rtol = 1e-05, double atol = 1e-08) */ template ::value> > -inline PromoteType +inline promote_t sq(T t) { return t*t; @@ -442,7 +282,7 @@ XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) // scalars and vectors alike #define XTENSOR_DEFINE_SCALAR_DOT(T) \ - inline PromoteType dot(T l, T r) { return l*r; } + inline promote_t dot(T l, T r) { return l*r; } XTENSOR_DEFINE_SCALAR_DOT(unsigned char) XTENSOR_DEFINE_SCALAR_DOT(unsigned short) @@ -611,7 +451,7 @@ using mathfunctions::sq; /**********************************************************/ template -inline SquaredNormType > +inline squared_norm_t > squaredNorm(std::complex const & t) { return sq(t.real()) + sq(t.imag()); @@ -639,10 +479,10 @@ norm(T const & t) -> decltype(sqrt(squaredNorm(t))) } #define XTENSOR_DEFINE_NORM(T) \ - inline SquaredNormType squaredNorm(T t) { return sq(t); } \ - inline NormType norm(T t) { return abs(t); } \ - inline SquaredNormType sizeDividedSquaredNorm(T t) { return sq(t); } \ - inline NormType sizeDividedNorm(T t) { return abs(t); } + inline squared_norm_t squaredNorm(T t) { return sq(t); } \ + inline norm_t norm(T t) { return abs(t); } \ + inline squared_norm_t sizeDividedSquaredNorm(T t) { return sq(t); } \ + inline norm_t sizeDividedNorm(T t) { return abs(t); } XTENSOR_DEFINE_NORM(signed char) XTENSOR_DEFINE_NORM(unsigned char) @@ -710,7 +550,7 @@ struct TinyShapeImpl; template struct TinyShapeImpl { - static_assert(N >= 0, "TinyArrayBase(): array must have non-negative shape."); + static_assert(N >= 0, "tiny_array_base(): array must have non-negative shape."); using NextType = TinyShapeImpl; static const ArrayIndex level = LEVEL; @@ -733,7 +573,7 @@ struct TinyShapeImpl template struct TinyShapeImpl { - static_assert(N >= 0, "TinyArrayBase(): array must have non-negative shape."); + static_assert(N >= 0, "tiny_array_base(): array must have non-negative shape."); static const ArrayIndex level = LEVEL; static const ArrayIndex stride = 1; static const ArrayIndex total_size = N; @@ -794,27 +634,27 @@ struct TinyArrayIsStatic /********************************************************/ /* */ -/* TinyArrayBase */ +/* tiny_array_base */ /* */ /********************************************************/ /** \brief Base class for fixed size vectors and matrices. This class contains functionality shared by - \ref TinyArray and \ref TinyArrayView, and enables these classes + \ref tiny_array and \ref tiny_array_view, and enables these classes to be freely mixed within expressions. It is typically not used directly. \#include \
Namespace: vigra **/ template -class TinyArrayBase -: public TinyArrayTag +class tiny_array_base +: public tiny_array_tag { protected: using ShapeHelper = TinyShapeImpl<0, N...>; - static const bool derived_is_array = std::is_same >::value; + static const bool derived_is_array = std::is_same >::value; using data_array_type = typename std::conditional::type; @@ -833,7 +673,7 @@ class TinyArrayBase } template ::value>> + XTENSOR_REQUIRE::value>> void initImpl(ITERATOR i) { for(ArrayIndex k=0; k < static_size; ++k, ++i) @@ -843,7 +683,7 @@ class TinyArrayBase public: template - using AsType = TinyArray; + using as_type = tiny_array; using value_type = VALUETYPE; using const_value_type = typename std::add_const::type; @@ -857,7 +697,7 @@ class TinyArrayBase using const_reverse_iterator = std::reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = TinyArray; + using index_type = tiny_array; static constexpr ArrayIndex static_ndim = sizeof...(N); static constexpr ArrayIndex static_size = ShapeHelper::total_size; @@ -866,26 +706,26 @@ class TinyArrayBase // constructors - constexpr TinyArrayBase(TinyArrayBase const &) = default; + constexpr tiny_array_base(tiny_array_base const &) = default; protected: - TinyArrayBase(SkipInitialization) + tiny_array_base(SkipInitialization) {} - // constructors to be used by TinyArray + // constructors to be used by tiny_array template - TinyArrayBase(TinyArrayBase const & other) + tiny_array_base(tiny_array_base const & other) { xtensor_precondition(size() == other.size(), - "TinyArrayBase(): shape mismatch."); + "tiny_array_base(): shape mismatch."); for(int i=0; i(other[i]); } // constructor for zero or one argument - explicit TinyArrayBase(value_type v = value_type()) + explicit tiny_array_base(value_type v = value_type()) { for(int i=0; i - // constexpr TinyArrayBase(value_type v0, value_type v1, V ... v) + // constexpr tiny_array_base(value_type v0, value_type v1, V ... v) // : data_{VALUETYPE(v0), VALUETYPE(v1), VALUETYPE(v)...} // { // static_assert(sizeof...(V)+2 == static_size, - // "TinyArrayBase(): number of constructor arguments contradicts size()."); + // "tiny_array_base(): number of constructor arguments contradicts size()."); // } template - explicit TinyArrayBase(U const * u) + explicit tiny_array_base(U const * u) { for(int i=0; i(u[i]); } template - TinyArrayBase(U const * u, ReverseCopyTag) + tiny_array_base(U const * u, ReverseCopyTag) { for(int i=0; i(u[static_size-1-i]); } - // for compatibility with TinyArrayBase<..., runtime_size> + // for compatibility with tiny_array_base<..., runtime_size> template - TinyArrayBase(U const * u, U const * /* end */, ReverseCopyTag) - : TinyArrayBase(u, ReverseCopy) + tiny_array_base(U const * u, U const * /* end */, ReverseCopyTag) + : tiny_array_base(u, ReverseCopy) {} public: // assignment - TinyArrayBase & operator=(TinyArrayBase const &) = default; + tiny_array_base & operator=(tiny_array_base const &) = default; - TinyArrayBase & operator=(value_type v) + tiny_array_base & operator=(value_type v) { for(int i=0; i - TinyArrayBase & operator=(TinyArrayBase const & other) + tiny_array_base & operator=(tiny_array_base const & other) { for(int i=0; i(other[i]); @@ -949,10 +789,10 @@ class TinyArrayBase } template - TinyArrayBase & operator=(TinyArrayBase const & other) + tiny_array_base & operator=(tiny_array_base const & other) { xtensor_precondition(size() == other.size(), - "TinyArrayBase::operator=(): size mismatch."); + "tiny_array_base::operator=(): size mismatch."); for(int i=0; i(other[i]); return *this; @@ -960,21 +800,21 @@ class TinyArrayBase template constexpr bool - sameShape(TinyArrayBase const & other) const + sameShape(tiny_array_base const & other) const { return false; } template constexpr bool - sameShape(TinyArrayBase const & other) const + sameShape(tiny_array_base const & other) const { return true; } template bool - sameShape(TinyArrayBase const & other) const + sameShape(tiny_array_base const & other) const { return sizeof...(N) == 1 && size() == other.size(); } @@ -990,7 +830,7 @@ class TinyArrayBase DERIVED & init(value_type v0, value_type v1, V... v) { static_assert(sizeof...(V)+2 == static_size, - "TinyArrayBase::init(): wrong number of arguments."); + "tiny_array_base::init(): wrong number of arguments."); initImpl<0>(v0, v1, v...); return static_cast(*this); } @@ -1021,14 +861,14 @@ class TinyArrayBase reference at(ArrayIndex i) { if(i < 0 || i >= static_size) - throw std::out_of_range("TinyArrayBase::at()"); + throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } const_reference at(ArrayIndex i) const { if(i < 0 || i >= static_size) - throw std::out_of_range("TinyArrayBase::at()"); + throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } @@ -1076,7 +916,7 @@ class TinyArrayBase reference operator()(V...v) { static_assert(sizeof...(V) == static_ndim, - "TinyArrayBase::operator(): wrong number of arguments."); + "tiny_array_base::operator(): wrong number of arguments."); return data_[ShapeHelper::offset(v...)]; } @@ -1084,7 +924,7 @@ class TinyArrayBase constexpr const_reference operator()(V...v) const { static_assert(sizeof...(V) == static_ndim, - "TinyArrayBase::operator(): wrong number of arguments."); + "tiny_array_base::operator(): wrong number of arguments."); return data_[ShapeHelper::offset(v...)]; } @@ -1093,33 +933,33 @@ class TinyArrayBase Only available if static_ndim == 1. */ template - TinyArrayView + tiny_array_view subarray() const { static_assert(sizeof...(N) == 1, - "TinyArrayBase::subarray(): array must be 1-dimensional."); + "tiny_array_base::subarray(): array must be 1-dimensional."); static_assert(FROM >= 0 && FROM < TO && TO <= static_size, - "TinyArrayBase::subarray(): range out of bounds."); - return TinyArrayView(const_cast(data_)+FROM); + "tiny_array_base::subarray(): range out of bounds."); + return tiny_array_view(const_cast(data_)+FROM); } - TinyArrayView + tiny_array_view subarray(ArrayIndex FROM, ArrayIndex TO) const { xtensor_precondition(FROM >= 0 && FROM < TO && TO <= static_size, - "TinyArrayBase::subarray(): range out of bounds."); - return TinyArrayView(TO-FROM, const_cast(data_)+FROM); + "tiny_array_base::subarray(): range out of bounds."); + return tiny_array_view(TO-FROM, const_cast(data_)+FROM); } template - TinyArray + tiny_array erase(ArrayIndex m) const { static_assert(sizeof...(N) == 1, - "TinyArrayBase::erase(): array must be 1-dimensional."); - xtensor_precondition(m >= 0 && m < static_size, "TinyArray::erase(): " + "tiny_array_base::erase(): array must be 1-dimensional."); + xtensor_precondition(m >= 0 && m < static_size, "tiny_array::erase(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); - TinyArray res(static_size-1, DontInit); + tiny_array res(static_size-1, DontInit); for(int k=0; k - TinyArray + tiny_array pop_front() const { static_assert(sizeof...(N) == 1, - "TinyArrayBase::pop_front(): array must be 1-dimensional."); + "tiny_array_base::pop_front(): array must be 1-dimensional."); return erase(0); } template - TinyArray + tiny_array pop_back() const { static_assert(sizeof...(N) == 1, - "TinyArrayBase::pop_back(): array must be 1-dimensional."); + "tiny_array_base::pop_back(): array must be 1-dimensional."); return erase(size()-1); } template - TinyArray + tiny_array insert(ArrayIndex m, value_type v) const { static_assert(sizeof...(N) == 1, - "TinyArrayBase::insert(): array must be 1-dimensional."); - xtensor_precondition(m >= 0 && m <= static_size, "TinyArray::insert(): " + "tiny_array_base::insert(): array must be 1-dimensional."); + xtensor_precondition(m >= 0 && m <= static_size, "tiny_array::insert(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); - TinyArray res(DontInit); + tiny_array res(DontInit); for(int k=0; k inline - TinyArray - transpose(TinyArrayBase const & permutation) const + tiny_array + transpose(tiny_array_base const & permutation) const { static_assert(sizeof...(N) == 1, - "TinyArray::transpose(): only allowed for 1-dimensional arrays."); + "tiny_array::transpose(): only allowed for 1-dimensional arrays."); static_assert(M == static_size || M == runtime_size, - "TinyArray::transpose(): size mismatch."); + "tiny_array::transpose(): size mismatch."); XTENSOR_ASSERT_RUNTIME_SIZE(M, size() == 0 || size() == permutation.size(), - "TinyArray::transpose(): size mismatch."); - TinyArray res(DontInit); + "tiny_array::transpose(): size mismatch."); + tiny_array res(DontInit); for(int k=0; k < size(); ++k) { XTENSOR_ASSERT_MSG(permutation[k] >= 0 && permutation[k] < size(), @@ -1213,7 +1053,7 @@ class TinyArrayBase constexpr index_type shape() const { return index_type{ N... }; } constexpr ArrayIndex ndim() const { return static_ndim; } - TinyArrayBase & reverse() + tiny_array_base & reverse() { ArrayIndex i=0, j=size()-1; while(i < j) @@ -1221,7 +1061,7 @@ class TinyArrayBase return *this; } - void swap(TinyArrayBase & other) + void swap(tiny_array_base & other) { for(int k=0; k - void swap(TinyArrayBase & other) + void swap(tiny_array_base & other) { for(int k=0; k t = data_[k]; + promote_t t = data_[k]; data_[k] = static_cast(other[k]); other[k] = static_cast(t); } @@ -1243,10 +1083,10 @@ class TinyArrayBase /// factory function for fixed-size unit matrix template static inline - TinyArray + tiny_array eye() { - TinyArray res; + tiny_array res; for(int k=0; k static inline - TinyArray + tiny_array unitVector(ArrayIndex k) { - TinyArray res; + tiny_array res; res(k) = 1; return res; } /// factory function for the k-th unit vector - // (for compatibility with TinyArray<..., runtime_size>) + // (for compatibility with tiny_array<..., runtime_size>) static inline - TinyArray + tiny_array unitVector(tags::SizeProxy const & size, ArrayIndex k) { XTENSOR_ASSERT_MSG(size.value == static_size, - "TinyArray::unitVector(): size mismatch."); - TinyArray res; + "tiny_array::unitVector(): size mismatch."); + tiny_array res; res(k) = 1; return res; } /// factory function for fixed-size linear sequence starting at start with stepsize step static inline - TinyArray + tiny_array linearSequence(value_type start = value_type(), value_type step = value_type(1)) { - TinyArray res(DontInit); + tiny_array res(DontInit); for(int k=0; k < static_size; ++k, start += step) res[k] = start; return res; @@ -1289,11 +1129,11 @@ class TinyArrayBase /// factory function for fixed-size linear sequence ending at end-1 static inline - TinyArray + tiny_array range(value_type end) { value_type start = end - static_size; - TinyArray res(DontInit); + tiny_array res(DontInit); for(int k=0; k < static_size; ++k, ++start) res[k] = start; return res; @@ -1305,34 +1145,34 @@ class TinyArrayBase /********************************************************/ /* */ -/* TinyArrayBase output */ +/* tiny_array_base output */ /* */ /********************************************************/ template -std::ostream & operator<<(std::ostream & o, TinyArrayBase const & v) +std::ostream & operator<<(std::ostream & o, tiny_array_base const & v) { o << "{"; if(v.size() > 0) - o << PromoteType(v[0]); + o << promote_t(v[0]); for(int i=1; i < v.size(); ++i) - o << ", " << PromoteType(v[i]); + o << ", " << promote_t(v[i]); o << "}"; return o; } template -std::ostream & operator<<(std::ostream & o, TinyArrayBase const & v) +std::ostream & operator<<(std::ostream & o, tiny_array_base const & v) { o << "{"; for(int i=0; N2>0 && i 0) o << ",\n "; - o << PromoteType(v(i,0)); + o << promote_t(v(i,0)); for(int j=1; j(v(i, j)); + o << ", " << promote_t(v(i, j)); } } o << "}"; @@ -1341,27 +1181,27 @@ std::ostream & operator<<(std::ostream & o, TinyArrayBase co /********************************************************/ /* */ -/* TinyArrayBase<..., runtime_size> */ +/* tiny_array_base<..., runtime_size> */ /* */ /********************************************************/ -/** \brief Specialization of TinyArrayBase for dynamic arrays. +/** \brief Specialization of tiny_array_base for dynamic arrays. This class contains functionality shared by - \ref TinyArray and \ref TinyArrayView, and enables these classes + \ref tiny_array and \ref tiny_array_view, and enables these classes to be freely mixed within expressions. It is typically not used directly. \#include \
Namespace: vigra **/ template -class TinyArrayBase -: public TinyArrayTag +class tiny_array_base +: public tiny_array_tag { public: template - using AsType = TinyArray; + using AsType = tiny_array; using value_type = VALUETYPE; using const_value_type = typename std::add_const::type; @@ -1399,36 +1239,36 @@ class TinyArrayBase public: - TinyArrayBase(ArrayIndex size=0, pointer data=0) + tiny_array_base(ArrayIndex size=0, pointer data=0) : size_(size) , data_(data) {} - TinyArrayBase(TinyArrayBase const &) = default; + tiny_array_base(tiny_array_base const &) = default; // assignment - TinyArrayBase & operator=(value_type v) + tiny_array_base & operator=(value_type v) { for(int i=0; i - TinyArrayBase & operator=(TinyArrayBase const & other) + tiny_array_base & operator=(tiny_array_base const & other) { xtensor_precondition(size_ == other.size(), - "TinyArrayBase::operator=(): size mismatch."); + "tiny_array_base::operator=(): size mismatch."); for(int i=0; i(other[i]); return *this; @@ -1436,14 +1276,14 @@ class TinyArrayBase template bool - sameShape(TinyArrayBase const & other) const + sameShape(tiny_array_base const & other) const { return sizeof...(M) == 1 && size() == other.size();; } template bool - sameShape(TinyArrayBase const & other) const + sameShape(tiny_array_base const & other) const { return size() == other.size(); } @@ -1459,7 +1299,7 @@ class TinyArrayBase DERIVED & init(value_type v0, value_type v1, V... v) { xtensor_precondition(sizeof...(V)+2 == size_, - "TinyArrayBase::init(): wrong number of arguments."); + "tiny_array_base::init(): wrong number of arguments."); initImpl<0>(v0, v1, v...); return static_cast(*this); } @@ -1496,14 +1336,14 @@ class TinyArrayBase reference at(ArrayIndex i) { if(i < 0 || i >= size_) - throw std::out_of_range("TinyArrayBase::at()"); + throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } const_reference at(ArrayIndex i) const { if(i < 0 || i >= size_) - throw std::out_of_range("TinyArrayBase::at()"); + throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } @@ -1511,34 +1351,34 @@ class TinyArrayBase The bounds must fullfill 0 <= FROM < TO <= size_. */ template - TinyArrayView + tiny_array_view subarray() const { static_assert(FROM >= 0 && FROM < TO, - "TinyArrayBase::subarray(): range out of bounds."); + "tiny_array_base::subarray(): range out of bounds."); xtensor_precondition(TO <= size_, - "TinyArrayBase::subarray(): range out of bounds."); - return TinyArrayView(data_+FROM); + "tiny_array_base::subarray(): range out of bounds."); + return tiny_array_view(data_+FROM); } /** Get a view to the subarray with length (TO-FROM) starting at FROM. The bounds must fullfill 0 <= FROM < TO <= size_. */ - TinyArrayView + tiny_array_view subarray(ArrayIndex FROM, ArrayIndex TO) const { xtensor_precondition(FROM >= 0 && FROM < TO && TO <= size_, - "TinyArrayBase::subarray(): range out of bounds."); - return TinyArrayView(TO-FROM, const_cast(data_)+FROM); + "tiny_array_base::subarray(): range out of bounds."); + return tiny_array_view(TO-FROM, const_cast(data_)+FROM); } - TinyArray + tiny_array erase(ArrayIndex m) const { - xtensor_precondition(m >= 0 && m < size(), "TinyArray::erase(): " + xtensor_precondition(m >= 0 && m < size(), "tiny_array::erase(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); - TinyArray res(size()-1, DontInit); + tiny_array res(size()-1, DontInit); for(int k=0; k return res; } - TinyArray + tiny_array pop_front() const { return erase(0); } - TinyArray + tiny_array pop_back() const { return erase(size()-1); } - TinyArray + tiny_array insert(ArrayIndex m, value_type v) const { - xtensor_precondition(m >= 0 && m <= size(), "TinyArray::insert(): " + xtensor_precondition(m >= 0 && m <= size(), "tiny_array::insert(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); - TinyArray res(size()+1, DontInit); + tiny_array res(size()+1, DontInit); for(int k=0; k template inline - TinyArray - transpose(TinyArrayBase const & permutation) const + tiny_array + transpose(tiny_array_base const & permutation) const { xtensor_precondition(size() == 0 || size() == permutation.size(), - "TinyArray::transpose(): size mismatch."); - TinyArray res(size(), DontInit); + "tiny_array::transpose(): size mismatch."); + tiny_array res(size(), DontInit); for(ArrayIndex k=0; k < size(); ++k) { XTENSOR_ASSERT_MSG(permutation[k] >= 0 && permutation[k] < size(), @@ -1618,7 +1458,7 @@ class TinyArrayBase ArrayIndex max_size() const { return size_; } ArrayIndex ndim() const { return static_ndim; } - TinyArrayBase & reverse() + tiny_array_base & reverse() { ArrayIndex i=0, j=size_-1; while(i < j) @@ -1626,7 +1466,7 @@ class TinyArrayBase return *this; } - void swap(TinyArrayBase & other) + void swap(tiny_array_base & other) { xt::swap(size_, other.size_); xt::swap(data_, other.data_); @@ -1634,10 +1474,10 @@ class TinyArrayBase /// factory function for the fixed-size k-th unit vector static inline - TinyArray + tiny_array unitVector(tags::SizeProxy const & size, ArrayIndex k) { - TinyArray res(size.value); + tiny_array res(size.value); res[k] = 1; return res; } @@ -1645,17 +1485,17 @@ class TinyArrayBase /// factory function for a linear sequence from begin to end /// (exclusive) with stepsize step static inline - TinyArray + tiny_array range(value_type begin, value_type end, value_type step = value_type(1)) { xtensor_precondition(step != 0, - "TinyArray::range(): step must be non-zero."); + "tiny_array::range(): step must be non-zero."); xtensor_precondition((step > 0 && begin <= end) || (step < 0 && begin >= end), - "TinyArray::range(): sign mismatch between step and (end-begin)."); + "tiny_array::range(): sign mismatch between step and (end-begin)."); ArrayIndex size = mathfunctions::floor((abs(end-begin+step)-1)/abs(step)); - TinyArray res(size, DontInit); + tiny_array res(size, DontInit); for(ArrayIndex k=0; k < size; ++k, begin += step) res[k] = begin; return res; @@ -1664,12 +1504,12 @@ class TinyArrayBase /// factory function for a linear sequence from 0 to end /// (exclusive) with stepsize 1 static inline - TinyArray + tiny_array range(value_type end) { xtensor_precondition(end >= 0, - "TinyArray::range(): end must be non-negative."); - TinyArray res(end, DontInit); + "tiny_array::range(): end must be non-negative."); + tiny_array res(end, DontInit); auto begin = value_type(); for(ArrayIndex k=0; k < res.size(); ++k, ++begin) res[k] = begin; @@ -1683,7 +1523,7 @@ class TinyArrayBase /********************************************************/ /* */ -/* TinyArray */ +/* tiny_array */ /* */ /********************************************************/ @@ -1693,7 +1533,7 @@ class TinyArrayBase This class contains an array of the specified VALUETYPE with (possibly multi-dimensional) shape given by the sequence ArrayIndex ... N. The interface conforms to STL vector, except that there are no functions - that change the size of a TinyArray. + that change the size of a tiny_array. \ref TinyArrayOperators "Arithmetic operations" on TinyArrays are defined as component-wise applications of these @@ -1701,51 +1541,51 @@ class TinyArrayBase See also:

    -
  • \ref vigra::TinyArrayBase -
  • \ref vigra::TinyArrayView +
  • \ref vigra::tiny_array_base +
  • \ref vigra::tiny_array_view
  • \ref TinyArrayOperators
- \#include \
+ \#include \
Namespace: vigra **/ template -class TinyArray -: public TinyArrayBase, M, N...> +class tiny_array +: public tiny_array_base, M, N...> { public: - using base_type = TinyArrayBase, M, N...>; + using base_type = tiny_array_base, M, N...>; typedef typename base_type::value_type value_type; static const ArrayIndex static_ndim = base_type::static_ndim; static const ArrayIndex static_size = base_type::static_size; explicit constexpr - TinyArray() + tiny_array() : base_type(value_type()) {} explicit - TinyArray(SkipInitialization) + tiny_array(SkipInitialization) : base_type(DontInit) {} // This constructor would allow construction with round brackets, e.g.: - // TinyArray a(2); + // tiny_array a(2); // However, this may lead to bugs when fixed-size arrays are mixed with // runtime_size arrays, where - // TinyArray a(2); + // tiny_array a(2); // constructs an array of length 2 with initial value 0. To avoid such bugs, // construction is restricted to curly braces: - // TinyArray a{2}; + // tiny_array a{2}; // // template - // constexpr TinyArray(value_type v0, V... v) + // constexpr tiny_array(value_type v0, V... v) // : base_type(v0, v...) // {} template - TinyArray(std::initializer_list v) + tiny_array(std::initializer_list v) : base_type(DontInit) { if(v.size() == 1) @@ -1754,44 +1594,44 @@ class TinyArray base_type::initImpl(v.begin()); else xtensor_precondition(false, - "TinyArray(std::initializer_list): wrong initialization size."); + "tiny_array(std::initializer_list): wrong initialization size."); } - // for compatibility with TinyArray + // for compatibility with tiny_array explicit - TinyArray(tags::SizeProxy const & size, + tiny_array(tags::SizeProxy const & size, value_type const & v = value_type()) : base_type(v) { XTENSOR_ASSERT_MSG(size.value == static_size, - "TinyArray(size): size argument conflicts with array length."); + "tiny_array(size): size argument conflicts with array length."); } - // for compatibility with TinyArray - TinyArray(tags::SizeProxy const & size, SkipInitialization) + // for compatibility with tiny_array + tiny_array(tags::SizeProxy const & size, SkipInitialization) : base_type(DontInit) { XTENSOR_ASSERT_MSG(size.value == static_size, - "TinyArray(size): size argument conflicts with array length."); + "tiny_array(size): size argument conflicts with array length."); } - // for compatibility with TinyArray - TinyArray(ArrayIndex size, SkipInitialization) + // for compatibility with tiny_array + tiny_array(ArrayIndex size, SkipInitialization) : base_type(DontInit) { XTENSOR_ASSERT_MSG(size == static_size, - "TinyArray(size): size argument conflicts with array length."); + "tiny_array(size): size argument conflicts with array length."); } - constexpr TinyArray(TinyArray const &) = default; + constexpr tiny_array(tiny_array const &) = default; template - TinyArray(TinyArrayBase const & other) + tiny_array(tiny_array_base const & other) : base_type(other) {} template - TinyArray(TinyArrayBase const & other) + tiny_array(tiny_array_base const & other) : base_type(DontInit) { if(other.size() == 0) @@ -1801,61 +1641,61 @@ class TinyArray else if(this->size() != 0) { xtensor_precondition(this->size() == other.size(), - "TinyArray(): shape mismatch."); + "tiny_array(): shape mismatch."); this->initImpl(other.begin()); } } - explicit TinyArray(value_type const (&u)[1]) + explicit tiny_array(value_type const (&u)[1]) : base_type(*u) {} template - explicit TinyArray(U const (&u)[1]) + explicit tiny_array(U const (&u)[1]) : base_type(static_cast(*u)) {} template > - explicit TinyArray(U const (&u)[static_size]) + explicit tiny_array(U const (&u)[static_size]) : base_type(u) {} template ::value> > - explicit TinyArray(U u, U end = U()) + XTENSOR_REQUIRE::value> > + explicit tiny_array(U u, U end = U()) : base_type(u) {} template ::value> > - TinyArray(U u, ReverseCopyTag) + XTENSOR_REQUIRE::value> > + tiny_array(U u, ReverseCopyTag) : base_type(u, ReverseCopy) {} - // for compatibility with TinyArray<..., runtime_size> + // for compatibility with tiny_array<..., runtime_size> template ::value> > - TinyArray(U u, U end, ReverseCopyTag) + XTENSOR_REQUIRE::value> > + tiny_array(U u, U end, ReverseCopyTag) : base_type(u, ReverseCopy) {} - TinyArray & operator=(TinyArray const &) = default; + tiny_array & operator=(tiny_array const &) = default; - TinyArray & operator=(value_type v) + tiny_array & operator=(value_type v) { base_type::operator=(v); return *this; } - TinyArray & operator=(value_type const (&v)[static_size]) + tiny_array & operator=(value_type const (&v)[static_size]) { base_type::operator=(v); return *this; } template - TinyArray & operator=(TinyArrayBase const & other) + tiny_array & operator=(tiny_array_base const & other) { base_type::operator=(other); return *this; @@ -1869,24 +1709,24 @@ class TinyArray }; template -struct UninitializedMemoryTraits> +struct UninitializedMemoryTraits> { static const bool value = UninitializedMemoryTraits::value; }; /********************************************************/ /* */ -/* TinyArray<..., runtime_size> */ +/* tiny_array<..., runtime_size> */ /* */ /********************************************************/ -/** \brief Specialization of TinyArray for dynamic arrays. +/** \brief Specialization of tiny_array for dynamic arrays. \ingroup RangesAndPoints This class contains an array of the specified VALUETYPE with size specified at runtim. The interface conforms to STL vector, except that there are no functions - that change the size of a TinyArray. + that change the size of a tiny_array. \ref TinyArrayOperators "Arithmetic operations" on TinyArrays are defined as component-wise applications of these @@ -1894,29 +1734,29 @@ struct UninitializedMemoryTraits> See also:
    -
  • \ref vigra::TinyArrayBase -
  • \ref vigra::TinyArrayView +
  • \ref vigra::tiny_array_base +
  • \ref vigra::tiny_array_view
  • \ref TinyArrayOperators
- \#include \
+ \#include \
Namespace: vigra **/ template -class TinyArray -: public TinyArrayBase, runtime_size> +class tiny_array +: public tiny_array_base, runtime_size> { public: - using base_type = TinyArrayBase, runtime_size>; + using base_type = tiny_array_base, runtime_size>; using value_type = VALUETYPE; - TinyArray() + tiny_array() : base_type() {} explicit - TinyArray(ArrayIndex size, + tiny_array(ArrayIndex size, value_type const & initial = value_type()) : base_type(size) { @@ -1925,12 +1765,12 @@ class TinyArray } explicit - TinyArray(tags::SizeProxy const & size, + tiny_array(tags::SizeProxy const & size, value_type const & initial = value_type()) - : TinyArray(size.value, initial) + : tiny_array(size.value, initial) {} - TinyArray(ArrayIndex size, SkipInitialization) + tiny_array(ArrayIndex size, SkipInitialization) : base_type(size) { this->data_ = alloc_.allocate(this->size_); @@ -1938,27 +1778,27 @@ class TinyArray std::uninitialized_fill(this->begin(), this->end(), value_type()); } - TinyArray(TinyArray const & rhs ) + tiny_array(tiny_array const & rhs ) : base_type(rhs.size()) { this->data_ = alloc_.allocate(this->size_); std::uninitialized_copy(rhs.begin(), rhs.end(), this->begin()); } - TinyArray(TinyArray && rhs) + tiny_array(tiny_array && rhs) : base_type() { this->swap(rhs); } template - TinyArray(TinyArrayBase const & other) - : TinyArray(other.begin(), other.end()) + tiny_array(tiny_array_base const & other) + : tiny_array(other.begin(), other.end()) {} template ::value> > - TinyArray(U begin, U end) + XTENSOR_REQUIRE::value> > + tiny_array(U begin, U end) : base_type(std::distance(begin, end)) { this->data_ = alloc_.allocate(this->size_); @@ -1967,8 +1807,8 @@ class TinyArray } template ::value> > - TinyArray(U begin, U end, ReverseCopyTag) + XTENSOR_REQUIRE::value> > + tiny_array(U begin, U end, ReverseCopyTag) : base_type(std::distance(begin, end)) { this->data_ = alloc_.allocate(this->size_); @@ -1977,22 +1817,22 @@ class TinyArray } template - TinyArray(const U (&u)[SIZE]) - : TinyArray(u, u+SIZE) + tiny_array(const U (&u)[SIZE]) + : tiny_array(u, u+SIZE) {} template - TinyArray(std::initializer_list rhs) - : TinyArray(rhs.begin(), rhs.end()) + tiny_array(std::initializer_list rhs) + : tiny_array(rhs.begin(), rhs.end()) {} - TinyArray & operator=(value_type const & v) + tiny_array & operator=(value_type const & v) { base_type::operator=(v); return *this; } - TinyArray & operator=(TinyArray && rhs) + tiny_array & operator=(tiny_array && rhs) { if(this->size_ != rhs.size()) rhs.swap(*this); @@ -2001,28 +1841,28 @@ class TinyArray return *this; } - TinyArray & operator=(TinyArray const & rhs) + tiny_array & operator=(tiny_array const & rhs) { if(this == &rhs) return *this; if(this->size_ != rhs.size()) - TinyArray(rhs).swap(*this); + tiny_array(rhs).swap(*this); else base_type::operator=(rhs); return *this; } template - TinyArray & operator=(TinyArrayBase const & rhs) + tiny_array & operator=(tiny_array_base const & rhs) { if(this->size_ == 0 || rhs.size() == 0) - TinyArray(rhs).swap(*this); + tiny_array(rhs).swap(*this); else base_type::operator=(rhs); return *this; } - ~TinyArray() + ~tiny_array() { if(!base_type::may_use_uninitialized_memory) { @@ -2033,7 +1873,7 @@ class TinyArray } #if 0 - // FIXME: hacks to use TinyArray as shape in xtensor + // FIXME: hacks to use tiny_array as shape in xtensor using base_type::erase; void erase(base_type::pointer p) @@ -2054,12 +1894,12 @@ class TinyArray } template - TinyArray(std::vector const & rhs) - : TinyArray(rhs.cbegin(), rhs.cend()) + tiny_array(std::vector const & rhs) + : tiny_array(rhs.cbegin(), rhs.cend()) {} template - TinyArray & operator=(std::vector const & rhs) + tiny_array & operator=(std::vector const & rhs) { resize(rhs.size()); for(int k=0; k < this->size_; ++k) @@ -2087,7 +1927,7 @@ class TinyArray template -bool operator==(std::vector const & l, TinyArray const & r) +bool operator==(std::vector const & l, tiny_array const & r) { if((int)l.size() != r.size()) return false; @@ -2099,7 +1939,7 @@ bool operator==(std::vector const & l, TinyArray const & r) template -struct UninitializedMemoryTraits> +struct UninitializedMemoryTraits> { static const bool value = false; }; @@ -2108,7 +1948,7 @@ struct UninitializedMemoryTraits> /********************************************************/ /* */ -/* TinyArrayView */ +/* tiny_array_view */ /* */ /********************************************************/ @@ -2118,7 +1958,7 @@ struct UninitializedMemoryTraits> with (possibly multi-dimensional) shape given by ArrayIndex....N. Thus, the array can be accessed with an interface similar to that of std::vector (except that there are no functions - that change the size of a TinyArrayView). The TinyArrayView + that change the size of a tiny_array_view). The tiny_array_view does not assume ownership of the given memory. \ref TinyArrayOperators "Arithmetic operations" @@ -2127,9 +1967,9 @@ struct UninitializedMemoryTraits> See also:
    -
  • \ref vigra::TinyArrayBase -
  • \ref vigra::TinyArray -
  • \ref vigra::TinySymmetricView +
  • \ref vigra::tiny_array_base +
  • \ref vigra::tiny_array +
  • \ref vigra::tiny_symmetric_view
  • \ref TinyArrayOperators
@@ -2137,11 +1977,11 @@ struct UninitializedMemoryTraits> Namespace: vigra **/ template -class TinyArrayView -: public TinyArrayBase, M, N...> +class tiny_array_view +: public tiny_array_base, M, N...> { public: - using base_type = TinyArrayBase, M, N...>; + using base_type = tiny_array_base, M, N...>; typedef typename base_type::value_type value_type; typedef typename base_type::pointer pointer; @@ -2149,7 +1989,7 @@ class TinyArrayView static const ArrayIndex static_size = base_type::static_size; static const ArrayIndex static_ndim = base_type::static_ndim; - TinyArrayView() + tiny_array_view() : base_type(DontInit) { base_type::data_ = nullptr; @@ -2157,7 +1997,7 @@ class TinyArrayView /** Construct view for given data array */ - TinyArrayView(const_pointer data) + tiny_array_view(const_pointer data) : base_type(DontInit) { base_type::data_ = const_cast(data); @@ -2165,16 +2005,16 @@ class TinyArrayView /** Copy constructor (shallow copy). */ - TinyArrayView(TinyArrayView const & other) + tiny_array_view(tiny_array_view const & other) : base_type(DontInit) { base_type::data_ = const_cast(other.data()); } - /** Construct view from other TinyArray. + /** Construct view from other tiny_array. */ template - TinyArrayView(TinyArrayBase const & other) + tiny_array_view(tiny_array_base const & other) : base_type(DontInit) { base_type::data_ = const_cast(other.data()); @@ -2183,14 +2023,14 @@ class TinyArrayView /** Reset to the other array's pointer. */ template - void reset(TinyArrayBase const & other) + void reset(tiny_array_base const & other) { base_type::data_ = const_cast(other.data()); } /** Copy the data (not the pointer) of the rhs. */ - TinyArrayView & operator=(TinyArrayView const & r) + tiny_array_view & operator=(tiny_array_view const & r) { for(int k=0; k(r[k]); @@ -2200,7 +2040,7 @@ class TinyArrayView /** Copy the data of the rhs with cast. */ template - TinyArrayView & operator=(TinyArrayBase const & r) + tiny_array_view & operator=(tiny_array_base const & r) { for(int k=0; k(r[k]); @@ -2215,11 +2055,11 @@ class TinyArrayView }; template -class TinyArrayView -: public TinyArrayBase, runtime_size> +class tiny_array_view +: public tiny_array_base, runtime_size> { public: - using base_type = TinyArrayBase, runtime_size>; + using base_type = tiny_array_base, runtime_size>; using base_type::base_type; using base_type::operator=; @@ -2227,7 +2067,7 @@ class TinyArrayView /********************************************************/ /* */ -/* TinyArraySymmetricView */ +/* tiny_symmetric_view */ /* */ /********************************************************/ @@ -2238,18 +2078,18 @@ class TinyArrayView matrix. Specifically, the data are interpreted as the row-wise representation of the upper triangular part of the symmetric matrix. All index access operations are overloaded such that the view appears - as if it were a full matrix. The TinySymmetricView + as if it were a full matrix. The tiny_symmetric_view does not assume ownership of the given memory. \ref TinyArrayOperators "Arithmetic operations" - on TinySymmetricView are defined as component-wise applications of these + on tiny_symmetric_view are defined as component-wise applications of these operations. See also:
    -
  • \ref vigra::TinyArrayBase -
  • \ref vigra::TinyArray -
  • \ref vigra::TinyArrayView +
  • \ref vigra::tiny_array_base +
  • \ref vigra::tiny_array +
  • \ref vigra::tiny_array_view
  • \ref TinyArrayOperators
@@ -2257,23 +2097,23 @@ class TinyArrayView Namespace: vigra **/ template -class TinySymmetricView -: public TinyArrayBase, N*(N+1)/2> +class tiny_symmetric_view +: public tiny_array_base, N*(N+1)/2> { public: - using base_type = TinyArrayBase, N*(N+1)/2>; + using base_type = tiny_array_base, N*(N+1)/2>; typedef typename base_type::value_type value_type; typedef typename base_type::pointer pointer; typedef typename base_type::const_pointer const_pointer; typedef typename base_type::reference reference; typedef typename base_type::const_reference const_reference; - using index_type = TinyArray; + using index_type = tiny_array; static const ArrayIndex static_size = base_type::static_size; static const ArrayIndex static_ndim = 2; - TinySymmetricView() + tiny_symmetric_view() : base_type(DontInit) { base_type::data_ = nullptr; @@ -2281,7 +2121,7 @@ class TinySymmetricView /** Construct view for given data array */ - TinySymmetricView(const_pointer data) + tiny_symmetric_view(const_pointer data) : base_type(DontInit) { base_type::data_ = const_cast(data); @@ -2289,16 +2129,16 @@ class TinySymmetricView /** Copy constructor (shallow copy). */ - TinySymmetricView(TinySymmetricView const & other) + tiny_symmetric_view(tiny_symmetric_view const & other) : base_type(DontInit) { base_type::data_ = const_cast(other.data()); } - /** Construct view from other TinyArray. + /** Construct view from other tiny_array. */ template - TinySymmetricView(TinyArrayBase const & other) + tiny_symmetric_view(tiny_array_base const & other) : base_type(DontInit) { base_type::data_ = const_cast(other.data()); @@ -2307,14 +2147,14 @@ class TinySymmetricView /** Reset to the other array's pointer. */ template - void reset(TinyArrayBase const & other) + void reset(tiny_array_base const & other) { base_type::data_ = const_cast(other.data()); } /** Copy the data (not the pointer) of the rhs. */ - TinySymmetricView & operator=(TinySymmetricView const & r) + tiny_symmetric_view & operator=(tiny_symmetric_view const & r) { for(int k=0; k(r[k]); @@ -2324,7 +2164,7 @@ class TinySymmetricView /** Copy the data of the rhs with cast. */ template - TinySymmetricView & operator=(TinyArrayBase const & r) + tiny_symmetric_view & operator=(tiny_array_base const & r) { for(int k=0; k(r[k]); @@ -2413,7 +2253,7 @@ class TinySymmetricView ? i + (j*((2*N-1) - j) >> 1) : j + (i*((2*N-1) - i) >> 1); if(k < 0 || k >= static_size) - throw std::out_of_range("TinySymmetricView::at()"); + throw std::out_of_range("tiny_symmetric_view::at()"); return base_type::data_[k]; } @@ -2423,7 +2263,7 @@ class TinySymmetricView ? i + N*j - (j*(j+1) >> 1) : N*i + j - (i*(i+1) >> 1); if(k < 0 || k >= static_size) - throw std::out_of_range("TinySymmetricView::at()"); + throw std::out_of_range("tiny_symmetric_view::at()"); return base_type::data_[k]; } @@ -2433,22 +2273,22 @@ class TinySymmetricView /********************************************************/ /* */ -/* TinyArraySymmetricView output */ +/* tiny_symmetric_view output */ /* */ /********************************************************/ template -std::ostream & operator<<(std::ostream & o, TinySymmetricView const & v) +std::ostream & operator<<(std::ostream & o, tiny_symmetric_view const & v) { o << "{"; for(int i=0; i 0) o << ",\n "; - o << PromoteType(v(i,0)); + o << promote_t(v(i,0)); for(int j=1; j(v(i, j)); + o << ", " << promote_t(v(i, j)); } } o << "}"; @@ -2458,18 +2298,18 @@ std::ostream & operator<<(std::ostream & o, TinySymmetricView const & v) /********************************************************/ /* */ -/* TinyArray Comparison */ +/* tiny_array Comparison */ /* */ /********************************************************/ -/** \addtogroup TinyArrayOperators Functions for TinyArray +/** \addtogroup TinyArrayOperators Functions for tiny_array - \brief Implement basic arithmetic and equality for TinyArray. + \brief Implement basic arithmetic and equality for tiny_array. These functions fulfill the requirements of a Linear Space (vector space). - Return types are determined according to \ref PromoteType or \ref RealPromoteType. + Return types are determined according to \ref promote_t or \ref real_promote_t. - \#include \
+ \#include \
Namespace: vigra */ //@{ @@ -2477,8 +2317,8 @@ std::ostream & operator<<(std::ostream & o, TinySymmetricView const & v) /// element-wise equal template inline bool -operator==(TinyArrayBase const & l, - TinyArrayBase const & r) +operator==(tiny_array_base const & l, + tiny_array_base const & r) { if(!l.sameShape(r)) return false; @@ -2490,10 +2330,10 @@ operator==(TinyArrayBase const & l, /// element-wise equal to a constant template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool -operator==(TinyArrayBase const & l, +operator==(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2504,11 +2344,11 @@ operator==(TinyArrayBase const & l, /// element-wise equal to a constant template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool operator==(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) if(l != r[k]) @@ -2519,8 +2359,8 @@ operator==(V1 const & l, /// element-wise not equal template inline bool -operator!=(TinyArrayBase const & l, - TinyArrayBase const & r) +operator!=(tiny_array_base const & l, + tiny_array_base const & r) { if(!l.sameShape(r)) return true; @@ -2532,10 +2372,10 @@ operator!=(TinyArrayBase const & l, /// element-wise not equal to a constant template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool -operator!=(TinyArrayBase const & l, +operator!=(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2546,11 +2386,11 @@ operator!=(TinyArrayBase const & l, /// element-wise not equal to a constant template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool operator!=(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) if(l != r[k]) @@ -2561,11 +2401,11 @@ operator!=(V1 const & l, /// lexicographical comparison template inline bool -operator<(TinyArrayBase const & l, - TinyArrayBase const & r) +operator<(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "TinyArrayBase::operator<(): size mismatch."); + "tiny_array_base::operator<(): size mismatch."); for(int k=0; k < l.size(); ++k) { if(l[k] < r[k]) @@ -2579,7 +2419,7 @@ operator<(TinyArrayBase const & l, /// lexicographical comparison template inline bool -operator<(TinyArrayBase const & l, +operator<(tiny_array_base const & l, std::vector const & r) { ArrayIndex size = r.size(); @@ -2602,7 +2442,7 @@ operator<(TinyArrayBase const & l, template inline bool operator<(std::vector const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { ArrayIndex size = r.size(); bool equal_res = false; @@ -2623,7 +2463,7 @@ operator<(std::vector const & l, template inline bool -operator>(TinyArrayBase const & l, +operator>(tiny_array_base const & l, std::vector const & r) { return r < l; @@ -2632,7 +2472,7 @@ operator>(TinyArrayBase const & l, template inline bool operator>(std::vector const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { return r < l; } @@ -2640,7 +2480,7 @@ operator>(std::vector const & l, /// check if all elements are non-zero (or 'true' if V is bool) template inline bool -all(TinyArrayBase const & t) +all(tiny_array_base const & t) { for(int i=0; i const & t) /// check if at least one element is non-zero (or 'true' if V is bool) template inline bool -any(TinyArrayBase const & t) +any(tiny_array_base const & t) { for(int i=0; i const & t) /// check if all elements are zero (or 'false' if V is bool) template inline bool -allZero(TinyArrayBase const & t) +allZero(tiny_array_base const & t) { for(int i=0; i const & t) /// pointwise less-than template inline bool -allLess(TinyArrayBase const & l, - TinyArrayBase const & r) +allLess(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "TinyArrayBase::allLess(): size mismatch."); + "tiny_array_base::allLess(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] >= r[k]) return false; @@ -2687,10 +2527,10 @@ allLess(TinyArrayBase const & l, /// pointwise less than a constant /// (typically used to check negativity with `r = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool -allLess(TinyArrayBase const & l, +allLess(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2702,11 +2542,11 @@ allLess(TinyArrayBase const & l, /// constant pointwise less than the vector /// (typically used to check positivity with `l = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool allLess(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) if (l >= r[k]) @@ -2717,11 +2557,11 @@ allLess(V1 const & l, /// pointwise less-equal template inline bool -allLessEqual(TinyArrayBase const & l, - TinyArrayBase const & r) +allLessEqual(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "TinyArrayBase::allLessEqual(): size mismatch."); + "tiny_array_base::allLessEqual(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] > r[k]) return false; @@ -2731,10 +2571,10 @@ allLessEqual(TinyArrayBase const & l, /// pointwise less-equal with a constant /// (typically used to check non-positivity with `r = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool -allLessEqual(TinyArrayBase const & l, +allLessEqual(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2746,11 +2586,11 @@ allLessEqual(TinyArrayBase const & l, /// pointwise less-equal with a constant /// (typically used to check non-negativity with `l = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool allLessEqual(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) if (l > r[k]) @@ -2761,11 +2601,11 @@ allLessEqual(V1 const & l, /// pointwise greater-than template inline bool -allGreater(TinyArrayBase const & l, - TinyArrayBase const & r) +allGreater(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "TinyArrayBase::allGreater(): size mismatch."); + "tiny_array_base::allGreater(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] <= r[k]) return false; @@ -2775,10 +2615,10 @@ allGreater(TinyArrayBase const & l, /// pointwise greater-than with a constant /// (typically used to check positivity with `r = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool -allGreater(TinyArrayBase const & l, +allGreater(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2790,11 +2630,11 @@ allGreater(TinyArrayBase const & l, /// constant pointwise greater-than a vector /// (typically used to check negativity with `l = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool allGreater(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) if (l <= r[k]) @@ -2805,11 +2645,11 @@ allGreater(V1 const & l, /// pointwise greater-equal template inline bool -allGreaterEqual(TinyArrayBase const & l, - TinyArrayBase const & r) +allGreaterEqual(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "TinyArrayBase::allGreaterEqual(): size mismatch."); + "tiny_array_base::allGreaterEqual(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] < r[k]) return false; @@ -2819,10 +2659,10 @@ allGreaterEqual(TinyArrayBase const & l, /// pointwise greater-equal with a constant /// (typically used to check non-negativity with `r = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool -allGreaterEqual(TinyArrayBase const & l, +allGreaterEqual(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2834,11 +2674,11 @@ allGreaterEqual(TinyArrayBase const & l, /// pointwise greater-equal with a constant /// (typically used to check non-positivity with `l = 0`) template ::value && - std::is_convertible::value> > + XTENSOR_REQUIRE::value && + std::is_convertible::value> > inline bool allGreaterEqual(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) if (l < r[k]) @@ -2848,12 +2688,12 @@ allGreaterEqual(V1 const & l, template inline bool -isclose(TinyArrayBase const & l, - TinyArrayBase const & r, - PromoteType epsilon = 2.0*std::numeric_limits >::epsilon()) +isclose(tiny_array_base const & l, + tiny_array_base const & r, + promote_t epsilon = 2.0*std::numeric_limits >::epsilon()) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "TinyArrayBase::isclose(): size mismatch."); + "tiny_array_base::isclose(): size mismatch."); for(int k=0; k < l.size(); ++k) if(!mathfunctions::isclose(l[k], r[k], epsilon, epsilon)) return false; @@ -2862,7 +2702,7 @@ isclose(TinyArrayBase const & l, // template // inline bool -// operator==(TinyArrayBase const & l, +// operator==(tiny_array_base const & l, // lemon::Invalid const &) // { // for(int k=0; k < l.size(); ++k) @@ -2874,14 +2714,14 @@ isclose(TinyArrayBase const & l, // template // inline bool // operator==(lemon::Invalid const &, - // TinyArrayBase const & r) + // tiny_array_base const & r) // { // return r == lemon::INVALID; // } // template // inline bool -// operator!=(TinyArrayBase const & l, +// operator!=(tiny_array_base const & l, // lemon::Invalid const &) // { // return !(l == lemon::INVALID); @@ -2890,7 +2730,7 @@ isclose(TinyArrayBase const & l, // template // inline bool // operator!=(lemon::Invalid const &, - // TinyArrayBase const & r) + // tiny_array_base const & r) // { // return !(r == lemon::INVALID); // } @@ -2899,7 +2739,7 @@ isclose(TinyArrayBase const & l, /********************************************************/ /* */ -/* TinyArray-Arithmetic */ +/* tiny_array-Arithmetic */ /* */ /********************************************************/ @@ -2915,165 +2755,165 @@ isclose(TinyArrayBase const & l, template ::value> > DERIVED & -operator+=(TinyArrayBase & l, +operator+=(tiny_array_base & l, V2 r); /// element-wise add-assignment template DERIVED & -operator+=(TinyArrayBase & l, - TinyArrayBase const & r); +operator+=(tiny_array_base & l, + tiny_array_base const & r); /// element-wise addition template -TinyArray, N...> -operator+(TinyArrayBase const & l, - TinyArrayBase const & r); +tiny_array, N...> +operator+(tiny_array_base const & l, + tiny_array_base const & r); /// element-wise scalar addition template -TinyArray, N...> -operator+(TinyArrayBase const & l, +tiny_array, N...> +operator+(tiny_array_base const & l, V2 r); /// element-wise left scalar addition template -TinyArray, N...> +tiny_array, N...> operator+(V1 l, - TinyArrayBase const & r); + tiny_array_base const & r); /// scalar subtract-assignment template ::value> > DERIVED & -operator-=(TinyArrayBase & l, +operator-=(tiny_array_base & l, V2 r); /// element-wise subtract-assignment template DERIVED & -operator-=(TinyArrayBase & l, - TinyArrayBase const & r); +operator-=(tiny_array_base & l, + tiny_array_base const & r); /// element-wise subtraction template -TinyArray, N...> -operator-(TinyArrayBase const & l, - TinyArrayBase const & r); +tiny_array, N...> +operator-(tiny_array_base const & l, + tiny_array_base const & r); /// element-wise scalar subtraction template -TinyArray, N...> -operator-(TinyArrayBase const & l, +tiny_array, N...> +operator-(tiny_array_base const & l, V2 r); /// element-wise left scalar subtraction template -TinyArray, N...> +tiny_array, N...> operator-(V1 l, - TinyArrayBase const & r); + tiny_array_base const & r); /// scalar multiply-assignment template ::value> > DERIVED & -operator*=(TinyArrayBase & l, +operator*=(tiny_array_base & l, V2 r); /// element-wise multiply-assignment template DERIVED & -operator*=(TinyArrayBase & l, - TinyArrayBase const & r); +operator*=(tiny_array_base & l, + tiny_array_base const & r); /// element-wise multiplication template -TinyArray, N...> -operator*(TinyArrayBase const & l, - TinyArrayBase const & r); +tiny_array, N...> +operator*(tiny_array_base const & l, + tiny_array_base const & r); /// element-wise scalar multiplication template -TinyArray, N...> -operator*(TinyArrayBase const & l, +tiny_array, N...> +operator*(tiny_array_base const & l, V2 r); /// element-wise left scalar multiplication template -TinyArray, N...> +tiny_array, N...> operator*(V1 l, - TinyArrayBase const & r); + tiny_array_base const & r); /// scalar divide-assignment template ::value> > DERIVED & -operator/=(TinyArrayBase & l, +operator/=(tiny_array_base & l, V2 r); /// element-wise divide-assignment template DERIVED & -operator/=(TinyArrayBase & l, - TinyArrayBase const & r); +operator/=(tiny_array_base & l, + tiny_array_base const & r); /// element-wise division template -TinyArray, N...> -operator/(TinyArrayBase const & l, - TinyArrayBase const & r); +tiny_array, N...> +operator/(tiny_array_base const & l, + tiny_array_base const & r); /// element-wise scalar division template -TinyArray, N...> -operator/(TinyArrayBase const & l, +tiny_array, N...> +operator/(tiny_array_base const & l, V2 r); /// element-wise left scalar division template -TinyArray, N...> +tiny_array, N...> operator/(V1 l, - TinyArrayBase const & r); + tiny_array_base const & r); /// scalar modulo-assignment template ::value> > DERIVED & -operator%=(TinyArrayBase & l, +operator%=(tiny_array_base & l, V2 r); /// element-wise modulo-assignment template DERIVED & -operator%=(TinyArrayBase & l, - TinyArrayBase const & r); +operator%=(tiny_array_base & l, + tiny_array_base const & r); /// element-wise modulo template -TinyArray, N...> -operator%(TinyArrayBase const & l, - TinyArrayBase const & r); +tiny_array, N...> +operator%(tiny_array_base const & l, + tiny_array_base const & r); /// element-wise scalar modulo template -TinyArray, N...> -operator%(TinyArrayBase const & l, +tiny_array, N...> +operator%(tiny_array_base const & l, V2 r); /// element-wise left scalar modulo template -TinyArray, N...> +tiny_array, N...> operator%(V1 l, - TinyArrayBase const & r); + tiny_array_base const & r); #else #define XTENSOR_TINYARRAY_OPERATORS(OP) \ template ::value && \ - std::is_convertible::value> > \ + XTENSOR_REQUIRE::value && \ + std::is_convertible::value> > \ DERIVED & \ -operator OP##=(TinyArrayBase & l, \ +operator OP##=(tiny_array_base & l, \ V2 r) \ { \ for(int i=0; i & l, \ \ template \ inline DERIVED & \ -operator OP##=(TinyArrayBase & l, \ - TinyArrayBase const & r) \ +operator OP##=(tiny_array_base & l, \ + tiny_array_base const & r) \ { \ XTENSOR_ASSERT_MSG(l.size() == r.size(), \ - "TinyArrayBase::operator" #OP "=(): size mismatch."); \ + "tiny_array_base::operator" #OP "=(): size mismatch."); \ for(int i=0; i(l); \ } \ template \ inline \ -TinyArray \ -operator OP(TinyArrayBase const & l, \ - TinyArrayBase const & r) \ +tiny_array \ +operator OP(tiny_array_base const & l, \ + tiny_array_base const & r) \ { \ - TinyArray res(l); \ + tiny_array res(l); \ return res OP##= r; \ } \ \ template ::value> >\ + XTENSOR_REQUIRE::value> >\ inline \ -TinyArray \ -operator OP(TinyArrayBase const & l, \ +tiny_array \ +operator OP(tiny_array_base const & l, \ V2 r) \ { \ - TinyArray res(l); \ + tiny_array res(l); \ return res OP##= r; \ } \ \ template ::value && \ - !std::is_base_of::value> >\ + XTENSOR_REQUIRE::value && \ + !std::is_base_of::value> >\ inline \ -TinyArray \ +tiny_array \ operator OP(V1 l, \ - TinyArrayBase const & r) \ + tiny_array_base const & r) \ { \ - TinyArray res{l}; \ + tiny_array res{l}; \ return res OP##= r; \ } \ \ template ::value && \ - !std::is_base_of::value> >\ + XTENSOR_REQUIRE::value && \ + !std::is_base_of::value> >\ inline \ -TinyArray \ +tiny_array \ operator OP(V1 l, \ - TinyArrayBase const & r) \ + tiny_array_base const & r) \ { \ - TinyArray res(tags::size=r.size(), l); \ + tiny_array res(tags::size=r.size(), l); \ return res OP##= r; \ } @@ -3155,10 +2995,10 @@ XTENSOR_TINYARRAY_OPERATORS(>>) #define XTENSOR_TINYARRAY_UNARY_FUNCTION(FCT) \ template \ inline \ -TinyArray, N...> \ -FCT(TinyArrayBase const & v) \ +tiny_array, N...> \ +FCT(tiny_array_base const & v) \ { \ - TinyArray, N...> res(v.size(), DontInit); \ + tiny_array, N...> res(v.size(), DontInit); \ for(int k=0; k < v.size(); ++k) \ res[k] = mathfunctions::FCT(v[k]); \ return res; \ @@ -3228,10 +3068,10 @@ XTENSOR_TINYARRAY_UNARY_FUNCTION(arg) /// Arithmetic negation template inline -TinyArray -operator-(TinyArrayBase const & v) +tiny_array +operator-(tiny_array_base const & v) { - TinyArray res(v.size(), DontInit); + tiny_array res(v.size(), DontInit); for(int k=0; k < v.size(); ++k) res[k] = -v[k]; return res; @@ -3240,10 +3080,10 @@ operator-(TinyArrayBase const & v) /// Boolean negation template inline -TinyArray -operator!(TinyArrayBase const & v) +tiny_array +operator!(tiny_array_base const & v) { - TinyArray res(v.size(), DontInit); + tiny_array res(v.size(), DontInit); for(int k=0; k < v.size(); ++k) res[k] = !v[k]; return res; @@ -3252,10 +3092,10 @@ operator!(TinyArrayBase const & v) /// Bitwise negation template inline -TinyArray -operator~(TinyArrayBase const & v) +tiny_array +operator~(tiny_array_base const & v) { - TinyArray res(v.size(), DontInit); + tiny_array res(v.size(), DontInit); for(int k=0; k < v.size(); ++k) res[k] = ~v[k]; return res; @@ -3264,12 +3104,12 @@ operator~(TinyArrayBase const & v) #define XTENSOR_TINYARRAY_BINARY_FUNCTION(FCT) \ template \ inline \ -TinyArray \ -FCT(TinyArrayBase const & l, \ - TinyArrayBase const & r) \ +tiny_array \ +FCT(tiny_array_base const & l, \ + tiny_array_base const & r) \ { \ - XTENSOR_ASSERT_MSG(l.size() == r.size(), #FCT "(TinyArray, TinyArray): size mismatch."); \ - TinyArray res(l.size(), DontInit); \ + XTENSOR_ASSERT_MSG(l.size() == r.size(), #FCT "(tiny_array, tiny_array): size mismatch."); \ + tiny_array res(l.size(), DontInit); \ for(int k=0; k < l.size(); ++k) \ res[k] = mathfunctions::FCT(l[k], r[k]); \ return res; \ @@ -3289,10 +3129,10 @@ XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot) */ template inline auto -pow(TinyArrayBase const & v, E exponent) -> - TinyArray +pow(tiny_array_base const & v, E exponent) -> + tiny_array { - TinyArray res(v.size(), DontInit); + tiny_array res(v.size(), DontInit); for(int k=0; k < v.size(); ++k) res[k] = mathfunctions::pow(v[k], exponent); return res; @@ -3302,13 +3142,13 @@ pow(TinyArrayBase const & v, E exponent) -> template > inline -TinyArray, N> -cross(TinyArrayBase const & r1, - TinyArrayBase const & r2) +tiny_array, N> +cross(tiny_array_base const & r1, + tiny_array_base const & r2) { XTENSOR_ASSERT_RUNTIME_SIZE(N, r1.size() == 3 && r2.size() == 3, "cross(): cross product requires size() == 3."); - typedef TinyArray, N> Res; + typedef tiny_array, N> Res; return Res{r1[1]*r2[2] - r1[2]*r2[1], r1[2]*r2[0] - r1[0]*r2[2], r1[0]*r2[1] - r1[1]*r2[0]}; @@ -3317,12 +3157,12 @@ cross(TinyArrayBase const & r1, /// dot product of two vectors template inline -PromoteType -dot(TinyArrayBase const & l, - TinyArrayBase const & r) +promote_t +dot(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_MSG(l.size() == r.size(), "dot(): size mismatch."); - PromoteType res = PromoteType(); + promote_t res = promote_t(); for(int k=0; k < l.size(); ++k) res += l[k] * r[k]; return res; @@ -3331,10 +3171,10 @@ dot(TinyArrayBase const & l, /// sum of the vector's elements template inline -PromoteType -sum(TinyArrayBase const & l) +promote_t +sum(tiny_array_base const & l) { - PromoteType res = PromoteType(); + promote_t res = promote_t(); for(int k=0; k < l.size(); ++k) res += l[k]; return res; @@ -3342,10 +3182,10 @@ sum(TinyArrayBase const & l) /// mean of the vector's elements template -inline RealPromoteType -mean(TinyArrayBase const & t) +inline real_promote_t +mean(tiny_array_base const & t) { - using Promote = RealPromoteType; + using Promote = real_promote_t; const Promote sumVal = static_cast(sum(t)); if(t.size() > 0) return sumVal / t.size(); @@ -3356,10 +3196,10 @@ mean(TinyArrayBase const & t) /// cumulative sum of the vector's elements template inline -TinyArray, N...> -cumsum(TinyArrayBase const & l) +tiny_array, N...> +cumsum(tiny_array_base const & l) { - TinyArray, N...> res(l); + tiny_array, N...> res(l); for(int k=1; k < l.size(); ++k) res[k] += res[k-1]; return res; @@ -3368,10 +3208,10 @@ cumsum(TinyArrayBase const & l) /// product of the vector's elements template inline -PromoteType -prod(TinyArrayBase const & l) +promote_t +prod(tiny_array_base const & l) { - using Promote = PromoteType; + using Promote = promote_t; if(l.size() == 0) return Promote(); Promote res = Promote(1); @@ -3383,10 +3223,10 @@ prod(TinyArrayBase const & l) /// cumulative product of the vector's elements template inline -TinyArray, N...> -cumprod(TinyArrayBase const & l) +tiny_array, N...> +cumprod(tiny_array_base const & l) { - TinyArray, N...> res(l); + tiny_array, N...> res(l); for(int k=1; k < l.size(); ++k) res[k] *= res[k-1]; return res; @@ -3396,11 +3236,11 @@ cumprod(TinyArrayBase const & l) // /// Example: {200, 100, 50} => {5000, 50, 1} // template // inline -// TinyArray, N> -// shapeToStrides(TinyArrayBase const & shape, +// tiny_array, N> +// shapeToStrides(tiny_array_base const & shape, // MemoryOrder order = C_ORDER) // { - // TinyArray, N> res(shape.size(), DontInit); + // tiny_array, N> res(shape.size(), DontInit); // if(order == C_ORDER) // { @@ -3420,13 +3260,13 @@ cumprod(TinyArrayBase const & l) /// element-wise minimum template inline -TinyArray, N...> -min(TinyArrayBase const & l, - TinyArrayBase const & r) +tiny_array, N...> +min(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), "min(): size mismatch."); - TinyArray, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), DontInit); for(int k=0; k < l.size(); ++k) res[k] = mathfunctions::min(l[k], r[k]); return res; @@ -3434,13 +3274,13 @@ min(TinyArrayBase const & l, /// element-wise minimum with a constant template ::value>> + XTENSOR_REQUIRE::value>> inline -TinyArray, N...> -min(TinyArrayBase const & l, +tiny_array, N...> +min(tiny_array_base const & l, V2 const & r) { - TinyArray, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), DontInit); for(int k=0; k < l.size(); ++k) res[k] = mathfunctions::min(l[k], r); return res; @@ -3448,13 +3288,13 @@ min(TinyArrayBase const & l, /// element-wise minimum with a constant template ::value>> + XTENSOR_REQUIRE::value>> inline -TinyArray, N...> +tiny_array, N...> min(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { - TinyArray, N...> res(r.size(), DontInit); + tiny_array, N...> res(r.size(), DontInit); for(int k=0; k < r.size(); ++k) res[k] = mathfunctions::min(l, r[k]); return res; @@ -3466,7 +3306,7 @@ min(V1 const & l, */ template inline int -min_element(TinyArrayBase const & l) +min_element(tiny_array_base const & l) { if(l.size() == 0) return -1; @@ -3481,23 +3321,23 @@ min_element(TinyArrayBase const & l) template inline V const & -min(TinyArrayBase const & l) +min(tiny_array_base const & l) { int m = min_element(l); - xtensor_precondition(m >= 0, "min() on empty TinyArray."); + xtensor_precondition(m >= 0, "min() on empty tiny_array."); return l[m]; } /// element-wise maximum template inline -TinyArray, N...> -max(TinyArrayBase const & l, - TinyArrayBase const & r) +tiny_array, N...> +max(tiny_array_base const & l, + tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), "max(): size mismatch."); - TinyArray, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), DontInit); for(int k=0; k < l.size(); ++k) res[k] = mathfunctions::max(l[k], r[k]); return res; @@ -3505,13 +3345,13 @@ max(TinyArrayBase const & l, /// element-wise maximum with a constant template ::value>> + XTENSOR_REQUIRE::value>> inline -TinyArray, N...> -max(TinyArrayBase const & l, +tiny_array, N...> +max(tiny_array_base const & l, V2 const & r) { - TinyArray, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), DontInit); for(int k=0; k < l.size(); ++k) res[k] = mathfunctions::max(l[k], r); return res; @@ -3519,13 +3359,13 @@ max(TinyArrayBase const & l, /// element-wise maximum with a constant template ::value>> + XTENSOR_REQUIRE::value>> inline -TinyArray, N...> +tiny_array, N...> max(V1 const & l, - TinyArrayBase const & r) + tiny_array_base const & r) { - TinyArray, N...> res(r.size(), DontInit); + tiny_array, N...> res(r.size(), DontInit); for(int k=0; k < r.size(); ++k) res[k] = mathfunctions::max(l, r[k]); return res; @@ -3537,7 +3377,7 @@ max(V1 const & l, */ template inline int -max_element(TinyArrayBase const & l) +max_element(tiny_array_base const & l) { if(l.size() == 0) return -1; @@ -3551,19 +3391,19 @@ max_element(TinyArrayBase const & l) /// maximal element template inline V const & -max(TinyArrayBase const & l) +max(tiny_array_base const & l) { int m = max_element(l); - xtensor_precondition(m >= 0, "max() on empty TinyArray."); + xtensor_precondition(m >= 0, "max() on empty tiny_array."); return l[m]; } /// squared norm template -inline SquaredNormType > -squaredNorm(TinyArrayBase const & t) +inline squared_norm_t > +squaredNorm(tiny_array_base const & t) { - using Type = SquaredNormType >; + using Type = squared_norm_t >; Type result = Type(); for(int i=0; i const & t) } template -inline SquaredNormType > -squaredNorm(TinySymmetricView const & t) +inline squared_norm_t > +squaredNorm(tiny_symmetric_view const & t) { - using Type = SquaredNormType >; + using Type = squared_norm_t >; Type result = Type(); for (int i = 0; i < N; ++i) { @@ -3591,27 +3431,27 @@ squaredNorm(TinySymmetricView const & t) template inline -NormType -sizeDividedSquaredNorm(TinyArrayBase const & t) +norm_t +sizeDividedSquaredNorm(tiny_array_base const & t) { - return NormType(squaredNorm(t)) / t.size(); + return norm_t(squaredNorm(t)) / t.size(); } template inline -NormType -sizeDividedNorm(TinyArrayBase const & t) +norm_t +sizeDividedNorm(tiny_array_base const & t) { - return NormType(norm(t)) / t.size(); + return norm_t(norm(t)) / t.size(); } /// reversed copy template inline -TinyArray -reversed(TinyArrayBase const & t) +tiny_array +reversed(tiny_array_base const & t) { - return TinyArray(t.begin(), t.end(), ReverseCopy); + return tiny_array(t.begin(), t.end(), ReverseCopy); } /** \brief transposed copy @@ -3620,27 +3460,27 @@ reversed(TinyArrayBase const & t) */ template inline -TinyArray -transpose(TinyArrayBase const & v, - TinyArrayBase const & permutation) +tiny_array +transpose(tiny_array_base const & v, + tiny_array_base const & permutation) { return v.transpose(permutation); } template inline -TinyArray -transpose(TinyArrayBase const & v) +tiny_array +transpose(tiny_array_base const & v) { return reversed(v); } template inline -TinyArray -transpose(TinyArrayBase const & v) +tiny_array +transpose(tiny_array_base const & v) { - TinyArray res(DontInit); + tiny_array res(DontInit); for(int i=0; i < N1; ++i) { for(int j=0; j < N2; ++j) @@ -3653,8 +3493,8 @@ transpose(TinyArrayBase const & v) template inline -TinySymmetricView -transpose(TinySymmetricView const & v) +tiny_symmetric_view +transpose(tiny_symmetric_view const & v) { return v; } @@ -3665,8 +3505,8 @@ transpose(TinySymmetricView const & v) */ template inline -TinyArray -clipLower(TinyArrayBase const & t) +tiny_array +clipLower(tiny_array_base const & t) { return clipLower(t, V()); } @@ -3677,10 +3517,10 @@ clipLower(TinyArrayBase const & t) */ template inline -TinyArray -clipLower(TinyArrayBase const & t, const V val) +tiny_array +clipLower(tiny_array_base const & t, const V val) { - TinyArray res(t.size(), DontInit); + tiny_array res(t.size(), DontInit); for(int k=0; k < t.size(); ++k) { res[k] = t[k] < val ? val : t[k]; @@ -3694,10 +3534,10 @@ clipLower(TinyArrayBase const & t, const V val) */ template inline -TinyArray -clipUpper(TinyArrayBase const & t, const V val) +tiny_array +clipUpper(tiny_array_base const & t, const V val) { - TinyArray res(t.size(), DontInit); + tiny_array res(t.size(), DontInit); for(int k=0; k < t.size(); ++k) { res[k] = t[k] > val ? val : t[k]; @@ -3712,11 +3552,11 @@ clipUpper(TinyArrayBase const & t, const V val) */ template inline -TinyArray -clip(TinyArrayBase const & t, +tiny_array +clip(tiny_array_base const & t, const V valLower, const V valUpper) { - TinyArray res(t.size(), DontInit); + tiny_array res(t.size(), DontInit); for(int k=0; k < t.size(); ++k) { res[k] = (t[k] < valLower) @@ -3735,14 +3575,14 @@ clip(TinyArrayBase const & t, */ template inline -TinyArray -clip(TinyArrayBase const & t, - TinyArrayBase const & valLower, - TinyArrayBase const & valUpper) +tiny_array +clip(tiny_array_base const & t, + tiny_array_base const & valLower, + tiny_array_base const & valUpper) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., t.size() == valLower.size() && t.size() == valUpper.size(), "clip(): size mismatch."); - TinyArray res(t.size(), DontInit); + tiny_array res(t.size(), DontInit); for(int k=0; k < t.size(); ++k) { res[k] = (t[k] < valLower[k]) @@ -3756,8 +3596,8 @@ clip(TinyArrayBase const & t, template inline void -swap(TinyArrayBase & l, - TinyArrayBase & r) +swap(tiny_array_base & l, + tiny_array_base & r) { l.swap(r); } @@ -3769,45 +3609,45 @@ swap(TinyArrayBase & l, // PromoteTraits specializations template -struct PromoteTraits, TinyArrayBase > +struct PromoteTraits, tiny_array_base > { static const bool value = PromoteTraits::value; - typedef TinyArray, N...> type; + typedef tiny_array, N...> type; }; template -struct PromoteTraits, TinyArray > +struct PromoteTraits, tiny_array > { static const bool value = PromoteTraits::value; - typedef TinyArray, N...> type; + typedef tiny_array, N...> type; }; template -struct PromoteTraits, TinyArrayView > +struct PromoteTraits, tiny_array_view > { static const bool value = PromoteTraits::value; - typedef TinyArray, N...> type; + typedef tiny_array, N...> type; }; template -struct PromoteTraits, TinySymmetricView > +struct PromoteTraits, tiny_symmetric_view > { static const bool value = PromoteTraits::value; - typedef TinyArray, N*(N+1)/2> type; + typedef tiny_array, N*(N+1)/2> type; }; //////////////////////////////////////////////////////////// // NumericTraits specializations template -struct NumericTraits> +struct NumericTraits> { - typedef TinyArrayBase Type; + typedef tiny_array_base Type; typedef T value_type; - typedef PromoteType Promote; - typedef RealPromoteType RealPromote; - typedef TinyArray::UnsignedPromote, N...> UnsignedPromote; - typedef TinyArray::ComplexPromote>, N...> ComplexPromote; + typedef promote_t Promote; + typedef real_promote_t RealPromote; + typedef tiny_array::UnsignedPromote, N...> UnsignedPromote; + typedef tiny_array::ComplexPromote>, N...> ComplexPromote; static Type zero() { return {}; } static Type one() { return {NumericTraits::one()}; } @@ -3823,24 +3663,24 @@ struct NumericTraits> }; template -struct NumericTraits> -: public NumericTraits::base_type> +struct NumericTraits> +: public NumericTraits::base_type> { - typedef TinyArray Type; + typedef tiny_array Type; }; template -struct NumericTraits> -: public NumericTraits::base_type> +struct NumericTraits> +: public NumericTraits::base_type> { - typedef TinyArrayView Type; + typedef tiny_array_view Type; }; template -struct NumericTraits> -: public NumericTraits::base_type> +struct NumericTraits> +: public NumericTraits::base_type> { - typedef TinySymmetricView Type; + typedef tiny_symmetric_view Type; }; // mask cl.exe shortcomings [end] diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 8343b76ee..ffcf352d8 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -50,9 +50,9 @@ bool equalIter(ITER1 i1, ITER1 i1end, ITER2 i2, xt::ArrayIndex size) namespace xt { static const int SIZE = 3; - using BV = TinyArray; - using IV = TinyArray; - using FV = TinyArray; + using BV = tiny_array; + using IV = tiny_array; + using FV = tiny_array; static float di[] = { 1, 2, 4}; static float df[] = { 1.2f, 2.4f, 3.6f}; @@ -64,20 +64,20 @@ namespace xt { EXPECT_TRUE(BV::may_use_uninitialized_memory); // FIXME: should be FALSE - EXPECT_TRUE((TinyArray::may_use_uninitialized_memory)); + EXPECT_TRUE((tiny_array::may_use_uninitialized_memory)); EXPECT_TRUE(UninitializedMemoryTraits::value == (SIZE != runtime_size)); - EXPECT_TRUE((UninitializedMemoryTraits, SIZE>>::value == false)); + EXPECT_TRUE((UninitializedMemoryTraits, SIZE>>::value == false)); //EXPECT_TRUE(ValueTypeTraits::value); //EXPECT_TRUE((std::is_same::type>::value)); - EXPECT_TRUE((std::is_same>::value)); - EXPECT_TRUE((std::is_same, RealPromoteType>::value)); - EXPECT_TRUE((std::is_same, RealPromoteType>::value)); + EXPECT_TRUE((std::is_same>::value)); + EXPECT_TRUE((std::is_same, real_promote_t>::value)); + EXPECT_TRUE((std::is_same, real_promote_t>::value)); - EXPECT_TRUE((std::is_same > >::value)); - EXPECT_TRUE((std::is_same, 1> > >::value)); - EXPECT_TRUE((std::is_same > >::value)); - EXPECT_TRUE((std::is_same, 1> > >::value)); + EXPECT_TRUE((std::is_same > >::value)); + EXPECT_TRUE((std::is_same, 1> > >::value)); + EXPECT_TRUE((std::is_same > >::value)); + EXPECT_TRUE((std::is_same, 1> > >::value)); } TEST(xtiny, construct) @@ -138,7 +138,7 @@ namespace xt EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), fv.begin(), SIZE)); EXPECT_TRUE(equalVector(bv3, fv)); - TinyArray fv5; + tiny_array fv5; fv5.init(fv3.begin(), fv3.end()); EXPECT_EQ(fv5[0], fv3[0]); EXPECT_EQ(fv5[1], fv3[1]); @@ -188,7 +188,7 @@ namespace xt r.reverse(); EXPECT_EQ(r, iv3); - typedef TinyArray FV1; + typedef tiny_array FV1; FV1 fv10(fv3.begin()); EXPECT_EQ(fv10, fv3.erase(SIZE - 1)); EXPECT_EQ(fv3, fv10.insert(SIZE - 1, fv3[SIZE - 1])); @@ -311,7 +311,7 @@ namespace xt EXPECT_EQ(dot(iv3, bv3), squaredNorm(iv3)); EXPECT_TRUE(mathfunctions::isclose(dot(fv3, fv3), squaredNorm(fv3))); - TinyArray ivv{ iv3, iv3, iv3 }; + tiny_array ivv{ iv3, iv3, iv3 }; EXPECT_EQ(squaredNorm(ivv), 3 * squaredNorm(iv3)); EXPECT_EQ(norm(ivv), sqrt(3.0*squaredNorm(iv3))); @@ -414,11 +414,11 @@ namespace xt FV cr = cumprod(fv3), crr(cumprodRef); EXPECT_TRUE(isclose(cr, crr, 1e-6f)); - TinyArray src{ 1, 2, -3, -4 }, signs{ 2, -3, 4, -5 }; - EXPECT_EQ(copysign(src, signs), (TinyArray{1, -2, 3, -4})); + tiny_array src{ 1, 2, -3, -4 }, signs{ 2, -3, 4, -5 }; + EXPECT_EQ(copysign(src, signs), (tiny_array{1, -2, 3, -4})); - TinyArray left{ 3., 5., 8. }, right{ 4., 12., 15. }; - EXPECT_EQ(hypot(left, right), (TinyArray{5., 13., 17.})); + tiny_array left{ 3., 5., 8. }, right{ 4., 12., 15. }; + EXPECT_EQ(hypot(left, right), (tiny_array{5., 13., 17.})); int oddRef[] = { 1, 0, 0, 1, 0, 0 }; EXPECT_TRUE(equalIter(oddRef, oddRef + SIZE, odd(iv3).begin(), SIZE)); @@ -447,8 +447,8 @@ namespace xt TEST(xtiny, 2D) { - using Array = TinyArray; - using Index = TinyArray; + using Array = tiny_array; + using Index = tiny_array; EXPECT_EQ(Array::static_ndim, 2); EXPECT_EQ(Array::static_size, 6); @@ -479,7 +479,7 @@ namespace xt EXPECT_EQ(s, ss.str()); } - TinySymmetricView sym(a.data()); + tiny_symmetric_view sym(a.data()); EXPECT_EQ(sym.shape(), (Index{ 3, 3 })); { std::string s = "{4, 5, 6,\n 5, 7, 8,\n 6, 8, 9}"; @@ -488,7 +488,7 @@ namespace xt EXPECT_EQ(s, ss.str()); } - Array::AsType b = a; + Array::as_type b = a; EXPECT_EQ(a, b); int adata2[] = { 0,1,2,3,4,5 }; @@ -528,10 +528,10 @@ namespace xt TEST(xtiny, runtime_size) { - using A = TinyArray; - using V1 = TinyArray; + using A = tiny_array; + using V1 = tiny_array; - EXPECT_TRUE(typeid(A) == typeid(TinyArray)); + EXPECT_TRUE(typeid(A) == typeid(tiny_array)); A a{ 1,2,3 }, b{ 1,2,3 }, c = a, d = a + b, e(3); EXPECT_EQ(a.size(), 3); @@ -614,7 +614,7 @@ namespace xt EXPECT_THROW(A(3) / A(2), std::runtime_error); - using TA = TinyArray; + using TA = tiny_array; TA s(A{ 1,2,3 }); EXPECT_EQ(s, (TA{ 1,2,3 })); s = A{ 3,4,5 }; From 488385e245f3eec8e3adfaa1d8507d14fe376815 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sat, 29 Jul 2017 18:24:33 +0200 Subject: [PATCH 06/27] finished first refactoring stage --- include/xtensor/xconcepts.hpp | 4 +- include/xtensor/xmath.hpp | 424 ++++++++++- include/xtensor/xoperation.hpp | 8 +- include/xtensor/xtags.hpp | 69 ++ include/xtensor/xtiny.hpp | 1284 ++++++++------------------------ test/test_xtiny.cpp | 78 +- 6 files changed, 856 insertions(+), 1011 deletions(-) create mode 100644 include/xtensor/xtags.hpp diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp index 808ea5592..e7b768ce5 100644 --- a/include/xtensor/xconcepts.hpp +++ b/include/xtensor/xconcepts.hpp @@ -85,9 +85,9 @@ struct iterator_concept /**********************************************************/ // result of arithmetic expressions - // (e.g. unsigned char * unsigned char => int) + // (e.g. unsigned char + unsigned char => int) template -using promote_t = decltype(*(typename std::decay::type*)0 * *(typename std::decay::type*)0); +using promote_t = decltype(*(typename std::decay::type*)0 + *(typename std::decay::type*)0); // result of algebraic expressions // (e.g. sqrt(int) => double) diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index 9079d4224..8ad1cb75a 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -14,9 +14,12 @@ #define XMATH_HPP #include +#include // std::abs(int) prior to C++ 17 #include +#include // std::min, std::max #include +#include "xconcepts.hpp" #include "xoperation.hpp" #include "xreducer.hpp" @@ -39,6 +42,403 @@ namespace xt static constexpr T LN2 = 0.693147180559945309417; }; + #if 0 // FIXME: @ukoethe thinks importing into namespace xt is desirable + 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::ceil; + using std::floor; + using std::trunc; + using std::round; + using std::lround; + using std::llround; + + 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; + #endif + + // fix/extend + + /**********************************************************/ + /* */ + /* abs() */ + /* */ + /**********************************************************/ + + using std::abs; + + // define missing abs() overloads to avoid 'ambiguous overload' + // errors in template functions + #define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ + inline T abs(T t) { return t; } + + XTENSOR_DEFINE_UNSIGNED_ABS(bool) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) + + #undef XTENSOR_DEFINE_UNSIGNED_ABS + + #define XTENSOR_DEFINE_MISSING_ABS(T) \ + inline T abs(T t) { return t < 0 ? static_cast(-t) : t; } + + XTENSOR_DEFINE_MISSING_ABS(signed char) + XTENSOR_DEFINE_MISSING_ABS(signed short) + + #undef XTENSOR_DEFINE_MISSING_ABS + + /**********************************************************/ + /* */ + /* isclose() */ + /* */ + /**********************************************************/ + + template >::value> > + inline bool + isclose(V1 v1, V2 v2, double rtol = 1e-05, double atol = 1e-08) + { + using P = promote_t; + return abs(v1-v2) <= (atol + rtol * std::max(abs(static_cast

(v1)), abs(static_cast

(v2)))); + } + + /**********************************************************/ + /* */ + /* sq() */ + /* */ + /**********************************************************/ + + /** \brief The square function. + + sq(x) = x*x is needed so often that it makes sense to define it as a function. + */ + template ::value> > + inline promote_t + sq(T t) + { + return t*t; + } + + /**********************************************************/ + /* */ + /* min() */ + /* */ + /**********************************************************/ + + /** \brief A proper minimum function. + + The std::min template matches everything -- this is way too + greedy to be useful. xtensor implements the basic min function + only for arithmetic types and provides explicit overloads for everything + else. Moreover, xtensor's min function also computes the minimum + between two different types, as long as they have a std::common_type. + */ + template ::value && std::is_arithmetic::value> > + inline std::common_type_t + min(T1 const & t1, T2 const & t2) + { + using T = std::common_type_t; + return std::min(static_cast(t1), static_cast(t2)); + } + + template ::value> > + inline T const & + min(T const & t1, T const & t2) + { + return std::min(t1, t2); + } + + /**********************************************************/ + /* */ + /* max() */ + /* */ + /**********************************************************/ + + /** \brief A proper maximum function. + + The std::max template matches everything -- this is way too + greedy to be useful. xtensor implements the basic max function + only for arithmetic types and provides explicit overloads for everything + else. Moreover, xtensor's max function also computes the maximum + between two different types, as long as they have a std::common_type. + */ + template ::value && std::is_arithmetic::value> > + inline std::common_type_t + max(T1 const & t1, T2 const & t2) + { + using T = std::common_type_t; + return std::max(static_cast(t1), static_cast(t2)); + } + + template ::value> > + inline T const & + max(T const & t1, T const & t2) + { + return std::max(t1, t2); + } + + /**********************************************************/ + /* */ + /* floor(), ceil() */ + /* */ + /**********************************************************/ + + using std::floor; + using std::ceil; + + // add missing floor() and ceil() overloads for integral types + #define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ + inline T floor(signed T t) { return t; } \ + inline T floor(unsigned T t) { return t; } \ + inline T ceil(signed T t) { return t; } \ + inline T ceil(unsigned T t) { return t; } + + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) + + #undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL + + /**********************************************************/ + /* */ + /* dot() */ + /* */ + /**********************************************************/ + + // scalar dot is needed for generic functions that should work with + // scalars and vectors alike + #define XTENSOR_DEFINE_SCALAR_DOT(T) \ + inline promote_t dot(T l, T r) { return l*r; } + + XTENSOR_DEFINE_SCALAR_DOT(unsigned char) + XTENSOR_DEFINE_SCALAR_DOT(unsigned short) + XTENSOR_DEFINE_SCALAR_DOT(unsigned int) + XTENSOR_DEFINE_SCALAR_DOT(unsigned long) + XTENSOR_DEFINE_SCALAR_DOT(unsigned long long) + XTENSOR_DEFINE_SCALAR_DOT(signed char) + XTENSOR_DEFINE_SCALAR_DOT(signed short) + XTENSOR_DEFINE_SCALAR_DOT(signed int) + XTENSOR_DEFINE_SCALAR_DOT(signed long) + XTENSOR_DEFINE_SCALAR_DOT(signed long long) + XTENSOR_DEFINE_SCALAR_DOT(float) + XTENSOR_DEFINE_SCALAR_DOT(double) + XTENSOR_DEFINE_SCALAR_DOT(long double) + + #undef XTENSOR_DEFINE_SCALAR_DOT + + /**********************************************************/ + /* */ + /* pow() */ + /* */ + /**********************************************************/ + + using std::pow; + + // support 'double' exponents for all floating point versions of pow() + inline float pow(float v, double e) + { + return std::pow(v, (float)e); + } + + inline long double pow(long double v, double e) + { + return std::pow(v, (long double)e); + } + + /**********************************************************/ + /* */ + /* even(), odd() */ + /* */ + /**********************************************************/ + + /** \brief Check if an integer is even. + */ + template ::value> > + inline bool + even(T const t) + { + using UT = typename std::make_unsigned::type; + return (static_cast(t)&1) == 0; + } + + /** \brief Check if an integer is odd. + */ + template ::value> > + inline bool + odd(T const t) + { + using UT = typename std::make_unsigned::type; + return (static_cast(t)&1) != 0; + } + + /**********************************************************/ + /* */ + /* sin_pi(), cos_pi() */ + /* */ + /**********************************************************/ + + /** \brief sin(pi*x). + + Essentially calls std::sin(PI*x) but uses a more accurate implementation + to make sure that sin_pi(1.0) == 0.0 (which does not hold for + std::sin(PI) due to round-off error), and sin_pi(0.5) == 1.0. + */ + template ::value> > + REAL sin_pi(REAL x) + { + if(x < 0.0) + return -sin_pi(-x); + if(x < 0.5) + return std::sin(numeric_constants::PI * x); + + bool invert = false; + if(x < 1.0) + { + invert = true; + x = -x; + } + + REAL rem = std::floor(x); + if(odd((int)rem)) + invert = !invert; + rem = x - rem; + if(rem > 0.5) + rem = 1.0 - rem; + if(rem == 0.5) + rem = REAL(1); + else + rem = std::sin(numeric_constants::PI * rem); + return invert + ? -rem + : rem; + } + + /** \brief cos(pi*x). + + Essentially calls std::cos(PI*x) but uses a more accurate implementation + to make sure that cos_pi(1.0) == -1.0 and cos_pi(0.5) == 0.0. + */ + template ::value> > + REAL cos_pi(REAL x) + { + return sin_pi(x+0.5); + } + + /**********************************************************/ + /* */ + /* norm() */ + /* */ + /**********************************************************/ + + /** \brief The norm of a numerical object. + + For scalar types: implemented as abs(t)
+ otherwise: implemented as sqrt(squared_norm(t)). + */ + template + inline auto + norm(T const & t) -> decltype(sqrt(squared_norm(t))) + { + return sqrt(squared_norm(t)); + } + + /**********************************************************/ + /* */ + /* squared_norm() */ + /* */ + /**********************************************************/ + + template + inline squared_norm_t > + squared_norm(std::complex const & t) + { + return sq(t.real()) + sq(t.imag()); + } + + #define XTENSOR_DEFINE_NORM(T) \ + inline squared_norm_t squared_norm(T t) { return sq(t); } \ + inline norm_t norm(T t) { return abs(t); } \ + inline squared_norm_t mean_square(T t) { return sq(t); } + + XTENSOR_DEFINE_NORM(signed char) + XTENSOR_DEFINE_NORM(unsigned char) + XTENSOR_DEFINE_NORM(short) + XTENSOR_DEFINE_NORM(unsigned short) + XTENSOR_DEFINE_NORM(int) + XTENSOR_DEFINE_NORM(unsigned int) + XTENSOR_DEFINE_NORM(long) + XTENSOR_DEFINE_NORM(unsigned long) + XTENSOR_DEFINE_NORM(long long) + XTENSOR_DEFINE_NORM(unsigned long long) + XTENSOR_DEFINE_NORM(float) + XTENSOR_DEFINE_NORM(double) + XTENSOR_DEFINE_NORM(long double) + + #undef XTENSOR_DEFINE_NORM + + /**********************************************************/ + /* */ + /* xexpression */ + /* */ + /**********************************************************/ + /*********** * Helpers * ***********/ @@ -185,7 +585,7 @@ namespace xt /** * @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 @@ -201,7 +601,7 @@ namespace xt /** * @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 @@ -217,7 +617,7 @@ namespace xt /** * @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 @@ -235,7 +635,7 @@ namespace xt /** * @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 @@ -478,8 +878,8 @@ namespace xt /** * @ingroup basic_functions * @brief Clip values between hi and lo - * - * Returns an \ref xfunction for the element-wise clipped + * + * 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 @@ -701,7 +1101,7 @@ namespace xt * @ingroup pow_functions * @brief Square root function. * - * Returns an \ref xfunction for the element-wise square + * Returns an \ref xfunction for the element-wise square * root of \em e. * @param e an \ref xexpression * @return an \ref xfunction @@ -1271,12 +1671,14 @@ namespace xt * @param equal_nan if true, isclose returns true if both elements of e1 and e2 are NaN * @return an \ref xfunction */ - template +#if 0 // FIXME: this template matches too greedily, add appropriate concept check + template inline auto isclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) noexcept { return detail::make_xfunction(std::make_tuple(rtol, atol, equal_nan), std::forward(e1), std::forward(e2)); } +#endif /** * @ingroup classif_functions @@ -1315,6 +1717,7 @@ namespace xt * @param axes the axes along which the sum is performed (optional) * @return an \ref xreducer */ +#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline auto sum(E&& e, X&& axes) noexcept { @@ -1343,6 +1746,7 @@ namespace xt using functor_type = std::plus::value_type>; return reduce(functor_type(), std::forward(e), axes); } +#endif #endif /** @@ -1355,6 +1759,7 @@ namespace xt * @param axes the axes along which the product is computed (optional) * @return an \ref xreducer */ +#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline auto prod(E&& e, X&& axes) noexcept { @@ -1383,6 +1788,7 @@ namespace xt using functor_type = std::multiplies::value_type>; return reduce(functor_type(), std::forward(e), axes); } +#endif #endif /** @@ -1395,6 +1801,7 @@ namespace xt * @param axes the axes along which the mean is computed (optional) * @return an \ref xexpression */ +#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline auto mean(E&& e, X&& axes) noexcept { @@ -1431,6 +1838,7 @@ namespace xt return std::move(s) / value_type(size / s.size()); } #endif +#endif } #endif diff --git a/include/xtensor/xoperation.hpp b/include/xtensor/xoperation.hpp index a1ca7dfa3..f8cb40181 100644 --- a/include/xtensor/xoperation.hpp +++ b/include/xtensor/xoperation.hpp @@ -409,7 +409,7 @@ namespace xt /** * @ingroup logical_operators * @brief return vector of indices where T is not zero - * + * * @param arr input array * @return vector of \a index_types where arr is not equal to zero */ @@ -457,7 +457,7 @@ namespace xt * @ingroup logical_operators * @brief return vector of indices where condition is true * (equivalent to \a nonzero(condition)) - * + * * @param condition input array * @return vector of \a index_types where condition is not equal to zero */ @@ -477,6 +477,7 @@ namespace xt * @param e an \ref xexpression * @return a boolean */ +#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline bool any(E&& e) { @@ -492,6 +493,7 @@ namespace xt [](const typename std::decay_t::value_type& el) { return el; }); } } +#endif /** * @ingroup logical_operators @@ -502,6 +504,7 @@ namespace xt * @param e an \ref xexpression * @return a boolean */ +#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline bool all(E&& e) { @@ -517,6 +520,7 @@ namespace xt [](const typename std::decay_t::value_type& el) { return el; }); } } +#endif } #endif diff --git a/include/xtensor/xtags.hpp b/include/xtensor/xtags.hpp new file mode 100644 index 000000000..b95ff8752 --- /dev/null +++ b/include/xtensor/xtags.hpp @@ -0,0 +1,69 @@ +/*************************************************************************** +* 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 XTAGS_HPP +#define XTAGS_HPP + +/**********************************************************/ +/* */ +/* helper for keyword arguments and related stuff */ +/* */ +/**********************************************************/ + +namespace xt +{ + + /// Determine size of an array type at runtime. +static const int runtime_size = -1; + + /// Don't initialize memory that gets overwritten anyway. +enum skip_initialization { dont_init }; + + /// Copy-construct array in reversed order. +enum reverse_copy_tag { copy_reversed }; + +namespace tags { + +/********************************************************/ +/* */ +/* tags::size */ +/* */ +/********************************************************/ + + // Support for tags::size keyword argument + // to disambiguate array sizes from initial values. +struct size_proxy +{ + size_t value; +}; + +struct size_tag +{ + size_proxy operator=(size_t s) const + { + return {s}; + } + + size_proxy operator()(size_t s) const + { + return {s}; + } +}; + +namespace { + +size_tag size; + +} + +} // namespace tags + + +} // namespace xt + +#endif // XTAGS_HPP diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 2e61dc9f2..abb193350 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -9,16 +9,15 @@ #ifndef XTENSOR_XTINY_HPP #define XTENSOR_XTINY_HPP +#include "xtags.hpp" #include "xconcepts.hpp" #include "xexception.hpp" -#include // ostream +#include "xmath.hpp" +#include #include #include #include #include -#include -#include -#include #ifdef XTENSOR_CHECK_BOUNDS #define XTENSOR_ASSERT_INSIDE(array, diff) \ @@ -29,25 +28,12 @@ namespace xt { -// FIXME: move these to the appropriate places + /** \brief The general type of array indices. -using std::swap; -using std::sqrt; -using std::abs; - -using ArrayIndex = std::ptrdiff_t; -static const int runtime_size = -1; -enum SkipInitialization { DontInit }; -enum ReverseCopyTag { ReverseCopy }; - -/////////////////////////////////////////////////////////////// -// UninitializedMemoryTraits - -template -struct UninitializedMemoryTraits -{ - static const bool value = std::is_scalar::value || std::is_pod::value; -}; + Note that this is a signed type, so that negative indices + and index differences work as intuitively expected. + */ +using index_t = std::ptrdiff_t; template class tiny_array; @@ -55,571 +41,103 @@ class tiny_array; template class tiny_array_view; -/**********************************************************/ -/* */ -/* abs() */ -/* */ -/**********************************************************/ - -// define the missing variants of abs() to avoid 'ambiguous overload' -// errors in template functions -#define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ - inline T abs(T t) { return t; } - -XTENSOR_DEFINE_UNSIGNED_ABS(bool) -XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) -XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) -XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) -XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) -XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) - -#undef XTENSOR_DEFINE_UNSIGNED_ABS - -#define XTENSOR_DEFINE_MISSING_ABS(T) \ - inline T abs(T t) { return t < 0 ? static_cast(-t) : t; } - -XTENSOR_DEFINE_MISSING_ABS(signed char) -XTENSOR_DEFINE_MISSING_ABS(signed short) - -#if defined(_MSC_VER) && _MSC_VER < 1600 -XTENSOR_DEFINE_MISSING_ABS(signed long long) -#endif - -#undef XTENSOR_DEFINE_MISSING_ABS - -namespace mathfunctions { - -using std::abs; -using std::fabs; - -using std::cos; -using std::sin; -using std::tan; -// using std::sin_pi; -// using std::cos_pi; -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::swap; using std::sqrt; -using std::cbrt; -// using std::sqrti; -// using std::sq; -// using std::elementwiseNorm; -// using std::elementwiseSquaredNorm; - -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::ceil; -using std::floor; -using std::trunc; -using std::round; -using std::lround; -using std::llround; -// using std::roundi; -// using std::even; -// using std::odd; -// using std::sign; -// using std::signi; - -using std::erf; -using std::erfc; -using std::erfc; -using std::tgamma; -using std::lgamma; -// using std::loggamma; - -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; - -template -inline -std::enable_if_t >::value, bool> -isclose(V1 v1, V2 v2, double rtol = 1e-05, double atol = 1e-08) -{ - using P = promote_t; - return abs(v1-v2) <= (atol + rtol * std::max(abs(static_cast

(v1)), abs(static_cast

(v2)))); -} - - /** \brief The square function. - - sq(x) = x*x is needed so often that it makes sense to define it as a function. - - \#include \
- Namespace: vigra - */ -template ::value> > -inline promote_t -sq(T t) -{ - return t*t; -} - -/**********************************************************/ -/* */ -/* min() */ -/* */ -/**********************************************************/ - - /** \brief A proper minimum function. - - The std::min template matches everything -- this is way too - greedy to be useful. VIGRA implements the basic min function - only for arithmetic types and provides explicit overloads for everything - else. Moreover, VIGRA's min function also computes the minimum - between two different types, as long as they have a std::common_type. - - \#include \
- Namespace: vigra - */ -template ::value && std::is_arithmetic::value> > -inline std::common_type_t -min(T1 const & t1, T2 const & t2) -{ - using T = std::common_type_t; - return std::min(static_cast(t1), static_cast(t2)); -} - -template ::value> > -inline T const & -min(T const & t1, T const & t2) -{ - return std::min(t1, t2); -} - -/**********************************************************/ -/* */ -/* max() */ -/* */ -/**********************************************************/ - - /** \brief A proper maximum function. - - The std::max template matches everything -- this is way too - greedy to be useful. VIGRA implements the basic max function - only for arithmetic types and provides explicit overloads for everything - else. Moreover, VIGRA's max function also computes the maximum - between two different types, as long as they have a std::common_type. - - \#include \
- Namespace: vigra - */ -template ::value && std::is_arithmetic::value> > -inline std::common_type_t -max(T1 const & t1, T2 const & t2) -{ - using T = std::common_type_t; - return std::max(static_cast(t1), static_cast(t2)); -} - -template ::value> > -inline T const & -max(T const & t1, T const & t2) -{ - return std::max(t1, t2); -} - -/**********************************************************/ -/* */ -/* floor(), ceil() */ -/* */ -/**********************************************************/ - - // add missing floor() and ceil() overloads for integral types - -#define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ - inline T floor(signed T t) { return t; } \ - inline T floor(unsigned T t) { return t; } \ - inline T ceil(signed T t) { return t; } \ - inline T ceil(unsigned T t) { return t; } - -XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) -XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) -XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) -XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) -XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) - -#undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL - -/**********************************************************/ -/* */ -/* dot() */ -/* */ -/**********************************************************/ - -// scalar dot is needed for generic functions that should work with -// scalars and vectors alike - -#define XTENSOR_DEFINE_SCALAR_DOT(T) \ - inline promote_t dot(T l, T r) { return l*r; } - -XTENSOR_DEFINE_SCALAR_DOT(unsigned char) -XTENSOR_DEFINE_SCALAR_DOT(unsigned short) -XTENSOR_DEFINE_SCALAR_DOT(unsigned int) -XTENSOR_DEFINE_SCALAR_DOT(unsigned long) -XTENSOR_DEFINE_SCALAR_DOT(unsigned long long) -XTENSOR_DEFINE_SCALAR_DOT(signed char) -XTENSOR_DEFINE_SCALAR_DOT(signed short) -XTENSOR_DEFINE_SCALAR_DOT(signed int) -XTENSOR_DEFINE_SCALAR_DOT(signed long) -XTENSOR_DEFINE_SCALAR_DOT(signed long long) -XTENSOR_DEFINE_SCALAR_DOT(float) -XTENSOR_DEFINE_SCALAR_DOT(double) -XTENSOR_DEFINE_SCALAR_DOT(long double) - -#undef XTENSOR_DEFINE_SCALAR_DOT - -/**********************************************************/ -/* */ -/* pow() */ -/* */ -/**********************************************************/ - -// support 'double' exponents for all floating point versions of pow() -inline float pow(float v, double e) -{ - return std::pow(v, (float)e); -} - -inline long double pow(long double v, double e) -{ - return std::pow(v, (long double)e); -} - -/**********************************************************/ -/* */ -/* roundi() */ -/* */ -/**********************************************************/ - - // round and cast to nearest long int -inline long int roundi(double t) -{ - return lround(t); -} - -/**********************************************************/ -/* */ -/* even(), odd() */ -/* */ -/**********************************************************/ - -template ::value> > -inline bool -even(T const t) -{ - return (t&1) == 0; -} - -template ::value> > -inline bool -odd(T const t) -{ - return (t&1) != 0; -} - -/**********************************************************/ -/* */ -/* sin_pi(), cos_pi() */ -/* */ -/**********************************************************/ - - /** \brief sin(pi*x). - - Essentially calls std::sin(M_PI*x) but uses a more accurate implementation - to make sure that sin_pi(1.0) == 0.0 (which does not hold for - std::sin(M_PI) due to round-off error), and sin_pi(0.5) == 1.0. - - \#include \
- Namespace: vigra - */ -template ::value> > -REAL sin_pi(REAL x) -{ - if(x < 0.0) - return -sin_pi(-x); - if(x < 0.5) - return std::sin(numeric_constants::PI * x); - - bool invert = false; - if(x < 1.0) - { - invert = true; - x = -x; - } - - REAL rem = std::floor(x); - if(odd((int)rem)) - invert = !invert; - rem = x - rem; - if(rem > 0.5) - rem = 1.0 - rem; - if(rem == 0.5) - rem = REAL(1); - else - rem = std::sin(numeric_constants::PI * rem); - return invert - ? -rem - : rem; -} - - /** \brief cos(pi*x). - - Essentially calls std::cos(M_PI*x) but uses a more accurate implementation - to make sure that cos_pi(1.0) == -1.0 and cos_pi(0.5) == 0.0. - - \#include \
- Namespace: vigra - */ -template ::value> > -REAL cos_pi(REAL x) -{ - return sin_pi(x+0.5); -} - -/**********************************************************/ -/* */ -/* gamma(), loggamma() */ -/* */ -/**********************************************************/ - -inline double gamma(double x) -{ - xtensor_precondition(x <= 171.0, - "gamma(): argument cannot exceed 171.0."); - - xtensor_precondition(x > 0.0 || fmod(x, 1.0) != 0, - "gamma(): gamma function is undefined for 0 and negative integers."); - - return tgamma(x); -} - -inline double loggamma(double x) -{ - xtensor_precondition(x > 0.0, - "loggamma(): argument must be positive."); - - xtensor_precondition(x <= 1.0e307, - "loggamma(): argument must not exceed 1e307."); - - return lgamma(x); -} - -} // namespace mathfunctions - -using mathfunctions::sq; - -/**********************************************************/ -/* */ -/* squaredNorm() */ -/* */ -/**********************************************************/ - -template -inline squared_norm_t > -squaredNorm(std::complex const & t) -{ - return sq(t.real()) + sq(t.imag()); -} -/**********************************************************/ -/* */ -/* norm() */ -/* */ -/**********************************************************/ +namespace detail { - /** \brief The norm of a numerical object. - - For scalar types: implemented as abs(t)
- otherwise: implemented as sqrt(squaredNorm(t)). - - \#include \
- Namespace: vigra - */ -template -inline auto -norm(T const & t) -> decltype(sqrt(squaredNorm(t))) +template +struct may_use_uninitialized_memory { - return sqrt(squaredNorm(t)); -} - -#define XTENSOR_DEFINE_NORM(T) \ - inline squared_norm_t squaredNorm(T t) { return sq(t); } \ - inline norm_t norm(T t) { return abs(t); } \ - inline squared_norm_t sizeDividedSquaredNorm(T t) { return sq(t); } \ - inline norm_t sizeDividedNorm(T t) { return abs(t); } - -XTENSOR_DEFINE_NORM(signed char) -XTENSOR_DEFINE_NORM(unsigned char) -XTENSOR_DEFINE_NORM(short) -XTENSOR_DEFINE_NORM(unsigned short) -XTENSOR_DEFINE_NORM(int) -XTENSOR_DEFINE_NORM(unsigned int) -XTENSOR_DEFINE_NORM(long) -XTENSOR_DEFINE_NORM(unsigned long) -XTENSOR_DEFINE_NORM(long long) -XTENSOR_DEFINE_NORM(unsigned long long) -XTENSOR_DEFINE_NORM(float) -XTENSOR_DEFINE_NORM(double) -XTENSOR_DEFINE_NORM(long double) - -#undef XTENSOR_DEFINE_NORM - -namespace tags { - -/********************************************************/ -/* */ -/* tags::size */ -/* */ -/********************************************************/ + static const bool value = std::is_scalar::value || std::is_pod::value; +}; - // Support for tags::size keyword argument - // to disambiguate array sizes from initial values. -struct SizeProxy +template +struct may_use_uninitialized_memory> { - ArrayIndex value; + static const bool value = may_use_uninitialized_memory::value; }; -struct SizeTag +template +struct may_use_uninitialized_memory> { - SizeProxy operator=(ArrayIndex s) const - { - return {s}; - } - - SizeProxy operator()(ArrayIndex s) const - { - return {s}; - } + static const bool value = false; }; -namespace { - -SizeTag size; +template +struct tiny_shape_helper; -} - -} // namespace tags - -// mask cl.exe shortcomings [begin] -// #if defined(_MSC_VER) -// #pragma warning( push ) -// #pragma warning( disable : 4503 ) -// #endif - - -// FIXME: document this -template -struct TinyShapeImpl; - -template -struct TinyShapeImpl +template +struct tiny_shape_helper { static_assert(N >= 0, "tiny_array_base(): array must have non-negative shape."); - using NextType = TinyShapeImpl; + using next_type = tiny_shape_helper; - static const ArrayIndex level = LEVEL; - static const ArrayIndex stride = NextType::total_size; - static const ArrayIndex total_size = N * stride; - static const ArrayIndex alloc_size = total_size; + static const index_t level = LEVEL; + static const index_t stride = next_type::total_size; + static const index_t total_size = N * stride; + static const index_t alloc_size = total_size; - static ArrayIndex offset(ArrayIndex const * coord) + static index_t offset(index_t const * coord) { - return stride*coord[level] + NextType::offset(coord); + return stride*coord[level] + next_type::offset(coord); } template - static ArrayIndex offset(ArrayIndex i, V...rest) + static index_t offset(index_t i, V...rest) { - return stride*i + NextType::offset(rest...); + return stride*i + next_type::offset(rest...); } }; -template -struct TinyShapeImpl +template +struct tiny_shape_helper { static_assert(N >= 0, "tiny_array_base(): array must have non-negative shape."); - static const ArrayIndex level = LEVEL; - static const ArrayIndex stride = 1; - static const ArrayIndex total_size = N; - static const ArrayIndex alloc_size = total_size; + static const index_t level = LEVEL; + static const index_t stride = 1; + static const index_t total_size = N; + static const index_t alloc_size = total_size; - static ArrayIndex offset(ArrayIndex const * coord) + static index_t offset(index_t const * coord) { return coord[level]; } - static ArrayIndex offset(ArrayIndex i) + static index_t offset(index_t i) { return i; } }; -template -struct TinyShapeImpl +template +struct tiny_shape_helper { - static const ArrayIndex level = LEVEL; - static const ArrayIndex stride = 1; - static const ArrayIndex total_size = 0; - static const ArrayIndex alloc_size = 1; + static const index_t level = LEVEL; + static const index_t stride = 1; + static const index_t total_size = 0; + static const index_t alloc_size = 1; - static ArrayIndex offset(ArrayIndex const * coord) + static index_t offset(index_t const * coord) { return coord[level]; } - static ArrayIndex offset(ArrayIndex i) + static index_t offset(index_t i) { return i; } }; template -struct TinySize +struct tiny_size_helper { - static const ArrayIndex value = TinyShapeImpl<0, N...>::total_size; - static const ArrayIndex ndim = sizeof...(N); + static const index_t value = tiny_shape_helper<0, N...>::total_size; + static const index_t ndim = sizeof...(N); }; -namespace detail { - template -struct TinyArrayIsStatic +struct tiny_array_is_static { static const int ndim = sizeof...(N)+1; static const bool value = ndim > 1 || N0 != runtime_size; @@ -628,10 +146,9 @@ struct TinyArrayIsStatic } // namespace detail #define XTENSOR_ASSERT_RUNTIME_SIZE(SHAPE, PREDICATE, MESSAGE) \ - if(detail::TinyArrayIsStatic::value) {} else \ + if(detail::tiny_array_is_static::value) {} else \ xtensor_precondition(PREDICATE, MESSAGE) - /********************************************************/ /* */ /* tiny_array_base */ @@ -652,31 +169,31 @@ class tiny_array_base : public tiny_array_tag { protected: - using ShapeHelper = TinyShapeImpl<0, N...>; + using shape_helper = detail::tiny_shape_helper<0, N...>; - static const bool derived_is_array = std::is_same >::value; - using data_array_type = typename std::conditional::type; + static const bool derived_is_view = !std::is_same >::value; + using data_array_type = typename std::conditional::type; template - void initImpl(VALUETYPE v1, V2... v2) + void init_impl(VALUETYPE v1, V2... v2) { data_[LEVEL] = v1; - initImpl(v2...); + init_impl(v2...); } template - void initImpl(VALUETYPE v1) + void init_impl(VALUETYPE v1) { data_[LEVEL] = v1; } template ::value>> - void initImpl(ITERATOR i) + void init_impl(ITERATOR i) { - for(ArrayIndex k=0; k < static_size; ++k, ++i) + for(index_t k=0; k < static_size; ++k, ++i) data_[k] = static_cast(*i); } @@ -697,12 +214,12 @@ class tiny_array_base using const_reverse_iterator = std::reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = tiny_array; + using index_type = tiny_array; - static constexpr ArrayIndex static_ndim = sizeof...(N); - static constexpr ArrayIndex static_size = ShapeHelper::total_size; + static constexpr index_t static_ndim = sizeof...(N); + static constexpr index_t static_size = shape_helper::total_size; static const bool may_use_uninitialized_memory = - UninitializedMemoryTraits::value; + detail::may_use_uninitialized_memory::value; // constructors @@ -710,7 +227,7 @@ class tiny_array_base protected: - tiny_array_base(SkipInitialization) + tiny_array_base(skip_initialization) {} // constructors to be used by tiny_array @@ -748,7 +265,7 @@ class tiny_array_base } template - tiny_array_base(U const * u, ReverseCopyTag) + tiny_array_base(U const * u, reverse_copy_tag) { for(int i=0; i(u[static_size-1-i]); @@ -756,8 +273,8 @@ class tiny_array_base // for compatibility with tiny_array_base<..., runtime_size> template - tiny_array_base(U const * u, U const * /* end */, ReverseCopyTag) - : tiny_array_base(u, ReverseCopy) + tiny_array_base(U const * u, U const * /* end */, reverse_copy_tag) + : tiny_array_base(u, copy_reversed) {} public: @@ -800,21 +317,21 @@ class tiny_array_base template constexpr bool - sameShape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const & other) const { return false; } template constexpr bool - sameShape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const & other) const { return true; } template bool - sameShape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const & other) const { return sizeof...(N) == 1 && size() == other.size(); } @@ -831,85 +348,85 @@ class tiny_array_base { static_assert(sizeof...(V)+2 == static_size, "tiny_array_base::init(): wrong number of arguments."); - initImpl<0>(v0, v1, v...); + init_impl<0>(v0, v1, v...); return static_cast(*this); } template DERIVED & init(Iterator first, Iterator end) { - ArrayIndex range = std::distance(first, end); + index_t range = std::distance(first, end); if(static_size < range) range = static_size; - for(ArrayIndex i=0; i(*first); return static_cast(*this); } // index access - reference operator[](ArrayIndex i) + reference operator[](index_t i) { return data_[i]; } - constexpr const_reference operator[](ArrayIndex i) const + constexpr const_reference operator[](index_t i) const { return data_[i]; } - reference at(ArrayIndex i) + reference at(index_t i) { if(i < 0 || i >= static_size) throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } - const_reference at(ArrayIndex i) const + const_reference at(index_t i) const { if(i < 0 || i >= static_size) throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } - reference operator[](ArrayIndex const (&i)[static_ndim]) + reference operator[](index_t const (&i)[static_ndim]) { - return data_[ShapeHelper::offset(i)]; + return data_[shape_helper::offset(i)]; } - constexpr const_reference operator[](ArrayIndex const (&i)[static_ndim]) const + constexpr const_reference operator[](index_t const (&i)[static_ndim]) const { - return data_[ShapeHelper::offset(i)]; + return data_[shape_helper::offset(i)]; } - reference at(ArrayIndex const (&i)[static_ndim]) + reference at(index_t const (&i)[static_ndim]) { - return at(ShapeHelper::offset(i)); + return at(shape_helper::offset(i)); } - const_reference at(ArrayIndex const (&i)[static_ndim]) const + const_reference at(index_t const (&i)[static_ndim]) const { - return at(ShapeHelper::offset(i)); + return at(shape_helper::offset(i)); } reference operator[](index_type const & i) { - return data_[ShapeHelper::offset(i.data())]; + return data_[shape_helper::offset(i.data())]; } constexpr const_reference operator[](index_type const & i) const { - return data_[ShapeHelper::offset(i.data())]; + return data_[shape_helper::offset(i.data())]; } reference at(index_type const & i) { - return at(ShapeHelper::offset(i.data())); + return at(shape_helper::offset(i.data())); } const_reference at(index_type const & i) const { - return at(ShapeHelper::offset(i.data())); + return at(shape_helper::offset(i.data())); } template @@ -917,7 +434,7 @@ class tiny_array_base { static_assert(sizeof...(V) == static_ndim, "tiny_array_base::operator(): wrong number of arguments."); - return data_[ShapeHelper::offset(v...)]; + return data_[shape_helper::offset(v...)]; } template @@ -925,7 +442,7 @@ class tiny_array_base { static_assert(sizeof...(V) == static_ndim, "tiny_array_base::operator(): wrong number of arguments."); - return data_[ShapeHelper::offset(v...)]; + return data_[shape_helper::offset(v...)]; } /** Get a view to the subarray with length (TO-FROM) starting at FROM. @@ -944,7 +461,7 @@ class tiny_array_base } tiny_array_view - subarray(ArrayIndex FROM, ArrayIndex TO) const + subarray(index_t FROM, index_t TO) const { xtensor_precondition(FROM >= 0 && FROM < TO && TO <= static_size, "tiny_array_base::subarray(): range out of bounds."); @@ -953,16 +470,16 @@ class tiny_array_base template tiny_array - erase(ArrayIndex m) const + erase(index_t m) const { static_assert(sizeof...(N) == 1, "tiny_array_base::erase(): array must be 1-dimensional."); xtensor_precondition(m >= 0 && m < static_size, "tiny_array::erase(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); - tiny_array res(static_size-1, DontInit); + tiny_array res(static_size-1, dont_init); for(int k=0; k tiny_array - insert(ArrayIndex m, value_type v) const + insert(index_t m, value_type v) const { static_assert(sizeof...(N) == 1, "tiny_array_base::insert(): array must be 1-dimensional."); xtensor_precondition(m >= 0 && m <= static_size, "tiny_array::insert(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); - tiny_array res(DontInit); + tiny_array res(dont_init); for(int k=0; k res(DontInit); + tiny_array res(dont_init); for(int k=0; k < size(); ++k) { XTENSOR_ASSERT_MSG(permutation[k] >= 0 && permutation[k] < size(), @@ -1048,14 +565,14 @@ class tiny_array_base constexpr const_reference back() const { return data_[static_size-1]; } constexpr bool empty() const { return static_size == 0; } - constexpr ArrayIndex size() const { return static_size; } - constexpr ArrayIndex max_size() const { return static_size; } + constexpr index_t size() const { return static_size; } + constexpr index_t max_size() const { return static_size; } constexpr index_type shape() const { return index_type{ N... }; } - constexpr ArrayIndex ndim() const { return static_ndim; } + constexpr index_t ndim() const { return static_ndim; } tiny_array_base & reverse() { - ArrayIndex i=0, j=size()-1; + index_t i=0, j=size()-1; while(i < j) xt::swap(data_[i++], data_[j--]); return *this; @@ -1096,7 +613,7 @@ class tiny_array_base template static inline tiny_array - unitVector(ArrayIndex k) + unit_vector(index_t k) { tiny_array res; res(k) = 1; @@ -1107,10 +624,10 @@ class tiny_array_base // (for compatibility with tiny_array<..., runtime_size>) static inline tiny_array - unitVector(tags::SizeProxy const & size, ArrayIndex k) + unit_vector(tags::size_proxy const & size, index_t k) { XTENSOR_ASSERT_MSG(size.value == static_size, - "tiny_array::unitVector(): size mismatch."); + "tiny_array::unit_vector(): size mismatch."); tiny_array res; res(k) = 1; return res; @@ -1119,9 +636,9 @@ class tiny_array_base /// factory function for fixed-size linear sequence starting at start with stepsize step static inline tiny_array - linearSequence(value_type start = value_type(), value_type step = value_type(1)) + linear_sequence(value_type start = value_type(), value_type step = value_type(1)) { - tiny_array res(DontInit); + tiny_array res(dont_init); for(int k=0; k < static_size; ++k, start += step) res[k] = start; return res; @@ -1133,7 +650,7 @@ class tiny_array_base range(value_type end) { value_type start = end - static_size; - tiny_array res(DontInit); + tiny_array res(dont_init); for(int k=0; k < static_size; ++k, ++start) res[k] = start; return res; @@ -1201,7 +718,7 @@ class tiny_array_base public: template - using AsType = tiny_array; + using as_type = tiny_array; using value_type = VALUETYPE; using const_value_type = typename std::add_const::type; @@ -1215,31 +732,31 @@ class tiny_array_base using const_reverse_iterator = std::reverse_iterator; using size_type = std::size_t; using difference_type = std::ptrdiff_t; - using index_type = ArrayIndex; + using index_type = index_t; - static const ArrayIndex static_size = runtime_size; - static const ArrayIndex static_ndim = 1; + static const index_t static_size = runtime_size; + static const index_t static_ndim = 1; static const bool may_use_uninitialized_memory = - UninitializedMemoryTraits::value; + detail::may_use_uninitialized_memory::value; protected: template - void initImpl(VALUETYPE v1, V2... v2) + void init_impl(VALUETYPE v1, V2... v2) { data_[LEVEL] = v1; - initImpl(v2...); + init_impl(v2...); } template - void initImpl(VALUETYPE v1) + void init_impl(VALUETYPE v1) { data_[LEVEL] = v1; } public: - tiny_array_base(ArrayIndex size=0, pointer data=0) + tiny_array_base(index_t size=0, pointer data=0) : size_(size) , data_(data) {} @@ -1276,14 +793,14 @@ class tiny_array_base template bool - sameShape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const & other) const { return sizeof...(M) == 1 && size() == other.size();; } template bool - sameShape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const & other) const { return size() == other.size(); } @@ -1300,17 +817,17 @@ class tiny_array_base { xtensor_precondition(sizeof...(V)+2 == size_, "tiny_array_base::init(): wrong number of arguments."); - initImpl<0>(v0, v1, v...); + init_impl<0>(v0, v1, v...); return static_cast(*this); } template DERIVED & init(Iterator first, Iterator end) { - ArrayIndex range = std::distance(first, end); + index_t range = std::distance(first, end); if(size_ < range) range = size_; - for(ArrayIndex i=0; i(*first); return static_cast(*this); } @@ -1323,24 +840,24 @@ class tiny_array_base // index access - reference operator[](ArrayIndex i) + reference operator[](index_t i) { return data_[i]; } - constexpr const_reference operator[](ArrayIndex i) const + constexpr const_reference operator[](index_t i) const { return data_[i]; } - reference at(ArrayIndex i) + reference at(index_t i) { if(i < 0 || i >= size_) throw std::out_of_range("tiny_array_base::at()"); return data_[i]; } - const_reference at(ArrayIndex i) const + const_reference at(index_t i) const { if(i < 0 || i >= size_) throw std::out_of_range("tiny_array_base::at()"); @@ -1365,7 +882,7 @@ class tiny_array_base The bounds must fullfill 0 <= FROM < TO <= size_. */ tiny_array_view - subarray(ArrayIndex FROM, ArrayIndex TO) const + subarray(index_t FROM, index_t TO) const { xtensor_precondition(FROM >= 0 && FROM < TO && TO <= size_, "tiny_array_base::subarray(): range out of bounds."); @@ -1374,14 +891,14 @@ class tiny_array_base tiny_array - erase(ArrayIndex m) const + erase(index_t m) const { xtensor_precondition(m >= 0 && m < size(), "tiny_array::erase(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+")."); - tiny_array res(size()-1, DontInit); + tiny_array res(size()-1, dont_init); for(int k=0; k } tiny_array - insert(ArrayIndex m, value_type v) const + insert(index_t m, value_type v) const { xtensor_precondition(m >= 0 && m <= size(), "tiny_array::insert(): " "Index "+std::to_string(m)+" out of bounds [0, "+std::to_string(size())+"]."); - tiny_array res(size()+1, DontInit); + tiny_array res(size()+1, dont_init); for(int k=0; k { xtensor_precondition(size() == 0 || size() == permutation.size(), "tiny_array::transpose(): size mismatch."); - tiny_array res(size(), DontInit); - for(ArrayIndex k=0; k < size(); ++k) + tiny_array res(size(), dont_init); + for(index_t k=0; k < size(); ++k) { XTENSOR_ASSERT_MSG(permutation[k] >= 0 && permutation[k] < size(), "transpose(): Permutation index out of bounds"); @@ -1454,13 +971,13 @@ class tiny_array_base const_reference back() const { return data_[size_-1]; } bool empty() const { return size_ == 0; } - ArrayIndex size() const { return size_; } - ArrayIndex max_size() const { return size_; } - ArrayIndex ndim() const { return static_ndim; } + index_t size() const { return size_; } + index_t max_size() const { return size_; } + index_t ndim() const { return static_ndim; } tiny_array_base & reverse() { - ArrayIndex i=0, j=size_-1; + index_t i=0, j=size_-1; while(i < j) xt::swap(data_[i++], data_[j--]); return *this; @@ -1475,7 +992,7 @@ class tiny_array_base /// factory function for the fixed-size k-th unit vector static inline tiny_array - unitVector(tags::SizeProxy const & size, ArrayIndex k) + unit_vector(tags::size_proxy const & size, index_t k) { tiny_array res(size.value); res[k] = 1; @@ -1494,9 +1011,9 @@ class tiny_array_base "tiny_array::range(): step must be non-zero."); xtensor_precondition((step > 0 && begin <= end) || (step < 0 && begin >= end), "tiny_array::range(): sign mismatch between step and (end-begin)."); - ArrayIndex size = mathfunctions::floor((abs(end-begin+step)-1)/abs(step)); - tiny_array res(size, DontInit); - for(ArrayIndex k=0; k < size; ++k, begin += step) + index_t size = floor((abs(end-begin+step)-1)/abs(step)); + tiny_array res(size, dont_init); + for(index_t k=0; k < size; ++k, begin += step) res[k] = begin; return res; } @@ -1509,15 +1026,15 @@ class tiny_array_base { xtensor_precondition(end >= 0, "tiny_array::range(): end must be non-negative."); - tiny_array res(end, DontInit); + tiny_array res(end, dont_init); auto begin = value_type(); - for(ArrayIndex k=0; k < res.size(); ++k, ++begin) + for(index_t k=0; k < res.size(); ++k, ++begin) res[k] = begin; return res; } protected: - ArrayIndex size_; + index_t size_; pointer data_; }; @@ -1531,7 +1048,7 @@ class tiny_array_base \ingroup RangesAndPoints This class contains an array of the specified VALUETYPE with - (possibly multi-dimensional) shape given by the sequence ArrayIndex ... N. + (possibly multi-dimensional) shape given by the sequence index_t ... N. The interface conforms to STL vector, except that there are no functions that change the size of a tiny_array. @@ -1557,8 +1074,8 @@ class tiny_array using base_type = tiny_array_base, M, N...>; typedef typename base_type::value_type value_type; - static const ArrayIndex static_ndim = base_type::static_ndim; - static const ArrayIndex static_size = base_type::static_size; + static const index_t static_ndim = base_type::static_ndim; + static const index_t static_size = base_type::static_size; explicit constexpr tiny_array() @@ -1566,8 +1083,8 @@ class tiny_array {} explicit - tiny_array(SkipInitialization) - : base_type(DontInit) + tiny_array(skip_initialization) + : base_type(dont_init) {} // This constructor would allow construction with round brackets, e.g.: @@ -1586,12 +1103,12 @@ class tiny_array template tiny_array(std::initializer_list v) - : base_type(DontInit) + : base_type(dont_init) { if(v.size() == 1) base_type::init(static_cast(*v.begin())); else if(v.size() == static_size) - base_type::initImpl(v.begin()); + base_type::init_impl(v.begin()); else xtensor_precondition(false, "tiny_array(std::initializer_list): wrong initialization size."); @@ -1599,7 +1116,7 @@ class tiny_array // for compatibility with tiny_array explicit - tiny_array(tags::SizeProxy const & size, + tiny_array(tags::size_proxy const & size, value_type const & v = value_type()) : base_type(v) { @@ -1608,16 +1125,16 @@ class tiny_array } // for compatibility with tiny_array - tiny_array(tags::SizeProxy const & size, SkipInitialization) - : base_type(DontInit) + tiny_array(tags::size_proxy const & size, skip_initialization) + : base_type(dont_init) { XTENSOR_ASSERT_MSG(size.value == static_size, "tiny_array(size): size argument conflicts with array length."); } // for compatibility with tiny_array - tiny_array(ArrayIndex size, SkipInitialization) - : base_type(DontInit) + tiny_array(index_t size, skip_initialization) + : base_type(dont_init) { XTENSOR_ASSERT_MSG(size == static_size, "tiny_array(size): size argument conflicts with array length."); @@ -1632,7 +1149,7 @@ class tiny_array template tiny_array(tiny_array_base const & other) - : base_type(DontInit) + : base_type(dont_init) { if(other.size() == 0) { @@ -1642,7 +1159,7 @@ class tiny_array { xtensor_precondition(this->size() == other.size(), "tiny_array(): shape mismatch."); - this->initImpl(other.begin()); + this->init_impl(other.begin()); } } @@ -1669,15 +1186,15 @@ class tiny_array template ::value> > - tiny_array(U u, ReverseCopyTag) - : base_type(u, ReverseCopy) + tiny_array(U u, reverse_copy_tag) + : base_type(u, copy_reversed) {} // for compatibility with tiny_array<..., runtime_size> template ::value> > - tiny_array(U u, U end, ReverseCopyTag) - : base_type(u, ReverseCopy) + tiny_array(U u, U end, reverse_copy_tag) + : base_type(u, copy_reversed) {} tiny_array & operator=(tiny_array const &) = default; @@ -1702,16 +1219,10 @@ class tiny_array } constexpr bool empty() const { return static_size == 0; } - constexpr ArrayIndex size() const { return static_size; } - constexpr ArrayIndex max_size() const { return static_size; } + constexpr index_t size() const { return static_size; } + constexpr index_t max_size() const { return static_size; } constexpr typename base_type::index_type shape() const { return typename base_type::index_type{ M, N... }; } - constexpr ArrayIndex ndim() const { return static_ndim; } -}; - -template -struct UninitializedMemoryTraits> -{ - static const bool value = UninitializedMemoryTraits::value; + constexpr index_t ndim() const { return static_ndim; } }; /********************************************************/ @@ -1756,8 +1267,8 @@ class tiny_array {} explicit - tiny_array(ArrayIndex size, - value_type const & initial = value_type()) + tiny_array(index_t size, + value_type const & initial = value_type()) : base_type(size) { this->data_ = alloc_.allocate(this->size_); @@ -1765,12 +1276,12 @@ class tiny_array } explicit - tiny_array(tags::SizeProxy const & size, - value_type const & initial = value_type()) + tiny_array(tags::size_proxy const & size, + value_type const & initial = value_type()) : tiny_array(size.value, initial) {} - tiny_array(ArrayIndex size, SkipInitialization) + tiny_array(index_t size, skip_initialization) : base_type(size) { this->data_ = alloc_.allocate(this->size_); @@ -1808,7 +1319,7 @@ class tiny_array template ::value> > - tiny_array(U begin, U end, ReverseCopyTag) + tiny_array(U begin, U end, reverse_copy_tag) : base_type(std::distance(begin, end)) { this->data_ = alloc_.allocate(this->size_); @@ -1866,7 +1377,7 @@ class tiny_array { if(!base_type::may_use_uninitialized_memory) { - for(ArrayIndex i=0; isize_; ++i) + for(index_t i=0; isize_; ++i) (this->data_+i)->~value_type(); } alloc_.deallocate(this->data_, this->size_); @@ -1937,15 +1448,6 @@ bool operator==(std::vector const & l, tiny_array const & r) return true; } - -template -struct UninitializedMemoryTraits> -{ - static const bool value = false; -}; - - - /********************************************************/ /* */ /* tiny_array_view */ @@ -1955,7 +1457,7 @@ struct UninitializedMemoryTraits> /** \brief Wrapper for fixed size arrays. This class wraps the memory of an array of the specified VALUETYPE - with (possibly multi-dimensional) shape given by ArrayIndex....N. + with (possibly multi-dimensional) shape given by index_t....N. Thus, the array can be accessed with an interface similar to that of std::vector (except that there are no functions that change the size of a tiny_array_view). The tiny_array_view @@ -1986,11 +1488,11 @@ class tiny_array_view typedef typename base_type::value_type value_type; typedef typename base_type::pointer pointer; typedef typename base_type::const_pointer const_pointer; - static const ArrayIndex static_size = base_type::static_size; - static const ArrayIndex static_ndim = base_type::static_ndim; + static const index_t static_size = base_type::static_size; + static const index_t static_ndim = base_type::static_ndim; tiny_array_view() - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = nullptr; } @@ -1998,7 +1500,7 @@ class tiny_array_view /** Construct view for given data array */ tiny_array_view(const_pointer data) - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = const_cast(data); } @@ -2006,7 +1508,7 @@ class tiny_array_view /** Copy constructor (shallow copy). */ tiny_array_view(tiny_array_view const & other) - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = const_cast(other.data()); } @@ -2015,7 +1517,7 @@ class tiny_array_view */ template tiny_array_view(tiny_array_base const & other) - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = const_cast(other.data()); } @@ -2048,10 +1550,10 @@ class tiny_array_view } constexpr bool empty() const { return static_size == 0; } - constexpr ArrayIndex size() const { return static_size; } - constexpr ArrayIndex max_size() const { return static_size; } + constexpr index_t size() const { return static_size; } + constexpr index_t max_size() const { return static_size; } constexpr typename base_type::index_type shape() const { return typename base_type::index_type{ M, N... }; } - constexpr ArrayIndex ndim() const { return static_ndim; } + constexpr index_t ndim() const { return static_ndim; } }; template @@ -2108,13 +1610,13 @@ class tiny_symmetric_view typedef typename base_type::const_pointer const_pointer; typedef typename base_type::reference reference; typedef typename base_type::const_reference const_reference; - using index_type = tiny_array; + using index_type = tiny_array; - static const ArrayIndex static_size = base_type::static_size; - static const ArrayIndex static_ndim = 2; + static const index_t static_size = base_type::static_size; + static const index_t static_ndim = 2; tiny_symmetric_view() - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = nullptr; } @@ -2122,7 +1624,7 @@ class tiny_symmetric_view /** Construct view for given data array */ tiny_symmetric_view(const_pointer data) - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = const_cast(data); } @@ -2130,7 +1632,7 @@ class tiny_symmetric_view /** Copy constructor (shallow copy). */ tiny_symmetric_view(tiny_symmetric_view const & other) - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = const_cast(other.data()); } @@ -2139,7 +1641,7 @@ class tiny_symmetric_view */ template tiny_symmetric_view(tiny_array_base const & other) - : base_type(DontInit) + : base_type(dont_init) { base_type::data_ = const_cast(other.data()); } @@ -2173,42 +1675,42 @@ class tiny_symmetric_view // index access - reference operator[](ArrayIndex i) + reference operator[](index_t i) { return base_type::operator[](i); } - constexpr const_reference operator[](ArrayIndex i) const + constexpr const_reference operator[](index_t i) const { return base_type::operator[](i); } - reference at(ArrayIndex i) + reference at(index_t i) { return base_type::at(i); } - const_reference at(ArrayIndex i) const + const_reference at(index_t i) const { return base_type::at(i); } - reference operator[](ArrayIndex const (&i)[2]) + reference operator[](index_t const (&i)[2]) { return this->operator()(i[0], i[1]); } - constexpr const_reference operator[](ArrayIndex const (&i)[2]) const + constexpr const_reference operator[](index_t const (&i)[2]) const { return this->operator()(i[0], i[1]); } - reference at(ArrayIndex const (&i)[static_ndim]) + reference at(index_t const (&i)[static_ndim]) { return this->at(i[0], i[1]); } - const_reference at(ArrayIndex const (&i)[static_ndim]) const + const_reference at(index_t const (&i)[static_ndim]) const { return this->at(i[0], i[1]); } @@ -2233,23 +1735,23 @@ class tiny_symmetric_view return this->at(i[0], i[1]); } - reference operator()(ArrayIndex i, ArrayIndex j) + reference operator()(index_t i, index_t j) { return (i > j) ? base_type::data_[i + N*j - (j*(j+1) >> 1)] : base_type::data_[N*i + j - (i*(i+1) >> 1)]; } - constexpr const_reference operator()(ArrayIndex const i, ArrayIndex const j) const + constexpr const_reference operator()(index_t const i, index_t const j) const { return (i > j) ? base_type::data_[i + (j*((2 * N - 1) - j) >> 1)] : base_type::data_[j + (i*((2 * N - 1) - i) >> 1)]; } - reference at(ArrayIndex i, ArrayIndex j) + reference at(index_t i, index_t j) { - ArrayIndex k = (i > j) + index_t k = (i > j) ? i + (j*((2*N-1) - j) >> 1) : j + (i*((2*N-1) - i) >> 1); if(k < 0 || k >= static_size) @@ -2257,9 +1759,9 @@ class tiny_symmetric_view return base_type::data_[k]; } - const_reference at(ArrayIndex i, ArrayIndex j) const + const_reference at(index_t i, index_t j) const { - ArrayIndex k = (i > j) + index_t k = (i > j) ? i + N*j - (j*(j+1) >> 1) : N*i + j - (i*(i+1) >> 1); if(k < 0 || k >= static_size) @@ -2268,7 +1770,7 @@ class tiny_symmetric_view } constexpr index_type shape() const { return index_type{N, N}; } - constexpr ArrayIndex ndim () const { return static_ndim; } + constexpr index_t ndim () const { return static_ndim; } }; /********************************************************/ @@ -2320,7 +1822,7 @@ inline bool operator==(tiny_array_base const & l, tiny_array_base const & r) { - if(!l.sameShape(r)) + if(!l.is_same_shape(r)) return false; for(int k=0; k < l.size(); ++k) if(l[k] != r[k]) @@ -2362,7 +1864,7 @@ inline bool operator!=(tiny_array_base const & l, tiny_array_base const & r) { - if(!l.sameShape(r)) + if(!l.is_same_shape(r)) return true; for(int k=0; k < l.size(); ++k) if(l[k] != r[k]) @@ -2422,7 +1924,7 @@ inline bool operator<(tiny_array_base const & l, std::vector const & r) { - ArrayIndex size = r.size(); + index_t size = r.size(); bool equal_res = false; if(l.size() < size) { @@ -2444,7 +1946,7 @@ inline bool operator<(std::vector const & l, tiny_array_base const & r) { - ArrayIndex size = r.size(); + index_t size = r.size(); bool equal_res = false; if(l.size() < size) { @@ -2695,48 +2197,11 @@ isclose(tiny_array_base const & l, XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), "tiny_array_base::isclose(): size mismatch."); for(int k=0; k < l.size(); ++k) - if(!mathfunctions::isclose(l[k], r[k], epsilon, epsilon)) + if(!isclose(l[k], r[k], epsilon, epsilon)) return false; return true; } -// template -// inline bool -// operator==(tiny_array_base const & l, - // lemon::Invalid const &) -// { - // for(int k=0; k < l.size(); ++k) - // if(l[k] != -1) - // return false; - // return true; -// } - -// template -// inline bool -// operator==(lemon::Invalid const &, - // tiny_array_base const & r) -// { - // return r == lemon::INVALID; -// } - -// template -// inline bool -// operator!=(tiny_array_base const & l, - // lemon::Invalid const &) -// { - // return !(l == lemon::INVALID); -// } - -// template -// inline bool -// operator!=(lemon::Invalid const &, - // tiny_array_base const & r) -// { - // return !(r == lemon::INVALID); -// } - - - /********************************************************/ /* */ /* tiny_array-Arithmetic */ @@ -2992,76 +2457,73 @@ XTENSOR_TINYARRAY_OPERATORS(>>) #endif // DOXYGEN -#define XTENSOR_TINYARRAY_UNARY_FUNCTION(FCT) \ +#define XTENSOR_TINYARRAY_UNARY_FUNCTION(NAME, FCT) \ template \ inline \ -tiny_array, N...> \ -FCT(tiny_array_base const & v) \ +tiny_array, N...> \ +NAME(tiny_array_base const & v) \ { \ - tiny_array, N...> res(v.size(), DontInit); \ + tiny_array, N...> res(v.size(), dont_init); \ for(int k=0; k < v.size(); ++k) \ - res[k] = mathfunctions::FCT(v[k]); \ + res[k] = FCT(v[k]); \ return res; \ } -XTENSOR_TINYARRAY_UNARY_FUNCTION(abs) -XTENSOR_TINYARRAY_UNARY_FUNCTION(fabs) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(cos) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sin) -XTENSOR_TINYARRAY_UNARY_FUNCTION(tan) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sin_pi) -XTENSOR_TINYARRAY_UNARY_FUNCTION(cos_pi) -XTENSOR_TINYARRAY_UNARY_FUNCTION(acos) -XTENSOR_TINYARRAY_UNARY_FUNCTION(asin) -XTENSOR_TINYARRAY_UNARY_FUNCTION(atan) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(cosh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sinh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(tanh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(acosh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(asinh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(atanh) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrt) -XTENSOR_TINYARRAY_UNARY_FUNCTION(cbrt) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrti) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sq) -XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseNorm) -XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseSquaredNorm) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(exp) -XTENSOR_TINYARRAY_UNARY_FUNCTION(exp2) -XTENSOR_TINYARRAY_UNARY_FUNCTION(expm1) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log2) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log10) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log1p) -XTENSOR_TINYARRAY_UNARY_FUNCTION(logb) -XTENSOR_TINYARRAY_UNARY_FUNCTION(ilogb) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(ceil) -XTENSOR_TINYARRAY_UNARY_FUNCTION(floor) -XTENSOR_TINYARRAY_UNARY_FUNCTION(trunc) -XTENSOR_TINYARRAY_UNARY_FUNCTION(round) -XTENSOR_TINYARRAY_UNARY_FUNCTION(lround) -XTENSOR_TINYARRAY_UNARY_FUNCTION(llround) -XTENSOR_TINYARRAY_UNARY_FUNCTION(roundi) -XTENSOR_TINYARRAY_UNARY_FUNCTION(even) -XTENSOR_TINYARRAY_UNARY_FUNCTION(odd) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sign) -XTENSOR_TINYARRAY_UNARY_FUNCTION(signi) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(erf) -XTENSOR_TINYARRAY_UNARY_FUNCTION(erfc) -XTENSOR_TINYARRAY_UNARY_FUNCTION(tgamma) -XTENSOR_TINYARRAY_UNARY_FUNCTION(lgamma) -XTENSOR_TINYARRAY_UNARY_FUNCTION(loggamma) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(conj) -XTENSOR_TINYARRAY_UNARY_FUNCTION(real) -XTENSOR_TINYARRAY_UNARY_FUNCTION(imag) -XTENSOR_TINYARRAY_UNARY_FUNCTION(arg) +XTENSOR_TINYARRAY_UNARY_FUNCTION(abs, abs) +XTENSOR_TINYARRAY_UNARY_FUNCTION(fabs, std::fabs) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(cos, std::cos) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sin, std::sin) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tan, std::tan) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sin_pi, sin_pi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(cos_pi, cos_pi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(acos, std::acos) +XTENSOR_TINYARRAY_UNARY_FUNCTION(asin, std::asin) +XTENSOR_TINYARRAY_UNARY_FUNCTION(atan, std::atan) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(cosh, std::cosh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sinh, std::sinh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tanh, std::tanh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(acosh, std::acosh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(asinh, std::asinh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(atanh, std::atanh) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrt, std::sqrt) +XTENSOR_TINYARRAY_UNARY_FUNCTION(cbrt, std::cbrt) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sq, sq) +XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseNorm, elementwiseNorm) +XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseSquaredNorm, elementwiseSquaredNorm) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(exp, std::exp) +XTENSOR_TINYARRAY_UNARY_FUNCTION(exp2, std::exp2) +XTENSOR_TINYARRAY_UNARY_FUNCTION(expm1, std::expm1) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log, std::log) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log2, std::log2) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log10, std::log10) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log1p, std::log1p) +XTENSOR_TINYARRAY_UNARY_FUNCTION(logb, std::logb) +XTENSOR_TINYARRAY_UNARY_FUNCTION(ilogb, std::ilogb) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(ceil, std::ceil) +XTENSOR_TINYARRAY_UNARY_FUNCTION(floor, std::floor) +XTENSOR_TINYARRAY_UNARY_FUNCTION(trunc, std::trunc) +XTENSOR_TINYARRAY_UNARY_FUNCTION(round, std::round) +XTENSOR_TINYARRAY_UNARY_FUNCTION(lround, std::lround) +XTENSOR_TINYARRAY_UNARY_FUNCTION(llround, std::llround) +XTENSOR_TINYARRAY_UNARY_FUNCTION(even, even) +XTENSOR_TINYARRAY_UNARY_FUNCTION(odd, odd) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sign, std::sign) +XTENSOR_TINYARRAY_UNARY_FUNCTION(signi, std::signi) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(erf, std::erf) +XTENSOR_TINYARRAY_UNARY_FUNCTION(erfc, std::erfc) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tgamma, std::tgamma) +XTENSOR_TINYARRAY_UNARY_FUNCTION(lgamma, std::lgamma) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(conj, std::conj) +XTENSOR_TINYARRAY_UNARY_FUNCTION(real, std::real) +XTENSOR_TINYARRAY_UNARY_FUNCTION(imag, std::imag) +XTENSOR_TINYARRAY_UNARY_FUNCTION(arg, std::arg) #undef XTENSOR_TINYARRAY_UNARY_FUNCTION @@ -3071,7 +2533,7 @@ inline tiny_array operator-(tiny_array_base const & v) { - tiny_array res(v.size(), DontInit); + tiny_array res(v.size(), dont_init); for(int k=0; k < v.size(); ++k) res[k] = -v[k]; return res; @@ -3083,7 +2545,7 @@ inline tiny_array operator!(tiny_array_base const & v) { - tiny_array res(v.size(), DontInit); + tiny_array res(v.size(), dont_init); for(int k=0; k < v.size(); ++k) res[k] = !v[k]; return res; @@ -3095,33 +2557,33 @@ inline tiny_array operator~(tiny_array_base const & v) { - tiny_array res(v.size(), DontInit); + tiny_array res(v.size(), dont_init); for(int k=0; k < v.size(); ++k) res[k] = ~v[k]; return res; } -#define XTENSOR_TINYARRAY_BINARY_FUNCTION(FCT) \ +#define XTENSOR_TINYARRAY_BINARY_FUNCTION(NAME, FCT) \ template \ inline \ -tiny_array \ -FCT(tiny_array_base const & l, \ +tiny_array \ +NAME(tiny_array_base const & l, \ tiny_array_base const & r) \ { \ XTENSOR_ASSERT_MSG(l.size() == r.size(), #FCT "(tiny_array, tiny_array): size mismatch."); \ - tiny_array res(l.size(), DontInit); \ + tiny_array res(l.size(), dont_init); \ for(int k=0; k < l.size(); ++k) \ - res[k] = mathfunctions::FCT(l[k], r[k]); \ + res[k] = FCT(l[k], r[k]); \ return res; \ } -XTENSOR_TINYARRAY_BINARY_FUNCTION(atan2) -XTENSOR_TINYARRAY_BINARY_FUNCTION(copysign) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fdim) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fmax) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fmin) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fmod) -XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot) +XTENSOR_TINYARRAY_BINARY_FUNCTION(atan2, std::atan2) +XTENSOR_TINYARRAY_BINARY_FUNCTION(copysign, std::copysign) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fdim, std::fdim) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmax, std::fmax) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmin, std::fmin) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmod, std::fmod) +XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot, std::hypot) #undef XTENSOR_TINYARRAY_BINARY_FUNCTION @@ -3130,11 +2592,11 @@ XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot) template inline auto pow(tiny_array_base const & v, E exponent) -> - tiny_array + tiny_array { - tiny_array res(v.size(), DontInit); + tiny_array res(v.size(), dont_init); for(int k=0; k < v.size(); ++k) - res[k] = mathfunctions::pow(v[k], exponent); + res[k] = pow(v[k], exponent); return res; } @@ -3240,7 +2702,7 @@ cumprod(tiny_array_base const & l) // shapeToStrides(tiny_array_base const & shape, // MemoryOrder order = C_ORDER) // { - // tiny_array, N> res(shape.size(), DontInit); + // tiny_array, N> res(shape.size(), dont_init); // if(order == C_ORDER) // { @@ -3266,9 +2728,9 @@ min(tiny_array_base const & l, { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), "min(): size mismatch."); - tiny_array, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) - res[k] = mathfunctions::min(l[k], r[k]); + res[k] = min(l[k], r[k]); return res; } @@ -3280,9 +2742,9 @@ tiny_array, N...> min(tiny_array_base const & l, V2 const & r) { - tiny_array, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) - res[k] = mathfunctions::min(l[k], r); + res[k] = min(l[k], r); return res; } @@ -3294,9 +2756,9 @@ tiny_array, N...> min(V1 const & l, tiny_array_base const & r) { - tiny_array, N...> res(r.size(), DontInit); + tiny_array, N...> res(r.size(), dont_init); for(int k=0; k < r.size(); ++k) - res[k] = mathfunctions::min(l, r[k]); + res[k] = min(l, r[k]); return res; } @@ -3337,9 +2799,9 @@ max(tiny_array_base const & l, { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), "max(): size mismatch."); - tiny_array, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) - res[k] = mathfunctions::max(l[k], r[k]); + res[k] = max(l[k], r[k]); return res; } @@ -3351,9 +2813,9 @@ tiny_array, N...> max(tiny_array_base const & l, V2 const & r) { - tiny_array, N...> res(l.size(), DontInit); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) - res[k] = mathfunctions::max(l[k], r); + res[k] = max(l[k], r); return res; } @@ -3365,9 +2827,9 @@ tiny_array, N...> max(V1 const & l, tiny_array_base const & r) { - tiny_array, N...> res(r.size(), DontInit); + tiny_array, N...> res(r.size(), dont_init); for(int k=0; k < r.size(); ++k) - res[k] = mathfunctions::max(l, r[k]); + res[k] = max(l, r[k]); return res; } @@ -3401,27 +2863,27 @@ max(tiny_array_base const & l) /// squared norm template inline squared_norm_t > -squaredNorm(tiny_array_base const & t) +squared_norm(tiny_array_base const & t) { using Type = squared_norm_t >; Type result = Type(); for(int i=0; i inline squared_norm_t > -squaredNorm(tiny_symmetric_view const & t) +squared_norm(tiny_symmetric_view const & t) { using Type = squared_norm_t >; Type result = Type(); for (int i = 0; i < N; ++i) { - result += squaredNorm(t(i, i)); + result += squared_norm(t(i, i)); for (int j = i + 1; j < N; ++j) { - auto c = squaredNorm(t(i, j)); + auto c = squared_norm(t(i, j)); result += c + c; } } @@ -3432,17 +2894,9 @@ squaredNorm(tiny_symmetric_view const & t) template inline norm_t -sizeDividedSquaredNorm(tiny_array_base const & t) +mean_square(tiny_array_base const & t) { - return norm_t(squaredNorm(t)) / t.size(); -} - -template -inline -norm_t -sizeDividedNorm(tiny_array_base const & t) -{ - return norm_t(norm(t)) / t.size(); + return norm_t(squared_norm(t)) / t.size(); } /// reversed copy @@ -3451,7 +2905,7 @@ inline tiny_array reversed(tiny_array_base const & t) { - return tiny_array(t.begin(), t.end(), ReverseCopy); + return tiny_array(t.begin(), t.end(), copy_reversed); } /** \brief transposed copy @@ -3480,7 +2934,7 @@ inline tiny_array transpose(tiny_array_base const & v) { - tiny_array res(DontInit); + tiny_array res(dont_init); for(int i=0; i < N1; ++i) { for(int j=0; j < N2; ++j) @@ -3506,9 +2960,9 @@ transpose(tiny_symmetric_view const & v) template inline tiny_array -clipLower(tiny_array_base const & t) +clip_lower(tiny_array_base const & t) { - return clipLower(t, V()); + return clip_lower(t, V()); } /** \brief Clip values below a threshold. @@ -3518,9 +2972,9 @@ clipLower(tiny_array_base const & t) template inline tiny_array -clipLower(tiny_array_base const & t, const V val) +clip_lower(tiny_array_base const & t, const V val) { - tiny_array res(t.size(), DontInit); + tiny_array res(t.size(), dont_init); for(int k=0; k < t.size(); ++k) { res[k] = t[k] < val ? val : t[k]; @@ -3535,9 +2989,9 @@ clipLower(tiny_array_base const & t, const V val) template inline tiny_array -clipUpper(tiny_array_base const & t, const V val) +clip_upper(tiny_array_base const & t, const V val) { - tiny_array res(t.size(), DontInit); + tiny_array res(t.size(), dont_init); for(int k=0; k < t.size(); ++k) { res[k] = t[k] > val ? val : t[k]; @@ -3556,7 +3010,7 @@ tiny_array clip(tiny_array_base const & t, const V valLower, const V valUpper) { - tiny_array res(t.size(), DontInit); + tiny_array res(t.size(), dont_init); for(int k=0; k < t.size(); ++k) { res[k] = (t[k] < valLower) @@ -3582,7 +3036,7 @@ clip(tiny_array_base const & t, { XTENSOR_ASSERT_RUNTIME_SIZE(N..., t.size() == valLower.size() && t.size() == valUpper.size(), "clip(): size mismatch."); - tiny_array res(t.size(), DontInit); + tiny_array res(t.size(), dont_init); for(int k=0; k < t.size(); ++k) { res[k] = (t[k] < valLower[k]) @@ -3602,94 +3056,6 @@ swap(tiny_array_base & l, l.swap(r); } -//@} - -#if 0 //##################################### -//////////////////////////////////////////////////////////// -// PromoteTraits specializations - -template -struct PromoteTraits, tiny_array_base > -{ - static const bool value = PromoteTraits::value; - typedef tiny_array, N...> type; -}; - -template -struct PromoteTraits, tiny_array > -{ - static const bool value = PromoteTraits::value; - typedef tiny_array, N...> type; -}; - -template -struct PromoteTraits, tiny_array_view > -{ - static const bool value = PromoteTraits::value; - typedef tiny_array, N...> type; -}; - -template -struct PromoteTraits, tiny_symmetric_view > -{ - static const bool value = PromoteTraits::value; - typedef tiny_array, N*(N+1)/2> type; -}; - -//////////////////////////////////////////////////////////// -// NumericTraits specializations - -template -struct NumericTraits> -{ - typedef tiny_array_base Type; - typedef T value_type; - typedef promote_t Promote; - typedef real_promote_t RealPromote; - typedef tiny_array::UnsignedPromote, N...> UnsignedPromote; - typedef tiny_array::ComplexPromote>, N...> ComplexPromote; - - static Type zero() { return {}; } - static Type one() { return {NumericTraits::one()}; } - static Type nonZero() { return {NumericTraits::one()}; } - static Type epsilon() { return {NumericTraits::epsilon()}; } - static Type smallestPositive() { return {NumericTraits::smallestPositive()}; } - - static const std::ptrdiff_t static_size = Type::static_size; - - static Promote toPromote(Type const & v) { return v; } - static Type fromPromote(Promote const & v) { return v; } - static Type fromRealPromote(RealPromote v) { return Type(v); } -}; - -template -struct NumericTraits> -: public NumericTraits::base_type> -{ - typedef tiny_array Type; -}; - -template -struct NumericTraits> -: public NumericTraits::base_type> -{ - typedef tiny_array_view Type; -}; - -template -struct NumericTraits> -: public NumericTraits::base_type> -{ - typedef tiny_symmetric_view Type; -}; - -// mask cl.exe shortcomings [end] -// #if defined(_MSC_VER) -// #pragma warning( pop ) -// #endif - -#endif // if 0 //##################################### - } // namespace xt #undef XTENSOR_ASSERT_INSIDE diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index ffcf352d8..5b661222e 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -36,7 +36,7 @@ bool equalVector(VECTOR1 const & v1, VECTOR2 const & v2) } template -bool equalIter(ITER1 i1, ITER1 i1end, ITER2 i2, xt::ArrayIndex size) +bool equalIter(ITER1 i1, ITER1 i1end, ITER2 i2, xt::index_t size) { if (i1end - i1 != size) return false; @@ -63,14 +63,10 @@ namespace xt TEST(xtiny, traits) { EXPECT_TRUE(BV::may_use_uninitialized_memory); - // FIXME: should be FALSE EXPECT_TRUE((tiny_array::may_use_uninitialized_memory)); - EXPECT_TRUE(UninitializedMemoryTraits::value == (SIZE != runtime_size)); - EXPECT_TRUE((UninitializedMemoryTraits, SIZE>>::value == false)); - //EXPECT_TRUE(ValueTypeTraits::value); - //EXPECT_TRUE((std::is_same::type>::value)); + EXPECT_FALSE((tiny_array, SIZE>::may_use_uninitialized_memory)); - EXPECT_TRUE((std::is_same>::value)); + EXPECT_TRUE((std::is_same>::value)); EXPECT_TRUE((std::is_same, real_promote_t>::value)); EXPECT_TRUE((std::is_same, real_promote_t>::value)); @@ -110,7 +106,7 @@ namespace xt EXPECT_EQ(iv1, (IV({ 1 }))); EXPECT_EQ(iv1, (IV({ 1.1 }))); EXPECT_EQ(iv1, IV(tags::size = SIZE, 1)); - // these should not compile: + // these should not compile: // EXPECT_EQ(iv1, IV(1)); // EXPECT_EQ(iv3, IV(1, 2, 4)); @@ -122,7 +118,7 @@ namespace xt EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), bv4.begin(), SIZE)); EXPECT_TRUE(equalVector(bv3, bv4)); - BV bv5(bv3.begin(), ReverseCopy); + BV bv5(bv3.begin(), copy_reversed); EXPECT_TRUE(equalIter(bv3.begin(), bv3.end(), std::reverse_iterator(bv5.end()), SIZE)); @@ -160,22 +156,22 @@ namespace xt for (int k = 0; k ivv{ iv3, iv3, iv3 }; - EXPECT_EQ(squaredNorm(ivv), 3 * squaredNorm(iv3)); - EXPECT_EQ(norm(ivv), sqrt(3.0*squaredNorm(iv3))); + EXPECT_EQ(squared_norm(ivv), 3 * squared_norm(iv3)); + EXPECT_EQ(norm(ivv), sqrt(3.0*squared_norm(iv3))); - EXPECT_TRUE(mathfunctions::isclose(sqrt(dot(bv3, bv3)), norm(bv3), 0.0)); - EXPECT_TRUE(mathfunctions::isclose(sqrt(dot(iv3, bv3)), norm(iv3), 0.0)); - EXPECT_TRUE(mathfunctions::isclose(sqrt(dot(fv3, fv3)), norm(fv3), 0.0f)); + EXPECT_TRUE(isclose(sqrt(dot(bv3, bv3)), norm(bv3), 0.0)); + EXPECT_TRUE(isclose(sqrt(dot(iv3, bv3)), norm(iv3), 0.0)); + EXPECT_TRUE(isclose(sqrt(dot(fv3, fv3)), norm(fv3), 0.0)); + EXPECT_NEAR(sqrt(dot(bv3, bv3)), norm(bv3), 1e-6); + EXPECT_NEAR(sqrt(dot(iv3, bv3)), norm(iv3), 1e-6); + EXPECT_NEAR(sqrt(dot(fv3, fv3)), norm(fv3), 1e-6); BV bv = bv3; bv[2] = 200; @@ -325,7 +322,7 @@ namespace xt if (SIZE == 6) expectedSM2 += 189; EXPECT_EQ(dot(bv, bv), expectedSM2); - EXPECT_EQ(squaredNorm(bv), expectedSM2); + EXPECT_EQ(squared_norm(bv), expectedSM2); EXPECT_TRUE(equalVector(bv0 + 1.0, fv1)); EXPECT_TRUE(equalVector(1.0 + bv0, fv1)); @@ -349,7 +346,7 @@ namespace xt bvp = bv3 / 2.0; fvp = bv3 / 2.0; - int ip[] = { 0, 1, 2, 3, 4, 5 }; + int ip[] = { 0, 1, 2, 3, 4, 5 }; float fp[] = { 0.5, 1.0, 2.0, 2.5, 4.0, 5.0 }; EXPECT_TRUE(equalIter(bvp.begin(), bvp.end(), ip, SIZE)); EXPECT_TRUE(equalIter(fvp.begin(), fvp.end(), fp, SIZE)); @@ -405,7 +402,7 @@ namespace xt EXPECT_EQ(sum(fv3), 7.2f); EXPECT_EQ(prod(iv3), 8); EXPECT_EQ(prod(fv3), 10.368f); - EXPECT_TRUE(mathfunctions::isclose(mean(iv3), 7.0 / SIZE, 1e-15)); + EXPECT_NEAR(mean(iv3), 7.0 / SIZE, 1e-7); float cumsumRef[] = { 1.2f, 3.6f, 7.2f}; FV cs = cumsum(fv3), csr(cumsumRef); @@ -448,7 +445,7 @@ namespace xt TEST(xtiny, 2D) { using Array = tiny_array; - using Index = tiny_array; + using Index = tiny_array; EXPECT_EQ(Array::static_ndim, 2); EXPECT_EQ(Array::static_size, 6); @@ -511,8 +508,9 @@ namespace xt EXPECT_TRUE(!allGreaterEqual(a, b)); EXPECT_TRUE(isclose(a, b, 10.0f)); - EXPECT_EQ(squaredNorm(a), 55); - EXPECT_TRUE(mathfunctions::isclose(norm(a), sqrt(55.0), 1e-15)); + EXPECT_EQ(squared_norm(a), 55); + EXPECT_TRUE(isclose(norm(a), sqrt(55.0), 1e-15)); + EXPECT_NEAR(norm(a), sqrt(55.0), 1e-15); EXPECT_EQ(min(a), 0); EXPECT_EQ(max(a), 5); EXPECT_EQ(max(a, b), b); @@ -583,7 +581,7 @@ namespace xt EXPECT_EQ(cross(a, a), e); EXPECT_EQ(dot(a, a), 14); - EXPECT_EQ(squaredNorm(a), 14); + EXPECT_EQ(squared_norm(a), 14); EXPECT_EQ(a.erase(1), (A{ 1,3 })); EXPECT_EQ(a.insert(3, 4), (A{ 1,2,3,4 })); @@ -625,7 +623,7 @@ namespace xt EXPECT_EQ((A{ 0,0,0 }), A(tags::size = 3)); EXPECT_EQ((A{ 1,1,1 }), A(tags::size = 3, 1)); - EXPECT_EQ(A::unitVector(tags::size = 3, 1), TA::unitVector(1)); + EXPECT_EQ(A::unit_vector(tags::size = 3, 1), TA::unit_vector(1)); } } // namespace xt \ No newline at end of file From ac2aa879bb8d99d1f1e5f9046d29e81e2d0de20b Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sat, 29 Jul 2017 18:46:02 +0200 Subject: [PATCH 07/27] replace decay => decay_t --- include/xtensor/xconcepts.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp index e7b768ce5..caaa60b5e 100644 --- a/include/xtensor/xconcepts.hpp +++ b/include/xtensor/xconcepts.hpp @@ -87,12 +87,12 @@ struct iterator_concept // result of arithmetic expressions // (e.g. unsigned char + unsigned char => int) template -using promote_t = decltype(*(typename std::decay::type*)0 + *(typename std::decay::type*)0); +using promote_t = decltype(*(std::decay_t*)0 + *(std::decay_t*)0); // result of algebraic expressions // (e.g. sqrt(int) => double) template -using real_promote_t = decltype(sqrt(*(typename std::decay::type*)0)); +using real_promote_t = decltype(sqrt(*(std::decay_t*)0)); // replace 'bool' with 'uint8_t', keep everything else template @@ -219,7 +219,7 @@ struct norm_of_vector_impl template struct norm_traits { - using T = typename std::decay::type; + using T = std::decay_t; static_assert(!std::is_same::value, "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); From e4a7bb91262cea9380b31b27ca1ff5038af8062e Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 11:42:31 +0200 Subject: [PATCH 08/27] improved isclose() --- include/xtensor/xmath.hpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index 8ad1cb75a..77062c0c0 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -139,13 +139,21 @@ namespace xt /* */ /**********************************************************/ - template >::value> > + template >::value> > inline bool - isclose(V1 v1, V2 v2, double rtol = 1e-05, double atol = 1e-08) + isclose(U u, V v, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) { - using P = promote_t; - return abs(v1-v2) <= (atol + rtol * std::max(abs(static_cast

(v1)), abs(static_cast

(v2)))); + using P = promote_t; + P a = static_cast

(u), + b = static_cast

(v); + + if(std::isnan(a) && std::isnan(b)) + return equal_nan; + if(std::isinf(a) && std::isinf(b)) + return std::signbit(a) == std::signbit(b); + P d = abs(a - b); + return d <= atol || d <= rtol * std::max(abs(a), abs(b)); } /**********************************************************/ @@ -1672,7 +1680,8 @@ namespace xt * @return an \ref xfunction */ #if 0 // FIXME: this template matches too greedily, add appropriate concept check - template + template ::value && !std::is_arithmetic::value>> inline auto isclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) noexcept { return detail::make_xfunction(std::make_tuple(rtol, atol, equal_nan), From 77f66216bb79cf5b5dfd6b3599ef678f18dc4b00 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 14:14:33 +0200 Subject: [PATCH 09/27] refactored algebraic operations --- include/xtensor/xconcepts.hpp | 10 +- include/xtensor/xmath.hpp | 239 +++++++++++++++------------------- include/xtensor/xtiny.hpp | 184 ++++++++++++-------------- test/test_xtiny.cpp | 7 + 4 files changed, 201 insertions(+), 239 deletions(-) diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp index caaa60b5e..6306a4cf2 100644 --- a/include/xtensor/xconcepts.hpp +++ b/include/xtensor/xconcepts.hpp @@ -89,10 +89,18 @@ struct iterator_concept template using promote_t = decltype(*(std::decay_t*)0 + *(std::decay_t*)0); +namespace promote_detail +{ + using std::sqrt; + + template + using real_promote_t = decltype(sqrt(*(std::decay_t*)0)); +} + // result of algebraic expressions // (e.g. sqrt(int) => double) template -using real_promote_t = decltype(sqrt(*(std::decay_t*)0)); +using real_promote_t = promote_detail::real_promote_t; // replace 'bool' with 'uint8_t', keep everything else template diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index 77062c0c0..052f4652c 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -42,96 +42,105 @@ namespace xt static constexpr T LN2 = 0.693147180559945309417; }; - #if 0 // FIXME: @ukoethe thinks importing into namespace xt is desirable - 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::ceil; - using std::floor; - using std::trunc; - using std::round; - using std::lround; - using std::llround; - - 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; - #endif - - // fix/extend - - /**********************************************************/ - /* */ - /* abs() */ - /* */ - /**********************************************************/ - - using std::abs; - - // define missing abs() overloads to avoid 'ambiguous overload' - // errors in template functions - #define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ - inline T abs(T t) { return t; } - - XTENSOR_DEFINE_UNSIGNED_ABS(bool) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) - - #undef XTENSOR_DEFINE_UNSIGNED_ABS - - #define XTENSOR_DEFINE_MISSING_ABS(T) \ - inline T abs(T t) { return t < 0 ? static_cast(-t) : t; } + namespace cmath + { + 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::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; + + // add missing abs() overloads for unsigned types + #define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ + inline T abs(T t) { return t; } + + XTENSOR_DEFINE_UNSIGNED_ABS(bool) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) + + #undef XTENSOR_DEFINE_UNSIGNED_ABS + + // add missing floor() and ceil() overloads for integral types + #define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ + inline T floor(signed T t) { return t; } \ + inline T floor(unsigned T t) { return t; } \ + inline T ceil(signed T t) { return t; } \ + inline T ceil(unsigned T t) { return t; } + + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) + + #undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL + + // support 'double' exponents for all floating point versions of pow() + inline float pow(float v, double e) + { + return std::pow(v, (float)e); + } - XTENSOR_DEFINE_MISSING_ABS(signed char) - XTENSOR_DEFINE_MISSING_ABS(signed short) + inline long double pow(long double v, double e) + { + return std::pow(v, (long double)e); + } + } // namespace cmath - #undef XTENSOR_DEFINE_MISSING_ABS /**********************************************************/ /* */ @@ -144,6 +153,7 @@ namespace xt inline bool isclose(U u, V v, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) { + using namespace cmath; using P = promote_t; P a = static_cast

(u), b = static_cast

(v); @@ -236,30 +246,6 @@ namespace xt return std::max(t1, t2); } - /**********************************************************/ - /* */ - /* floor(), ceil() */ - /* */ - /**********************************************************/ - - using std::floor; - using std::ceil; - - // add missing floor() and ceil() overloads for integral types - #define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ - inline T floor(signed T t) { return t; } \ - inline T floor(unsigned T t) { return t; } \ - inline T ceil(signed T t) { return t; } \ - inline T ceil(unsigned T t) { return t; } - - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) - - #undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL - /**********************************************************/ /* */ /* dot() */ @@ -287,25 +273,6 @@ namespace xt #undef XTENSOR_DEFINE_SCALAR_DOT - /**********************************************************/ - /* */ - /* pow() */ - /* */ - /**********************************************************/ - - using std::pow; - - // support 'double' exponents for all floating point versions of pow() - inline float pow(float v, double e) - { - return std::pow(v, (float)e); - } - - inline long double pow(long double v, double e) - { - return std::pow(v, (long double)e); - } - /**********************************************************/ /* */ /* even(), odd() */ @@ -401,9 +368,9 @@ namespace xt otherwise: implemented as sqrt(squared_norm(t)). */ template - inline auto - norm(T const & t) -> decltype(sqrt(squared_norm(t))) + inline auto norm(T const & t) // -> decltype(std::sqrt(squared_norm(t))) { + using cmath::sqrt; return sqrt(squared_norm(t)); } @@ -422,8 +389,10 @@ namespace xt #define XTENSOR_DEFINE_NORM(T) \ inline squared_norm_t squared_norm(T t) { return sq(t); } \ - inline norm_t norm(T t) { return abs(t); } \ - inline squared_norm_t mean_square(T t) { return sq(t); } + inline norm_t norm(T t) { using cmath::abs; return abs(t); } \ + inline squared_norm_t mean_square(T t) { return sq(t); } \ + inline squared_norm_t elementwise_squared_norm(T t) { return squared_norm(t); } \ + inline norm_t elementwise_norm(T t) { return norm(t); } XTENSOR_DEFINE_NORM(signed char) XTENSOR_DEFINE_NORM(unsigned char) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index abb193350..fa238b7d3 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -41,9 +41,6 @@ class tiny_array; template class tiny_array_view; -using std::swap; -using std::sqrt; - namespace detail { template @@ -572,17 +569,19 @@ class tiny_array_base tiny_array_base & reverse() { + using std::swap; index_t i=0, j=size()-1; while(i < j) - xt::swap(data_[i++], data_[j--]); + swap(data_[i++], data_[j--]); return *this; } void swap(tiny_array_base & other) { + using std::swap; for(int k=0; k tiny_array_base & reverse() { + using std::swap; index_t i=0, j=size_-1; while(i < j) - xt::swap(data_[i++], data_[j--]); + swap(data_[i++], data_[j--]); return *this; } void swap(tiny_array_base & other) { - xt::swap(size_, other.size_); - xt::swap(data_, other.data_); + using std::swap; + swap(size_, other.size_); + swap(data_, other.data_); } /// factory function for the fixed-size k-th unit vector @@ -1007,6 +1008,7 @@ class tiny_array_base value_type end, value_type step = value_type(1)) { + using namespace cmath; xtensor_precondition(step != 0, "tiny_array::range(): step must be non-zero."); xtensor_precondition((step > 0 && begin <= end) || (step < 0 && begin >= end), @@ -2457,73 +2459,73 @@ XTENSOR_TINYARRAY_OPERATORS(>>) #endif // DOXYGEN -#define XTENSOR_TINYARRAY_UNARY_FUNCTION(NAME, FCT) \ +#define XTENSOR_TINYARRAY_UNARY_FUNCTION(FCT) \ template \ -inline \ -tiny_array, N...> \ -NAME(tiny_array_base const & v) \ +inline auto \ +FCT(tiny_array_base const & v) \ { \ + using namespace cmath; \ tiny_array, N...> res(v.size(), dont_init); \ for(int k=0; k < v.size(); ++k) \ res[k] = FCT(v[k]); \ return res; \ } -XTENSOR_TINYARRAY_UNARY_FUNCTION(abs, abs) -XTENSOR_TINYARRAY_UNARY_FUNCTION(fabs, std::fabs) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(cos, std::cos) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sin, std::sin) -XTENSOR_TINYARRAY_UNARY_FUNCTION(tan, std::tan) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sin_pi, sin_pi) -XTENSOR_TINYARRAY_UNARY_FUNCTION(cos_pi, cos_pi) -XTENSOR_TINYARRAY_UNARY_FUNCTION(acos, std::acos) -XTENSOR_TINYARRAY_UNARY_FUNCTION(asin, std::asin) -XTENSOR_TINYARRAY_UNARY_FUNCTION(atan, std::atan) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(cosh, std::cosh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sinh, std::sinh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(tanh, std::tanh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(acosh, std::acosh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(asinh, std::asinh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(atanh, std::atanh) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrt, std::sqrt) -XTENSOR_TINYARRAY_UNARY_FUNCTION(cbrt, std::cbrt) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sq, sq) -XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseNorm, elementwiseNorm) -XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwiseSquaredNorm, elementwiseSquaredNorm) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(exp, std::exp) -XTENSOR_TINYARRAY_UNARY_FUNCTION(exp2, std::exp2) -XTENSOR_TINYARRAY_UNARY_FUNCTION(expm1, std::expm1) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log, std::log) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log2, std::log2) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log10, std::log10) -XTENSOR_TINYARRAY_UNARY_FUNCTION(log1p, std::log1p) -XTENSOR_TINYARRAY_UNARY_FUNCTION(logb, std::logb) -XTENSOR_TINYARRAY_UNARY_FUNCTION(ilogb, std::ilogb) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(ceil, std::ceil) -XTENSOR_TINYARRAY_UNARY_FUNCTION(floor, std::floor) -XTENSOR_TINYARRAY_UNARY_FUNCTION(trunc, std::trunc) -XTENSOR_TINYARRAY_UNARY_FUNCTION(round, std::round) -XTENSOR_TINYARRAY_UNARY_FUNCTION(lround, std::lround) -XTENSOR_TINYARRAY_UNARY_FUNCTION(llround, std::llround) -XTENSOR_TINYARRAY_UNARY_FUNCTION(even, even) -XTENSOR_TINYARRAY_UNARY_FUNCTION(odd, odd) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sign, std::sign) -XTENSOR_TINYARRAY_UNARY_FUNCTION(signi, std::signi) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(erf, std::erf) -XTENSOR_TINYARRAY_UNARY_FUNCTION(erfc, std::erfc) -XTENSOR_TINYARRAY_UNARY_FUNCTION(tgamma, std::tgamma) -XTENSOR_TINYARRAY_UNARY_FUNCTION(lgamma, std::lgamma) - -XTENSOR_TINYARRAY_UNARY_FUNCTION(conj, std::conj) -XTENSOR_TINYARRAY_UNARY_FUNCTION(real, std::real) -XTENSOR_TINYARRAY_UNARY_FUNCTION(imag, std::imag) -XTENSOR_TINYARRAY_UNARY_FUNCTION(arg, std::arg) +XTENSOR_TINYARRAY_UNARY_FUNCTION(abs) +XTENSOR_TINYARRAY_UNARY_FUNCTION(fabs) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(cos) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sin) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tan) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sin_pi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(cos_pi) +XTENSOR_TINYARRAY_UNARY_FUNCTION(acos) +XTENSOR_TINYARRAY_UNARY_FUNCTION(asin) +XTENSOR_TINYARRAY_UNARY_FUNCTION(atan) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(cosh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sinh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tanh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(acosh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(asinh) +XTENSOR_TINYARRAY_UNARY_FUNCTION(atanh) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrt) +XTENSOR_TINYARRAY_UNARY_FUNCTION(cbrt) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sq) +XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwise_norm) +XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwise_squared_norm) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(exp) +XTENSOR_TINYARRAY_UNARY_FUNCTION(exp2) +XTENSOR_TINYARRAY_UNARY_FUNCTION(expm1) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log2) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log10) +XTENSOR_TINYARRAY_UNARY_FUNCTION(log1p) +XTENSOR_TINYARRAY_UNARY_FUNCTION(logb) +XTENSOR_TINYARRAY_UNARY_FUNCTION(ilogb) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(ceil) +XTENSOR_TINYARRAY_UNARY_FUNCTION(floor) +XTENSOR_TINYARRAY_UNARY_FUNCTION(trunc) +XTENSOR_TINYARRAY_UNARY_FUNCTION(round) +XTENSOR_TINYARRAY_UNARY_FUNCTION(lround) +XTENSOR_TINYARRAY_UNARY_FUNCTION(llround) +XTENSOR_TINYARRAY_UNARY_FUNCTION(even) +XTENSOR_TINYARRAY_UNARY_FUNCTION(odd) +XTENSOR_TINYARRAY_UNARY_FUNCTION(sign) +XTENSOR_TINYARRAY_UNARY_FUNCTION(signi) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(erf) +XTENSOR_TINYARRAY_UNARY_FUNCTION(erfc) +XTENSOR_TINYARRAY_UNARY_FUNCTION(tgamma) +XTENSOR_TINYARRAY_UNARY_FUNCTION(lgamma) + +XTENSOR_TINYARRAY_UNARY_FUNCTION(conj) +XTENSOR_TINYARRAY_UNARY_FUNCTION(real) +XTENSOR_TINYARRAY_UNARY_FUNCTION(imag) +XTENSOR_TINYARRAY_UNARY_FUNCTION(arg) #undef XTENSOR_TINYARRAY_UNARY_FUNCTION @@ -2563,27 +2565,27 @@ operator~(tiny_array_base const & v) return res; } -#define XTENSOR_TINYARRAY_BINARY_FUNCTION(NAME, FCT) \ +#define XTENSOR_TINYARRAY_BINARY_FUNCTION(FCT) \ template \ -inline \ -tiny_array \ -NAME(tiny_array_base const & l, \ +inline auto \ +FCT(tiny_array_base const & l, \ tiny_array_base const & r) \ { \ XTENSOR_ASSERT_MSG(l.size() == r.size(), #FCT "(tiny_array, tiny_array): size mismatch."); \ + using namespace cmath; \ tiny_array res(l.size(), dont_init); \ for(int k=0; k < l.size(); ++k) \ res[k] = FCT(l[k], r[k]); \ return res; \ } -XTENSOR_TINYARRAY_BINARY_FUNCTION(atan2, std::atan2) -XTENSOR_TINYARRAY_BINARY_FUNCTION(copysign, std::copysign) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fdim, std::fdim) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fmax, std::fmax) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fmin, std::fmin) -XTENSOR_TINYARRAY_BINARY_FUNCTION(fmod, std::fmod) -XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot, std::hypot) +XTENSOR_TINYARRAY_BINARY_FUNCTION(atan2) +XTENSOR_TINYARRAY_BINARY_FUNCTION(copysign) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fdim) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmax) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmin) +XTENSOR_TINYARRAY_BINARY_FUNCTION(fmod) +XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot) #undef XTENSOR_TINYARRAY_BINARY_FUNCTION @@ -2594,6 +2596,7 @@ inline auto pow(tiny_array_base const & v, E exponent) -> tiny_array { + using namespace cmath; tiny_array res(v.size(), dont_init); for(int k=0; k < v.size(); ++k) res[k] = pow(v[k], exponent); @@ -2694,31 +2697,6 @@ cumprod(tiny_array_base const & l) return res; } - // /// \brief compute the F-order or C-order (default) stride of a given shape. - // /// Example: {200, 100, 50} => {5000, 50, 1} -// template -// inline -// tiny_array, N> -// shapeToStrides(tiny_array_base const & shape, - // MemoryOrder order = C_ORDER) -// { - // tiny_array, N> res(shape.size(), dont_init); - - // if(order == C_ORDER) - // { - // res[shape.size()-1] = 1; - // for(int k=shape.size()-2; k >= 0; --k) - // res[k] = res[k+1] * shape[k+1]; - // } - // else - // { - // res[0] = 1; - // for(int k=1; k < shape.size(); ++k) - // res[k] = res[k-1] * shape[k-1]; - // } - // return res; -// } - /// element-wise minimum template inline diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 5b661222e..c5b3f5286 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -74,6 +74,7 @@ namespace xt EXPECT_TRUE((std::is_same, 1> > >::value)); EXPECT_TRUE((std::is_same > >::value)); EXPECT_TRUE((std::is_same, 1> > >::value)); + EXPECT_TRUE((std::is_same, decltype(cos(iv3))>::value)); } TEST(xtiny, construct) @@ -253,6 +254,8 @@ namespace xt TEST(xtiny, arithmetic) { + using namespace cmath; + IV ivm3 = -iv3; FV fvm3 = -fv3; @@ -308,6 +311,8 @@ namespace xt tiny_array ivv{ iv3, iv3, iv3 }; EXPECT_EQ(squared_norm(ivv), 3 * squared_norm(iv3)); EXPECT_EQ(norm(ivv), sqrt(3.0*squared_norm(iv3))); + EXPECT_EQ(elementwise_norm(iv3), iv3); + EXPECT_EQ(elementwise_squared_norm(iv3), (IV{ 1, 4, 16 })); EXPECT_TRUE(isclose(sqrt(dot(bv3, bv3)), norm(bv3), 0.0)); EXPECT_TRUE(isclose(sqrt(dot(iv3, bv3)), norm(iv3), 0.0)); @@ -444,6 +449,8 @@ namespace xt TEST(xtiny, 2D) { + using std::sqrt; + using Array = tiny_array; using Index = tiny_array; From c50d1bcf4c9a0820e1eac6c2b158cdb6fdcb866b Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 15:27:56 +0200 Subject: [PATCH 10/27] enabled concept check in xexpression functions --- include/xtensor/xconcepts.hpp | 23 +++++++++++++++++++++-- include/xtensor/xexpression.hpp | 2 ++ include/xtensor/xiterable.hpp | 2 ++ include/xtensor/xmath.hpp | 24 +++++++++++------------- include/xtensor/xoperation.hpp | 11 +++++------ include/xtensor/xtags.hpp | 2 +- include/xtensor/xtiny.hpp | 10 +++++----- 7 files changed, 47 insertions(+), 27 deletions(-) diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp index 6306a4cf2..0a7ca7b43 100644 --- a/include/xtensor/xconcepts.hpp +++ b/include/xtensor/xconcepts.hpp @@ -33,6 +33,25 @@ using concept_check = typename std::enable_if::type; #define XTENSOR_REQUIRE typename Require = concept_check +/**********************************************************/ +/* */ +/* xexpression_concept */ +/* */ +/**********************************************************/ + +struct xexpression_tag {}; + + // xexpression_concept is fulfilled by data structures that can be used + // in xexpressions (xarray, xtensor, xfunction). By default, 'T' fulfills + // the concept if it is derived from xexpression_tag. + // + // Alternatively, one can partially specialize xexpression_concept. +template +struct xexpression_concept +{ + static const bool value = std::is_base_of >::value; +}; + /**********************************************************/ /* */ /* tiny_array_concept */ @@ -49,7 +68,7 @@ struct tiny_array_tag {}; template struct tiny_array_concept { - static const bool value = std::is_base_of::value; + static const bool value = std::is_base_of >::value; }; /**********************************************************/ @@ -65,7 +84,7 @@ struct tiny_array_concept template struct iterator_concept { - typedef typename std::decay::type V; + using V = std::decay_t; static char test(...); diff --git a/include/xtensor/xexpression.hpp b/include/xtensor/xexpression.hpp index ff13fb4f8..f07402381 100644 --- a/include/xtensor/xexpression.hpp +++ b/include/xtensor/xexpression.hpp @@ -13,6 +13,7 @@ #include #include +#include "xconcepts.hpp" #include "xutils.hpp" namespace xt @@ -38,6 +39,7 @@ namespace xt */ template class xexpression + : public xexpression_tag { public: diff --git a/include/xtensor/xiterable.hpp b/include/xtensor/xiterable.hpp index 7b45f00f8..238d9f65a 100644 --- a/include/xtensor/xiterable.hpp +++ b/include/xtensor/xiterable.hpp @@ -9,6 +9,7 @@ #ifndef XITERABLE_HPP #define XITERABLE_HPP +#include "xconcepts.hpp" #include "xiterator.hpp" namespace xt @@ -35,6 +36,7 @@ namespace xt */ template class xconst_iterable + : public xexpression_tag { public: diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index 052f4652c..146ab773b 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -44,6 +44,9 @@ namespace xt namespace cmath { + // create a namespace for just the algebraic functions from std + // and add a few fixes to avoid ambiguous overloads in templates + using std::abs; using std::fabs; @@ -129,7 +132,7 @@ namespace xt #undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL - // support 'double' exponents for all floating point versions of pow() + // support 'double' exponents for all floating-point versions of pow() inline float pow(float v, double e) { return std::pow(v, (float)e); @@ -1648,15 +1651,13 @@ namespace xt * @param equal_nan if true, isclose returns true if both elements of e1 and e2 are NaN * @return an \ref xfunction */ -#if 0 // FIXME: this template matches too greedily, add appropriate concept check template ::value && !std::is_arithmetic::value>> + XTENSOR_REQUIRE::value || xexpression_concept::value> > inline auto isclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) noexcept { return detail::make_xfunction(std::make_tuple(rtol, atol, equal_nan), std::forward(e1), std::forward(e2)); } -#endif /** * @ingroup classif_functions @@ -1695,7 +1696,6 @@ namespace xt * @param axes the axes along which the sum is performed (optional) * @return an \ref xreducer */ -#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline auto sum(E&& e, X&& axes) noexcept { @@ -1703,7 +1703,8 @@ namespace xt return reduce(functor_type(), std::forward(e), std::forward(axes)); } - template + template ::value> > inline auto sum(E&& e) noexcept { using functor_type = std::plus::value_type>; @@ -1724,7 +1725,6 @@ namespace xt using functor_type = std::plus::value_type>; return reduce(functor_type(), std::forward(e), axes); } -#endif #endif /** @@ -1737,7 +1737,6 @@ namespace xt * @param axes the axes along which the product is computed (optional) * @return an \ref xreducer */ -#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline auto prod(E&& e, X&& axes) noexcept { @@ -1745,7 +1744,8 @@ namespace xt return reduce(functor_type(), std::forward(e), std::forward(axes)); } - template + template ::value> > inline auto prod(E&& e) noexcept { using functor_type = std::multiplies::value_type>; @@ -1766,7 +1766,6 @@ namespace xt using functor_type = std::multiplies::value_type>; return reduce(functor_type(), std::forward(e), axes); } -#endif #endif /** @@ -1779,7 +1778,6 @@ namespace xt * @param axes the axes along which the mean is computed (optional) * @return an \ref xexpression */ -#if 0 // FIXME: this template matches too greedily, add appropriate concept check template inline auto mean(E&& e, X&& axes) noexcept { @@ -1789,7 +1787,8 @@ namespace xt return std::move(s) / value_type(size / s.size()); } - template + template ::value> > inline auto mean(E&& e) noexcept { using value_type = typename std::decay_t::value_type; @@ -1816,7 +1815,6 @@ namespace xt return std::move(s) / value_type(size / s.size()); } #endif -#endif } #endif diff --git a/include/xtensor/xoperation.hpp b/include/xtensor/xoperation.hpp index f8cb40181..495fa7c62 100644 --- a/include/xtensor/xoperation.hpp +++ b/include/xtensor/xoperation.hpp @@ -13,6 +13,7 @@ #include #include +#include "xconcepts.hpp" #include "xfunction.hpp" #include "xscalar.hpp" #include "xstrides.hpp" @@ -477,8 +478,8 @@ namespace xt * @param e an \ref xexpression * @return a boolean */ -#if 0 // FIXME: this template matches too greedily, add appropriate concept check - template + template ::value> > inline bool any(E&& e) { using xtype = std::decay_t; @@ -493,7 +494,6 @@ namespace xt [](const typename std::decay_t::value_type& el) { return el; }); } } -#endif /** * @ingroup logical_operators @@ -504,8 +504,8 @@ namespace xt * @param e an \ref xexpression * @return a boolean */ -#if 0 // FIXME: this template matches too greedily, add appropriate concept check - template + template ::value> > inline bool all(E&& e) { using xtype = std::decay_t; @@ -520,7 +520,6 @@ namespace xt [](const typename std::decay_t::value_type& el) { return el; }); } } -#endif } #endif diff --git a/include/xtensor/xtags.hpp b/include/xtensor/xtags.hpp index b95ff8752..9c7d2a185 100644 --- a/include/xtensor/xtags.hpp +++ b/include/xtensor/xtags.hpp @@ -22,7 +22,7 @@ namespace xt static const int runtime_size = -1; /// Don't initialize memory that gets overwritten anyway. -enum skip_initialization { dont_init }; +enum skip_initialization_tag { dont_init }; /// Copy-construct array in reversed order. enum reverse_copy_tag { copy_reversed }; diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index fa238b7d3..ffb7f5f0e 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -224,7 +224,7 @@ class tiny_array_base protected: - tiny_array_base(skip_initialization) + tiny_array_base(skip_initialization_tag) {} // constructors to be used by tiny_array @@ -1085,7 +1085,7 @@ class tiny_array {} explicit - tiny_array(skip_initialization) + tiny_array(skip_initialization_tag) : base_type(dont_init) {} @@ -1127,7 +1127,7 @@ class tiny_array } // for compatibility with tiny_array - tiny_array(tags::size_proxy const & size, skip_initialization) + tiny_array(tags::size_proxy const & size, skip_initialization_tag) : base_type(dont_init) { XTENSOR_ASSERT_MSG(size.value == static_size, @@ -1135,7 +1135,7 @@ class tiny_array } // for compatibility with tiny_array - tiny_array(index_t size, skip_initialization) + tiny_array(index_t size, skip_initialization_tag) : base_type(dont_init) { XTENSOR_ASSERT_MSG(size == static_size, @@ -1283,7 +1283,7 @@ class tiny_array : tiny_array(size.value, initial) {} - tiny_array(index_t size, skip_initialization) + tiny_array(index_t size, skip_initialization_tag) : base_type(size) { this->data_ = alloc_.allocate(this->size_); From 13969b0e668102eceaa955bbf02d18a080eada5e Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 15:45:08 +0200 Subject: [PATCH 11/27] added another concept check --- include/xtensor/xmath.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index 146ab773b..a33f2cde9 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -1070,7 +1070,8 @@ namespace xt * @return an \ref xfunction * @note e1 and e2 can't be both scalars. */ - template + template ::value || xexpression_concept::value> > inline auto pow(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t { From 098908c8c34f9720c1f09a930aa1b641298a7425 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 15:49:41 +0200 Subject: [PATCH 12/27] improved pow(tiny_array) --- include/xtensor/xtiny.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index ffb7f5f0e..d604db5cf 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -2593,8 +2593,7 @@ XTENSOR_TINYARRAY_BINARY_FUNCTION(hypot) */ template inline auto -pow(tiny_array_base const & v, E exponent) -> - tiny_array +pow(tiny_array_base const & v, E exponent) { using namespace cmath; tiny_array res(v.size(), dont_init); From c27819cdd6140c54b52ef8ccd2f9f85547fa832b Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 15:53:55 +0200 Subject: [PATCH 13/27] changed const -> constexpr --- include/xtensor/xtiny.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index d604db5cf..28cfae3a9 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -1076,8 +1076,8 @@ class tiny_array using base_type = tiny_array_base, M, N...>; typedef typename base_type::value_type value_type; - static const index_t static_ndim = base_type::static_ndim; - static const index_t static_size = base_type::static_size; + static constexpr index_t static_ndim = base_type::static_ndim; + static constexpr index_t static_size = base_type::static_size; explicit constexpr tiny_array() From 298bd237f36513017ee0d96fbb4fb15905b09ed0 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 17:30:21 +0200 Subject: [PATCH 14/27] improved type inference, finished transition to lowercase --- include/xtensor/xconcepts.hpp | 87 ++++++++++++------------- include/xtensor/xmath.hpp | 18 +++--- include/xtensor/xtiny.hpp | 115 +++++++++++++++------------------- test/test_xtiny.cpp | 47 +++++++------- 4 files changed, 121 insertions(+), 146 deletions(-) diff --git a/include/xtensor/xconcepts.hpp b/include/xtensor/xconcepts.hpp index 0a7ca7b43..7b621aa68 100644 --- a/include/xtensor/xconcepts.hpp +++ b/include/xtensor/xconcepts.hpp @@ -103,12 +103,7 @@ struct iterator_concept /* */ /**********************************************************/ - // result of arithmetic expressions - // (e.g. unsigned char + unsigned char => int) -template -using promote_t = decltype(*(std::decay_t*)0 + *(std::decay_t*)0); - -namespace promote_detail +namespace concepts_detail { using std::sqrt; @@ -116,10 +111,15 @@ namespace promote_detail using real_promote_t = decltype(sqrt(*(std::decay_t*)0)); } + // result of arithmetic expressions + // (e.g. unsigned char + unsigned char => int) +template +using promote_t = decltype(*(std::decay_t*)0 + *(std::decay_t*)0); + // result of algebraic expressions // (e.g. sqrt(int) => double) template -using real_promote_t = promote_detail::real_promote_t; +using real_promote_t = concepts_detail::real_promote_t; // replace 'bool' with 'uint8_t', keep everything else template @@ -134,7 +134,7 @@ using bool_promote_t = typename std::conditional::value, u template struct norm_traits; -namespace detail { +namespace concepts_detail { template ::value> struct norm_of_scalar_impl; @@ -143,22 +143,16 @@ template struct norm_of_scalar_impl { static const bool value = false; - typedef void * norm_type; - typedef void * squared_norm_type; + using norm_type = void *; + using squared_norm_type = void *; }; template struct norm_of_scalar_impl { static const bool value = true; - typedef T norm_type; - typedef typename - std::conditional::value, - typename std::conditional= 4, - uint64_t, - uint32_t>::type, - T>::type - squared_norm_type; + using norm_type = decltype(norm(*(T*)0)); + using squared_norm_type = decltype(squared_norm(*(T*)0)); }; template ::value, @@ -168,15 +162,15 @@ struct norm_of_array_elements_impl; template <> struct norm_of_array_elements_impl { - typedef void * norm_type; - typedef void * squared_norm_type; + using norm_type = void *; + using squared_norm_type = void *; }; template struct norm_of_array_elements_impl { - typedef typename norm_traits::norm_type norm_type; - typedef typename norm_traits::squared_norm_type squared_norm_type; + using norm_type = typename norm_traits::norm_type; + using squared_norm_type = typename norm_traits::squared_norm_type; }; template @@ -185,22 +179,22 @@ struct norm_of_array_elements_impl static_assert(!std::is_same::value, "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); - typedef double norm_type; - typedef uint64_t squared_norm_type; + using norm_type = double; + using squared_norm_type = uint64_t; }; template struct norm_of_array_elements_impl { - typedef double norm_type; - typedef double squared_norm_type; + using norm_type = double; + using squared_norm_type = double; }; template <> struct norm_of_array_elements_impl { - typedef long double norm_type; - typedef long double squared_norm_type; + using norm_type = long double; + using squared_norm_type = long double; }; template @@ -211,23 +205,21 @@ struct norm_of_vector_impl template static typename U::value_type test(U*, typename U::value_type * = 0); - typedef decltype(test((ARRAY*)0)) T; + using T = decltype(test((ARRAY*)0)); static const bool value = !std::is_same::value; - typedef typename norm_of_array_elements_impl::norm_type norm_type; - typedef typename norm_of_array_elements_impl::squared_norm_type squared_norm_type; + using norm_type = typename norm_of_array_elements_impl::norm_type; + using squared_norm_type = typename norm_of_array_elements_impl::squared_norm_type; }; -} // namespace detail +} // namespace concepts_detail /* norm_traits implement the following default rules, which are designed to minimize the possibility of overflow: - * T is an integer type: - norm_type is T itself, - squared_norm_type is 'uint32_t' (sizeof(T) < 4) or 'uint64_t' (otherwise) - * T is a floating-point type: - norm_type and squared_norm_type are T itself, + * T is a built-in type: + norm_type is the result type of abs(), + squared_norm_type is the result type of sq() * T is a container of 'long double' elements: norm_type and squared_norm_type are 'long double' * T is a container of another floating-point type: @@ -251,22 +243,22 @@ struct norm_traits static_assert(!std::is_same::value, "'char' is not a numeric type, use 'signed char' or 'unsigned char'."); - typedef detail::norm_of_scalar_impl norm_of_scalar; - typedef detail::norm_of_vector_impl norm_of_vector; + using norm_of_scalar = concepts_detail::norm_of_scalar_impl; + using norm_of_vector = concepts_detail::norm_of_vector_impl; static const bool value = norm_of_scalar::value || norm_of_vector::value; static_assert(value, "norm_traits are undefined for type U."); - typedef typename std::conditional::type - norm_type; + using norm_type = + typename std::conditional::type; - typedef typename std::conditional::type - squared_norm_type; + using squared_norm_type = + typename std::conditional::type; }; template @@ -275,7 +267,6 @@ using squared_norm_t = typename norm_traits::squared_norm_type; template using norm_t = typename norm_traits::norm_type; - } // namespace xt #endif // XCONCEPTS_HPP diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index a33f2cde9..7d83a6d8a 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -181,7 +181,7 @@ namespace xt */ template ::value> > - inline promote_t + inline auto sq(T t) { return t*t; @@ -258,7 +258,7 @@ namespace xt // scalar dot is needed for generic functions that should work with // scalars and vectors alike #define XTENSOR_DEFINE_SCALAR_DOT(T) \ - inline promote_t dot(T l, T r) { return l*r; } + inline auto dot(T l, T r) { return l*r; } XTENSOR_DEFINE_SCALAR_DOT(unsigned char) XTENSOR_DEFINE_SCALAR_DOT(unsigned short) @@ -371,7 +371,7 @@ namespace xt otherwise: implemented as sqrt(squared_norm(t)). */ template - inline auto norm(T const & t) // -> decltype(std::sqrt(squared_norm(t))) + inline auto norm(T const & t) { using cmath::sqrt; return sqrt(squared_norm(t)); @@ -384,18 +384,18 @@ namespace xt /**********************************************************/ template - inline squared_norm_t > + inline auto squared_norm(std::complex const & t) { return sq(t.real()) + sq(t.imag()); } #define XTENSOR_DEFINE_NORM(T) \ - inline squared_norm_t squared_norm(T t) { return sq(t); } \ - inline norm_t norm(T t) { using cmath::abs; return abs(t); } \ - inline squared_norm_t mean_square(T t) { return sq(t); } \ - inline squared_norm_t elementwise_squared_norm(T t) { return squared_norm(t); } \ - inline norm_t elementwise_norm(T t) { return norm(t); } + inline auto squared_norm(T t) { return sq(t); } \ + inline auto mean_square(T t) { return sq(t); } \ + inline auto elementwise_squared_norm(T t) { return sq(t); } \ + inline auto norm(T t) { return cmath::abs(t); } \ + inline auto elementwise_norm(T t) { return cmath::abs(t); } XTENSOR_DEFINE_NORM(signed char) XTENSOR_DEFINE_NORM(unsigned char) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 28cfae3a9..724676fe1 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -213,8 +213,8 @@ class tiny_array_base using difference_type = std::ptrdiff_t; using index_type = tiny_array; - static constexpr index_t static_ndim = sizeof...(N); - static constexpr index_t static_size = shape_helper::total_size; + static const index_t static_ndim = sizeof...(N); + static const index_t static_size = shape_helper::total_size; static const bool may_use_uninitialized_memory = detail::may_use_uninitialized_memory::value; @@ -314,14 +314,14 @@ class tiny_array_base template constexpr bool - is_same_shape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const &) const { return false; } template constexpr bool - is_same_shape(tiny_array_base const & other) const + is_same_shape(tiny_array_base const &) const { return true; } @@ -1074,10 +1074,7 @@ class tiny_array { public: using base_type = tiny_array_base, M, N...>; - - typedef typename base_type::value_type value_type; - static constexpr index_t static_ndim = base_type::static_ndim; - static constexpr index_t static_size = base_type::static_size; + using value_type = VALUETYPE; explicit constexpr tiny_array() @@ -1219,12 +1216,6 @@ class tiny_array base_type::operator=(other); return *this; } - - constexpr bool empty() const { return static_size == 0; } - constexpr index_t size() const { return static_size; } - constexpr index_t max_size() const { return static_size; } - constexpr typename base_type::index_type shape() const { return typename base_type::index_type{ M, N... }; } - constexpr index_t ndim() const { return static_ndim; } }; /********************************************************/ @@ -1261,7 +1252,6 @@ class tiny_array { public: using base_type = tiny_array_base, runtime_size>; - using value_type = VALUETYPE; tiny_array() @@ -1485,11 +1475,11 @@ class tiny_array_view : public tiny_array_base, M, N...> { public: - using base_type = tiny_array_base, M, N...>; + using base_type = tiny_array_base, M, N...>; + using value_type = VALUETYPE; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; - typedef typename base_type::value_type value_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; static const index_t static_size = base_type::static_size; static const index_t static_ndim = base_type::static_ndim; @@ -1550,12 +1540,6 @@ class tiny_array_view base_type::data_[k] = static_cast(r[k]); return *this; } - - constexpr bool empty() const { return static_size == 0; } - constexpr index_t size() const { return static_size; } - constexpr index_t max_size() const { return static_size; } - constexpr typename base_type::index_type shape() const { return typename base_type::index_type{ M, N... }; } - constexpr index_t ndim() const { return static_ndim; } }; template @@ -1571,7 +1555,7 @@ class tiny_array_view /********************************************************/ /* */ -/* tiny_symmetric_view */ +/* tiny_symmetric_view */ /* */ /********************************************************/ @@ -1605,17 +1589,16 @@ class tiny_symmetric_view : public tiny_array_base, N*(N+1)/2> { public: - using base_type = tiny_array_base, N*(N+1)/2>; - - typedef typename base_type::value_type value_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; - using index_type = tiny_array; + using base_type = tiny_array_base, N*(N+1)/2>; + using value_type = VALUETYPE; + 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 index_type = tiny_array; - static const index_t static_size = base_type::static_size; - static const index_t static_ndim = 2; + static const index_t static_size = base_type::static_size; + static const index_t static_ndim = 2; tiny_symmetric_view() : base_type(dont_init) @@ -1777,7 +1760,7 @@ class tiny_symmetric_view /********************************************************/ /* */ -/* tiny_symmetric_view output */ +/* tiny_symmetric_view output */ /* */ /********************************************************/ @@ -2006,7 +1989,7 @@ any(tiny_array_base const & t) /// check if all elements are zero (or 'false' if V is bool) template inline bool -allZero(tiny_array_base const & t) +all_zero(tiny_array_base const & t) { for(int i=0; i const & t) /// pointwise less-than template inline bool -allLess(tiny_array_base const & l, +all_less(tiny_array_base const & l, tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "tiny_array_base::allLess(): size mismatch."); + "tiny_array_base::all_less(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] >= r[k]) return false; @@ -2034,7 +2017,7 @@ template ::value && std::is_convertible::value> > inline bool -allLess(tiny_array_base const & l, +all_less(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2049,7 +2032,7 @@ template ::value && std::is_convertible::value> > inline bool -allLess(V1 const & l, +all_less(V1 const & l, tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) @@ -2061,11 +2044,11 @@ allLess(V1 const & l, /// pointwise less-equal template inline bool -allLessEqual(tiny_array_base const & l, +all_less_equal(tiny_array_base const & l, tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "tiny_array_base::allLessEqual(): size mismatch."); + "tiny_array_base::all_less_equal(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] > r[k]) return false; @@ -2078,7 +2061,7 @@ template ::value && std::is_convertible::value> > inline bool -allLessEqual(tiny_array_base const & l, +all_less_equal(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2093,7 +2076,7 @@ template ::value && std::is_convertible::value> > inline bool -allLessEqual(V1 const & l, +all_less_equal(V1 const & l, tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) @@ -2105,11 +2088,11 @@ allLessEqual(V1 const & l, /// pointwise greater-than template inline bool -allGreater(tiny_array_base const & l, +all_greater(tiny_array_base const & l, tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "tiny_array_base::allGreater(): size mismatch."); + "tiny_array_base::all_greater(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] <= r[k]) return false; @@ -2122,7 +2105,7 @@ template ::value && std::is_convertible::value> > inline bool -allGreater(tiny_array_base const & l, +all_greater(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2137,7 +2120,7 @@ template ::value && std::is_convertible::value> > inline bool -allGreater(V1 const & l, +all_greater(V1 const & l, tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) @@ -2149,11 +2132,11 @@ allGreater(V1 const & l, /// pointwise greater-equal template inline bool -allGreaterEqual(tiny_array_base const & l, +all_greater_equal(tiny_array_base const & l, tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "tiny_array_base::allGreaterEqual(): size mismatch."); + "tiny_array_base::all_greater_equal(): size mismatch."); for(int k=0; k < l.size(); ++k) if (l[k] < r[k]) return false; @@ -2166,7 +2149,7 @@ template ::value && std::is_convertible::value> > inline bool -allGreaterEqual(tiny_array_base const & l, +all_greater_equal(tiny_array_base const & l, V2 const & r) { for(int k=0; k < l.size(); ++k) @@ -2181,7 +2164,7 @@ template ::value && std::is_convertible::value> > inline bool -allGreaterEqual(V1 const & l, +all_greater_equal(V1 const & l, tiny_array_base const & r) { for(int k=0; k < r.size(); ++k) @@ -2206,7 +2189,7 @@ isclose(tiny_array_base const & l, /********************************************************/ /* */ -/* tiny_array-Arithmetic */ +/* tiny_array-Arithmetic */ /* */ /********************************************************/ @@ -2379,7 +2362,7 @@ operator%(V1 l, template ::value && \ std::is_convertible::value> > \ -DERIVED & \ +inline DERIVED & \ operator OP##=(tiny_array_base & l, \ V2 r) \ { \ @@ -2715,11 +2698,11 @@ min(tiny_array_base const & l, template ::value>> inline -tiny_array, N...> +tiny_array, N...> min(tiny_array_base const & l, V2 const & r) { - tiny_array, N...> res(l.size(), dont_init); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) res[k] = min(l[k], r); return res; @@ -2729,11 +2712,11 @@ min(tiny_array_base const & l, template ::value>> inline -tiny_array, N...> +tiny_array, N...> min(V1 const & l, tiny_array_base const & r) { - tiny_array, N...> res(r.size(), dont_init); + tiny_array, N...> res(r.size(), dont_init); for(int k=0; k < r.size(); ++k) res[k] = min(l, r[k]); return res; @@ -2770,13 +2753,13 @@ min(tiny_array_base const & l) /// element-wise maximum template inline -tiny_array, N...> +tiny_array, N...> max(tiny_array_base const & l, tiny_array_base const & r) { XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), "max(): size mismatch."); - tiny_array, N...> res(l.size(), dont_init); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) res[k] = max(l[k], r[k]); return res; @@ -2786,11 +2769,11 @@ max(tiny_array_base const & l, template ::value>> inline -tiny_array, N...> +tiny_array, N...> max(tiny_array_base const & l, V2 const & r) { - tiny_array, N...> res(l.size(), dont_init); + tiny_array, N...> res(l.size(), dont_init); for(int k=0; k < l.size(); ++k) res[k] = max(l[k], r); return res; @@ -2800,11 +2783,11 @@ max(tiny_array_base const & l, template ::value>> inline -tiny_array, N...> +tiny_array, N...> max(V1 const & l, tiny_array_base const & r) { - tiny_array, N...> res(r.size(), dont_init); + tiny_array, N...> res(r.size(), dont_init); for(int k=0; k < r.size(); ++k) res[k] = max(l, r[k]); return res; diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index c5b3f5286..e8f4f57ce 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -70,8 +70,9 @@ namespace xt EXPECT_TRUE((std::is_same, real_promote_t>::value)); EXPECT_TRUE((std::is_same, real_promote_t>::value)); - EXPECT_TRUE((std::is_same > >::value)); - EXPECT_TRUE((std::is_same, 1> > >::value)); + EXPECT_TRUE((std::is_same > >::value)); + EXPECT_TRUE((std::is_same, 1> > >::value)); + EXPECT_TRUE((std::is_same, 1> > >::value)); EXPECT_TRUE((std::is_same > >::value)); EXPECT_TRUE((std::is_same, 1> > >::value)); EXPECT_TRUE((std::is_same, decltype(cos(iv3))>::value)); @@ -219,18 +220,18 @@ namespace xt EXPECT_TRUE(bv0 < bv1); - EXPECT_TRUE(allLess(bv0, bv1)); - EXPECT_TRUE(!allLess(bv1, bv3)); - EXPECT_TRUE(allGreater(bv1, bv0)); - EXPECT_TRUE(!allGreater(bv3, bv1)); - EXPECT_TRUE(allLessEqual(bv0, bv1)); - EXPECT_TRUE(allLessEqual(0, bv0)); - EXPECT_TRUE(allLessEqual(bv0, 0)); - EXPECT_TRUE(allLessEqual(bv1, bv3)); - EXPECT_TRUE(!allLessEqual(bv3, bv1)); - EXPECT_TRUE(allGreaterEqual(bv1, bv0)); - EXPECT_TRUE(allGreaterEqual(bv3, bv1)); - EXPECT_TRUE(!allGreaterEqual(bv1, bv3)); + EXPECT_TRUE(all_less(bv0, bv1)); + EXPECT_TRUE(!all_less(bv1, bv3)); + EXPECT_TRUE(all_greater(bv1, bv0)); + EXPECT_TRUE(!all_greater(bv3, bv1)); + EXPECT_TRUE(all_less_equal(bv0, bv1)); + EXPECT_TRUE(all_less_equal(0, bv0)); + EXPECT_TRUE(all_less_equal(bv0, 0)); + EXPECT_TRUE(all_less_equal(bv1, bv3)); + EXPECT_TRUE(!all_less_equal(bv3, bv1)); + EXPECT_TRUE(all_greater_equal(bv1, bv0)); + EXPECT_TRUE(all_greater_equal(bv3, bv1)); + EXPECT_TRUE(!all_greater_equal(bv1, bv3)); EXPECT_TRUE(isclose(fv3, fv3)); @@ -454,8 +455,8 @@ namespace xt using Array = tiny_array; using Index = tiny_array; - EXPECT_EQ(Array::static_ndim, 2); - EXPECT_EQ(Array::static_size, 6); + EXPECT_TRUE(Array::static_ndim == 2); + EXPECT_TRUE(Array::static_size == 6); EXPECT_TRUE((std::is_same::value)); int adata[] = { 4,5,6,7,8,9 }; @@ -508,11 +509,11 @@ namespace xt EXPECT_TRUE(!all(a)); EXPECT_TRUE(any(b)); EXPECT_TRUE(all(b)); - EXPECT_TRUE(!allZero(a)); - EXPECT_TRUE(allLess(a, b)); - EXPECT_TRUE(allLessEqual(a, b)); - EXPECT_TRUE(!allGreater(a, b)); - EXPECT_TRUE(!allGreaterEqual(a, b)); + EXPECT_TRUE(!all_zero(a)); + EXPECT_TRUE(all_less(a, b)); + EXPECT_TRUE(all_less_equal(a, b)); + EXPECT_TRUE(!all_greater(a, b)); + EXPECT_TRUE(!all_greater_equal(a, b)); EXPECT_TRUE(isclose(a, b, 10.0f)); EXPECT_EQ(squared_norm(a), 55); @@ -578,10 +579,10 @@ namespace xt EXPECT_TRUE(all(d)); EXPECT_TRUE(!all(c)); EXPECT_TRUE(any(c)); - EXPECT_TRUE(!allZero(c)); + EXPECT_TRUE(!all_zero(c)); EXPECT_TRUE(!all(e)); EXPECT_TRUE(!any(e)); - EXPECT_TRUE(allZero(e)); + EXPECT_TRUE(all_zero(e)); EXPECT_EQ(prod(a), 6); EXPECT_EQ(prod(A()), 0); From 10e7bb9558758591d909d1e866bdddb8ee080e32 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 17:40:36 +0200 Subject: [PATCH 15/27] minor fixes --- include/xtensor/xtiny.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 724676fe1..614bcef37 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -638,7 +638,7 @@ class tiny_array_base linear_sequence(value_type start = value_type(), value_type step = value_type(1)) { tiny_array res(dont_init); - for(int k=0; k < static_size; ++k, start += step) + for(index_t k=0; k < static_size; ++k, start += step) res[k] = start; return res; } @@ -648,9 +648,9 @@ class tiny_array_base tiny_array range(value_type end) { - value_type start = end - static_size; + value_type start = end - static_cast(static_size); tiny_array res(dont_init); - for(int k=0; k < static_size; ++k, ++start) + for(index_t k=0; k < static_size; ++k, ++start) res[k] = start; return res; } @@ -1075,6 +1075,7 @@ class tiny_array public: using base_type = tiny_array_base, M, N...>; using value_type = VALUETYPE; + static const int static_size = base_type::static_size; explicit constexpr tiny_array() @@ -1179,7 +1180,7 @@ class tiny_array template ::value> > - explicit tiny_array(U u, U end = U()) + explicit tiny_array(U u, U /* end */ = U()) : base_type(u) {} From 85f9f60b61e143f608d9614871c2555b335fa856 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 17:44:54 +0200 Subject: [PATCH 16/27] fixed warnings --- include/xtensor/xtiny.hpp | 4 ++-- test/test_xtiny.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 614bcef37..c2f5f5e57 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -1193,7 +1193,7 @@ class tiny_array // for compatibility with tiny_array<..., runtime_size> template ::value> > - tiny_array(U u, U end, reverse_copy_tag) + tiny_array(U u, U /* end */, reverse_copy_tag) : base_type(u, copy_reversed) {} @@ -2636,7 +2636,7 @@ mean(tiny_array_base const & t) using Promote = real_promote_t; const Promote sumVal = static_cast(sum(t)); if(t.size() > 0) - return sumVal / t.size(); + return sumVal / static_cast(t.size()); else return sumVal; } diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index e8f4f57ce..d7daf1e69 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -311,7 +311,7 @@ namespace xt tiny_array ivv{ iv3, iv3, iv3 }; EXPECT_EQ(squared_norm(ivv), 3 * squared_norm(iv3)); - EXPECT_EQ(norm(ivv), sqrt(3.0*squared_norm(iv3))); + EXPECT_EQ(norm(ivv), sqrt(3.0*static_cast(squared_norm(iv3)))); EXPECT_EQ(elementwise_norm(iv3), iv3); EXPECT_EQ(elementwise_squared_norm(iv3), (IV{ 1, 4, 16 })); From 1b7a2c76dcb611ab9e8215856f007370d40a1dc5 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 17:50:09 +0200 Subject: [PATCH 17/27] fixed warnings --- test/test_xtiny.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index d7daf1e69..622f480c5 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -305,7 +305,7 @@ namespace xt float expectedSM = 1.2f*1.2f + 2.4f*2.4f + 3.6f*3.6f; EXPECT_NEAR(squared_norm(fv3), expectedSM, 1e-6); - EXPECT_EQ(dot(bv3, bv3), squared_norm(bv3)); + EXPECT_EQ(static_cast(dot(bv3, bv3)), squared_norm(bv3)); EXPECT_EQ(dot(iv3, bv3), squared_norm(iv3)); EXPECT_NEAR(dot(fv3, fv3), squared_norm(fv3), 1e-6); @@ -324,10 +324,8 @@ namespace xt BV bv = bv3; bv[2] = 200; - int expectedSM2 = 40005; - if (SIZE == 6) - expectedSM2 += 189; - EXPECT_EQ(dot(bv, bv), expectedSM2); + uint64_t expectedSM2 = 40005; + EXPECT_EQ(static_cast(dot(bv, bv)), expectedSM2); EXPECT_EQ(squared_norm(bv), expectedSM2); EXPECT_TRUE(equalVector(bv0 + 1.0, fv1)); From bf747c48d614e62b90ac298f866f97ff1be8237e Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 17:52:42 +0200 Subject: [PATCH 18/27] fixed warnings --- test/test_xtiny.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index 622f480c5..d31807bf6 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -306,7 +306,7 @@ namespace xt EXPECT_NEAR(squared_norm(fv3), expectedSM, 1e-6); EXPECT_EQ(static_cast(dot(bv3, bv3)), squared_norm(bv3)); - EXPECT_EQ(dot(iv3, bv3), squared_norm(iv3)); + EXPECT_EQ(static_cast(dot(iv3, bv3)), squared_norm(iv3)); EXPECT_NEAR(dot(fv3, fv3), squared_norm(fv3), 1e-6); tiny_array ivv{ iv3, iv3, iv3 }; @@ -514,7 +514,7 @@ namespace xt EXPECT_TRUE(!all_greater_equal(a, b)); EXPECT_TRUE(isclose(a, b, 10.0f)); - EXPECT_EQ(squared_norm(a), 55); + EXPECT_EQ(squared_norm(a), 55u); EXPECT_TRUE(isclose(norm(a), sqrt(55.0), 1e-15)); EXPECT_NEAR(norm(a), sqrt(55.0), 1e-15); EXPECT_EQ(min(a), 0); From bc1039530ea147c0749beb6b5b0ea8e1ebd256df Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 17:53:48 +0200 Subject: [PATCH 19/27] fixed warnings --- test/test_xtiny.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_xtiny.cpp b/test/test_xtiny.cpp index d31807bf6..39abfbd76 100644 --- a/test/test_xtiny.cpp +++ b/test/test_xtiny.cpp @@ -587,7 +587,7 @@ namespace xt EXPECT_EQ(cross(a, a), e); EXPECT_EQ(dot(a, a), 14); - EXPECT_EQ(squared_norm(a), 14); + EXPECT_EQ(squared_norm(a), 14u); EXPECT_EQ(a.erase(1), (A{ 1,3 })); EXPECT_EQ(a.insert(3, 4), (A{ 1,2,3,4 })); From 07f01e68cf3198e90a2780123fe9bac67f9f2768 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 21:10:32 +0200 Subject: [PATCH 20/27] created xmathutil.hpp --- include/xtensor/xmath.hpp | 399 +------------------------------- include/xtensor/xmathutil.hpp | 415 ++++++++++++++++++++++++++++++++++ include/xtensor/xtiny.hpp | 9 +- 3 files changed, 422 insertions(+), 401 deletions(-) create mode 100644 include/xtensor/xmathutil.hpp diff --git a/include/xtensor/xmath.hpp b/include/xtensor/xmath.hpp index 7d83a6d8a..f714c63be 100644 --- a/include/xtensor/xmath.hpp +++ b/include/xtensor/xmath.hpp @@ -14,411 +14,15 @@ #define XMATH_HPP #include -#include // std::abs(int) prior to C++ 17 #include -#include // std::min, std::max #include -#include "xconcepts.hpp" +#include "xmathutil.hpp" #include "xoperation.hpp" #include "xreducer.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; - }; - - namespace cmath - { - // create a namespace for just the algebraic functions from std - // and add a few fixes to avoid ambiguous overloads in templates - - 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::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; - - // add missing abs() overloads for unsigned types - #define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ - inline T abs(T t) { return t; } - - XTENSOR_DEFINE_UNSIGNED_ABS(bool) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) - XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) - - #undef XTENSOR_DEFINE_UNSIGNED_ABS - - // add missing floor() and ceil() overloads for integral types - #define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ - inline T floor(signed T t) { return t; } \ - inline T floor(unsigned T t) { return t; } \ - inline T ceil(signed T t) { return t; } \ - inline T ceil(unsigned T t) { return t; } - - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) - XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) - - #undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL - - // support 'double' exponents for all floating-point versions of pow() - inline float pow(float v, double e) - { - return std::pow(v, (float)e); - } - - inline long double pow(long double v, double e) - { - return std::pow(v, (long double)e); - } - } // namespace cmath - - - /**********************************************************/ - /* */ - /* isclose() */ - /* */ - /**********************************************************/ - - template >::value> > - inline bool - isclose(U u, V v, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) - { - using namespace cmath; - using P = promote_t; - P a = static_cast

(u), - b = static_cast

(v); - - if(std::isnan(a) && std::isnan(b)) - return equal_nan; - if(std::isinf(a) && std::isinf(b)) - return std::signbit(a) == std::signbit(b); - P d = abs(a - b); - return d <= atol || d <= rtol * std::max(abs(a), abs(b)); - } - - /**********************************************************/ - /* */ - /* sq() */ - /* */ - /**********************************************************/ - - /** \brief The square function. - - sq(x) = x*x is needed so often that it makes sense to define it as a function. - */ - template ::value> > - inline auto - sq(T t) - { - return t*t; - } - - /**********************************************************/ - /* */ - /* min() */ - /* */ - /**********************************************************/ - - /** \brief A proper minimum function. - - The std::min template matches everything -- this is way too - greedy to be useful. xtensor implements the basic min function - only for arithmetic types and provides explicit overloads for everything - else. Moreover, xtensor's min function also computes the minimum - between two different types, as long as they have a std::common_type. - */ - template ::value && std::is_arithmetic::value> > - inline std::common_type_t - min(T1 const & t1, T2 const & t2) - { - using T = std::common_type_t; - return std::min(static_cast(t1), static_cast(t2)); - } - - template ::value> > - inline T const & - min(T const & t1, T const & t2) - { - return std::min(t1, t2); - } - - /**********************************************************/ - /* */ - /* max() */ - /* */ - /**********************************************************/ - - /** \brief A proper maximum function. - - The std::max template matches everything -- this is way too - greedy to be useful. xtensor implements the basic max function - only for arithmetic types and provides explicit overloads for everything - else. Moreover, xtensor's max function also computes the maximum - between two different types, as long as they have a std::common_type. - */ - template ::value && std::is_arithmetic::value> > - inline std::common_type_t - max(T1 const & t1, T2 const & t2) - { - using T = std::common_type_t; - return std::max(static_cast(t1), static_cast(t2)); - } - - template ::value> > - inline T const & - max(T const & t1, T const & t2) - { - return std::max(t1, t2); - } - - /**********************************************************/ - /* */ - /* dot() */ - /* */ - /**********************************************************/ - - // scalar dot is needed for generic functions that should work with - // scalars and vectors alike - #define XTENSOR_DEFINE_SCALAR_DOT(T) \ - inline auto dot(T l, T r) { return l*r; } - - XTENSOR_DEFINE_SCALAR_DOT(unsigned char) - XTENSOR_DEFINE_SCALAR_DOT(unsigned short) - XTENSOR_DEFINE_SCALAR_DOT(unsigned int) - XTENSOR_DEFINE_SCALAR_DOT(unsigned long) - XTENSOR_DEFINE_SCALAR_DOT(unsigned long long) - XTENSOR_DEFINE_SCALAR_DOT(signed char) - XTENSOR_DEFINE_SCALAR_DOT(signed short) - XTENSOR_DEFINE_SCALAR_DOT(signed int) - XTENSOR_DEFINE_SCALAR_DOT(signed long) - XTENSOR_DEFINE_SCALAR_DOT(signed long long) - XTENSOR_DEFINE_SCALAR_DOT(float) - XTENSOR_DEFINE_SCALAR_DOT(double) - XTENSOR_DEFINE_SCALAR_DOT(long double) - - #undef XTENSOR_DEFINE_SCALAR_DOT - - /**********************************************************/ - /* */ - /* even(), odd() */ - /* */ - /**********************************************************/ - - /** \brief Check if an integer is even. - */ - template ::value> > - inline bool - even(T const t) - { - using UT = typename std::make_unsigned::type; - return (static_cast(t)&1) == 0; - } - - /** \brief Check if an integer is odd. - */ - template ::value> > - inline bool - odd(T const t) - { - using UT = typename std::make_unsigned::type; - return (static_cast(t)&1) != 0; - } - - /**********************************************************/ - /* */ - /* sin_pi(), cos_pi() */ - /* */ - /**********************************************************/ - - /** \brief sin(pi*x). - - Essentially calls std::sin(PI*x) but uses a more accurate implementation - to make sure that sin_pi(1.0) == 0.0 (which does not hold for - std::sin(PI) due to round-off error), and sin_pi(0.5) == 1.0. - */ - template ::value> > - REAL sin_pi(REAL x) - { - if(x < 0.0) - return -sin_pi(-x); - if(x < 0.5) - return std::sin(numeric_constants::PI * x); - - bool invert = false; - if(x < 1.0) - { - invert = true; - x = -x; - } - - REAL rem = std::floor(x); - if(odd((int)rem)) - invert = !invert; - rem = x - rem; - if(rem > 0.5) - rem = 1.0 - rem; - if(rem == 0.5) - rem = REAL(1); - else - rem = std::sin(numeric_constants::PI * rem); - return invert - ? -rem - : rem; - } - - /** \brief cos(pi*x). - - Essentially calls std::cos(PI*x) but uses a more accurate implementation - to make sure that cos_pi(1.0) == -1.0 and cos_pi(0.5) == 0.0. - */ - template ::value> > - REAL cos_pi(REAL x) - { - return sin_pi(x+0.5); - } - - /**********************************************************/ - /* */ - /* norm() */ - /* */ - /**********************************************************/ - - /** \brief The norm of a numerical object. - - For scalar types: implemented as abs(t)
- otherwise: implemented as sqrt(squared_norm(t)). - */ - template - inline auto norm(T const & t) - { - using cmath::sqrt; - return sqrt(squared_norm(t)); - } - - /**********************************************************/ - /* */ - /* squared_norm() */ - /* */ - /**********************************************************/ - - template - inline auto - squared_norm(std::complex const & t) - { - return sq(t.real()) + sq(t.imag()); - } - - #define XTENSOR_DEFINE_NORM(T) \ - inline auto squared_norm(T t) { return sq(t); } \ - inline auto mean_square(T t) { return sq(t); } \ - inline auto elementwise_squared_norm(T t) { return sq(t); } \ - inline auto norm(T t) { return cmath::abs(t); } \ - inline auto elementwise_norm(T t) { return cmath::abs(t); } - - XTENSOR_DEFINE_NORM(signed char) - XTENSOR_DEFINE_NORM(unsigned char) - XTENSOR_DEFINE_NORM(short) - XTENSOR_DEFINE_NORM(unsigned short) - XTENSOR_DEFINE_NORM(int) - XTENSOR_DEFINE_NORM(unsigned int) - XTENSOR_DEFINE_NORM(long) - XTENSOR_DEFINE_NORM(unsigned long) - XTENSOR_DEFINE_NORM(long long) - XTENSOR_DEFINE_NORM(unsigned long long) - XTENSOR_DEFINE_NORM(float) - XTENSOR_DEFINE_NORM(double) - XTENSOR_DEFINE_NORM(long double) - - #undef XTENSOR_DEFINE_NORM - - /**********************************************************/ - /* */ - /* xexpression */ - /* */ - /**********************************************************/ - /*********** * Helpers * ***********/ @@ -882,6 +486,7 @@ namespace xt constexpr std::enable_if_t::value, T> sign_impl(T x) { + using namespace cmath; return std::isnan(x) ? std::numeric_limits::quiet_NaN() : x == 0 ? (T)copysign(T(0), x) : (T)copysign(T(1), x); } diff --git a/include/xtensor/xmathutil.hpp b/include/xtensor/xmathutil.hpp new file mode 100644 index 000000000..441c1e4e8 --- /dev/null +++ b/include/xtensor/xmathutil.hpp @@ -0,0 +1,415 @@ +/*************************************************************************** +* 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 XMATHUTIL_HPP +#define XMATHUTIL_HPP + +#include +#include // std::abs(int) prior to C++ 17 +#include +#include // std::min, std::max +#include + +#include "xconcepts.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; + }; + + namespace cmath + { + // create a namespace for just the algebraic functions from std + // and add a few fixes to avoid ambiguous overloads in templates + + 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::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; + + // add missing abs() overloads for unsigned types + #define XTENSOR_DEFINE_UNSIGNED_ABS(T) \ + inline T abs(T t) { return t; } + + XTENSOR_DEFINE_UNSIGNED_ABS(bool) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned char) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned short) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned int) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long) + XTENSOR_DEFINE_UNSIGNED_ABS(unsigned long long) + + #undef XTENSOR_DEFINE_UNSIGNED_ABS + + // add missing floor() and ceil() overloads for integral types + #define XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(T) \ + inline T floor(signed T t) { return t; } \ + inline T floor(unsigned T t) { return t; } \ + inline T ceil(signed T t) { return t; } \ + inline T ceil(unsigned T t) { return t; } + + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(char) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(short) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(int) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long) + XTENSOR_DEFINE_INTEGER_FLOOR_CEIL(long long) + + #undef XTENSOR_DEFINE_INTEGER_FLOOR_CEIL + + // support 'double' exponents for all floating-point versions of pow() + inline float pow(float v, double e) + { + return std::pow(v, (float)e); + } + + inline long double pow(long double v, double e) + { + return std::pow(v, (long double)e); + } + } // namespace cmath + + + /**********************************************************/ + /* */ + /* isclose() */ + /* */ + /**********************************************************/ + + template >::value> > + inline bool + isclose(U u, V v, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) + { + using namespace cmath; + using P = promote_t; + P a = static_cast

(u), + b = static_cast

(v); + + if(std::isnan(a) && std::isnan(b)) + return equal_nan; + if(std::isinf(a) && std::isinf(b)) + return std::signbit(a) == std::signbit(b); + P d = abs(a - b); + return d <= atol || d <= rtol * std::max(abs(a), abs(b)); + } + + /**********************************************************/ + /* */ + /* sq() */ + /* */ + /**********************************************************/ + + /** \brief The square function. + + sq(x) = x*x is needed so often that it makes sense to define it as a function. + */ + template ::value> > + inline auto + sq(T t) + { + return t*t; + } + + /**********************************************************/ + /* */ + /* min() */ + /* */ + /**********************************************************/ + + /** \brief A proper minimum function. + + The std::min template matches everything -- this is way too + greedy to be useful. xtensor implements the basic min function + only for arithmetic types and provides explicit overloads for everything + else. Moreover, xtensor's min function also computes the minimum + between two different types, as long as they have a std::common_type. + */ + template ::value && std::is_arithmetic::value> > + inline std::common_type_t + min(T1 const & t1, T2 const & t2) + { + using T = std::common_type_t; + return std::min(static_cast(t1), static_cast(t2)); + } + + template ::value> > + inline T const & + min(T const & t1, T const & t2) + { + return std::min(t1, t2); + } + + /**********************************************************/ + /* */ + /* max() */ + /* */ + /**********************************************************/ + + /** \brief A proper maximum function. + + The std::max template matches everything -- this is way too + greedy to be useful. xtensor implements the basic max function + only for arithmetic types and provides explicit overloads for everything + else. Moreover, xtensor's max function also computes the maximum + between two different types, as long as they have a std::common_type. + */ + template ::value && std::is_arithmetic::value> > + inline std::common_type_t + max(T1 const & t1, T2 const & t2) + { + using T = std::common_type_t; + return std::max(static_cast(t1), static_cast(t2)); + } + + template ::value> > + inline T const & + max(T const & t1, T const & t2) + { + return std::max(t1, t2); + } + + /**********************************************************/ + /* */ + /* dot() */ + /* */ + /**********************************************************/ + + // scalar dot is needed for generic functions that should work with + // scalars and vectors alike + #define XTENSOR_DEFINE_SCALAR_DOT(T) \ + inline auto dot(T l, T r) { return l*r; } + + XTENSOR_DEFINE_SCALAR_DOT(unsigned char) + XTENSOR_DEFINE_SCALAR_DOT(unsigned short) + XTENSOR_DEFINE_SCALAR_DOT(unsigned int) + XTENSOR_DEFINE_SCALAR_DOT(unsigned long) + XTENSOR_DEFINE_SCALAR_DOT(unsigned long long) + XTENSOR_DEFINE_SCALAR_DOT(signed char) + XTENSOR_DEFINE_SCALAR_DOT(signed short) + XTENSOR_DEFINE_SCALAR_DOT(signed int) + XTENSOR_DEFINE_SCALAR_DOT(signed long) + XTENSOR_DEFINE_SCALAR_DOT(signed long long) + XTENSOR_DEFINE_SCALAR_DOT(float) + XTENSOR_DEFINE_SCALAR_DOT(double) + XTENSOR_DEFINE_SCALAR_DOT(long double) + + #undef XTENSOR_DEFINE_SCALAR_DOT + + /**********************************************************/ + /* */ + /* even(), odd() */ + /* */ + /**********************************************************/ + + /** \brief Check if an integer is even. + */ + template ::value> > + inline bool + even(T const t) + { + using UT = typename std::make_unsigned::type; + return (static_cast(t)&1) == 0; + } + + /** \brief Check if an integer is odd. + */ + template ::value> > + inline bool + odd(T const t) + { + using UT = typename std::make_unsigned::type; + return (static_cast(t)&1) != 0; + } + + /**********************************************************/ + /* */ + /* sin_pi(), cos_pi() */ + /* */ + /**********************************************************/ + + /** \brief sin(pi*x). + + Essentially calls std::sin(PI*x) but uses a more accurate implementation + to make sure that sin_pi(1.0) == 0.0 (which does not hold for + std::sin(PI) due to round-off error), and sin_pi(0.5) == 1.0. + */ + template ::value> > + REAL sin_pi(REAL x) + { + if(x < 0.0) + return -sin_pi(-x); + if(x < 0.5) + return std::sin(numeric_constants::PI * x); + + bool invert = false; + if(x < 1.0) + { + invert = true; + x = -x; + } + + REAL rem = std::floor(x); + if(odd((int)rem)) + invert = !invert; + rem = x - rem; + if(rem > 0.5) + rem = 1.0 - rem; + if(rem == 0.5) + rem = REAL(1); + else + rem = std::sin(numeric_constants::PI * rem); + return invert + ? -rem + : rem; + } + + /** \brief cos(pi*x). + + Essentially calls std::cos(PI*x) but uses a more accurate implementation + to make sure that cos_pi(1.0) == -1.0 and cos_pi(0.5) == 0.0. + */ + template ::value> > + REAL cos_pi(REAL x) + { + return sin_pi(x+0.5); + } + + /**********************************************************/ + /* */ + /* norm() */ + /* */ + /**********************************************************/ + + /** \brief The norm of a numerical object. + + For scalar types: implemented as abs(t)
+ otherwise: implemented as sqrt(squared_norm(t)). + */ + template + inline auto norm(T const & t) + { + using cmath::sqrt; + return sqrt(squared_norm(t)); + } + + /**********************************************************/ + /* */ + /* squared_norm() */ + /* */ + /**********************************************************/ + + template + inline auto + squared_norm(std::complex const & t) + { + return sq(t.real()) + sq(t.imag()); + } + + #define XTENSOR_DEFINE_NORM(T) \ + inline auto squared_norm(T t) { return sq(t); } \ + inline auto mean_square(T t) { return sq(t); } \ + inline auto elementwise_squared_norm(T t) { return sq(t); } \ + inline auto norm(T t) { return cmath::abs(t); } \ + inline auto elementwise_norm(T t) { return cmath::abs(t); } + + XTENSOR_DEFINE_NORM(signed char) + XTENSOR_DEFINE_NORM(unsigned char) + XTENSOR_DEFINE_NORM(short) + XTENSOR_DEFINE_NORM(unsigned short) + XTENSOR_DEFINE_NORM(int) + XTENSOR_DEFINE_NORM(unsigned int) + XTENSOR_DEFINE_NORM(long) + XTENSOR_DEFINE_NORM(unsigned long) + XTENSOR_DEFINE_NORM(long long) + XTENSOR_DEFINE_NORM(unsigned long long) + XTENSOR_DEFINE_NORM(float) + XTENSOR_DEFINE_NORM(double) + XTENSOR_DEFINE_NORM(long double) + + #undef XTENSOR_DEFINE_NORM +} + +#endif diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index c2f5f5e57..e7f48b2e7 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -9,16 +9,17 @@ #ifndef XTENSOR_XTINY_HPP #define XTENSOR_XTINY_HPP -#include "xtags.hpp" -#include "xconcepts.hpp" -#include "xexception.hpp" -#include "xmath.hpp" #include #include #include #include #include +#include "xtags.hpp" +#include "xconcepts.hpp" +#include "xexception.hpp" +#include "xmathutil.hpp" + #ifdef XTENSOR_CHECK_BOUNDS #define XTENSOR_ASSERT_INSIDE(array, diff) \ xtensor_precondition(diff >= 0 && diff < array.size(), "Index out of bounds") From 7dd9b64d4ca2e329051a26935e6c3e6a3ee5db11 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Sun, 30 Jul 2017 23:59:08 +0200 Subject: [PATCH 21/27] replaced std::array => tiny_array --- include/xtensor/xadapt.hpp | 16 +-- include/xtensor/xarray.hpp | 2 +- include/xtensor/xassign.hpp | 2 +- include/xtensor/xbroadcast.hpp | 5 +- include/xtensor/xbuilder.hpp | 34 +++--- include/xtensor/xexception.hpp | 4 +- include/xtensor/xexpression.hpp | 3 +- include/xtensor/xfunctorview.hpp | 2 +- include/xtensor/xgenerator.hpp | 7 +- include/xtensor/xindexview.hpp | 18 +-- include/xtensor/xio.hpp | 5 + include/xtensor/xiterator.hpp | 9 +- include/xtensor/xreducer.hpp | 11 +- include/xtensor/xscalar.hpp | 3 +- include/xtensor/xstridedview.hpp | 22 ++-- include/xtensor/xstrides.hpp | 2 +- include/xtensor/xtensor.hpp | 5 +- include/xtensor/xtensor_config.hpp | 2 +- include/xtensor/xtensor_forward.hpp | 6 +- include/xtensor/xtiny.hpp | 178 +++++++++++++++++++--------- include/xtensor/xutils.hpp | 48 ++++++-- include/xtensor/xview.hpp | 4 +- include/xtensor/xview_utils.hpp | 3 +- test/test_common.hpp | 69 +++++------ test/test_xadapt.cpp | 6 +- test/test_xarray.cpp | 6 +- test/test_xbroadcast.cpp | 12 +- test/test_xdynamicview.cpp | 8 +- test/test_xeval.cpp | 6 +- test/test_xoperation.cpp | 3 +- test/test_xreducer.cpp | 2 +- test/test_xtensor.cpp | 6 +- test/test_xtensor_adaptor.cpp | 2 +- test/test_xview.cpp | 13 +- 34 files changed, 321 insertions(+), 203 deletions(-) diff --git a/include/xtensor/xadapt.hpp b/include/xtensor/xadapt.hpp index 4b3b87207..359dcec86 100644 --- a/include/xtensor/xadapt.hpp +++ b/include/xtensor/xadapt.hpp @@ -89,7 +89,7 @@ namespace xt */ template xtensor_adaptor - xadapt(C& container, const std::array& shape, layout_type l = L); + xadapt(C& container, const stat_shape& shape, layout_type l = L); /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -100,7 +100,7 @@ namespace xt */ template xtensor_adaptor - xadapt(C& container, const std::array& shape, const std::array& strides); + xadapt(C& container, const stat_shape& shape, const stat_shape& strides); /** * Constructs an xtensor_adaptor of the given dynamically allocated C array, @@ -116,7 +116,7 @@ namespace xt template >> xtensor_adaptor, O, A>, N, L> xadapt(P& pointer, typename A::size_type size, O ownership, - const std::array& shape, layout_type l = L, const A& alloc = A()); + const stat_shape& shape, layout_type l = L, const A& alloc = A()); /** * Constructs an xtensor_adaptor of the given dynamically allocated C array, @@ -132,7 +132,7 @@ namespace xt template >> xtensor_adaptor, O, A>, N, layout_type::dynamic> xadapt(P& pointer, typename A::size_type size, O ownership, - const std::array& shape, const std::array& strides, const A& alloc = A()); + const stat_shape& shape, const stat_shape& strides, const A& alloc = A()); /***************************************** * xarray_adaptor builder implementation * @@ -176,14 +176,14 @@ namespace xt template inline xtensor_adaptor - xadapt(C& container, const std::array& shape, layout_type l) + xadapt(C& container, const stat_shape& shape, layout_type l) { return xtensor_adaptor(container, shape, l); } template inline xtensor_adaptor - xadapt(C& container, const std::array& shape, const std::array& strides) + xadapt(C& container, const stat_shape& shape, const stat_shape& strides) { return xtensor_adaptor(container, shape, strides); } @@ -191,7 +191,7 @@ namespace xt template inline xtensor_adaptor, O, A>, N, L> xadapt(P& pointer, typename A::size_type size, O, - const std::array& shape, layout_type l, const A& alloc) + const stat_shape& shape, layout_type l, const A& alloc) { using buffer_type = xbuffer_adaptor, O, A>; buffer_type buf(pointer, size, alloc); @@ -201,7 +201,7 @@ namespace xt template inline xtensor_adaptor, O, A>, N, layout_type::dynamic> xadapt(P& pointer, typename A::size_type size, O, - const std::array& shape, const std::array& strides, const A& alloc) + const stat_shape& shape, const stat_shape& strides, const A& alloc) { using buffer_type = xbuffer_adaptor, O, A>; buffer_type buf(pointer, size, alloc); diff --git a/include/xtensor/xarray.hpp b/include/xtensor/xarray.hpp index c40b1a64a..e4bfbf988 100644 --- a/include/xtensor/xarray.hpp +++ b/include/xtensor/xarray.hpp @@ -121,7 +121,7 @@ namespace xt * xarray_adaptor declaration * ******************************/ - template > + template > class xarray_adaptor; template diff --git a/include/xtensor/xassign.hpp b/include/xtensor/xassign.hpp index fbb7223ca..9d5c66820 100644 --- a/include/xtensor/xassign.hpp +++ b/include/xtensor/xassign.hpp @@ -157,7 +157,7 @@ namespace xt shape_type shape = make_sequence(dim, size_type(1)); bool trivial_broadcast = de2.broadcast_shape(shape); - // FIXME: The second comparison is lexicographic. Comment why this is correct. + // FIXME: The second comparison is lexicographic. Comment why this is intended. if (dim > de1.dimension() || shape > de1.shape()) { typename E1::temporary_type tmp(shape); diff --git a/include/xtensor/xbroadcast.hpp b/include/xtensor/xbroadcast.hpp index 0413e29c8..2db9a5fc2 100644 --- a/include/xtensor/xbroadcast.hpp +++ b/include/xtensor/xbroadcast.hpp @@ -21,6 +21,7 @@ #include "xiterable.hpp" #include "xstrides.hpp" #include "xutils.hpp" +// #include "xtiny.hpp" namespace xt { @@ -159,7 +160,7 @@ namespace xt template inline auto broadcast(E&& e, std::initializer_list s) noexcept { - using broadcast_type = xbroadcast, std::vector>; + using broadcast_type = xbroadcast, dyn_shape>; using shape_type = typename broadcast_type::shape_type; return broadcast_type(std::forward(e), forward_sequence(s)); } @@ -167,7 +168,7 @@ namespace xt template inline auto broadcast(E&& e, const I (&s)[L]) noexcept { - using broadcast_type = xbroadcast, std::array>; + using broadcast_type = xbroadcast, stat_shape>; using shape_type = typename broadcast_type::shape_type; return broadcast_type(std::forward(e), forward_sequence(s)); } diff --git a/include/xtensor/xbuilder.hpp b/include/xtensor/xbuilder.hpp index eb16ed0e7..b9d7ae11b 100644 --- a/include/xtensor/xbuilder.hpp +++ b/include/xtensor/xbuilder.hpp @@ -207,7 +207,7 @@ namespace xt * @return xgenerator that generates the values on access */ template - inline auto eye(const std::vector& shape, int k = 0) + inline auto eye(const dyn_shape& shape, int k = 0) { return detail::make_xgenerator(detail::fn_impl>(detail::eye_fn(k)), shape); } @@ -412,7 +412,7 @@ namespace xt template value_type operator()(Args... args) const { - std::array args_arr = {static_cast(args)...}; + stat_shape args_arr = {static_cast(args)...}; return m_source(args_arr[m_axis]); } @@ -469,9 +469,9 @@ namespace xt namespace detail { template - inline std::array add_axis(std::array arr, std::size_t axis, std::size_t value) + inline stat_shape add_axis(stat_shape arr, std::size_t axis, std::size_t value) { - std::array temp; + stat_shape temp; std::copy(arr.begin(), arr.begin() + axis, temp.begin()); temp[axis] = value; std::copy(arr.begin() + axis, arr.end(), temp.begin() + axis + 1); @@ -520,7 +520,7 @@ namespace xt 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]... }; + const stat_shape shape { e.shape()[0]... }; return std::make_tuple( detail::make_xgenerator( detail::repeat_impl>(std::forward(e), I), @@ -652,7 +652,7 @@ namespace xt template inline value_type operator()(Args... args) const { - std::array idx({static_cast(args)...}); + stat_shape idx({static_cast(args)...}); return access_impl(idx.begin(), idx.end()); } @@ -719,27 +719,27 @@ namespace xt }; template - struct diagonal_shape_type> + struct diagonal_shape_type> { - using type = std::array; + using type = stat_shape; }; } /** * @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 + * 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. + * @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} @@ -810,7 +810,7 @@ namespace xt * @brief Reverse the order of elements in an xexpression along the given axis. * Note: A NumPy/Matlab style `flipud(arr)` is equivalent to `xt::flip(arr, 0)`, * `fliplr(arr)` to `xt::flip(arr, 1)`. - * + * * @param arr the input xexpression * @param axis the axis along which elements should be reversed * diff --git a/include/xtensor/xexception.hpp b/include/xtensor/xexception.hpp index 39e2c0aec..fe89e0682 100644 --- a/include/xtensor/xexception.hpp +++ b/include/xtensor/xexception.hpp @@ -172,7 +172,7 @@ namespace xt #define XTENSOR_ASSERT_MSG(PREDICATE, MESSAGE) \ if((PREDICATE)) {} else { \ throw std::runtime_error(std::string("Assertion error!\n") + MESSAGE + \ - "\n(" + __FILE__ + ':' + std::to_string(__LINE__) + ")\n"); } + "\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n"); } #else #define XTENSOR_ASSERT_MSG(PREDICATE, MESSAGE) @@ -181,6 +181,6 @@ namespace xt #define xtensor_precondition(PREDICATE, MESSAGE) \ if((PREDICATE)) {} else { \ throw std::runtime_error(std::string("Precondition violation!\n") + MESSAGE + \ - "\n(" + __FILE__ + ':' + std::to_string(__LINE__) + ")\n"); } + "\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n"); } #endif // XEXCEPTION_HPP diff --git a/include/xtensor/xexpression.hpp b/include/xtensor/xexpression.hpp index f07402381..74864a6a9 100644 --- a/include/xtensor/xexpression.hpp +++ b/include/xtensor/xexpression.hpp @@ -15,11 +15,12 @@ #include "xconcepts.hpp" #include "xutils.hpp" +// #include "xtiny.hpp" namespace xt { - using xindex = std::vector; + using xindex = dyn_shape; /*************************** * xexpression declaration * diff --git a/include/xtensor/xfunctorview.hpp b/include/xtensor/xfunctorview.hpp index b9db6bc02..a750b9c47 100644 --- a/include/xtensor/xfunctorview.hpp +++ b/include/xtensor/xfunctorview.hpp @@ -52,7 +52,7 @@ namespace xt }; template - struct functorview_temporary_type_impl, L> + struct functorview_temporary_type_impl, L> { using type = xtensor; }; diff --git a/include/xtensor/xgenerator.hpp b/include/xtensor/xgenerator.hpp index 734c03840..cb5015675 100644 --- a/include/xtensor/xgenerator.hpp +++ b/include/xtensor/xgenerator.hpp @@ -20,6 +20,7 @@ #include "xiterable.hpp" #include "xstrides.hpp" #include "xutils.hpp" +// #include "xtiny.hpp" namespace xt { @@ -124,7 +125,7 @@ namespace xt */ //@{ /** - * Constructs an xgenerator applying the specified function over the + * Constructs an xgenerator applying the specified function over the * given shape. * @param f the function to apply * @param shape the shape of the xgenerator @@ -272,7 +273,7 @@ namespace xt template inline auto make_xgenerator(Functor&& f, std::initializer_list shape) noexcept { - using shape_type = std::vector; + using shape_type = dyn_shape; using type = xgenerator; return type(std::forward(f), forward_sequence(shape)); } @@ -280,7 +281,7 @@ namespace xt template inline auto make_xgenerator(Functor&& f, const I (&shape)[L]) noexcept { - using shape_type = std::array; + using shape_type = stat_shape; using type = xgenerator; return type(std::forward(f), forward_sequence(shape)); } diff --git a/include/xtensor/xindexview.hpp b/include/xtensor/xindexview.hpp index 7f4a0b1c6..6665d912f 100644 --- a/include/xtensor/xindexview.hpp +++ b/include/xtensor/xindexview.hpp @@ -18,7 +18,7 @@ #include "xexpression.hpp" #include "xiterable.hpp" #include "xstrides.hpp" -#include "xutils.hpp" +// #include "xutils.hpp" namespace xt { @@ -36,7 +36,7 @@ namespace xt template struct xiterable_inner_types> { - using inner_shape_type = std::array; + using inner_shape_type = stat_shape; using const_stepper = xindexed_stepper>; using stepper = xindexed_stepper, false>; using const_iterator = xiterator; @@ -224,7 +224,7 @@ namespace xt /** * Constructs an xindexview, 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 */ @@ -327,8 +327,8 @@ namespace xt } /** - * Returns the element at the specified position in the xindexview. - * + * Returns the element at the specified position in the xindexview. + * * @param idx the position in the view */ template @@ -457,7 +457,7 @@ namespace xt //@{ /** * Constructs a xfiltration on the given expression \c e, selecting - * the elements matching the specified \c condition. + * the elements matching the specified \c condition. * * @param e the \ref xexpression to filter. * @param condition the filtering \ref xexpression to apply. @@ -548,12 +548,12 @@ namespace xt /** * @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}}); @@ -591,7 +591,7 @@ namespace xt /** * @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 diff --git a/include/xtensor/xio.hpp b/include/xtensor/xio.hpp index 5b70d72bb..758156e46 100644 --- a/include/xtensor/xio.hpp +++ b/include/xtensor/xio.hpp @@ -616,6 +616,11 @@ namespace xt { static constexpr std::size_t value = XTENSOR_MIN(5, N); }; + template + struct recursion_depth> + { + static constexpr std::size_t value = XTENSOR_MIN(5, N); + }; #undef XTENSOR_MIN } diff --git a/include/xtensor/xiterator.hpp b/include/xtensor/xiterator.hpp index 02605cb27..6073dbeef 100644 --- a/include/xtensor/xiterator.hpp +++ b/include/xtensor/xiterator.hpp @@ -18,6 +18,7 @@ #include "xexception.hpp" #include "xlayout.hpp" #include "xutils.hpp" +// #include "xtiny.hpp" namespace xt { @@ -64,7 +65,7 @@ namespace xt template struct index_type_impl { - using type = std::vector; + using type = dyn_shape; }; template @@ -72,6 +73,12 @@ namespace xt { using type = std::array; }; + + template + struct index_type_impl> + { + using type = tiny_array; + }; } template diff --git a/include/xtensor/xreducer.hpp b/include/xtensor/xreducer.hpp index 204135d06..17d46afd0 100644 --- a/include/xtensor/xreducer.hpp +++ b/include/xtensor/xreducer.hpp @@ -26,6 +26,7 @@ #include "xiterable.hpp" #include "xreducer.hpp" #include "xutils.hpp" +// #include "xtiny.hpp" namespace xt { @@ -192,7 +193,7 @@ namespace xt template inline auto reduce(F&& f, E&& e, std::initializer_list axes) noexcept { - using axes_type = std::vector::size_type>; + using axes_type = dyn_shape::size_type>; using reducer_type = xreducer, axes_type>; return reducer_type(std::forward(f), std::forward(e), forward_sequence(axes)); } @@ -200,7 +201,7 @@ namespace xt template inline auto reduce(F&& f, E&& e, const I (&axes)[N]) noexcept { - using axes_type = std::array::size_type, N>; + using axes_type = stat_shape::size_type, N>; using reducer_type = xreducer, axes_type>; return reducer_type(std::forward(f), std::forward(e), forward_sequence(axes)); } @@ -276,9 +277,9 @@ namespace xt }; template - struct xreducer_shape_type, std::array> + struct xreducer_shape_type, stat_shape> { - using type = std::array; + using type = stat_shape; }; namespace detail @@ -397,7 +398,7 @@ namespace xt template inline auto xreducer::operator()(Args... args) const -> const_reference { - std::array arg_array = {{static_cast(args)...}}; + stat_shape arg_array = {{static_cast(args)...}}; return element(arg_array.cbegin(), arg_array.cend()); } diff --git a/include/xtensor/xscalar.hpp b/include/xtensor/xscalar.hpp index 39650ae0e..bdab7c6e2 100644 --- a/include/xtensor/xscalar.hpp +++ b/include/xtensor/xscalar.hpp @@ -16,6 +16,7 @@ #include "xexpression.hpp" #include "xiterable.hpp" #include "xlayout.hpp" +// #include "xtiny.hpp" namespace xt { @@ -469,7 +470,7 @@ namespace xt { return m_value; } - + template inline auto xscalar::data_element(size_type) const noexcept->const_reference { diff --git a/include/xtensor/xstridedview.hpp b/include/xtensor/xstridedview.hpp index 7f11a7ec1..1c6f19a43 100644 --- a/include/xtensor/xstridedview.hpp +++ b/include/xtensor/xstridedview.hpp @@ -55,12 +55,12 @@ namespace xt * @class xstrided_view * @brief View of an xexpression using strides * - * The xstrided_view class implements a view utilizing an offset and strides - * into a multidimensional xcontainer. The xstridedview is currently used + * The xstrided_view class implements a view utilizing an offset and strides + * into a multidimensional xcontainer. The xstridedview is currently used * to implement `transpose`. * @tparam CT the closure type of the \ref xexpression type underlying this view * @tparam CD the closure type of the underlying data container - * + * * @sa stridedview, transpose */ template @@ -199,8 +199,8 @@ namespace xt */ //@{ /** - * Constructs an xstrided_view - * + * Constructs an xstrided_view + * * @param e the underlying xexpression for this view * @param shape the shape of the view * @param strides the strides of the view @@ -357,8 +357,8 @@ namespace xt } /** - * Returns the element at the specified position in the xstrided_view. - * + * Returns the element at the specified position in the xstrided_view. + * * @param args a list of indices specifying the position in the view. Indices * must be unsigned integers, the number of indices should be equal or greater than * the number of dimensions of the view. @@ -722,7 +722,7 @@ namespace xt } template - inline slice_vector(const std::vector& shape, Args... args) + inline slice_vector(const dyn_shape& shape, Args... args) { m_shape = shape; append(args...); @@ -781,7 +781,7 @@ namespace xt private: - std::vector m_shape; + dyn_shape m_shape; std::size_t newaxis_count = 0; }; @@ -820,7 +820,7 @@ namespace xt template >::value>* = nullptr> inline auto get_strides(E&& e) { - std::vector strides; + dyn_shape strides; strides.resize(e.shape().size()); compute_strides(e.shape(), layout_type::row_major, strides); return strides; @@ -850,7 +850,7 @@ namespace xt // Compute strided view std::size_t offset = detail::get_offset(e); - using shape_type = typename std::vector; + using shape_type = typename dyn_shape; shape_type new_shape(dimension); shape_type new_strides(dimension); diff --git a/include/xtensor/xstrides.hpp b/include/xtensor/xstrides.hpp index a9e03a720..08ee167eb 100644 --- a/include/xtensor/xstrides.hpp +++ b/include/xtensor/xstrides.hpp @@ -120,7 +120,7 @@ namespace xt template inline size_type element_offset(const S& strides, It first, It last) noexcept { - auto size = std::min(static_cast(std::distance(first, last)), strides.size()); + auto size = min(static_cast(std::distance(first, last)), strides.size()); return std::inner_product(last - size, last, strides.cend() - size, size_type(0)); } diff --git a/include/xtensor/xtensor.hpp b/include/xtensor/xtensor.hpp index f75fae70b..61e305d4c 100644 --- a/include/xtensor/xtensor.hpp +++ b/include/xtensor/xtensor.hpp @@ -18,6 +18,7 @@ #include "xbuffer_adaptor.hpp" #include "xcontainer.hpp" #include "xsemantic.hpp" +#include "xtiny.hpp" namespace xt { @@ -30,7 +31,7 @@ namespace xt struct xcontainer_inner_types> { using container_type = EC; - using shape_type = std::array; + using shape_type = stat_shape; using strides_type = shape_type; using backstrides_type = shape_type; using inner_shape_type = shape_type; @@ -125,7 +126,7 @@ namespace xt struct xcontainer_inner_types> { using container_type = EC; - using shape_type = std::array; + using shape_type = stat_shape; using strides_type = shape_type; using backstrides_type = shape_type; using inner_shape_type = shape_type; diff --git a/include/xtensor/xtensor_config.hpp b/include/xtensor/xtensor_config.hpp index 72af5dca3..4ae57bb81 100644 --- a/include/xtensor/xtensor_config.hpp +++ b/include/xtensor/xtensor_config.hpp @@ -28,7 +28,7 @@ #ifndef DEFAULT_SHAPE_CONTAINER #define DEFAULT_SHAPE_CONTAINER(T, EA, SA) \ - std::vector + dyn_shape #endif #ifndef DEFAULT_LAYOUT diff --git a/include/xtensor/xtensor_forward.hpp b/include/xtensor/xtensor_forward.hpp index f14a06dde..38d9eafbe 100644 --- a/include/xtensor/xtensor_forward.hpp +++ b/include/xtensor/xtensor_forward.hpp @@ -41,7 +41,7 @@ namespace xt * \code{.cpp} * xt::xarray_container, std::vector> a = ... * \endcode - * + * * @tparam T The value type of the elements. * @tparam L The layout_type of the xarray_container (default: row_major). * @tparam A The allocator of the container holding the elements. @@ -49,7 +49,7 @@ namespace xt */ template , - class SA = std::allocator::size_type>> + class SA = std::allocator::size_type>> using xarray = xarray_container; template @@ -97,7 +97,7 @@ namespace xt template , class BA = std::allocator, - class SA = std::allocator::size_type>> + class SA = std::allocator::size_type>> using xarray_optional = xarray_container, L, DEFAULT_SHAPE_CONTAINER(T, A, SA)>; /** diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index e7f48b2e7..98b4f7368 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -1078,7 +1078,7 @@ class tiny_array using value_type = VALUETYPE; static const int static_size = base_type::static_size; - explicit constexpr + constexpr tiny_array() : base_type(value_type()) {} @@ -1088,6 +1088,7 @@ class tiny_array : base_type(dont_init) {} + // FIXME // This constructor would allow construction with round brackets, e.g.: // tiny_array a(2); // However, this may lead to bugs when fixed-size arrays are mixed with @@ -1097,10 +1098,10 @@ class tiny_array // construction is restricted to curly braces: // tiny_array a{2}; // - // template - // constexpr tiny_array(value_type v0, V... v) - // : base_type(v0, v...) - // {} + template + constexpr tiny_array(value_type v0, V... v) + : base_type(v0, v...) + {} template tiny_array(std::initializer_list v) @@ -1112,7 +1113,8 @@ class tiny_array base_type::init_impl(v.begin()); else xtensor_precondition(false, - "tiny_array(std::initializer_list): wrong initialization size."); + "tiny_array(std::initializer_list): wrong initialization size (expected: " + + std::to_string(static_size) + ", got: " + std::to_string(v.size()) +")"); } // for compatibility with tiny_array @@ -1179,10 +1181,29 @@ class tiny_array : base_type(u) {} + // FIXME + template > + tiny_array(std::array const & a) + : tiny_array(&a[0]) + {} + + // FIXME + template > + bool operator==(std::array const & a) const + { + for(index_t k=0; k::value> > explicit tiny_array(U u, U /* end */ = U()) - : base_type(u) + : base_type(&*u) {} template std::allocator alloc_; }; - -template -bool operator==(std::vector const & l, tiny_array const & r) + //FIXME +template +bool operator==(std::vector const & l, tiny_array const & r) { if((int)l.size() != r.size()) return false; @@ -1442,6 +1463,18 @@ bool operator==(std::vector const & l, tiny_array const & r) return true; } + //FIXME +template +bool operator==(tiny_array const & l, std::vector const & r) +{ + if(l.size() != (int)r.size()) + return false; + for(int k=0; k < (int)l.size(); ++k) + if(l[k] != r[k]) + return false; + return true; +} + /********************************************************/ /* */ /* tiny_array_view */ @@ -1887,7 +1920,7 @@ operator!=(V1 const & l, return false; } - /// lexicographical comparison + /// lexicographical less template inline bool operator<(tiny_array_base const & l, @@ -1905,67 +1938,94 @@ operator<(tiny_array_base const & l, return false; } - /// lexicographical comparison -template -inline bool -operator<(tiny_array_base const & l, - std::vector const & r) -{ - index_t size = r.size(); - bool equal_res = false; - if(l.size() < size) - { - size = l.size(); - equal_res = true; - } - for(int k=0; k < size; ++k) - { - if(l[k] < r[k]) - return true; - if(r[k] < l[k]) - return false; - } - return equal_res; -} - -template + /// lexicographical less-equal +template inline bool -operator<(std::vector const & l, - tiny_array_base const & r) +operator<=(tiny_array_base const & l, + tiny_array_base const & r) { - index_t size = r.size(); - bool equal_res = false; - if(l.size() < size) - { - size = l.size(); - equal_res = true; - } - for(int k=0; k < size; ++k) - { - if(l[k] < r[k]) - return true; - if(r[k] < l[k]) - return false; - } - return equal_res; + return !(r < l); } -template + /// lexicographical greater +template inline bool -operator>(tiny_array_base const & l, - std::vector const & r) +operator>(tiny_array_base const & l, + tiny_array_base const & r) { return r < l; } -template + /// lexicographical greater-equal +template inline bool -operator>(std::vector const & l, - tiny_array_base const & r) +operator>=(tiny_array_base const & l, + tiny_array_base const & r) { - return r < l; + return !(l < r); } + // /// lexicographical comparison +// template +// inline bool +// operator<(tiny_array_base const & l, + // std::vector const & r) +// { + // index_t size = r.size(); + // bool equal_res = false; + // if(l.size() < size) + // { + // size = l.size(); + // equal_res = true; + // } + // for(int k=0; k < size; ++k) + // { + // if(l[k] < r[k]) + // return true; + // if(r[k] < l[k]) + // return false; + // } + // return equal_res; +// } + +// template +// inline bool +// operator<(std::vector const & l, + // tiny_array_base const & r) +// { + // index_t size = r.size(); + // bool equal_res = false; + // if(l.size() < size) + // { + // size = l.size(); + // equal_res = true; + // } + // for(int k=0; k < size; ++k) + // { + // if(l[k] < r[k]) + // return true; + // if(r[k] < l[k]) + // return false; + // } + // return equal_res; +// } + +// template +// inline bool +// operator>(tiny_array_base const & l, + // std::vector const & r) +// { + // return r < l; +// } + +// template +// inline bool +// operator>(std::vector const & l, + // tiny_array_base const & r) +// { + // return r < l; +// } + /// check if all elements are non-zero (or 'true' if V is bool) template inline bool diff --git a/include/xtensor/xutils.hpp b/include/xtensor/xutils.hpp index 6361edceb..8ec66173b 100644 --- a/include/xtensor/xutils.hpp +++ b/include/xtensor/xutils.hpp @@ -20,9 +20,18 @@ #include #include "xtensor_config.hpp" +#include "xtiny.hpp" namespace xt { + // FIXME: dyn_shape and stat_shape are just a helper classes for refactoring + template > + using dyn_shape = std::vector; + + template + //using stat_shape = std::array; + using stat_shape = tiny_array; + /**************** * declarations * ****************/ @@ -440,6 +449,12 @@ namespace xt return size == N; } + template + inline bool resize_container(tiny_array& a, typename tiny_array::size_type size) + { + return a.size() == size; + } + /******************************** * make_sequence implementation * ********************************/ @@ -472,6 +487,19 @@ namespace xt return s; } }; + + template + struct sequence_builder> + { + using sequence_type = tiny_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(tags::size=size, v ); + } + }; } template @@ -578,6 +606,12 @@ namespace xt static constexpr bool value = true; }; + //template + //struct is_array> + //{ + // static constexpr bool value = true; + //}; + template using only_array = and_...>; @@ -917,7 +951,7 @@ namespace xt }; /***************************** - * is_complete implemenation * + * is_complete implemenation * *****************************/ namespace detail @@ -936,7 +970,7 @@ namespace xt struct is_complete : detail::is_complete_impl::type {}; /******************************************** - * xtrivial_default_construct implemenation * + * xtrivial_default_construct implemenation * ********************************************/ #if defined(__clang__) @@ -963,14 +997,14 @@ namespace xt struct xtrivial_default_construct_impl : std::has_trivial_default_constructor {}; } - template + template using xtrivially_default_constructible = detail::xtrivial_default_construct_impl>::value, T>; #pragma clang diagnostic pop #else // CLANG && APPLE - template + template using xtrivially_default_constructible = std::is_trivially_default_constructible; #endif @@ -979,18 +1013,18 @@ namespace xt #if defined(__GNUC__) && (__GNUC__ < 5 || (__GNUC__ == 5 && __GNUC_MINOR__ < 1)) // OLD GCC - template + template using xtrivially_default_constructible = std::has_trivial_default_constructor; #else - template + template using xtrivially_default_constructible = std::is_trivially_default_constructible; #endif #endif - + } #endif diff --git a/include/xtensor/xview.hpp b/include/xtensor/xview.hpp index 2d78600d6..f8d7cf12c 100644 --- a/include/xtensor/xview.hpp +++ b/include/xtensor/xview.hpp @@ -310,9 +310,9 @@ namespace xt }; template - struct xview_shape_type, S...> + struct xview_shape_type, S...> { - using type = std::array() + newaxis_count()>; + using type = stat_shape() + newaxis_count())>; }; /************************ diff --git a/include/xtensor/xview_utils.hpp b/include/xtensor/xview_utils.hpp index f0e7f4044..90d364454 100644 --- a/include/xtensor/xview_utils.hpp +++ b/include/xtensor/xview_utils.hpp @@ -12,6 +12,7 @@ #include #include "xslice.hpp" +// #include "xtiny.hpp" namespace xt { @@ -70,7 +71,7 @@ namespace xt }; template - struct view_temporary_type_impl, L, SL...> + struct view_temporary_type_impl, L, SL...> { using type = xtensor() - integral_count(), L>; }; diff --git a/test/test_common.hpp b/test/test_common.hpp index 05c5623c6..0d392547e 100644 --- a/test/test_common.hpp +++ b/test/test_common.hpp @@ -11,6 +11,7 @@ #include "xtensor/xlayout.hpp" #include "xtensor/xstridedview.hpp" +#include "xtensor/xtiny.hpp" namespace xt { @@ -26,7 +27,7 @@ namespace xt return rhs == lhs; } - template > + template > struct layout_result { using vector_type = uvector; @@ -67,7 +68,7 @@ namespace xt inline const vector_type& data() const { return m_data; } }; - template > + template > struct row_major_result : layout_result { inline row_major_result() @@ -81,7 +82,7 @@ namespace xt } }; - template > + template > struct column_major_result : layout_result { inline column_major_result() @@ -96,7 +97,7 @@ namespace xt } }; - template > + template > struct central_major_result : layout_result { inline central_major_result() @@ -110,7 +111,7 @@ namespace xt } }; - template > + template > struct unit_shape_result { using vector_type = std::vector; @@ -165,7 +166,7 @@ namespace xt } } - template > + template > void test_reshape(V& vec) { { @@ -180,8 +181,8 @@ namespace xt row_major_result rm; auto v_copy_a = vec; auto v_copy_b = vec; - std::array ar = {3, 2, 4}; - std::vector vr = {3, 2, 4}; + stat_shape ar = {3, 2, 4}; + dyn_shape vr = {3, 2, 4}; v_copy_a.reshape(ar, true); compare_shape(v_copy_a, rm); v_copy_b.reshape(vr, true); @@ -211,7 +212,7 @@ namespace xt } } - template > + template > void test_transpose(V& vec) { using shape_type = typename V::shape_type; @@ -288,7 +289,7 @@ namespace xt EXPECT_EQ(vec_copy(1, 1, 2), vt(1, 1, 2)); // Compilation check only - std::vector perm = {1, 0, 2}; + dyn_shape perm = {1, 0, 2}; transpose(vec, perm); } @@ -329,7 +330,7 @@ namespace xt #endif } - template > + template > void test_access(V& vec) { { @@ -377,7 +378,7 @@ namespace xt } } - template > + template > void test_element(V& vec) { { @@ -386,10 +387,10 @@ namespace xt vec.reshape(rm.m_shape, layout_type::row_major); assign_array(vec, rm.m_assigner); EXPECT_EQ(vec.data(), rm.m_data); - std::vector index1 = {0, 1, 1}; - std::vector index2 = {1, 1}; - std::vector index3 = {2, 1, 3}; - std::vector index4 = {2, 2, 2, 1, 3}; + dyn_shape index1 = {0, 1, 1}; + dyn_shape index2 = {1, 1}; + dyn_shape index3 = {2, 1, 3}; + dyn_shape index4 = {2, 2, 2, 1, 3}; EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); test_bound_check(vec); @@ -401,10 +402,10 @@ namespace xt vec.reshape(cm.m_shape, layout_type::column_major); assign_array(vec, cm.m_assigner); EXPECT_EQ(vec.data(), cm.m_data); - std::vector index1 = {0, 1, 1}; - std::vector index2 = {1, 1}; - std::vector index3 = {2, 1, 3}; - std::vector index4 = {2, 2, 2, 1, 3}; + dyn_shape index1 = {0, 1, 1}; + dyn_shape index2 = {1, 1}; + dyn_shape index3 = {2, 1, 3}; + dyn_shape index4 = {2, 2, 2, 1, 3}; EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); test_bound_check(vec); @@ -416,10 +417,10 @@ namespace xt vec.reshape(cem.m_shape, cem.m_strides); assign_array(vec, cem.m_assigner); EXPECT_EQ(vec.data(), cem.m_data); - std::vector index1 = {0, 1, 1}; - std::vector index2 = {1, 1}; - std::vector index3 = {2, 1, 3}; - std::vector index4 = {2, 2, 2, 1, 3}; + dyn_shape index1 = {0, 1, 1}; + dyn_shape index2 = {1, 1}; + dyn_shape index3 = {2, 1, 3}; + dyn_shape index4 = {2, 2, 2, 1, 3}; EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); test_bound_check(vec); @@ -431,10 +432,10 @@ namespace xt vec.reshape(usr.m_shape, layout_type::row_major); assign_array(vec, usr.m_assigner); EXPECT_EQ(vec.data(), usr.m_data); - std::vector index1 = {0, 1, 0}; - std::vector index2 = {1, 0}; - std::vector index3 = {2, 0, 3}; - std::vector index4 = {2, 2, 2, 0, 3}; + dyn_shape index1 = {0, 1, 0}; + dyn_shape index2 = {1, 0}; + dyn_shape index3 = {2, 0, 3}; + dyn_shape index4 = {2, 2, 2, 0, 3}; EXPECT_EQ(vec.element(index1.begin(), index1.end()), vec.element(index2.begin(), index2.end())); EXPECT_EQ(vec.element(index3.begin(), index3.end()), vec.element(index4.begin(), index4.end())); test_bound_check(vec); @@ -460,7 +461,7 @@ namespace xt } } - template > + template > void test_indexed_access(V& vec) { xindex index1 = {1, 1}; @@ -567,7 +568,7 @@ namespace xt } } - template > + template > void test_iterator(V& vec) { { @@ -607,14 +608,14 @@ namespace xt } } - template > + template > void test_xiterator(V& vec) { row_major_result rm; vec.reshape(rm.m_shape, layout_type::row_major); indexed_assign_array(vec, rm.m_assigner); size_t nb_iter = vec.size() / 2; - using shape_type = std::vector; + using shape_type = dyn_shape; // broadcast_iterator { @@ -671,7 +672,7 @@ namespace xt } } - template > + template > void test_reverse_xiterator(V& vec) { row_major_result rm; @@ -693,7 +694,7 @@ namespace xt // shaped_xiterator { - using shape_type = std::vector; + using shape_type = dyn_shape; shape_type shape(rm.m_shape.size() + 1); std::copy(rm.m_shape.begin(), rm.m_shape.end(), shape.begin() + 1); shape[0] = 2; diff --git a/test/test_xadapt.cpp b/test/test_xadapt.cpp index 79ec86a4a..b5bb8e3d2 100644 --- a/test/test_xadapt.cpp +++ b/test/test_xadapt.cpp @@ -69,7 +69,7 @@ namespace xt TEST(xtensor_adaptor, xadapt) { vec_type v(4, 0); - using shape_type = std::array; + using shape_type = stat_shape; shape_type s = {2, 2}; auto a1 = xadapt(v, s); @@ -86,7 +86,7 @@ namespace xt { size_t size = 4; int* data = new int[size]; - using shape_type = std::array; + using shape_type = stat_shape; shape_type s = {2, 2}; auto a1 = xadapt(data, size, no_ownership(), s); @@ -106,7 +106,7 @@ namespace xt size_t size = 4; int* data = new int[size]; int* data2 = new int[size]; - using shape_type = std::array; + using shape_type = stat_shape; shape_type s = {2, 2}; auto a1 = xadapt(data, size, acquire_ownership(), s); diff --git a/test/test_xarray.cpp b/test/test_xarray.cpp index 408d9ba06..474a80f77 100644 --- a/test/test_xarray.cpp +++ b/test/test_xarray.cpp @@ -32,11 +32,11 @@ namespace xt { SCOPED_TRACE("from shape"); - std::array shp = {5, 4, 2}; - std::vector shp_as_vec = {5, 4, 2}; + stat_shape shp = {5, 4, 2}; + dyn_shape shp_as_vec = {5, 4, 2}; auto ca = xarray::from_shape({3, 2, 1}); auto cb = xarray::from_shape(shp); - std::vector expected_shape = {3, 2, 1}; + dyn_shape expected_shape = {3, 2, 1}; EXPECT_EQ(expected_shape, ca.shape()); EXPECT_EQ(shp_as_vec, cb.shape()); } diff --git a/test/test_xbroadcast.cpp b/test/test_xbroadcast.cpp index e8b96b619..4de8b19a6 100644 --- a/test/test_xbroadcast.cpp +++ b/test/test_xbroadcast.cpp @@ -24,7 +24,7 @@ namespace xt ASSERT_EQ(5.0, m1_broadcast(0, 1, 1)); ASSERT_EQ(m1_broadcast.layout(), m1.layout()); - auto shape = std::vector{1, 2, 3}; + auto shape = dyn_shape{1, 2, 3}; auto m1_broadcast2 = broadcast(m1, shape); ASSERT_EQ(1.0, m1_broadcast2(0, 0, 0)); ASSERT_EQ(4.0, m1_broadcast2(0, 1, 0)); @@ -44,16 +44,16 @@ namespace xt auto m1_broadcast = broadcast(m1, {4, 2, 3}); // access with the right number of arguments - std::array index1 = {0, 1, 1}; + stat_shape index1 = {0, 1, 1}; ASSERT_EQ(5.0, m1_broadcast.element(index1.begin(), index1.end())); // too many arguments = using the last ones only - std::array index3 = {4, 0, 1, 1}; + stat_shape index3 = {4, 0, 1, 1}; ASSERT_EQ(5.0, m1_broadcast.element(index3.begin(), index3.end())); } TEST(xbroadcast, shape_forwarding) { - std::array bc_shape; + stat_shape bc_shape; auto m1_broadcast = broadcast(123, bc_shape); } @@ -62,7 +62,7 @@ namespace xt xarray m1 = {1, 2, 3}; auto m1_broadcast = broadcast(m1, {2, 3}); size_t nb_iter = 3; - using shape_type = std::vector; + using shape_type = dyn_shape; // broadcast_iterator { @@ -95,7 +95,7 @@ namespace xt xarray m1 = {1, 2, 3}; auto m1_broadcast = broadcast(m1, {2, 3}); size_t nb_iter = 3; - using shape_type = std::vector; + using shape_type = dyn_shape; // reverse_broadcast_iterator { diff --git a/test/test_xdynamicview.cpp b/test/test_xdynamicview.cpp index 8c994c2dc..8c7d4b0b7 100644 --- a/test/test_xdynamicview.cpp +++ b/test/test_xdynamicview.cpp @@ -15,7 +15,7 @@ namespace xt { using std::size_t; - using view_shape_type = std::vector; + using view_shape_type = dyn_shape; TEST(xdynview, simple) { @@ -92,7 +92,7 @@ namespace xt EXPECT_EQ(a(1, 1, 0), view1(1, 0)); EXPECT_EQ(a(1, 1, 1), view1(1, 1)); - std::array idx = {1, 1}; + stat_shape idx = {1, 1}; EXPECT_EQ(a(1, 1, 1), view1.element(idx.cbegin(), idx.cend())); } @@ -241,10 +241,10 @@ namespace xt EXPECT_EQ(a(1, 2), view6(2, 0)); EXPECT_EQ(2, view6.dimension()); - std::array idx1 = {1, 0, 2}; + stat_shape idx1 = {1, 0, 2}; EXPECT_EQ(a(1, 2), view1.element(idx1.begin(), idx1.end())); - std::array idx2 = {1, 2, 0}; + stat_shape idx2 = {1, 2, 0}; EXPECT_EQ(a(1, 2), view2.element(idx2.begin(), idx2.end())); } diff --git a/test/test_xeval.cpp b/test/test_xeval.cpp index 47596c037..08e2f3148 100644 --- a/test/test_xeval.cpp +++ b/test/test_xeval.cpp @@ -50,12 +50,14 @@ namespace xt auto m = k * k - 4; auto&& n = eval(m); bool type_eq_3 = std::is_same&&>::value; - EXPECT_TRUE(type_eq_3); + // FIXME: std::is_same&&>::value fails + //EXPECT_TRUE(type_eq_3); #ifndef X_OLD_CLANG auto&& i = eval(linspace(0, 100)); bool type_eq_2 = std::is_same&&>::value; - EXPECT_TRUE(type_eq_2); + // FIXME: std::is_same&&>::value fails + //EXPECT_TRUE(type_eq_2); #endif } } diff --git a/test/test_xoperation.cpp b/test/test_xoperation.cpp index e19ae549c..56cdb8e24 100644 --- a/test/test_xoperation.cpp +++ b/test/test_xoperation.cpp @@ -342,7 +342,8 @@ namespace xt auto c = equal(b, 0); std::vector> expected_c = {{0, 0}, {1, 2}}; - EXPECT_EQ(expected_c, nonzero(c)); + // FIXME: vector == vector undefined + // EXPECT_EQ(expected_c, nonzero(c)); shape_type s = {3, 3, 3}; bool_container d(s); diff --git a/test/test_xreducer.cpp b/test/test_xreducer.cpp index 203960c8f..af6c654ee 100644 --- a/test/test_xreducer.cpp +++ b/test/test_xreducer.cpp @@ -17,7 +17,7 @@ namespace xt { struct xreducer_features { - using axes_type = std::array; + using axes_type = stat_shape; axes_type m_axes; xarray m_a; using shape_type = xarray::shape_type; diff --git a/test/test_xtensor.cpp b/test/test_xtensor.cpp index 9d6aa0e3b..4a42ae0a3 100644 --- a/test/test_xtensor.cpp +++ b/test/test_xtensor.cpp @@ -47,11 +47,11 @@ namespace xt { SCOPED_TRACE("from shape"); - std::array shp = {5, 4, 2}; - std::vector shp_as_vec = {5, 4, 2}; + stat_shape shp = {5, 4, 2}; + dyn_shape shp_as_vec = {5, 4, 2}; auto ca = xtensor::from_shape({3, 2, 1}); auto cb = xtensor::from_shape(shp_as_vec); - std::vector expected_shape = {3, 2, 1}; + dyn_shape expected_shape = {3, 2, 1}; EXPECT_TRUE(std::equal(expected_shape.begin(), expected_shape.end(), ca.shape().begin())); EXPECT_TRUE(std::equal(shp.begin(), shp.end(), cb.shape().begin())); } diff --git a/test/test_xtensor_adaptor.cpp b/test/test_xtensor_adaptor.cpp index 84c3b0948..9b8d07682 100644 --- a/test/test_xtensor_adaptor.cpp +++ b/test/test_xtensor_adaptor.cpp @@ -14,7 +14,7 @@ namespace xt { using vec_type = std::vector; using adaptor_type = xtensor_adaptor; - using container_type = std::array; + using container_type = stat_shape; TEST(xtensor_adaptor, shaped_constructor) { diff --git a/test/test_xview.cpp b/test/test_xview.cpp index 09bf801e9..191810cbd 100644 --- a/test/test_xview.cpp +++ b/test/test_xview.cpp @@ -15,7 +15,7 @@ namespace xt { using std::size_t; - using view_shape_type = std::vector; + using view_shape_type = dyn_shape; TEST(xview, temporary_type) { @@ -114,7 +114,7 @@ namespace xt EXPECT_EQ(a(1, 1, 0), view1(1, 0)); EXPECT_EQ(a(1, 1, 1), view1(1, 1)); - std::array idx = {1, 1}; + stat_shape idx = {1, 1}; EXPECT_EQ(a(1, 1, 1), view1.element(idx.cbegin(), idx.cend())); } @@ -377,14 +377,15 @@ namespace xt EXPECT_EQ(a(1, 2), view6(2, 0)); EXPECT_EQ(2, view6.dimension()); - std::array idx1 = {1, 0, 2}; + stat_shape idx1 = {1, 0, 2}; EXPECT_EQ(a(1, 2), view1.element(idx1.begin(), idx1.end())); - std::array idx2 = {1, 2, 0}; + stat_shape idx2 = {1, 2, 0}; EXPECT_EQ(a(1, 2), view2.element(idx2.begin(), idx2.end())); - std::array idx3 = {1, 2}; - EXPECT_EQ(a(1, 2), view3.element(idx2.begin(), idx2.end())); + // FIXME: test is broken, idx3 is incorrectly initialized and unused + //stat_shape idx3 = {1, 2}; + //EXPECT_EQ(a(1, 2), view3.element(idx2.begin(), idx2.end())); } TEST(xview, newaxis_iterating) From 55b9d222c76e204358e777f551717b0e2f1516b4 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 31 Jul 2017 00:29:30 +0200 Subject: [PATCH 22/27] added xreducer::operator() with zero arguments --- include/xtensor/xreducer.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/xtensor/xreducer.hpp b/include/xtensor/xreducer.hpp index 17d46afd0..66842b2f6 100644 --- a/include/xtensor/xreducer.hpp +++ b/include/xtensor/xreducer.hpp @@ -26,7 +26,6 @@ #include "xiterable.hpp" #include "xreducer.hpp" #include "xutils.hpp" -// #include "xtiny.hpp" namespace xt { @@ -127,6 +126,7 @@ namespace xt const inner_shape_type& shape() const noexcept; layout_type layout() const noexcept; + const_reference operator()() const; template const_reference operator()(Args... args) const; const_reference operator[](const xindex& index) const; @@ -402,6 +402,15 @@ namespace xt return element(arg_array.cbegin(), arg_array.cend()); } + // FIXME: what does it mean if a reducer is called with zero arguments? + template + inline auto xreducer::operator()() const -> const_reference + { + stat_shape arg_array; + // call element() with empty range + return element(arg_array.cbegin(), arg_array.cbegin()); + } + /** * Returns a constant reference to the element at the specified position in the reducer. * @param index a sequence of indices specifying the position in the reducer. Indices From 6d43ea466010f3d4ef31996f72cc9beebb93b3f6 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 31 Jul 2017 00:40:48 +0200 Subject: [PATCH 23/27] fixed ambiguities --- test/test_xdynamicview.cpp | 4 +++- test/test_xeval.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/test_xdynamicview.cpp b/test/test_xdynamicview.cpp index 8c7d4b0b7..deca8fdf1 100644 --- a/test/test_xdynamicview.cpp +++ b/test/test_xdynamicview.cpp @@ -164,7 +164,9 @@ namespace xt TEST(xdynview, xdynview_on_xtensor) { - xtensor a({3, 4}); + using X = xtensor; + // FIXME: xtensor a({3, 4}) is ambiguous + xtensor a(X::shape_type{3, 4}); std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; std::copy(data.cbegin(), data.cend(), a.xbegin()); diff --git a/test/test_xeval.cpp b/test/test_xeval.cpp index 08e2f3148..e1e5d491f 100644 --- a/test/test_xeval.cpp +++ b/test/test_xeval.cpp @@ -26,7 +26,8 @@ namespace xt bool type_eq = std::is_same&>::value; EXPECT_TRUE(type_eq); - xtensor t({3, 3}); + //FIXME: xtensor t({3, 3}) is ambiguous + xtensor t(xtensor::shape_type{3, 3}); auto&& i = eval(t); @@ -46,7 +47,8 @@ namespace xt bool type_eq = std::is_same&&>::value; EXPECT_TRUE(type_eq); - xtensor k({3, 3}); + // FIXME: xtensor k({3, 3}) is ambiguous + xtensor k(xtensor::shape_type{3, 3}); auto m = k * k - 4; auto&& n = eval(m); bool type_eq_3 = std::is_same&&>::value; From 2f1d7ea306dc53e452e89a9d1673a63c68473a7c Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 31 Jul 2017 12:52:32 +0200 Subject: [PATCH 24/27] replaced std::vector => tiny_array<..., runtime_size> --- include/xtensor/xbroadcast.hpp | 1 - include/xtensor/xbuilder.hpp | 22 ++++++++-- include/xtensor/xeval.hpp | 23 +++++++++-- include/xtensor/xexpression.hpp | 1 - include/xtensor/xfunctorview.hpp | 14 ++++++- include/xtensor/xgenerator.hpp | 1 - include/xtensor/xio.hpp | 8 +++- include/xtensor/xiterator.hpp | 1 - include/xtensor/xreducer.hpp | 12 +++++- include/xtensor/xscalar.hpp | 1 - include/xtensor/xtiny.hpp | 70 +++++++++++++++++++++++++++----- include/xtensor/xutils.hpp | 47 ++++++++++++++++----- include/xtensor/xview.hpp | 16 +++++++- include/xtensor/xview_utils.hpp | 15 ++++++- test/test_xeval.cpp | 6 +-- test/test_xutils.cpp | 8 ++-- 16 files changed, 197 insertions(+), 49 deletions(-) diff --git a/include/xtensor/xbroadcast.hpp b/include/xtensor/xbroadcast.hpp index 2db9a5fc2..3da0df8d7 100644 --- a/include/xtensor/xbroadcast.hpp +++ b/include/xtensor/xbroadcast.hpp @@ -21,7 +21,6 @@ #include "xiterable.hpp" #include "xstrides.hpp" #include "xutils.hpp" -// #include "xtiny.hpp" namespace xt { diff --git a/include/xtensor/xbuilder.hpp b/include/xtensor/xbuilder.hpp index b9d7ae11b..9cb55dca8 100644 --- a/include/xtensor/xbuilder.hpp +++ b/include/xtensor/xbuilder.hpp @@ -469,15 +469,21 @@ namespace xt namespace detail { template - inline stat_shape add_axis(stat_shape arr, std::size_t axis, std::size_t value) + inline std::array add_axis(std::array arr, std::size_t axis, std::size_t value) { - stat_shape temp; + 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 auto add_axis(tiny_array arr, std::size_t axis, std::size_t value) + { + return arr.insert(axis, value); + } + template inline T add_axis(T arr, std::size_t axis, std::size_t value) { @@ -719,9 +725,17 @@ namespace xt }; template - struct diagonal_shape_type> + struct diagonal_shape_type> + { + using type = std::array; + }; + + template + struct diagonal_shape_type> { - using type = stat_shape; + using type = std::conditional_t<(L > 0), + tiny_array, + tiny_array>; }; } diff --git a/include/xtensor/xeval.hpp b/include/xtensor/xeval.hpp index 7fdeb25ac..d842e8061 100644 --- a/include/xtensor/xeval.hpp +++ b/include/xtensor/xeval.hpp @@ -19,11 +19,28 @@ namespace xt { template using is_container = std::is_base_of>, T>; + + template + struct shape_ndim + : public std::tuple_size + {}; + + template + struct shape_ndim> + { + static const int value = N; + }; + + template + struct shape_ndim> + { + static const int value = 0; + }; } /** * 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! @@ -40,9 +57,9 @@ namespace xt /// @cond DOXYGEN_INCLUDE_SFINAE template > inline auto eval(T&& t) - -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> + -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> { - return xtensor::value>(std::forward(t)); + return xtensor::value>(std::forward(t)); } template > diff --git a/include/xtensor/xexpression.hpp b/include/xtensor/xexpression.hpp index 74864a6a9..7defa5744 100644 --- a/include/xtensor/xexpression.hpp +++ b/include/xtensor/xexpression.hpp @@ -15,7 +15,6 @@ #include "xconcepts.hpp" #include "xutils.hpp" -// #include "xtiny.hpp" namespace xt { diff --git a/include/xtensor/xfunctorview.hpp b/include/xtensor/xfunctorview.hpp index a750b9c47..c9c805807 100644 --- a/include/xtensor/xfunctorview.hpp +++ b/include/xtensor/xfunctorview.hpp @@ -52,10 +52,22 @@ namespace xt }; template - struct functorview_temporary_type_impl, L> + struct functorview_temporary_type_impl, L> { using type = xtensor; }; + + template + struct functorview_temporary_type_impl, L> + { + using type = xtensor; + }; + + template + struct functorview_temporary_type_impl, L> + { + using type = xarray; + }; } template diff --git a/include/xtensor/xgenerator.hpp b/include/xtensor/xgenerator.hpp index cb5015675..81a8ce42a 100644 --- a/include/xtensor/xgenerator.hpp +++ b/include/xtensor/xgenerator.hpp @@ -20,7 +20,6 @@ #include "xiterable.hpp" #include "xstrides.hpp" #include "xutils.hpp" -// #include "xtiny.hpp" namespace xt { diff --git a/include/xtensor/xio.hpp b/include/xtensor/xio.hpp index 758156e46..3ed0231ed 100644 --- a/include/xtensor/xio.hpp +++ b/include/xtensor/xio.hpp @@ -609,7 +609,13 @@ namespace xt static constexpr std::size_t value = 5; }; -// Note: std::min is not constexpr on old versions of gcc (4.x) and clang. + template + struct recursion_depth> + { + static constexpr std::size_t value = 5; + }; + + // Note: std::min is not constexpr on old versions of gcc (4.x) and clang. #define XTENSOR_MIN(x, y) (x > y ? y : x) template struct recursion_depth> diff --git a/include/xtensor/xiterator.hpp b/include/xtensor/xiterator.hpp index 6073dbeef..3e37a431c 100644 --- a/include/xtensor/xiterator.hpp +++ b/include/xtensor/xiterator.hpp @@ -18,7 +18,6 @@ #include "xexception.hpp" #include "xlayout.hpp" #include "xutils.hpp" -// #include "xtiny.hpp" namespace xt { diff --git a/include/xtensor/xreducer.hpp b/include/xtensor/xreducer.hpp index 66842b2f6..a3ef999de 100644 --- a/include/xtensor/xreducer.hpp +++ b/include/xtensor/xreducer.hpp @@ -277,9 +277,17 @@ namespace xt }; template - struct xreducer_shape_type, stat_shape> + struct xreducer_shape_type, std::array> { - using type = stat_shape; + using type = std::array; + }; + + template + struct xreducer_shape_type, tiny_array> + { + using type = std::conditional_t<(N1 > 0 && N2 > 0 && N1 > N2), + tiny_array, + tiny_array>; }; namespace detail diff --git a/include/xtensor/xscalar.hpp b/include/xtensor/xscalar.hpp index bdab7c6e2..aff780983 100644 --- a/include/xtensor/xscalar.hpp +++ b/include/xtensor/xscalar.hpp @@ -16,7 +16,6 @@ #include "xexpression.hpp" #include "xiterable.hpp" #include "xlayout.hpp" -// #include "xtiny.hpp" namespace xt { diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index 98b4f7368..eec38f85f 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -1176,7 +1176,7 @@ class tiny_array {} template > + XTENSOR_REQUIRE<(S > 1)>> explicit tiny_array(U const (&u)[static_size]) : base_type(u) {} @@ -1398,17 +1398,24 @@ class tiny_array alloc_.deallocate(this->data_, this->size_); } -#if 0 +#if 1 // FIXME: hacks to use tiny_array as shape in xtensor using base_type::erase; void erase(base_type::pointer p) { - --this->size_; - for(; p < this->data_ + this->size_; ++p) - *p = p[1]; + base_type::erase(p-this->begin()).swap(*this); } + // FIXME: hacks to use tiny_array as shape in xtensor + using base_type::insert; + + void insert(base_type::pointer p, value_type v) + { + base_type::insert(p-this->begin(), v).swap(*this); + } + + // FIXME: hacks to use tiny_array as shape in xtensor void resize(size_t s) { if(s > this->size_) @@ -1419,11 +1426,13 @@ class tiny_array this->size_ = s; } + // FIXME: hacks to use tiny_array as shape in xtensor template tiny_array(std::vector const & rhs) : tiny_array(rhs.cbegin(), rhs.cend()) {} + // FIXME: hacks to use tiny_array as shape in xtensor template tiny_array & operator=(std::vector const & rhs) { @@ -1433,6 +1442,7 @@ class tiny_array return *this; } + // FIXME: hacks to use tiny_array as shape in xtensor template bool operator==(std::vector const & rhs) const { @@ -1475,6 +1485,35 @@ bool operator==(tiny_array const & l, std::vector const & r) return true; } +// // FIXME +// template +// class tiny_array +// : public tiny_array +// { + // public: + // using base_type = tiny_array; + // using base_type::base_type; + + // tiny_array(base_type const & other) + // : base_type(other) + // {} +// }; + +// // FIXME +// template +// class tiny_array +// : public tiny_array +// { + // public: + // using base_type = tiny_array; + // using base_type::base_type; + + // tiny_array(base_type const & other) + // : base_type(other) + // {} +// }; + + /********************************************************/ /* */ /* tiny_array_view */ @@ -1926,16 +1965,15 @@ inline bool operator<(tiny_array_base const & l, tiny_array_base const & r) { - XTENSOR_ASSERT_RUNTIME_SIZE(N..., l.size() == r.size(), - "tiny_array_base::operator<(): size mismatch."); - for(int k=0; k < l.size(); ++k) + const int min_size = min(l.size(), r.size()); + for(int k = 0; k < min_size; ++k) { if(l[k] < r[k]) return true; if(r[k] < l[k]) return false; } - return false; + return (l.size() < r.size()); } /// lexicographical less-equal @@ -2504,6 +2542,19 @@ XTENSOR_TINYARRAY_OPERATORS(>>) #endif // DOXYGEN + // define sqrt() explicitly because its return type + // is needed for type inference +template +inline tiny_array, N...> +sqrt(tiny_array_base const & v) +{ + using namespace cmath; + tiny_array, N...> res(v.size(), dont_init); + for(int k=0; k < v.size(); ++k) + res[k] = sqrt(v[k]); + return res; +} + #define XTENSOR_TINYARRAY_UNARY_FUNCTION(FCT) \ template \ inline auto \ @@ -2535,7 +2586,6 @@ XTENSOR_TINYARRAY_UNARY_FUNCTION(acosh) XTENSOR_TINYARRAY_UNARY_FUNCTION(asinh) XTENSOR_TINYARRAY_UNARY_FUNCTION(atanh) -XTENSOR_TINYARRAY_UNARY_FUNCTION(sqrt) XTENSOR_TINYARRAY_UNARY_FUNCTION(cbrt) XTENSOR_TINYARRAY_UNARY_FUNCTION(sq) XTENSOR_TINYARRAY_UNARY_FUNCTION(elementwise_norm) diff --git a/include/xtensor/xutils.hpp b/include/xtensor/xutils.hpp index 8ec66173b..078742a09 100644 --- a/include/xtensor/xutils.hpp +++ b/include/xtensor/xutils.hpp @@ -26,7 +26,8 @@ namespace xt { // FIXME: dyn_shape and stat_shape are just a helper classes for refactoring template > - using dyn_shape = std::vector; + //using dyn_shape = std::vector; + using dyn_shape = tiny_array; template //using stat_shape = std::array; @@ -452,7 +453,14 @@ namespace xt template inline bool resize_container(tiny_array& a, typename tiny_array::size_type size) { - return a.size() == size; + return size == N; + } + + template + inline bool resize_container(tiny_array& a, typename tiny_array::size_type size) + { + tiny_array(size).swap(a); + return true; } /******************************** @@ -573,7 +581,7 @@ namespace xt namespace detail { template - constexpr std::common_type_t imax(const T1& a, const T2& b) + constexpr std::common_type_t imax(const T1 a, const T2 b) { return a > b ? a : b; } @@ -593,6 +601,16 @@ namespace xt { }; + template + struct max_array_size, Ts...> : std::integral_constant::value)> + { + }; + + template + struct max_array_size, Ts...> : std::integral_constant::value> + { + }; + // Simple is_array and only_array meta-functions template struct is_array @@ -606,15 +624,22 @@ namespace xt static constexpr bool value = true; }; - //template - //struct is_array> - //{ - // static constexpr bool value = true; - //}; + template + struct is_array> + { + static constexpr bool value = true; + }; + + template + struct is_array> + { + static constexpr bool value = false; + }; template using only_array = and_...>; + // FIXME: port promote_index_impl to tiny_array // The promote_index meta-function returns std::vector in the // general case and an array of the promoted value type and maximal size if all // arguments are of type std::array @@ -625,19 +650,19 @@ namespace xt template struct promote_index_impl { - using type = std::vector::type>; + using type = dyn_shape::type>; }; template struct promote_index_impl { - using type = std::array::type, max_array_size::value>; + using type = stat_shape::type, max_array_size::value>; }; template <> struct promote_index_impl { - using type = std::array; + using type = stat_shape; }; template diff --git a/include/xtensor/xview.hpp b/include/xtensor/xview.hpp index f8d7cf12c..e5cc74bfd 100644 --- a/include/xtensor/xview.hpp +++ b/include/xtensor/xview.hpp @@ -310,9 +310,21 @@ namespace xt }; template - struct xview_shape_type, S...> + struct xview_shape_type, S...> { - using type = stat_shape() + newaxis_count())>; + using type = std::array() + newaxis_count()>; + }; + + template + struct xview_shape_type, S...> + { + using type = tiny_array() + newaxis_count())>; + }; + + template + struct xview_shape_type, S...> + { + using type = tiny_array; }; /************************ diff --git a/include/xtensor/xview_utils.hpp b/include/xtensor/xview_utils.hpp index 90d364454..38bedc3c2 100644 --- a/include/xtensor/xview_utils.hpp +++ b/include/xtensor/xview_utils.hpp @@ -12,7 +12,6 @@ #include #include "xslice.hpp" -// #include "xtiny.hpp" namespace xt { @@ -71,10 +70,22 @@ namespace xt }; template - struct view_temporary_type_impl, L, SL...> + struct view_temporary_type_impl, L, SL...> { using type = xtensor() - integral_count(), L>; }; + + template + struct view_temporary_type_impl, L, SL...> + { + using type = xtensor() - integral_count(), L>; + }; + + template + struct view_temporary_type_impl, L, SL...> + { + using type = xarray; + }; } template diff --git a/test/test_xeval.cpp b/test/test_xeval.cpp index e1e5d491f..9341f62ac 100644 --- a/test/test_xeval.cpp +++ b/test/test_xeval.cpp @@ -52,14 +52,12 @@ namespace xt auto m = k * k - 4; auto&& n = eval(m); bool type_eq_3 = std::is_same&&>::value; - // FIXME: std::is_same&&>::value fails - //EXPECT_TRUE(type_eq_3); + EXPECT_TRUE(type_eq_3); #ifndef X_OLD_CLANG auto&& i = eval(linspace(0, 100)); bool type_eq_2 = std::is_same&&>::value; - // FIXME: std::is_same&&>::value fails - //EXPECT_TRUE(type_eq_2); + EXPECT_TRUE(type_eq_2); #endif } } diff --git a/test/test_xutils.cpp b/test/test_xutils.cpp index 49238c066..c664c62ea 100644 --- a/test/test_xutils.cpp +++ b/test/test_xutils.cpp @@ -94,13 +94,13 @@ namespace xt TEST(utils, promote_shape) { bool expect_v = std::is_same< - std::vector, - promote_shape_t, std::array, std::array> + dyn_shape, + promote_shape_t, stat_shape, stat_shape> >::value; bool expect_a = std::is_same< - std::array, - promote_shape_t, std::array, std::array> + stat_shape, + promote_shape_t, stat_shape, stat_shape> >::value; ASSERT_TRUE(expect_v); From 1fab593aab510ef5d6ad6c7c17b51a1081343708 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 31 Jul 2017 13:55:05 +0200 Subject: [PATCH 25/27] resolved FIXMEs --- include/xtensor/xbuilder.hpp | 15 ++- include/xtensor/xtiny.hpp | 217 ++++------------------------------- include/xtensor/xutils.hpp | 8 +- test/test_xbuilder.cpp | 2 +- test/test_xdynamicview.cpp | 3 +- test/test_xeval.cpp | 6 +- test/test_xiterator.cpp | 61 +++++----- test/test_xmath.cpp | 2 +- test/test_xoperation.cpp | 3 +- test/test_xtensor.cpp | 2 +- test/test_xvectorize.cpp | 2 +- 11 files changed, 79 insertions(+), 242 deletions(-) diff --git a/include/xtensor/xbuilder.hpp b/include/xtensor/xbuilder.hpp index 9cb55dca8..e51f38e7b 100644 --- a/include/xtensor/xbuilder.hpp +++ b/include/xtensor/xbuilder.hpp @@ -379,7 +379,8 @@ namespace xt private: - inline value_type access_impl(xindex idx) const + template + inline value_type access_impl(std::vector idx) const { auto get_item = [&idx](auto& arr) { @@ -390,6 +391,18 @@ namespace xt return apply(i, get_item, m_t); } + template + inline value_type access_impl(tiny_array const & old_idx) const + { + size_type i = old_idx[m_axis]; + auto idx = old_idx.erase(m_axis); + auto get_item = [&idx](auto& arr) + { + return arr[idx]; + }; + return apply(i, get_item, m_t); + } + const std::tuple m_t; const size_type m_axis; }; diff --git a/include/xtensor/xtiny.hpp b/include/xtensor/xtiny.hpp index eec38f85f..1c54f77aa 100644 --- a/include/xtensor/xtiny.hpp +++ b/include/xtensor/xtiny.hpp @@ -256,7 +256,7 @@ class tiny_array_base // } template - explicit tiny_array_base(U const * u) + explicit tiny_array_base(U const * u, U const * /* end */ = 0) { for(int i=0; i(u[i]); @@ -275,6 +275,14 @@ class tiny_array_base : tiny_array_base(u, copy_reversed) {} + template ::value> > + tiny_array_base(U u, U /* end */) + { + for(int i=0; i(*u); + } + public: // assignment @@ -1088,7 +1096,6 @@ class tiny_array : base_type(dont_init) {} - // FIXME // This constructor would allow construction with round brackets, e.g.: // tiny_array a(2); // However, this may lead to bugs when fixed-size arrays are mixed with @@ -1098,10 +1105,10 @@ class tiny_array // construction is restricted to curly braces: // tiny_array a{2}; // - template - constexpr tiny_array(value_type v0, V... v) - : base_type(v0, v...) - {} + // template + // constexpr tiny_array(value_type v0, V... v) + // : base_type(v0, v...) + // {} template tiny_array(std::initializer_list v) @@ -1181,35 +1188,22 @@ class tiny_array : base_type(u) {} - // FIXME - template > - tiny_array(std::array const & a) - : tiny_array(&a[0]) + template + explicit tiny_array(U const * u, U const * /* end */ = 0) + : base_type(u) {} - // FIXME - template > - bool operator==(std::array const & a) const - { - for(index_t k=0; k::value> > - explicit tiny_array(U u, U /* end */ = U()) - : base_type(&*u) + tiny_array(U u, reverse_copy_tag) + : base_type(u, copy_reversed) {} + // for compatibility with tiny_array<..., runtime_size> template ::value> > - tiny_array(U u, reverse_copy_tag) - : base_type(u, copy_reversed) + explicit tiny_array(U u, U end = U()) + : base_type(u, end) {} // for compatibility with tiny_array<..., runtime_size> @@ -1398,122 +1392,20 @@ class tiny_array alloc_.deallocate(this->data_, this->size_); } -#if 1 - // FIXME: hacks to use tiny_array as shape in xtensor - using base_type::erase; - - void erase(base_type::pointer p) - { - base_type::erase(p-this->begin()).swap(*this); - } - - // FIXME: hacks to use tiny_array as shape in xtensor - using base_type::insert; - - void insert(base_type::pointer p, value_type v) - { - base_type::insert(p-this->begin(), v).swap(*this); - } - - // FIXME: hacks to use tiny_array as shape in xtensor - void resize(size_t s) + void resize(size_t new_size) { - if(s > this->size_) + if(new_size != this->size()) { - alloc_.deallocate(this->data_, this->size_); - this->data_ = alloc_.allocate(s); + tiny_array(new_size).swap(*this); } - this->size_ = s; - } - - // FIXME: hacks to use tiny_array as shape in xtensor - template - tiny_array(std::vector const & rhs) - : tiny_array(rhs.cbegin(), rhs.cend()) - {} - - // FIXME: hacks to use tiny_array as shape in xtensor - template - tiny_array & operator=(std::vector const & rhs) - { - resize(rhs.size()); - for(int k=0; k < this->size_; ++k) - this->data_[k] = rhs[k]; - return *this; } - // FIXME: hacks to use tiny_array as shape in xtensor - template - bool operator==(std::vector const & rhs) const - { - if(this->size_ != (int)rhs.size()) - return false; - for(int k=0; k < this->size_; ++k) - if(this->data_[k] != rhs[k]) - return false; - return true; - } -#endif - private: // FIXME: implement an optimized allocator // FIXME: (look at Alexandrescu's Loki library or Kolmogorov's code) std::allocator alloc_; }; - //FIXME -template -bool operator==(std::vector const & l, tiny_array const & r) -{ - if((int)l.size() != r.size()) - return false; - for(int k=0; k < (int)l.size(); ++k) - if(l[k] != r[k]) - return false; - return true; -} - - //FIXME -template -bool operator==(tiny_array const & l, std::vector const & r) -{ - if(l.size() != (int)r.size()) - return false; - for(int k=0; k < (int)l.size(); ++k) - if(l[k] != r[k]) - return false; - return true; -} - -// // FIXME -// template -// class tiny_array -// : public tiny_array -// { - // public: - // using base_type = tiny_array; - // using base_type::base_type; - - // tiny_array(base_type const & other) - // : base_type(other) - // {} -// }; - -// // FIXME -// template -// class tiny_array -// : public tiny_array -// { - // public: - // using base_type = tiny_array; - // using base_type::base_type; - - // tiny_array(base_type const & other) - // : base_type(other) - // {} -// }; - - /********************************************************/ /* */ /* tiny_array_view */ @@ -2003,67 +1895,6 @@ operator>=(tiny_array_base const & l, return !(l < r); } - // /// lexicographical comparison -// template -// inline bool -// operator<(tiny_array_base const & l, - // std::vector const & r) -// { - // index_t size = r.size(); - // bool equal_res = false; - // if(l.size() < size) - // { - // size = l.size(); - // equal_res = true; - // } - // for(int k=0; k < size; ++k) - // { - // if(l[k] < r[k]) - // return true; - // if(r[k] < l[k]) - // return false; - // } - // return equal_res; -// } - -// template -// inline bool -// operator<(std::vector const & l, - // tiny_array_base const & r) -// { - // index_t size = r.size(); - // bool equal_res = false; - // if(l.size() < size) - // { - // size = l.size(); - // equal_res = true; - // } - // for(int k=0; k < size; ++k) - // { - // if(l[k] < r[k]) - // return true; - // if(r[k] < l[k]) - // return false; - // } - // return equal_res; -// } - -// template -// inline bool -// operator>(tiny_array_base const & l, - // std::vector const & r) -// { - // return r < l; -// } - -// template -// inline bool -// operator>(std::vector const & l, - // tiny_array_base const & r) -// { - // return r < l; -// } - /// check if all elements are non-zero (or 'true' if V is bool) template inline bool diff --git a/include/xtensor/xutils.hpp b/include/xtensor/xutils.hpp index 078742a09..8149424e9 100644 --- a/include/xtensor/xutils.hpp +++ b/include/xtensor/xutils.hpp @@ -24,7 +24,8 @@ namespace xt { - // FIXME: dyn_shape and stat_shape are just a helper classes for refactoring + // dyn_shape and stat_shape are centralized declarations of + // shape types for xarray and xtensor respectively template > //using dyn_shape = std::vector; using dyn_shape = tiny_array; @@ -639,10 +640,9 @@ namespace xt template using only_array = and_...>; - // FIXME: port promote_index_impl to tiny_array - // The promote_index meta-function returns std::vector in the + // The promote_index meta-function returns dyn_shape in the // general case and an array of the promoted value type and maximal size if all - // arguments are of type std::array + // arguments are of type stat_shape template struct promote_index_impl; diff --git a/test/test_xbuilder.cpp b/test/test_xbuilder.cpp index 628eb2a8d..bd6ec3d5f 100644 --- a/test/test_xbuilder.cpp +++ b/test/test_xbuilder.cpp @@ -16,7 +16,7 @@ namespace xt { using std::size_t; - using shape_t = std::vector; + using shape_t = dyn_shape; TEST(xbuilder, ones) { diff --git a/test/test_xdynamicview.cpp b/test/test_xdynamicview.cpp index deca8fdf1..bb7689ec6 100644 --- a/test/test_xdynamicview.cpp +++ b/test/test_xdynamicview.cpp @@ -165,8 +165,7 @@ namespace xt TEST(xdynview, xdynview_on_xtensor) { using X = xtensor; - // FIXME: xtensor a({3, 4}) is ambiguous - xtensor a(X::shape_type{3, 4}); + xtensor a({ 3, 4 }); std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; std::copy(data.cbegin(), data.cend(), a.xbegin()); diff --git a/test/test_xeval.cpp b/test/test_xeval.cpp index 9341f62ac..1002efe49 100644 --- a/test/test_xeval.cpp +++ b/test/test_xeval.cpp @@ -26,8 +26,7 @@ namespace xt bool type_eq = std::is_same&>::value; EXPECT_TRUE(type_eq); - //FIXME: xtensor t({3, 3}) is ambiguous - xtensor t(xtensor::shape_type{3, 3}); + xtensor t({ 3, 3 }); auto&& i = eval(t); @@ -47,8 +46,7 @@ namespace xt bool type_eq = std::is_same&&>::value; EXPECT_TRUE(type_eq); - // FIXME: xtensor k({3, 3}) is ambiguous - xtensor k(xtensor::shape_type{3, 3}); + xtensor k({3, 3}); auto m = k * k - 4; auto&& n = eval(m); bool type_eq_3 = std::is_same&&>::value; diff --git a/test/test_xiterator.cpp b/test/test_xiterator.cpp index 81f393fca..fd8a89ecb 100644 --- a/test/test_xiterator.cpp +++ b/test/test_xiterator.cpp @@ -12,6 +12,19 @@ namespace xt { + template + void shape_insert(SHAPE & s, int i, int j) + { + s.insert(s.begin(), i); + s.insert(s.begin(), j); + } + + template + void shape_insert(tiny_array & s, int i, int j) + { + s.insert(0, i).insert(0, j).swap(s); + } + using std::size_t; template @@ -48,8 +61,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_increment(rm, rm.shape()); } } @@ -65,8 +77,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_increment(rm, rm.shape()); } } @@ -82,8 +93,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_increment(rm, rm.shape()); } } @@ -99,8 +109,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_increment(rm, rm.shape()); } } @@ -136,8 +145,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_end(rm); } } @@ -153,8 +161,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_end(rm); } } @@ -170,8 +177,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_end(rm); } } @@ -187,8 +193,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_end(rm); } } @@ -226,8 +231,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_decrement(rm, rm.shape()); } } @@ -243,8 +247,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_decrement(rm, rm.shape()); } } @@ -260,8 +263,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_decrement(rm, rm.shape()); } } @@ -277,8 +279,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_decrement(rm, rm.shape()); } } @@ -314,8 +315,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_rend(rm); } } @@ -331,8 +331,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_rend(rm); } } @@ -348,8 +347,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_rend(rm); } } @@ -365,8 +363,7 @@ namespace xt { SCOPED_TRACE("broadcasting shape"); layout_result<>::shape_type sh = rm.shape(); - sh.insert(sh.begin(), 2); - sh.insert(sh.begin(), 4); + shape_insert(sh, 2, 4); test_rend(rm); } } diff --git a/test/test_xmath.cpp b/test/test_xmath.cpp index 968c41eff..c580926fb 100644 --- a/test/test_xmath.cpp +++ b/test/test_xmath.cpp @@ -16,7 +16,7 @@ namespace xt { using std::size_t; - using shape_type = std::vector; + using shape_type = dyn_shape; /******************** * Basic operations * diff --git a/test/test_xoperation.cpp b/test/test_xoperation.cpp index 56cdb8e24..e19ae549c 100644 --- a/test/test_xoperation.cpp +++ b/test/test_xoperation.cpp @@ -342,8 +342,7 @@ namespace xt auto c = equal(b, 0); std::vector> expected_c = {{0, 0}, {1, 2}}; - // FIXME: vector == vector undefined - // EXPECT_EQ(expected_c, nonzero(c)); + EXPECT_EQ(expected_c, nonzero(c)); shape_type s = {3, 3, 3}; bool_container d(s); diff --git a/test/test_xtensor.cpp b/test/test_xtensor.cpp index 4a42ae0a3..4f3cee090 100644 --- a/test/test_xtensor.cpp +++ b/test/test_xtensor.cpp @@ -12,7 +12,7 @@ namespace xt { - using container_type = std::array; + using container_type = stat_shape; using xtensor_dynamic = xtensor; TEST(xtensor, initializer_constructor) diff --git a/test/test_xvectorize.cpp b/test/test_xvectorize.cpp index ecf3aa4b4..112c63f02 100644 --- a/test/test_xvectorize.cpp +++ b/test/test_xvectorize.cpp @@ -18,7 +18,7 @@ namespace xt return d1 + d2; } - using shape_type = std::vector; + using shape_type = dyn_shape; TEST(xvectorize, function) { From 906494149f4935690714e20728edad74aa54352e Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 31 Jul 2017 14:30:58 +0200 Subject: [PATCH 26/27] removed incorrect 'typename' --- include/xtensor/xstridedview.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xtensor/xstridedview.hpp b/include/xtensor/xstridedview.hpp index 1c6f19a43..b4e87f70c 100644 --- a/include/xtensor/xstridedview.hpp +++ b/include/xtensor/xstridedview.hpp @@ -850,7 +850,7 @@ namespace xt // Compute strided view std::size_t offset = detail::get_offset(e); - using shape_type = typename dyn_shape; + using shape_type = dyn_shape; shape_type new_shape(dimension); shape_type new_strides(dimension); From eed85b0f2035ea3ddbb1bef31a1b7ea818dc8206 Mon Sep 17 00:00:00 2001 From: Ullrich Koethe Date: Mon, 31 Jul 2017 15:38:48 +0200 Subject: [PATCH 27/27] more dyn_shape replacements --- include/xtensor/xindexview.hpp | 1 - test/test_xadapt.cpp | 6 +++--- test/test_xdynamicview.cpp | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/include/xtensor/xindexview.hpp b/include/xtensor/xindexview.hpp index 6665d912f..78b4ef96c 100644 --- a/include/xtensor/xindexview.hpp +++ b/include/xtensor/xindexview.hpp @@ -18,7 +18,6 @@ #include "xexpression.hpp" #include "xiterable.hpp" #include "xstrides.hpp" -// #include "xutils.hpp" namespace xt { diff --git a/test/test_xadapt.cpp b/test/test_xadapt.cpp index b5bb8e3d2..e3738acc1 100644 --- a/test/test_xadapt.cpp +++ b/test/test_xadapt.cpp @@ -16,7 +16,7 @@ namespace xt TEST(xarray_adaptor, xadapt) { vec_type v(4, 0); - using shape_type = std::vector; + using shape_type = dyn_shape; shape_type s({2, 2}); auto a1 = xadapt(v, s); @@ -33,7 +33,7 @@ namespace xt { size_t size = 4; int* data = new int[size]; - using shape_type = std::vector; + using shape_type = dyn_shape; shape_type s({2, 2}); auto a1 = xadapt(data, size, no_ownership(), s); @@ -53,7 +53,7 @@ namespace xt size_t size = 4; int* data = new int[size]; int* data2 = new int[size]; - using shape_type = std::vector; + using shape_type = dyn_shape; shape_type s({2, 2}); auto a1 = xadapt(data, size, acquire_ownership(), s); diff --git a/test/test_xdynamicview.cpp b/test/test_xdynamicview.cpp index bb7689ec6..832899c84 100644 --- a/test/test_xdynamicview.cpp +++ b/test/test_xdynamicview.cpp @@ -164,7 +164,6 @@ namespace xt TEST(xdynview, xdynview_on_xtensor) { - using X = xtensor; xtensor a({ 3, 4 }); std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; std::copy(data.cbegin(), data.cend(), a.xbegin());