| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329 |
- /***************************************************************************
- * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
- * Copyright (c) QuantStack *
- * *
- * Distributed under the terms of the BSD 3-Clause License. *
- * *
- * The full license is in the file LICENSE, distributed with this software. *
- ****************************************************************************/
- /**
- * @brief standard mathematical functions for xexpressions
- */
- #ifndef XTENSOR_MATH_HPP
- #define XTENSOR_MATH_HPP
- #include <algorithm>
- #include <array>
- #include <cmath>
- #include <complex>
- #include <type_traits>
- #include <xtl/xcomplex.hpp>
- #include <xtl/xsequence.hpp>
- #include <xtl/xtype_traits.hpp>
- #include "xaccumulator.hpp"
- #include "xeval.hpp"
- #include "xmanipulation.hpp"
- #include "xoperation.hpp"
- #include "xreducer.hpp"
- #include "xslice.hpp"
- #include "xstrided_view.hpp"
- #include "xtensor_config.hpp"
- namespace xt
- {
- template <class T = double>
- struct numeric_constants
- {
- static constexpr T PI = 3.141592653589793238463;
- static constexpr T PI_2 = 1.57079632679489661923;
- static constexpr T PI_4 = 0.785398163397448309616;
- static constexpr T D_1_PI = 0.318309886183790671538;
- static constexpr T D_2_PI = 0.636619772367581343076;
- static constexpr T D_2_SQRTPI = 1.12837916709551257390;
- static constexpr T SQRT2 = 1.41421356237309504880;
- static constexpr T SQRT1_2 = 0.707106781186547524401;
- static constexpr T E = 2.71828182845904523536;
- static constexpr T LOG2E = 1.44269504088896340736;
- static constexpr T LOG10E = 0.434294481903251827651;
- static constexpr T LN2 = 0.693147180559945309417;
- };
- /***********
- * Helpers *
- ***********/
- #define XTENSOR_UNSIGNED_ABS_FUNC(T) \
- constexpr inline T abs(const T& x) \
- { \
- return x; \
- }
- #define XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, T) \
- constexpr inline bool FUNC_NAME(const T& /*x*/) noexcept \
- { \
- return RETURN_VAL; \
- }
- #define XTENSOR_INT_SPECIALIZATION(FUNC_NAME, RETURN_VAL) \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, char); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, short); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, int); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, long long); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned char); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned short); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned int); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long); \
- XTENSOR_INT_SPECIALIZATION_IMPL(FUNC_NAME, RETURN_VAL, unsigned long long);
- #define XTENSOR_UNARY_MATH_FUNCTOR(NAME) \
- struct NAME##_fun \
- { \
- template <class T> \
- constexpr auto operator()(const T& arg) const \
- { \
- using math::NAME; \
- return NAME(arg); \
- } \
- template <class B> \
- constexpr auto simd_apply(const B& arg) const \
- { \
- using math::NAME; \
- return NAME(arg); \
- } \
- }
- #define XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(NAME) \
- struct NAME##_fun \
- { \
- template <class T> \
- constexpr auto operator()(const T& arg) const \
- { \
- using math::NAME; \
- return NAME(arg); \
- } \
- template <class B> \
- constexpr auto simd_apply(const B& arg) const \
- { \
- using math::NAME; \
- return NAME(arg); \
- } \
- }
- #define XTENSOR_BINARY_MATH_FUNCTOR(NAME) \
- struct NAME##_fun \
- { \
- template <class T1, class T2> \
- constexpr auto operator()(const T1& arg1, const T2& arg2) const \
- { \
- using math::NAME; \
- return NAME(arg1, arg2); \
- } \
- template <class B> \
- constexpr auto simd_apply(const B& arg1, const B& arg2) const \
- { \
- using math::NAME; \
- return NAME(arg1, arg2); \
- } \
- }
- #define XTENSOR_TERNARY_MATH_FUNCTOR(NAME) \
- struct NAME##_fun \
- { \
- template <class T1, class T2, class T3> \
- constexpr auto operator()(const T1& arg1, const T2& arg2, const T3& arg3) const \
- { \
- using math::NAME; \
- return NAME(arg1, arg2, arg3); \
- } \
- template <class B> \
- auto simd_apply(const B& arg1, const B& arg2, const B& arg3) const \
- { \
- using math::NAME; \
- return NAME(arg1, arg2, arg3); \
- } \
- }
- namespace math
- {
- using std::abs;
- using std::fabs;
- using std::acos;
- using std::asin;
- using std::atan;
- using std::cos;
- using std::sin;
- using std::tan;
- using std::acosh;
- using std::asinh;
- using std::atanh;
- using std::cosh;
- using std::sinh;
- using std::tanh;
- using std::cbrt;
- using std::sqrt;
- using std::exp;
- using std::exp2;
- using std::expm1;
- using std::ilogb;
- using std::log;
- using std::log10;
- using std::log1p;
- using std::log2;
- using std::logb;
- using std::ceil;
- using std::floor;
- using std::llround;
- using std::lround;
- using std::nearbyint;
- using std::remainder;
- using std::rint;
- using std::round;
- using std::trunc;
- using std::erf;
- using std::erfc;
- using std::lgamma;
- using std::tgamma;
- using std::arg;
- using std::conj;
- using std::imag;
- using std::real;
- using std::atan2;
- // copysign is not in the std namespace for MSVC
- #if !defined(_MSC_VER)
- using std::copysign;
- #endif
- using std::fdim;
- using std::fmax;
- using std::fmin;
- using std::fmod;
- using std::hypot;
- using std::pow;
- using std::fma;
- using std::fpclassify;
- // Overload isinf, isnan and isfinite because glibc implementation
- // might return int instead of bool and the SIMD detection requires
- // bool return type.
- template <class T>
- inline std::enable_if_t<xtl::is_arithmetic<T>::value, bool> isinf(const T& t)
- {
- return bool(std::isinf(t));
- }
- template <class T>
- inline std::enable_if_t<xtl::is_arithmetic<T>::value, bool> isnan(const T& t)
- {
- return bool(std::isnan(t));
- }
- template <class T>
- inline std::enable_if_t<xtl::is_arithmetic<T>::value, bool> isfinite(const T& t)
- {
- return bool(std::isfinite(t));
- }
- // Overload isinf, isnan and isfinite for complex datatypes,
- // following the Python specification:
- template <class T>
- inline bool isinf(const std::complex<T>& c)
- {
- return std::isinf(std::real(c)) || std::isinf(std::imag(c));
- }
- template <class T>
- inline bool isnan(const std::complex<T>& c)
- {
- return std::isnan(std::real(c)) || std::isnan(std::imag(c));
- }
- template <class T>
- inline bool isfinite(const std::complex<T>& c)
- {
- return !isinf(c) && !isnan(c);
- }
- // VS2015 STL defines isnan, isinf and isfinite as template
- // functions, breaking ADL.
- #if defined(_WIN32) && defined(XTENSOR_USE_XSIMD)
- /*template <class T, class A>
- inline xsimd::batch_bool<T, A> isinf(const xsimd::batch<T, A>& b)
- {
- return xsimd::isinf(b);
- }
- template <class T, class A>
- inline xsimd::batch_bool<T, A> isnan(const xsimd::batch<T, A>& b)
- {
- return xsimd::isnan(b);
- }
- template <class T, class A>
- inline xsimd::batch_bool<T, A> isfinite(const xsimd::batch<T, A>& b)
- {
- return xsimd::isfinite(b);
- }*/
- #endif
- // The following specializations are needed to avoid 'ambiguous overload' errors,
- // whereas 'unsigned char' and 'unsigned short' are automatically converted to 'int'.
- // we're still adding those functions to silence warnings
- XTENSOR_UNSIGNED_ABS_FUNC(unsigned char)
- XTENSOR_UNSIGNED_ABS_FUNC(unsigned short)
- XTENSOR_UNSIGNED_ABS_FUNC(unsigned int)
- XTENSOR_UNSIGNED_ABS_FUNC(unsigned long)
- XTENSOR_UNSIGNED_ABS_FUNC(unsigned long long)
- #ifdef _WIN32
- XTENSOR_INT_SPECIALIZATION(isinf, false);
- XTENSOR_INT_SPECIALIZATION(isnan, false);
- XTENSOR_INT_SPECIALIZATION(isfinite, true);
- #endif
- XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(abs);
- XTENSOR_UNARY_MATH_FUNCTOR(fabs);
- XTENSOR_BINARY_MATH_FUNCTOR(fmod);
- XTENSOR_BINARY_MATH_FUNCTOR(remainder);
- XTENSOR_TERNARY_MATH_FUNCTOR(fma);
- XTENSOR_BINARY_MATH_FUNCTOR(fmax);
- XTENSOR_BINARY_MATH_FUNCTOR(fmin);
- XTENSOR_BINARY_MATH_FUNCTOR(fdim);
- XTENSOR_UNARY_MATH_FUNCTOR(exp);
- XTENSOR_UNARY_MATH_FUNCTOR(exp2);
- XTENSOR_UNARY_MATH_FUNCTOR(expm1);
- XTENSOR_UNARY_MATH_FUNCTOR(log);
- XTENSOR_UNARY_MATH_FUNCTOR(log10);
- XTENSOR_UNARY_MATH_FUNCTOR(log2);
- XTENSOR_UNARY_MATH_FUNCTOR(log1p);
- XTENSOR_BINARY_MATH_FUNCTOR(pow);
- XTENSOR_UNARY_MATH_FUNCTOR(sqrt);
- XTENSOR_UNARY_MATH_FUNCTOR(cbrt);
- XTENSOR_BINARY_MATH_FUNCTOR(hypot);
- XTENSOR_UNARY_MATH_FUNCTOR(sin);
- XTENSOR_UNARY_MATH_FUNCTOR(cos);
- XTENSOR_UNARY_MATH_FUNCTOR(tan);
- XTENSOR_UNARY_MATH_FUNCTOR(asin);
- XTENSOR_UNARY_MATH_FUNCTOR(acos);
- XTENSOR_UNARY_MATH_FUNCTOR(atan);
- XTENSOR_BINARY_MATH_FUNCTOR(atan2);
- XTENSOR_UNARY_MATH_FUNCTOR(sinh);
- XTENSOR_UNARY_MATH_FUNCTOR(cosh);
- XTENSOR_UNARY_MATH_FUNCTOR(tanh);
- XTENSOR_UNARY_MATH_FUNCTOR(asinh);
- XTENSOR_UNARY_MATH_FUNCTOR(acosh);
- XTENSOR_UNARY_MATH_FUNCTOR(atanh);
- XTENSOR_UNARY_MATH_FUNCTOR(erf);
- XTENSOR_UNARY_MATH_FUNCTOR(erfc);
- XTENSOR_UNARY_MATH_FUNCTOR(tgamma);
- XTENSOR_UNARY_MATH_FUNCTOR(lgamma);
- XTENSOR_UNARY_MATH_FUNCTOR(ceil);
- XTENSOR_UNARY_MATH_FUNCTOR(floor);
- XTENSOR_UNARY_MATH_FUNCTOR(trunc);
- XTENSOR_UNARY_MATH_FUNCTOR(round);
- XTENSOR_UNARY_MATH_FUNCTOR(nearbyint);
- XTENSOR_UNARY_MATH_FUNCTOR(rint);
- XTENSOR_UNARY_MATH_FUNCTOR(isfinite);
- XTENSOR_UNARY_MATH_FUNCTOR(isinf);
- XTENSOR_UNARY_MATH_FUNCTOR(isnan);
- }
- #undef XTENSOR_UNARY_MATH_FUNCTOR
- #undef XTENSOR_BINARY_MATH_FUNCTOR
- #undef XTENSOR_TERNARY_MATH_FUNCTOR
- #undef XTENSOR_UNARY_MATH_FUNCTOR_COMPLEX_REDUCING
- #undef XTENSOR_UNSIGNED_ABS_FUNC
- namespace detail
- {
- template <class R, class T>
- std::enable_if_t<!has_iterator_interface<R>::value, R> fill_init(T init)
- {
- return R(init);
- }
- template <class R, class T>
- std::enable_if_t<has_iterator_interface<R>::value, R> fill_init(T init)
- {
- R result;
- std::fill(std::begin(result), std::end(result), init);
- return result;
- }
- }
- #define XTENSOR_REDUCER_FUNCTION(NAME, FUNCTOR, INIT_VALUE_TYPE, INIT) \
- template < \
- class T = void, \
- class E, \
- class X, \
- class EVS = DEFAULT_STRATEGY_REDUCERS, \
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<std::decay_t<X>>>)> \
- inline auto NAME(E&& e, X&& axes, EVS es = EVS()) \
- { \
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, INIT_VALUE_TYPE, T>; \
- using functor_type = FUNCTOR; \
- using init_value_fct = xt::const_value<init_value_type>; \
- return xt::reduce( \
- make_xreducer_functor(functor_type(), init_value_fct(detail::fill_init<init_value_type>(INIT))), \
- std::forward<E>(e), \
- std::forward<X>(axes), \
- es \
- ); \
- } \
- \
- template < \
- class T = void, \
- class E, \
- class X, \
- class EVS = DEFAULT_STRATEGY_REDUCERS, \
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<std::decay_t<X>>)> \
- inline auto NAME(E&& e, X axis, EVS es = EVS()) \
- { \
- return NAME(std::forward<E>(e), {axis}, es); \
- } \
- \
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)> \
- inline auto NAME(E&& e, EVS es = EVS()) \
- { \
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, INIT_VALUE_TYPE, T>; \
- using functor_type = FUNCTOR; \
- using init_value_fct = xt::const_value<init_value_type>; \
- return xt::reduce( \
- make_xreducer_functor(functor_type(), init_value_fct(detail::fill_init<init_value_type>(INIT))), \
- std::forward<E>(e), \
- es \
- ); \
- } \
- \
- template <class T = void, class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS> \
- inline auto NAME(E&& e, const I(&axes)[N], EVS es = EVS()) \
- { \
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, INIT_VALUE_TYPE, T>; \
- using functor_type = FUNCTOR; \
- using init_value_fct = xt::const_value<init_value_type>; \
- return xt::reduce( \
- make_xreducer_functor(functor_type(), init_value_fct(detail::fill_init<init_value_type>(INIT))), \
- std::forward<E>(e), \
- axes, \
- es \
- ); \
- }
- /*******************
- * basic functions *
- *******************/
- /**
- * @defgroup basic_functions Basic functions
- */
- /**
- * @ingroup basic_functions
- * @brief Absolute value function.
- *
- * Returns an \ref xfunction for the element-wise absolute value
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto abs(E&& e) noexcept -> detail::xfunction_type_t<math::abs_fun, E>
- {
- return detail::make_xfunction<math::abs_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup basic_functions
- * @brief Absolute value function.
- *
- * Returns an \ref xfunction for the element-wise absolute value
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto fabs(E&& e) noexcept -> detail::xfunction_type_t<math::fabs_fun, E>
- {
- return detail::make_xfunction<math::fabs_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup basic_functions
- * @brief Remainder of the floating point division operation.
- *
- * Returns an \ref xfunction for the element-wise remainder of
- * the floating point division operation <em>e1 / e2</em>.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto fmod(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fmod_fun, E1, E2>
- {
- return detail::make_xfunction<math::fmod_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /**
- * @ingroup basic_functions
- * @brief Signed remainder of the division operation.
- *
- * Returns an \ref xfunction for the element-wise signed remainder
- * of the floating point division operation <em>e1 / e2</em>.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto remainder(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::remainder_fun, E1, E2>
- {
- return detail::make_xfunction<math::remainder_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /**
- * @ingroup basic_functions
- * @brief Fused multiply-add operation.
- *
- * Returns an \ref xfunction for <em>e1 * e2 + e3</em> as if
- * to infinite precision and rounded only once to fit the result type.
- * @param e1 an \ref xfunction or a scalar
- * @param e2 an \ref xfunction or a scalar
- * @param e3 an \ref xfunction or a scalar
- * @return an \ref xfunction
- * @note e1, e2 and e3 can't be scalars every three.
- */
- template <class E1, class E2, class E3>
- inline auto fma(E1&& e1, E2&& e2, E3&& e3) noexcept -> detail::xfunction_type_t<math::fma_fun, E1, E2, E3>
- {
- return detail::make_xfunction<math::fma_fun>(
- std::forward<E1>(e1),
- std::forward<E2>(e2),
- std::forward<E3>(e3)
- );
- }
- /**
- * @ingroup basic_functions
- * @brief Maximum function.
- *
- * Returns an \ref xfunction for the element-wise maximum
- * of \a e1 and \a e2.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto fmax(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fmax_fun, E1, E2>
- {
- return detail::make_xfunction<math::fmax_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /**
- * @ingroup basic_functions
- * @brief Minimum function.
- *
- * Returns an \ref xfunction for the element-wise minimum
- * of \a e1 and \a e2.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto fmin(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fmin_fun, E1, E2>
- {
- return detail::make_xfunction<math::fmin_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /**
- * @ingroup basic_functions
- * @brief Positive difference function.
- *
- * Returns an \ref xfunction for the element-wise positive
- * difference of \a e1 and \a e2.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto fdim(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::fdim_fun, E1, E2>
- {
- return detail::make_xfunction<math::fdim_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- namespace math
- {
- template <class T = void>
- struct minimum
- {
- template <class A1, class A2>
- constexpr auto operator()(const A1& t1, const A2& t2) const noexcept
- {
- return xtl::select(t1 < t2, t1, t2);
- }
- template <class A1, class A2>
- constexpr auto simd_apply(const A1& t1, const A2& t2) const noexcept
- {
- return xt_simd::select(t1 < t2, t1, t2);
- }
- };
- template <class T = void>
- struct maximum
- {
- template <class A1, class A2>
- constexpr auto operator()(const A1& t1, const A2& t2) const noexcept
- {
- return xtl::select(t1 > t2, t1, t2);
- }
- template <class A1, class A2>
- constexpr auto simd_apply(const A1& t1, const A2& t2) const noexcept
- {
- return xt_simd::select(t1 > t2, t1, t2);
- }
- };
- struct clamp_fun
- {
- template <class A1, class A2, class A3>
- constexpr auto operator()(const A1& v, const A2& lo, const A3& hi) const
- {
- return xtl::select(v < lo, lo, xtl::select(hi < v, hi, v));
- }
- template <class A1, class A2, class A3>
- constexpr auto simd_apply(const A1& v, const A2& lo, const A3& hi) const
- {
- return xt_simd::select(v < lo, lo, xt_simd::select(hi < v, hi, v));
- }
- };
- struct deg2rad
- {
- template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
- constexpr double operator()(const A& a) const noexcept
- {
- return a * xt::numeric_constants<double>::PI / 180.0;
- }
- template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
- constexpr auto operator()(const A& a) const noexcept
- {
- return a * xt::numeric_constants<A>::PI / A(180.0);
- }
- template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
- constexpr double simd_apply(const A& a) const noexcept
- {
- return a * xt::numeric_constants<double>::PI / 180.0;
- }
- template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
- constexpr auto simd_apply(const A& a) const noexcept
- {
- return a * xt::numeric_constants<A>::PI / A(180.0);
- }
- };
- struct rad2deg
- {
- template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
- constexpr double operator()(const A& a) const noexcept
- {
- return a * 180.0 / xt::numeric_constants<double>::PI;
- }
- template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
- constexpr auto operator()(const A& a) const noexcept
- {
- return a * A(180.0) / xt::numeric_constants<A>::PI;
- }
- template <class A, std::enable_if_t<xtl::is_integral<A>::value, int> = 0>
- constexpr double simd_apply(const A& a) const noexcept
- {
- return a * 180.0 / xt::numeric_constants<double>::PI;
- }
- template <class A, std::enable_if_t<std::is_floating_point<A>::value, int> = 0>
- constexpr auto simd_apply(const A& a) const noexcept
- {
- return a * A(180.0) / xt::numeric_constants<A>::PI;
- }
- };
- }
- /**
- * @ingroup basic_functions
- * @brief Convert angles from degrees to radians.
- *
- * Returns an \ref xfunction for the element-wise corresponding
- * angle in radians of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto deg2rad(E&& e) noexcept -> detail::xfunction_type_t<math::deg2rad, E>
- {
- return detail::make_xfunction<math::deg2rad>(std::forward<E>(e));
- }
- /**
- * @ingroup basic_functions
- * @brief Convert angles from degrees to radians.
- *
- * Returns an \ref xfunction for the element-wise corresponding
- * angle in radians of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto radians(E&& e) noexcept -> detail::xfunction_type_t<math::deg2rad, E>
- {
- return detail::make_xfunction<math::deg2rad>(std::forward<E>(e));
- }
- /**
- * @ingroup basic_functions
- * @brief Convert angles from radians to degrees.
- *
- * Returns an \ref xfunction for the element-wise corresponding
- * angle in degrees of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto rad2deg(E&& e) noexcept -> detail::xfunction_type_t<math::rad2deg, E>
- {
- return detail::make_xfunction<math::rad2deg>(std::forward<E>(e));
- }
- /**
- * @ingroup basic_functions
- * @brief Convert angles from radians to degrees.
- *
- * Returns an \ref xfunction for the element-wise corresponding
- * angle in degrees of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto degrees(E&& e) noexcept -> detail::xfunction_type_t<math::rad2deg, E>
- {
- return detail::make_xfunction<math::rad2deg>(std::forward<E>(e));
- }
- /**
- * @ingroup basic_functions
- * @brief Elementwise maximum
- *
- * Returns an \ref xfunction for the element-wise
- * maximum between e1 and e2.
- * @param e1 an \ref xexpression
- * @param e2 an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E1, class E2>
- inline auto maximum(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::maximum<void>, E1, E2>
- {
- return detail::make_xfunction<math::maximum<void>>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /**
- * @ingroup basic_functions
- * @brief Elementwise minimum
- *
- * Returns an \ref xfunction for the element-wise
- * minimum between e1 and e2.
- * @param e1 an \ref xexpression
- * @param e2 an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E1, class E2>
- inline auto minimum(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::minimum<void>, E1, E2>
- {
- return detail::make_xfunction<math::minimum<void>>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /**
- * @ingroup basic_functions
- * @brief Maximum element along given axis.
- *
- * Returns an \ref xreducer for the maximum of elements over given
- * \em axes.
- * @param e an \ref xexpression
- * @param axes the axes along which the maximum is found (optional)
- * @param es evaluation strategy of the reducer
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(
- amax,
- math::maximum<void>,
- typename std::decay_t<E>::value_type,
- std::numeric_limits<xvalue_type_t<std::decay_t<E>>>::lowest()
- )
- /**
- * @ingroup basic_functions
- * @brief Minimum element along given axis.
- *
- * Returns an \ref xreducer for the minimum of elements over given
- * \em axes.
- * @param e an \ref xexpression
- * @param axes the axes along which the minimum is found (optional)
- * @param es evaluation strategy of the reducer
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(
- amin,
- math::minimum<void>,
- typename std::decay_t<E>::value_type,
- std::numeric_limits<xvalue_type_t<std::decay_t<E>>>::max()
- )
- /**
- * @ingroup basic_functions
- * @brief Clip values between hi and lo
- *
- * Returns an \ref xfunction for the element-wise clipped
- * values between lo and hi
- * @param e1 an \ref xexpression or a scalar
- * @param lo a scalar
- * @param hi a scalar
- *
- * @return a \ref xfunction
- */
- template <class E1, class E2, class E3>
- inline auto clip(E1&& e1, E2&& lo, E3&& hi) noexcept
- -> detail::xfunction_type_t<math::clamp_fun, E1, E2, E3>
- {
- return detail::make_xfunction<math::clamp_fun>(
- std::forward<E1>(e1),
- std::forward<E2>(lo),
- std::forward<E3>(hi)
- );
- }
- namespace math
- {
- template <class T>
- struct sign_impl
- {
- template <class XT = T>
- static constexpr std::enable_if_t<xtl::is_signed<XT>::value, T> run(T x)
- {
- return std::isnan(x) ? std::numeric_limits<T>::quiet_NaN()
- : x == 0 ? T(copysign(T(0), x))
- : T(copysign(T(1), x));
- }
- template <class XT = T>
- static constexpr std::enable_if_t<xtl::is_complex<XT>::value, T> run(T x)
- {
- return T(
- sign_impl<typename T::value_type>::run(
- (x.real() != typename T::value_type(0)) ? x.real() : x.imag()
- ),
- 0
- );
- }
- template <class XT = T>
- static constexpr std::enable_if_t<std::is_unsigned<XT>::value, T> run(T x)
- {
- return T(x > T(0));
- }
- };
- struct sign_fun
- {
- template <class T>
- constexpr auto operator()(const T& x) const
- {
- return sign_impl<T>::run(x);
- }
- };
- }
- /**
- * @ingroup basic_functions
- * @brief Returns an element-wise indication of the sign of a number
- *
- * If the number is positive, returns +1. If negative, -1. If the number
- * is zero, returns 0.
- *
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto sign(E&& e) noexcept -> detail::xfunction_type_t<math::sign_fun, E>
- {
- return detail::make_xfunction<math::sign_fun>(std::forward<E>(e));
- }
- /*************************
- * exponential functions *
- *************************/
- /**
- * @defgroup exp_functions Exponential functions
- */
- /**
- * @ingroup exp_functions
- * @brief Natural exponential function.
- *
- * Returns an \ref xfunction for the element-wise natural
- * exponential of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto exp(E&& e) noexcept -> detail::xfunction_type_t<math::exp_fun, E>
- {
- return detail::make_xfunction<math::exp_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup exp_functions
- * @brief Base 2 exponential function.
- *
- * Returns an \ref xfunction for the element-wise base 2
- * exponential of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto exp2(E&& e) noexcept -> detail::xfunction_type_t<math::exp2_fun, E>
- {
- return detail::make_xfunction<math::exp2_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup exp_functions
- * @brief Natural exponential minus one function.
- *
- * Returns an \ref xfunction for the element-wise natural
- * exponential of \em e, minus 1.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto expm1(E&& e) noexcept -> detail::xfunction_type_t<math::expm1_fun, E>
- {
- return detail::make_xfunction<math::expm1_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup exp_functions
- * @brief Natural logarithm function.
- *
- * Returns an \ref xfunction for the element-wise natural
- * logarithm of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto log(E&& e) noexcept -> detail::xfunction_type_t<math::log_fun, E>
- {
- return detail::make_xfunction<math::log_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup exp_functions
- * @brief Base 10 logarithm function.
- *
- * Returns an \ref xfunction for the element-wise base 10
- * logarithm of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto log10(E&& e) noexcept -> detail::xfunction_type_t<math::log10_fun, E>
- {
- return detail::make_xfunction<math::log10_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup exp_functions
- * @brief Base 2 logarithm function.
- *
- * Returns an \ref xfunction for the element-wise base 2
- * logarithm of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto log2(E&& e) noexcept -> detail::xfunction_type_t<math::log2_fun, E>
- {
- return detail::make_xfunction<math::log2_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup exp_functions
- * @brief Natural logarithm of one plus function.
- *
- * Returns an \ref xfunction for the element-wise natural
- * logarithm of \em e, plus 1.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto log1p(E&& e) noexcept -> detail::xfunction_type_t<math::log1p_fun, E>
- {
- return detail::make_xfunction<math::log1p_fun>(std::forward<E>(e));
- }
- /*******************
- * power functions *
- *******************/
- /**
- * @defgroup pow_functions Power functions
- */
- /**
- * @ingroup pow_functions
- * @brief Power function.
- *
- * Returns an \ref xfunction for the element-wise value of
- * of \em e1 raised to the power \em e2.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto pow(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::pow_fun, E1, E2>
- {
- return detail::make_xfunction<math::pow_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- namespace detail
- {
- template <class F, class... T, typename = decltype(std::declval<F>()(std::declval<T>()...))>
- std::true_type supports_test(const F&, const T&...);
- std::false_type supports_test(...);
- template <class... T>
- struct supports;
- template <class F, class... T>
- struct supports<F(T...)> : decltype(supports_test(std::declval<F>(), std::declval<T>()...))
- {
- };
- template <class F>
- struct lambda_adapt
- {
- explicit lambda_adapt(F&& lmbd)
- : m_lambda(std::move(lmbd))
- {
- }
- template <class... T>
- auto operator()(T... args) const
- {
- return m_lambda(args...);
- }
- template <class... T, XTL_REQUIRES(detail::supports<F(T...)>)>
- auto simd_apply(T... args) const
- {
- return m_lambda(args...);
- }
- F m_lambda;
- };
- }
- /**
- * Create a xfunction from a lambda
- *
- * This function can be used to easily create performant xfunctions from lambdas:
- *
- * @code{cpp}
- * template <class E1>
- * inline auto square(E1&& e1) noexcept
- * {
- * auto fnct = [](auto x) -> decltype(x * x) {
- * return x * x;
- * };
- * return make_lambda_xfunction(std::move(fnct), std::forward<E1>(e1));
- * }
- * @endcode
- *
- * Lambda function allow the reusal of a single arguments in multiple places (otherwise
- * only correctly possible when using xshared_expressions). ``auto`` lambda functions are
- * automatically vectorized with ``xsimd`` if possible (note that the trailing
- * ``-> decltype(...)`` is mandatory for the feature detection to work).
- *
- * @param lambda the lambda to be vectorized
- * @param args forwarded arguments
- *
- * @return lazy xfunction
- */
- template <class F, class... E>
- inline auto make_lambda_xfunction(F&& lambda, E&&... args)
- {
- using xfunction_type = typename detail::xfunction_type<detail::lambda_adapt<F>, E...>::type;
- return xfunction_type(detail::lambda_adapt<F>(std::forward<F>(lambda)), std::forward<E>(args)...);
- }
- #define XTENSOR_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
- // Workaround for MSVC 2015 & GCC 4.9
- #if (defined(_MSC_VER) && _MSC_VER < 1910) || (defined(__GNUC__) && GCC_VERSION < 49999)
- #define XTENSOR_DISABLE_LAMBDA_FCT
- #endif
- #ifdef XTENSOR_DISABLE_LAMBDA_FCT
- struct square_fct
- {
- template <class T>
- auto operator()(T x) const -> decltype(x * x)
- {
- return x * x;
- }
- };
- struct cube_fct
- {
- template <class T>
- auto operator()(T x) const -> decltype(x * x * x)
- {
- return x * x * x;
- }
- };
- #endif
- /**
- * @ingroup pow_functions
- * @brief Square power function, equivalent to e1 * e1.
- *
- * Returns an \ref xfunction for the element-wise value of
- * of \em e1 * \em e1.
- * @param e1 an \ref xexpression or a scalar
- * @return an \ref xfunction
- */
- template <class E1>
- inline auto square(E1&& e1) noexcept
- {
- #ifdef XTENSOR_DISABLE_LAMBDA_FCT
- return make_lambda_xfunction(square_fct{}, std::forward<E1>(e1));
- #else
- auto fnct = [](auto x) -> decltype(x * x)
- {
- return x * x;
- };
- return make_lambda_xfunction(std::move(fnct), std::forward<E1>(e1));
- #endif
- }
- /**
- * @ingroup pow_functions
- * @brief Cube power function, equivalent to e1 * e1 * e1.
- *
- * Returns an \ref xfunction for the element-wise value of
- * of \em e1 * \em e1.
- * @param e1 an \ref xexpression or a scalar
- * @return an \ref xfunction
- */
- template <class E1>
- inline auto cube(E1&& e1) noexcept
- {
- #ifdef XTENSOR_DISABLE_LAMBDA_FCT
- return make_lambda_xfunction(cube_fct{}, std::forward<E1>(e1));
- #else
- auto fnct = [](auto x) -> decltype(x * x * x)
- {
- return x * x * x;
- };
- return make_lambda_xfunction(std::move(fnct), std::forward<E1>(e1));
- #endif
- }
- #undef XTENSOR_GCC_VERSION
- #undef XTENSOR_DISABLE_LAMBDA_FCT
- namespace detail
- {
- // Thanks to Matt Pharr in http://pbrt.org/hair.pdf
- template <std::size_t N>
- struct pow_impl;
- template <std::size_t N>
- struct pow_impl
- {
- template <class T>
- auto operator()(T v) const -> decltype(v * v)
- {
- T temp = pow_impl<N / 2>{}(v);
- return temp * temp * pow_impl<N & 1>{}(v);
- }
- };
- template <>
- struct pow_impl<1>
- {
- template <class T>
- auto operator()(T v) const -> T
- {
- return v;
- }
- };
- template <>
- struct pow_impl<0>
- {
- template <class T>
- auto operator()(T /*v*/) const -> T
- {
- return T(1);
- }
- };
- }
- /**
- * @ingroup pow_functions
- * @brief Integer power function.
- *
- * Returns an \ref xfunction for the element-wise power of e1 to
- * an integral constant.
- *
- * Instead of computing the power by using the (expensive) logarithm, this function
- * computes the power in a number of straight-forward multiplication steps. This function
- * is therefore much faster (even for high N) than the generic pow-function.
- *
- * For example, `e1^20` can be expressed as `(((e1^2)^2)^2)^2*(e1^2)^2`, which is just 5 multiplications.
- *
- * @param e an \ref xexpression
- * @tparam N the exponent (has to be positive integer)
- * @return an \ref xfunction
- */
- template <std::size_t N, class E>
- inline auto pow(E&& e) noexcept
- {
- static_assert(N > 0, "integer power cannot be negative");
- return make_lambda_xfunction(detail::pow_impl<N>{}, std::forward<E>(e));
- }
- /**
- * @ingroup pow_functions
- * @brief Square root function.
- *
- * Returns an \ref xfunction for the element-wise square
- * root of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto sqrt(E&& e) noexcept -> detail::xfunction_type_t<math::sqrt_fun, E>
- {
- return detail::make_xfunction<math::sqrt_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup pow_functions
- * @brief Cubic root function.
- *
- * Returns an \ref xfunction for the element-wise cubic
- * root of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto cbrt(E&& e) noexcept -> detail::xfunction_type_t<math::cbrt_fun, E>
- {
- return detail::make_xfunction<math::cbrt_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup pow_functions
- * @brief Hypotenuse function.
- *
- * Returns an \ref xfunction for the element-wise square
- * root of the sum of the square of \em e1 and \em e2, avoiding
- * overflow and underflow at intermediate stages of computation.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto hypot(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::hypot_fun, E1, E2>
- {
- return detail::make_xfunction<math::hypot_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /***************************
- * trigonometric functions *
- ***************************/
- /**
- * @defgroup trigo_functions Trigonometric function
- */
- /**
- * @ingroup trigo_functions
- * @brief Sine function.
- *
- * Returns an \ref xfunction for the element-wise sine
- * of \em e (measured in radians).
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto sin(E&& e) noexcept -> detail::xfunction_type_t<math::sin_fun, E>
- {
- return detail::make_xfunction<math::sin_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup trigo_functions
- * @brief Cosine function.
- *
- * Returns an \ref xfunction for the element-wise cosine
- * of \em e (measured in radians).
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto cos(E&& e) noexcept -> detail::xfunction_type_t<math::cos_fun, E>
- {
- return detail::make_xfunction<math::cos_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup trigo_functions
- * @brief Tangent function.
- *
- * Returns an \ref xfunction for the element-wise tangent
- * of \em e (measured in radians).
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto tan(E&& e) noexcept -> detail::xfunction_type_t<math::tan_fun, E>
- {
- return detail::make_xfunction<math::tan_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup trigo_functions
- * @brief Arcsine function.
- *
- * Returns an \ref xfunction for the element-wise arcsine
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto asin(E&& e) noexcept -> detail::xfunction_type_t<math::asin_fun, E>
- {
- return detail::make_xfunction<math::asin_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup trigo_functions
- * @brief Arccosine function.
- *
- * Returns an \ref xfunction for the element-wise arccosine
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto acos(E&& e) noexcept -> detail::xfunction_type_t<math::acos_fun, E>
- {
- return detail::make_xfunction<math::acos_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup trigo_functions
- * @brief Arctangent function.
- *
- * Returns an \ref xfunction for the element-wise arctangent
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto atan(E&& e) noexcept -> detail::xfunction_type_t<math::atan_fun, E>
- {
- return detail::make_xfunction<math::atan_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup trigo_functions
- * @brief Artangent function, using signs to determine quadrants.
- *
- * Returns an \ref xfunction for the element-wise arctangent
- * of <em>e1 / e2</em>, using the signs of arguments to determine the
- * correct quadrant.
- * @param e1 an \ref xexpression or a scalar
- * @param e2 an \ref xexpression or a scalar
- * @return an \ref xfunction
- * @note e1 and e2 can't be both scalars.
- */
- template <class E1, class E2>
- inline auto atan2(E1&& e1, E2&& e2) noexcept -> detail::xfunction_type_t<math::atan2_fun, E1, E2>
- {
- return detail::make_xfunction<math::atan2_fun>(std::forward<E1>(e1), std::forward<E2>(e2));
- }
- /************************
- * hyperbolic functions *
- ************************/
- /**
- * @defgroup hyper_functions Hyperbolic functions
- */
- /**
- * @ingroup hyper_functions
- * @brief Hyperbolic sine function.
- *
- * Returns an \ref xfunction for the element-wise hyperbolic
- * sine of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto sinh(E&& e) noexcept -> detail::xfunction_type_t<math::sinh_fun, E>
- {
- return detail::make_xfunction<math::sinh_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup hyper_functions
- * @brief Hyperbolic cosine function.
- *
- * Returns an \ref xfunction for the element-wise hyperbolic
- * cosine of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto cosh(E&& e) noexcept -> detail::xfunction_type_t<math::cosh_fun, E>
- {
- return detail::make_xfunction<math::cosh_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup hyper_functions
- * @brief Hyperbolic tangent function.
- *
- * Returns an \ref xfunction for the element-wise hyperbolic
- * tangent of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto tanh(E&& e) noexcept -> detail::xfunction_type_t<math::tanh_fun, E>
- {
- return detail::make_xfunction<math::tanh_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup hyper_functions
- * @brief Inverse hyperbolic sine function.
- *
- * Returns an \ref xfunction for the element-wise inverse hyperbolic
- * sine of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto asinh(E&& e) noexcept -> detail::xfunction_type_t<math::asinh_fun, E>
- {
- return detail::make_xfunction<math::asinh_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup hyper_functions
- * @brief Inverse hyperbolic cosine function.
- *
- * Returns an \ref xfunction for the element-wise inverse hyperbolic
- * cosine of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto acosh(E&& e) noexcept -> detail::xfunction_type_t<math::acosh_fun, E>
- {
- return detail::make_xfunction<math::acosh_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup hyper_functions
- * @brief Inverse hyperbolic tangent function.
- *
- * Returns an \ref xfunction for the element-wise inverse hyperbolic
- * tangent of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto atanh(E&& e) noexcept -> detail::xfunction_type_t<math::atanh_fun, E>
- {
- return detail::make_xfunction<math::atanh_fun>(std::forward<E>(e));
- }
- /*****************************
- * error and gamma functions *
- *****************************/
- /**
- * @defgroup err_functions Error and gamma functions
- */
- /**
- * @ingroup err_functions
- * @brief Error function.
- *
- * Returns an \ref xfunction for the element-wise error function
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto erf(E&& e) noexcept -> detail::xfunction_type_t<math::erf_fun, E>
- {
- return detail::make_xfunction<math::erf_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup err_functions
- * @brief Complementary error function.
- *
- * Returns an \ref xfunction for the element-wise complementary
- * error function of \em e, whithout loss of precision for large argument.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto erfc(E&& e) noexcept -> detail::xfunction_type_t<math::erfc_fun, E>
- {
- return detail::make_xfunction<math::erfc_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup err_functions
- * @brief Gamma function.
- *
- * Returns an \ref xfunction for the element-wise gamma function
- * of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto tgamma(E&& e) noexcept -> detail::xfunction_type_t<math::tgamma_fun, E>
- {
- return detail::make_xfunction<math::tgamma_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup err_functions
- * @brief Natural logarithm of the gamma function.
- *
- * Returns an \ref xfunction for the element-wise logarithm of
- * the asbolute value fo the gamma function of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto lgamma(E&& e) noexcept -> detail::xfunction_type_t<math::lgamma_fun, E>
- {
- return detail::make_xfunction<math::lgamma_fun>(std::forward<E>(e));
- }
- /*********************************************
- * nearest integer floating point operations *
- *********************************************/
- /**
- * @defgroup nearint_functions Nearest integer floating point operations
- */
- /**
- * @ingroup nearint_functions
- * @brief ceil function.
- *
- * Returns an \ref xfunction for the element-wise smallest integer value
- * not less than \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto ceil(E&& e) noexcept -> detail::xfunction_type_t<math::ceil_fun, E>
- {
- return detail::make_xfunction<math::ceil_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup nearint_functions
- * @brief floor function.
- *
- * Returns an \ref xfunction for the element-wise smallest integer value
- * not greater than \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto floor(E&& e) noexcept -> detail::xfunction_type_t<math::floor_fun, E>
- {
- return detail::make_xfunction<math::floor_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup nearint_functions
- * @brief trunc function.
- *
- * Returns an \ref xfunction for the element-wise nearest integer not greater
- * in magnitude than \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto trunc(E&& e) noexcept -> detail::xfunction_type_t<math::trunc_fun, E>
- {
- return detail::make_xfunction<math::trunc_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup nearint_functions
- * @brief round function.
- *
- * Returns an \ref xfunction for the element-wise nearest integer value
- * to \em e, rounding halfway cases away from zero, regardless of the
- * current rounding mode.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto round(E&& e) noexcept -> detail::xfunction_type_t<math::round_fun, E>
- {
- return detail::make_xfunction<math::round_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup nearint_functions
- * @brief nearbyint function.
- *
- * Returns an \ref xfunction for the element-wise rounding of \em e to integer
- * values in floating point format, using the current rounding mode. nearbyint
- * never raises FE_INEXACT error.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto nearbyint(E&& e) noexcept -> detail::xfunction_type_t<math::nearbyint_fun, E>
- {
- return detail::make_xfunction<math::nearbyint_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup nearint_functions
- * @brief rint function.
- *
- * Returns an \ref xfunction for the element-wise rounding of \em e to integer
- * values in floating point format, using the current rounding mode. Contrary
- * to nearbyint, rint may raise FE_INEXACT error.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto rint(E&& e) noexcept -> detail::xfunction_type_t<math::rint_fun, E>
- {
- return detail::make_xfunction<math::rint_fun>(std::forward<E>(e));
- }
- /****************************
- * classification functions *
- ****************************/
- /**
- * @defgroup classif_functions Classification functions
- */
- /**
- * @ingroup classif_functions
- * @brief finite value check
- *
- * Returns an \ref xfunction for the element-wise finite value check
- * tangent of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto isfinite(E&& e) noexcept -> detail::xfunction_type_t<math::isfinite_fun, E>
- {
- return detail::make_xfunction<math::isfinite_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup classif_functions
- * @brief infinity check
- *
- * Returns an \ref xfunction for the element-wise infinity check
- * tangent of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto isinf(E&& e) noexcept -> detail::xfunction_type_t<math::isinf_fun, E>
- {
- return detail::make_xfunction<math::isinf_fun>(std::forward<E>(e));
- }
- /**
- * @ingroup classif_functions
- * @brief NaN check
- *
- * Returns an \ref xfunction for the element-wise NaN check
- * tangent of \em e.
- * @param e an \ref xexpression
- * @return an \ref xfunction
- */
- template <class E>
- inline auto isnan(E&& e) noexcept -> detail::xfunction_type_t<math::isnan_fun, E>
- {
- return detail::make_xfunction<math::isnan_fun>(std::forward<E>(e));
- }
- namespace detail
- {
- template <class FUNCTOR, class T, std::size_t... Is>
- inline auto get_functor(T&& args, std::index_sequence<Is...>)
- {
- return FUNCTOR(std::get<Is>(args)...);
- }
- template <class F, class... A, class... E>
- inline auto make_xfunction(std::tuple<A...>&& f_args, E&&... e) noexcept
- {
- using functor_type = F;
- using expression_tag = xexpression_tag_t<E...>;
- using type = select_xfunction_expression_t<expression_tag, functor_type, const_xclosure_t<E>...>;
- auto functor = get_functor<functor_type>(
- std::forward<std::tuple<A...>>(f_args),
- std::make_index_sequence<sizeof...(A)>{}
- );
- return type(std::move(functor), std::forward<E>(e)...);
- }
- struct isclose
- {
- using result_type = bool;
- isclose(double rtol, double atol, bool equal_nan)
- : m_rtol(rtol)
- , m_atol(atol)
- , m_equal_nan(equal_nan)
- {
- }
- template <class A1, class A2>
- bool operator()(const A1& a, const A2& b) const
- {
- using internal_type = xtl::promote_type_t<A1, A2, double>;
- if (math::isnan(a) && math::isnan(b))
- {
- return m_equal_nan;
- }
- if (math::isinf(a) && math::isinf(b))
- {
- // check for both infinity signs equal
- return a == b;
- }
- auto d = math::abs(internal_type(a) - internal_type(b));
- return d <= m_atol
- || d <= m_rtol
- * double((std::max)(math::abs(internal_type(a)), math::abs(internal_type(b)))
- );
- }
- private:
- double m_rtol;
- double m_atol;
- bool m_equal_nan;
- };
- }
- /**
- * @ingroup classif_functions
- * @brief Element-wise closeness detection
- *
- * Returns an \ref xfunction that evaluates to
- * true if the elements in ``e1`` and ``e2`` are close to each other
- * according to parameters ``atol`` and ``rtol``.
- * The equation is: ``std::abs(a - b) <= (m_atol + m_rtol * std::abs(b))``.
- * @param e1 input array to compare
- * @param e2 input array to compare
- * @param rtol the relative tolerance parameter (default 1e-05)
- * @param atol the absolute tolerance parameter (default 1e-08)
- * @param equal_nan if true, isclose returns true if both elements of e1 and e2 are NaN
- * @return an \ref xfunction
- */
- template <class E1, class E2>
- inline auto
- isclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08, bool equal_nan = false) noexcept
- {
- return detail::make_xfunction<detail::isclose>(
- std::make_tuple(rtol, atol, equal_nan),
- std::forward<E1>(e1),
- std::forward<E2>(e2)
- );
- }
- /**
- * @ingroup classif_functions
- * @brief Check if all elements in \em e1 are close to the
- * corresponding elements in \em e2.
- *
- * Returns true if all elements in ``e1`` and ``e2`` are close to each other
- * according to parameters ``atol`` and ``rtol``.
- * @param e1 input array to compare
- * @param e2 input arrays to compare
- * @param rtol the relative tolerance parameter (default 1e-05)
- * @param atol the absolute tolerance parameter (default 1e-08)
- * @return a boolean
- */
- template <class E1, class E2>
- inline auto allclose(E1&& e1, E2&& e2, double rtol = 1e-05, double atol = 1e-08) noexcept
- {
- return xt::all(isclose(std::forward<E1>(e1), std::forward<E2>(e2), rtol, atol));
- }
- /**********************
- * Reducing functions *
- **********************/
- /**
- * @defgroup red_functions reducing functions
- */
- /**
- * @ingroup red_functions
- * @brief Sum of elements over given axes.
- *
- * Returns an \ref xreducer for the sum of elements over given
- * \em axes.
- * @param e an \ref xexpression
- * @param axes the axes along which the sum is performed (optional)
- * @param es evaluation strategy of the reducer
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T` is also used for determining the value type
- * of the result, which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(sum, detail::plus, typename std::decay_t<E>::value_type, 0)
- /**
- * @ingroup red_functions
- * @brief Product of elements over given axes.
- *
- * Returns an \ref xreducer for the product of elements over given
- * \em axes.
- * @param e an \ref xexpression
- * @param axes the axes along which the product is computed (optional)
- * @param ddof delta degrees of freedom (optional).
- * The divisor used in calculations is N - ddof, where N represents the number of
- * elements. By default ddof is zero.
- * @param es evaluation strategy of the reducer
- * @tparam T the value type used for internal computation. The default is `E::value_type`.
- * `T` is also used for determining the value type of the result, which is the type
- * of `T() * E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(prod, detail::multiplies, typename std::decay_t<E>::value_type, 1)
- namespace detail
- {
- template <class T, class S, class ST>
- inline auto mean_division(S&& s, ST e_size)
- {
- using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
- // Avoids floating point exception when s.size is 0
- value_type div = s.size() != ST(0) ? static_cast<value_type>(e_size / s.size()) : value_type(0);
- return std::move(s) / std::move(div);
- }
- template <
- class T,
- class E,
- class X,
- class D,
- class EVS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<D>)>
- inline auto mean(E&& e, X&& axes, const D& ddof, EVS es)
- {
- // sum cannot always be a double. It could be a complex number which cannot operate on
- // std::plus<double>.
- using size_type = typename std::decay_t<E>::size_type;
- const size_type size = e.size();
- XTENSOR_ASSERT(static_cast<size_type>(ddof) <= size);
- auto s = sum<T>(std::forward<E>(e), std::forward<X>(axes), es);
- return mean_division<T>(std::move(s), size - static_cast<size_type>(ddof));
- }
- template <class T, class E, class I, std::size_t N, class D, class EVS>
- inline auto mean(E&& e, const I (&axes)[N], const D& ddof, EVS es)
- {
- using size_type = typename std::decay_t<E>::size_type;
- const size_type size = e.size();
- XTENSOR_ASSERT(static_cast<size_type>(ddof) <= size);
- auto s = sum<T>(std::forward<E>(e), axes, es);
- return mean_division<T>(std::move(s), size - static_cast<size_type>(ddof));
- }
- template <class T, class E, class D, class EVS, XTL_REQUIRES(is_reducer_options<EVS>, xtl::is_integral<D>)>
- inline auto mean_noaxis(E&& e, const D& ddof, EVS es)
- {
- using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
- using size_type = typename std::decay_t<E>::size_type;
- const size_type size = e.size();
- XTENSOR_ASSERT(static_cast<size_type>(ddof) <= size);
- auto s = sum<T>(std::forward<E>(e), es);
- return std::move(s) / static_cast<value_type>((size - static_cast<size_type>(ddof)));
- }
- }
- /**
- * @ingroup red_functions
- * @brief Mean of elements over given axes.
- *
- * Returns an \ref xreducer for the mean of elements over given
- * \em axes.
- * @param e an \ref xexpression
- * @param axes the axes along which the mean is computed (optional)
- * @param es the evaluation strategy (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T` is also used for determining the value type
- * of the result, which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- */
- template <
- class T = void,
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
- inline auto mean(E&& e, X&& axes, EVS es = EVS())
- {
- return detail::mean<T>(std::forward<E>(e), std::forward<X>(axes), 0u, es);
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto mean(E&& e, EVS es = EVS())
- {
- return detail::mean_noaxis<T>(std::forward<E>(e), 0u, es);
- }
- template <class T = void, class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto mean(E&& e, const I (&axes)[N], EVS es = EVS())
- {
- return detail::mean<T>(std::forward<E>(e), axes, 0u, es);
- }
- /**
- * @ingroup red_functions
- * @brief Average of elements over given axes using weights.
- *
- * Returns an \ref xreducer for the mean of elements over given
- * \em axes.
- * @param e an \ref xexpression
- * @param weights \ref xexpression containing weights associated with the values in \ref e
- * @param axes the axes along which the mean is computed (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T`is also used for determining the value type of the result,
- * which is the type of `T() + E::value_type().
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- *
- * @sa mean
- */
- template <
- class T = void,
- class E,
- class W,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(is_reducer_options<EVS>, xtl::negation<xtl::is_integral<X>>)>
- inline auto average(E&& e, W&& weights, X&& axes, EVS ev = EVS())
- {
- xindex_type_t<typename std::decay_t<E>::shape_type> broadcast_shape;
- xt::resize_container(broadcast_shape, e.dimension());
- auto ax = normalize_axis(e, axes);
- if (weights.dimension() == 1)
- {
- if (weights.size() != e.shape()[ax[0]])
- {
- XTENSOR_THROW(std::runtime_error, "Weights need to have the same shape as expression at axes.");
- }
- std::fill(broadcast_shape.begin(), broadcast_shape.end(), std::size_t(1));
- broadcast_shape[ax[0]] = weights.size();
- }
- else
- {
- if (!same_shape(e.shape(), weights.shape()))
- {
- XTENSOR_THROW(
- std::runtime_error,
- "Weights with dim > 1 need to have the same shape as expression."
- );
- }
- std::copy(e.shape().begin(), e.shape().end(), broadcast_shape.begin());
- }
- constexpr layout_type L = default_assignable_layout(std::decay_t<W>::static_layout);
- auto weights_view = reshape_view<L>(std::forward<W>(weights), std::move(broadcast_shape));
- auto scl = sum<T>(weights_view, ax, xt::evaluation_strategy::immediate);
- return sum<T>(std::forward<E>(e) * std::move(weights_view), std::move(ax), ev) / std::move(scl);
- }
- template <
- class T = void,
- class E,
- class W,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(is_reducer_options<EVS>, xtl::is_integral<X>)>
- inline auto average(E&& e, W&& weights, X axis, EVS ev = EVS())
- {
- return average(std::forward<E>(e), std::forward<W>(weights), {axis}, std::forward<EVS>(ev));
- }
- template <class T = void, class E, class W, class X, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto average(E&& e, W&& weights, const X (&axes)[N], EVS ev = EVS())
- {
- // need to select the X&& overload and forward to different type
- using ax_t = std::array<std::size_t, N>;
- return average<T>(std::forward<E>(e), std::forward<W>(weights), xt::forward_normalize<ax_t>(e, axes), ev);
- }
- template <class T = void, class E, class W, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto average(E&& e, W&& weights, EVS ev = EVS())
- {
- if (weights.dimension() != e.dimension()
- || !std::equal(weights.shape().begin(), weights.shape().end(), e.shape().begin()))
- {
- XTENSOR_THROW(std::runtime_error, "Weights need to have the same shape as expression.");
- }
- auto div = sum<T>(weights, evaluation_strategy::immediate)();
- auto s = sum<T>(std::forward<E>(e) * std::forward<W>(weights), ev) / std::move(div);
- return s;
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto average(E&& e, EVS ev = EVS())
- {
- return mean<T>(e, ev);
- }
- namespace detail
- {
- template <typename E>
- std::enable_if_t<std::is_lvalue_reference<E>::value, E> shared_forward(E e) noexcept
- {
- return e;
- }
- template <typename E>
- std::enable_if_t<!std::is_lvalue_reference<E>::value, xshared_expression<E>> shared_forward(E e) noexcept
- {
- return make_xshared(std::move(e));
- }
- }
- template <
- class T = void,
- class E,
- class D,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(is_reducer_options<EVS>, xtl::is_integral<D>)>
- inline auto variance(E&& e, const D& ddof, EVS es = EVS())
- {
- auto cached_mean = mean<T>(e, es)();
- return detail::mean_noaxis<T>(square(std::forward<E>(e) - std::move(cached_mean)), ddof, es);
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto variance(E&& e, EVS es = EVS())
- {
- return variance<T>(std::forward<E>(e), 0u, es);
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto stddev(E&& e, EVS es = EVS())
- {
- return sqrt(variance<T>(std::forward<E>(e), es));
- }
- /**
- * @ingroup red_functions
- * @brief Compute the variance along the specified axes
- *
- * Returns the variance of the array elements, a measure of the spread of a
- * distribution. The variance is computed for the flattened array by default,
- * otherwise over the specified axes.
- *
- * Note: this function is not yet specialized for complex numbers.
- *
- * @param e an \ref xexpression
- * @param axes the axes along which the variance is computed (optional)
- * @param ddof delta degrees of freedom (optional).
- * The divisor used in calculations is N - ddof, where N represents the number of
- * elements. By default ddof is zero.
- * @param es evaluation strategy to use (lazy (default), or immediate)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T`is also used for determining the value type of the result,
- * which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- *
- * @sa stddev, mean
- */
- template <
- class T = void,
- class E,
- class X,
- class D,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<D>)>
- inline auto variance(E&& e, X&& axes, const D& ddof, EVS es = EVS())
- {
- decltype(auto) sc = detail::shared_forward<E>(e);
- // note: forcing copy of first axes argument -- is there a better solution?
- auto axes_copy = axes;
- // always eval to prevent repeated evaluations in the next calls
- auto inner_mean = eval(mean<T>(sc, std::move(axes_copy), evaluation_strategy::immediate));
- // fake keep_dims = 1
- // Since the inner_shape might have a reference semantic (e.g. xbuffer_adaptor in bindings)
- // We need to map it to another type before modifying it.
- // We pragmatically abuse `get_strides_t`
- using tmp_shape_t = get_strides_t<typename std::decay_t<E>::shape_type>;
- tmp_shape_t keep_dim_shape = xtl::forward_sequence<tmp_shape_t, decltype(e.shape())>(e.shape());
- for (const auto& el : axes)
- {
- keep_dim_shape[el] = 1u;
- }
- auto mrv = reshape_view<XTENSOR_DEFAULT_LAYOUT>(std::move(inner_mean), std::move(keep_dim_shape));
- return detail::mean<T>(square(sc - std::move(mrv)), std::forward<X>(axes), ddof, es);
- }
- template <
- class T = void,
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<std::decay_t<X>>>, is_reducer_options<EVS>)>
- inline auto variance(E&& e, X&& axes, EVS es = EVS())
- {
- return variance<T>(std::forward<E>(e), std::forward<X>(axes), 0u, es);
- }
- /**
- * @ingroup red_functions
- * @brief Compute the standard deviation along the specified axis.
- *
- * Returns the standard deviation, a measure of the spread of a distribution,
- * of the array elements. The standard deviation is computed for the flattened
- * array by default, otherwise over the specified axis.
- *
- * Note: this function is not yet specialized for complex numbers.
- *
- * @param e an \ref xexpression
- * @param axes the axes along which the standard deviation is computed (optional)
- * @param es evaluation strategy to use (lazy (default), or immediate)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T`is also used for determining the value type of the result,
- * which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- *
- * @sa variance, mean
- */
- template <
- class T = void,
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
- inline auto stddev(E&& e, X&& axes, EVS es = EVS())
- {
- return sqrt(variance<T>(std::forward<E>(e), std::forward<X>(axes), es));
- }
- template <class T = void, class E, class A, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto stddev(E&& e, const A (&axes)[N], EVS es = EVS())
- {
- return stddev<T>(
- std::forward<E>(e),
- xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
- es
- );
- }
- template <
- class T = void,
- class E,
- class A,
- std::size_t N,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto variance(E&& e, const A (&axes)[N], EVS es = EVS())
- {
- return variance<T>(
- std::forward<E>(e),
- xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
- es
- );
- }
- template <class T = void, class E, class A, std::size_t N, class D, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto variance(E&& e, const A (&axes)[N], const D& ddof, EVS es = EVS())
- {
- return variance<T>(
- std::forward<E>(e),
- xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
- ddof,
- es
- );
- }
- /**
- * @ingroup red_functions
- * @brief Minimum and maximum among the elements of an array or expression.
- *
- * Returns an \ref xreducer for the minimum and maximum of an expression's elements.
- * @param e an \ref xexpression
- * @param es evaluation strategy to use (lazy (default), or immediate)
- * @return an \ref xexpression of type ``std::array<value_type, 2>``, whose first
- * and second element represent the minimum and maximum respectively
- */
- template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto minmax(E&& e, EVS es = EVS())
- {
- using std::max;
- using std::min;
- using value_type = typename std::decay_t<E>::value_type;
- using result_type = std::array<value_type, 2>;
- using init_value_fct = xt::const_value<result_type>;
- auto reduce_func = [](auto r, const auto& v)
- {
- r[0] = (min) (r[0], v);
- r[1] = (max) (r[1], v);
- return r;
- };
- auto init_func = init_value_fct(
- result_type{std::numeric_limits<value_type>::max(), std::numeric_limits<value_type>::lowest()}
- );
- auto merge_func = [](auto r, const auto& s)
- {
- r[0] = (min) (r[0], s[0]);
- r[1] = (max) (r[1], s[1]);
- return r;
- };
- return xt::reduce(
- make_xreducer_functor(std::move(reduce_func), std::move(init_func), std::move(merge_func)),
- std::forward<E>(e),
- arange(e.dimension()),
- es
- );
- }
- /**
- * @defgroup acc_functions accumulating functions
- */
- /**
- * @ingroup acc_functions
- * @brief Cumulative sum.
- *
- * Returns the accumulated sum for the elements over given
- * \em axis (or flattened).
- * @param e an \ref xexpression
- * @param axis the axes along which the cumulative sum is computed (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T`is also used for determining the value type of the result,
- * which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xarray<T>
- */
- template <class T = void, class E>
- inline auto cumsum(E&& e, std::ptrdiff_t axis)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::plus(), detail::accumulator_identity<init_value_type>()),
- std::forward<E>(e),
- axis
- );
- }
- template <class T = void, class E>
- inline auto cumsum(E&& e)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::plus(), detail::accumulator_identity<init_value_type>()),
- std::forward<E>(e)
- );
- }
- /**
- * @ingroup acc_functions
- * @brief Cumulative product.
- *
- * Returns the accumulated product for the elements over given
- * \em axis (or flattened).
- * @param e an \ref xexpression
- * @param axis the axes along which the cumulative product is computed (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T`is also used for determining the value type of the result,
- * which is the type of `T() * E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xarray<T>
- */
- template <class T = void, class E>
- inline auto cumprod(E&& e, std::ptrdiff_t axis)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::multiplies(), detail::accumulator_identity<init_value_type>()),
- std::forward<E>(e),
- axis
- );
- }
- template <class T = void, class E>
- inline auto cumprod(E&& e)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::multiplies(), detail::accumulator_identity<init_value_type>()),
- std::forward<E>(e)
- );
- }
- /*****************
- * nan functions *
- *****************/
- namespace detail
- {
- struct nan_to_num_functor
- {
- template <class A>
- inline auto operator()(const A& a) const
- {
- if (math::isnan(a))
- {
- return A(0);
- }
- if (math::isinf(a))
- {
- if (a < 0)
- {
- return std::numeric_limits<A>::lowest();
- }
- else
- {
- return (std::numeric_limits<A>::max)();
- }
- }
- return a;
- }
- };
- struct nan_min
- {
- template <class T, class U>
- constexpr auto operator()(const T lhs, const U rhs) const
- {
- // Clunky expression for working with GCC 4.9
- return math::isnan(lhs)
- ? rhs
- : (math::isnan(rhs) ? lhs
- : std::common_type_t<T, U>(
- detail::make_xfunction<math::minimum<void>>(lhs, rhs)
- ));
- }
- };
- struct nan_max
- {
- template <class T, class U>
- constexpr auto operator()(const T lhs, const U rhs) const
- {
- // Clunky expression for working with GCC 4.9
- return math::isnan(lhs)
- ? rhs
- : (math::isnan(rhs) ? lhs
- : std::common_type_t<T, U>(
- detail::make_xfunction<math::maximum<void>>(lhs, rhs)
- ));
- }
- };
- struct nan_plus
- {
- template <class T, class U>
- constexpr auto operator()(const T lhs, const U rhs) const
- {
- return !math::isnan(rhs) ? lhs + rhs : lhs;
- }
- };
- struct nan_multiplies
- {
- template <class T, class U>
- constexpr auto operator()(const T lhs, const U rhs) const
- {
- return !math::isnan(rhs) ? lhs * rhs : lhs;
- }
- };
- template <class T, int V>
- struct nan_init
- {
- using value_type = T;
- using result_type = T;
- constexpr result_type operator()(const value_type lhs) const
- {
- return math::isnan(lhs) ? result_type(V) : lhs;
- }
- };
- }
- /**
- * @defgroup nan_functions nan functions
- */
- /**
- * @ingroup nan_functions
- * @brief Convert nan or +/- inf to numbers
- *
- * This functions converts NaN to 0, and +inf to the highest, -inf to the lowest
- * floating point value of the same type.
- *
- * @param e input \ref xexpression
- * @return an \ref xexpression
- */
- template <class E>
- inline auto nan_to_num(E&& e)
- {
- return detail::make_xfunction<detail::nan_to_num_functor>(std::forward<E>(e));
- }
- /**
- * @ingroup nan_functions
- * @brief Minimum element over given axes, ignoring NaNs.
- *
- * Returns an \ref xreducer for the minimum of elements over given
- * @p axes, ignoring NaNs.
- * @warning Casting the result to an integer type can cause undefined behavior.
- * @param e an \ref xexpression
- * @param axes the axes along which the minimum is found (optional)
- * @param es evaluation strategy of the reducer (optional)
- * @tparam T the result type. The default is `E::value_type`.
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(nanmin, detail::nan_min, typename std::decay_t<E>::value_type, std::nan("0"))
- /**
- * @ingroup nan_functions
- * @brief Maximum element along given axes, ignoring NaNs.
- *
- * Returns an \ref xreducer for the sum of elements over given
- * @p axes, ignoring NaN.
- * @warning Casting the result to an integer type can cause undefined behavior.
- * @param e an \ref xexpression
- * @param axes the axes along which the sum is performed (optional)
- * @param es evaluation strategy of the reducer (optional)
- * @tparam T the result type. The default is `E::value_type`.
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(nanmax, detail::nan_max, typename std::decay_t<E>::value_type, std::nan("0"))
- /**
- * @ingroup nan_functions
- * @brief Sum of elements over given axes, replacing NaN with 0.
- *
- * Returns an \ref xreducer for the sum of elements over given
- * @p axes, ignoring NaN.
- * @param e an \ref xexpression
- * @param axes the axes along which the sum is performed (optional)
- * @param es evaluation strategy of the reducer (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T` is also used for determining the value type
- * of the result, which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(nansum, detail::nan_plus, typename std::decay_t<E>::value_type, 0)
- /**
- * @ingroup nan_functions
- * @brief Product of elements over given axes, replacing NaN with 1.
- *
- * Returns an \ref xreducer for the sum of elements over given
- * @p axes, replacing nan with 1.
- * @param e an \ref xexpression
- * @param axes the axes along which the sum is performed (optional)
- * @param es evaluation strategy of the reducer (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T` is also used for determining the value type
- * of the result, which is the type of `T() * E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xreducer
- */
- XTENSOR_REDUCER_FUNCTION(nanprod, detail::nan_multiplies, typename std::decay_t<E>::value_type, 1)
- #define COUNT_NON_ZEROS_CONTENT \
- using value_type = typename std::decay_t<E>::value_type; \
- using result_type = xt::detail::xreducer_size_type_t<value_type>; \
- using init_value_fct = xt::const_value<result_type>; \
- \
- auto init_fct = init_value_fct(0); \
- \
- auto reduce_fct = [](const auto& lhs, const auto& rhs) \
- { \
- using value_t = xt::detail::xreducer_temporary_type_t<std::decay_t<decltype(rhs)>>; \
- using result_t = std::decay_t<decltype(lhs)>; \
- \
- return (rhs != value_t(0)) ? lhs + result_t(1) : lhs; \
- }; \
- auto merge_func = detail::plus();
- template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto count_nonzero(E&& e, EVS es = EVS())
- {
- COUNT_NON_ZEROS_CONTENT;
- return xt::reduce(
- make_xreducer_functor(std::move(reduce_fct), std::move(init_fct), std::move(merge_func)),
- std::forward<E>(e),
- es
- );
- }
- template <
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<X>>)>
- inline auto count_nonzero(E&& e, X&& axes, EVS es = EVS())
- {
- COUNT_NON_ZEROS_CONTENT;
- return xt::reduce(
- make_xreducer_functor(std::move(reduce_fct), std::move(init_fct), std::move(merge_func)),
- std::forward<E>(e),
- std::forward<X>(axes),
- es
- );
- }
- template <
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<X>)>
- inline auto count_nonzero(E&& e, X axis, EVS es = EVS())
- {
- return count_nonzero(std::forward<E>(e), {axis}, es);
- }
- template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto count_nonzero(E&& e, const I (&axes)[N], EVS es = EVS())
- {
- COUNT_NON_ZEROS_CONTENT;
- return xt::reduce(
- make_xreducer_functor(std::move(reduce_fct), std::move(init_fct), std::move(merge_func)),
- std::forward<E>(e),
- axes,
- es
- );
- }
- #undef COUNT_NON_ZEROS_CONTENT
- template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto count_nonnan(E&& e, EVS es = EVS())
- {
- return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), es);
- }
- template <
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::negation<xtl::is_integral<X>>)>
- inline auto count_nonnan(E&& e, X&& axes, EVS es = EVS())
- {
- return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), std::forward<X>(axes), es);
- }
- template <
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>, xtl::is_integral<X>)>
- inline auto count_nonnan(E&& e, X&& axes, EVS es = EVS())
- {
- return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), {axes}, es);
- }
- template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto count_nonnan(E&& e, const I (&axes)[N], EVS es = EVS())
- {
- return xt::count_nonzero(!xt::isnan(std::forward<E>(e)), axes, es);
- }
- /**
- * @ingroup nan_functions
- * @brief Cumulative sum, replacing nan with 0.
- *
- * Returns an xaccumulator for the sum of elements over given
- * \em axis, replacing nan with 0.
- * @param e an \ref xexpression
- * @param axis the axis along which the elements are accumulated (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T` is also used for determining the value type
- * of the result, which is the type of `T() + E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an xaccumulator
- */
- template <class T = void, class E>
- inline auto nancumsum(E&& e, std::ptrdiff_t axis)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::nan_plus(), detail::nan_init<init_value_type, 0>()),
- std::forward<E>(e),
- axis
- );
- }
- template <class T = void, class E>
- inline auto nancumsum(E&& e)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::nan_plus(), detail::nan_init<init_value_type, 0>()),
- std::forward<E>(e)
- );
- }
- /**
- * @ingroup nan_functions
- * @brief Cumulative product, replacing nan with 1.
- *
- * Returns an xaccumulator for the product of elements over given
- * \em axis, replacing nan with 1.
- * @param e an \ref xexpression
- * @param axis the axis along which the elements are accumulated (optional)
- * @tparam T the value type used for internal computation. The default is
- * `E::value_type`. `T` is also used for determining the value type
- * of the result, which is the type of `T() * E::value_type()`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an xaccumulator
- */
- template <class T = void, class E>
- inline auto nancumprod(E&& e, std::ptrdiff_t axis)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::nan_multiplies(), detail::nan_init<init_value_type, 1>()),
- std::forward<E>(e),
- axis
- );
- }
- template <class T = void, class E>
- inline auto nancumprod(E&& e)
- {
- using init_value_type = std::conditional_t<std::is_same<T, void>::value, typename std::decay_t<E>::value_type, T>;
- return accumulate(
- make_xaccumulator_functor(detail::nan_multiplies(), detail::nan_init<init_value_type, 1>()),
- std::forward<E>(e)
- );
- }
- namespace detail
- {
- template <class T>
- struct diff_impl
- {
- template <class Arg>
- inline void operator()(
- Arg& ad,
- const std::size_t& n,
- xstrided_slice_vector& slice1,
- xstrided_slice_vector& slice2,
- std::size_t saxis
- )
- {
- for (std::size_t i = 0; i < n; ++i)
- {
- slice2[saxis] = range(xnone(), ad.shape()[saxis] - 1);
- ad = strided_view(ad, slice1) - strided_view(ad, slice2);
- }
- }
- };
- template <>
- struct diff_impl<bool>
- {
- template <class Arg>
- inline void operator()(
- Arg& ad,
- const std::size_t& n,
- xstrided_slice_vector& slice1,
- xstrided_slice_vector& slice2,
- std::size_t saxis
- )
- {
- for (std::size_t i = 0; i < n; ++i)
- {
- slice2[saxis] = range(xnone(), ad.shape()[saxis] - 1);
- ad = not_equal(strided_view(ad, slice1), strided_view(ad, slice2));
- }
- }
- };
- }
- /**
- * @ingroup nan_functions
- * @brief Mean of elements over given axes, excluding NaNs.
- *
- * Returns an \ref xreducer for the mean of elements over given
- * \em axes, excluding NaNs.
- * This is not the same as counting NaNs as zero, since excluding NaNs changes the number
- * of elements considered in the statistic.
- * @param e an \ref xexpression
- * @param axes the axes along which the mean is computed (optional)
- * @param es the evaluation strategy (optional)
- * @tparam T the result type. The default is `E::value_type`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- */
- template <
- class T = void,
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
- inline auto nanmean(E&& e, X&& axes, EVS es = EVS())
- {
- decltype(auto) sc = detail::shared_forward<E>(e);
- // note: forcing copy of first axes argument -- is there a better solution?
- auto axes_copy = axes;
- using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
- using sum_type = typename std::conditional_t<
- std::is_same<T, void>::value,
- typename std::common_type_t<typename std::decay_t<E>::value_type, value_type>,
- T>;
- // sum cannot always be a double. It could be a complex number which cannot operate on
- // std::plus<double>.
- return nansum<sum_type>(sc, std::forward<X>(axes), es)
- / xt::cast<value_type>(count_nonnan(sc, std::move(axes_copy), es));
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto nanmean(E&& e, EVS es = EVS())
- {
- decltype(auto) sc = detail::shared_forward<E>(e);
- using value_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
- using sum_type = typename std::conditional_t<
- std::is_same<T, void>::value,
- typename std::common_type_t<typename std::decay_t<E>::value_type, value_type>,
- T>;
- return nansum<sum_type>(sc, es) / xt::cast<value_type>(count_nonnan(sc, es));
- }
- template <class T = void, class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto nanmean(E&& e, const I (&axes)[N], EVS es = EVS())
- {
- return nanmean<T>(
- std::forward<E>(e),
- xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
- es
- );
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto nanvar(E&& e, EVS es = EVS())
- {
- decltype(auto) sc = detail::shared_forward<E>(e);
- return nanmean<T>(square(sc - nanmean<T>(sc)), es);
- }
- template <class T = void, class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTL_REQUIRES(is_reducer_options<EVS>)>
- inline auto nanstd(E&& e, EVS es = EVS())
- {
- return sqrt(nanvar<T>(std::forward<E>(e), es));
- }
- /**
- * @ingroup nan_functions
- * @brief Compute the variance along the specified axes, excluding NaNs
- *
- * Returns the variance of the array elements, a measure of the spread of a
- * distribution. The variance is computed for the flattened array by default,
- * otherwise over the specified axes.
- * Excluding NaNs changes the number of elements considered in the statistic.
- *
- * Note: this function is not yet specialized for complex numbers.
- *
- * @param e an \ref xexpression
- * @param axes the axes along which the variance is computed (optional)
- * @param es evaluation strategy to use (lazy (default), or immediate)
- * @tparam T the result type. The default is `E::value_type`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- *
- * @sa nanstd, nanmean
- */
- template <
- class T = void,
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
- inline auto nanvar(E&& e, X&& axes, EVS es = EVS())
- {
- decltype(auto) sc = detail::shared_forward<E>(e);
- // note: forcing copy of first axes argument -- is there a better solution?
- auto axes_copy = axes;
- using result_type = typename std::conditional_t<std::is_same<T, void>::value, double, T>;
- auto inner_mean = nanmean<result_type>(sc, std::move(axes_copy));
- // fake keep_dims = 1
- // Since the inner_shape might have a reference semantic (e.g. xbuffer_adaptor in bindings)
- // We need to map it to another type before modifying it.
- // We pragmatically abuse `get_strides_t`
- using tmp_shape_t = get_strides_t<typename std::decay_t<E>::shape_type>;
- tmp_shape_t keep_dim_shape = xtl::forward_sequence<tmp_shape_t, decltype(e.shape())>(e.shape());
- for (const auto& el : axes)
- {
- keep_dim_shape[el] = 1;
- }
- auto mrv = reshape_view<XTENSOR_DEFAULT_LAYOUT>(std::move(inner_mean), std::move(keep_dim_shape));
- return nanmean<result_type>(square(cast<result_type>(sc) - std::move(mrv)), std::forward<X>(axes), es);
- }
- /**
- * @ingroup nan_functions
- * @brief Compute the standard deviation along the specified axis, excluding nans.
- *
- * Returns the standard deviation, a measure of the spread of a distribution,
- * of the array elements. The standard deviation is computed for the flattened
- * array by default, otherwise over the specified axis.
- * Excluding NaNs changes the number of elements considered in the statistic.
- *
- * Note: this function is not yet specialized for complex numbers.
- *
- * @param e an \ref xexpression
- * @param axes the axes along which the standard deviation is computed (optional)
- * @param es evaluation strategy to use (lazy (default), or immediate)
- * @tparam T the result type. The default is `E::value_type`.
- * You can pass `big_promote_value_type_t<E>` to avoid overflow in computation.
- * @return an \ref xexpression
- *
- * @sa nanvar, nanmean
- */
- template <
- class T = void,
- class E,
- class X,
- class EVS = DEFAULT_STRATEGY_REDUCERS,
- XTL_REQUIRES(xtl::negation<is_reducer_options<X>>)>
- inline auto nanstd(E&& e, X&& axes, EVS es = EVS())
- {
- return sqrt(nanvar<T>(std::forward<E>(e), std::forward<X>(axes), es));
- }
- template <class T = void, class E, class A, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto nanstd(E&& e, const A (&axes)[N], EVS es = EVS())
- {
- return nanstd<T>(
- std::forward<E>(e),
- xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
- es
- );
- }
- template <class T = void, class E, class A, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
- inline auto nanvar(E&& e, const A (&axes)[N], EVS es = EVS())
- {
- return nanvar<T>(
- std::forward<E>(e),
- xtl::forward_sequence<std::array<std::size_t, N>, decltype(axes)>(axes),
- es
- );
- }
- /**
- * @ingroup red_functions
- * @brief Calculate the n-th discrete difference along the given axis.
- *
- * Calculate the n-th discrete difference along the given axis. This function is not lazy (might change in
- * the future).
- * @param a an \ref xexpression
- * @param n The number of times values are differenced. If zero, the input is returned as-is. (optional)
- * @param axis The axis along which the difference is taken, default is the last axis.
- * @return an xarray
- */
- template <class T>
- auto diff(const xexpression<T>& a, std::size_t n = 1, std::ptrdiff_t axis = -1)
- {
- typename std::decay_t<T>::temporary_type ad = a.derived_cast();
- std::size_t saxis = normalize_axis(ad.dimension(), axis);
- if (n <= ad.size())
- {
- if (n != std::size_t(0))
- {
- xstrided_slice_vector slice1(ad.dimension(), all());
- xstrided_slice_vector slice2(ad.dimension(), all());
- slice1[saxis] = range(1, xnone());
- detail::diff_impl<typename T::value_type> impl;
- impl(ad, n, slice1, slice2, saxis);
- }
- }
- else
- {
- auto shape = ad.shape();
- shape[saxis] = std::size_t(0);
- ad.resize(shape);
- }
- return ad;
- }
- /**
- * @ingroup red_functions
- * @brief Integrate along the given axis using the composite trapezoidal rule.
- *
- * Returns definite integral as approximated by trapezoidal rule. This function is not lazy (might change
- * in the future).
- * @param y an \ref xexpression
- * @param dx the spacing between sample points (optional)
- * @param axis the axis along which to integrate.
- * @return an xarray
- */
- template <class T>
- auto trapz(const xexpression<T>& y, double dx = 1.0, std::ptrdiff_t axis = -1)
- {
- auto& yd = y.derived_cast();
- std::size_t saxis = normalize_axis(yd.dimension(), axis);
- xstrided_slice_vector slice1(yd.dimension(), all());
- xstrided_slice_vector slice2(yd.dimension(), all());
- slice1[saxis] = range(1, xnone());
- slice2[saxis] = range(xnone(), yd.shape()[saxis] - 1);
- auto trap = dx * (strided_view(yd, slice1) + strided_view(yd, slice2)) * 0.5;
- return eval(sum(trap, {saxis}));
- }
- /**
- * @ingroup red_functions
- * @brief Integrate along the given axis using the composite trapezoidal rule.
- *
- * Returns definite integral as approximated by trapezoidal rule. This function is not lazy (might change
- * in the future).
- * @param y an \ref xexpression
- * @param x an \ref xexpression representing the sample points corresponding to the y values.
- * @param axis the axis along which to integrate.
- * @return an xarray
- */
- template <class T, class E>
- auto trapz(const xexpression<T>& y, const xexpression<E>& x, std::ptrdiff_t axis = -1)
- {
- auto& yd = y.derived_cast();
- auto& xd = x.derived_cast();
- decltype(diff(x)) dx;
- std::size_t saxis = normalize_axis(yd.dimension(), axis);
- if (xd.dimension() == 1)
- {
- dx = diff(x);
- typename std::decay_t<decltype(yd)>::shape_type shape;
- resize_container(shape, yd.dimension());
- std::fill(shape.begin(), shape.end(), 1);
- shape[saxis] = dx.shape()[0];
- dx.reshape(shape);
- }
- else
- {
- dx = diff(x, 1, axis);
- }
- xstrided_slice_vector slice1(yd.dimension(), all());
- xstrided_slice_vector slice2(yd.dimension(), all());
- slice1[saxis] = range(1, xnone());
- slice2[saxis] = range(xnone(), yd.shape()[saxis] - 1);
- auto trap = dx * (strided_view(yd, slice1) + strided_view(yd, slice2)) * 0.5;
- return eval(sum(trap, {saxis}));
- }
- /**
- * @ingroup basic_functions
- * @brief Returns the one-dimensional piecewise linear interpolant to a function with given discrete data
- * points (xp, fp), evaluated at x.
- *
- * @param x The x-coordinates at which to evaluate the interpolated values (sorted).
- * @param xp The x-coordinates of the data points (sorted).
- * @param fp The y-coordinates of the data points, same length as xp.
- * @param left Value to return for x < xp[0].
- * @param right Value to return for x > xp[-1]
- * @return an one-dimensional xarray, same length as x.
- */
- template <class E1, class E2, class E3, typename T>
- inline auto interp(const E1& x, const E2& xp, const E3& fp, T left, T right)
- {
- using size_type = common_size_type_t<E1, E2, E3>;
- using value_type = typename E3::value_type;
- // basic checks
- XTENSOR_ASSERT(xp.dimension() == 1);
- XTENSOR_ASSERT(std::is_sorted(x.cbegin(), x.cend()));
- XTENSOR_ASSERT(std::is_sorted(xp.cbegin(), xp.cend()));
- // allocate output
- auto f = xtensor<value_type, 1>::from_shape(x.shape());
- // counter in "x": from left
- size_type i = 0;
- // fill f[i] for x[i] <= xp[0]
- for (; i < x.size(); ++i)
- {
- if (x[i] > xp[0])
- {
- break;
- }
- f[i] = static_cast<value_type>(left);
- }
- // counter in "x": from right
- // (index counts one right, to terminate the reverse loop, without risking being negative)
- size_type imax = x.size();
- // fill f[i] for x[-1] >= xp[-1]
- for (; imax > 0; --imax)
- {
- if (x[imax - 1] < xp[xp.size() - 1])
- {
- break;
- }
- f[imax - 1] = static_cast<value_type>(right);
- }
- // catch edge case: all entries are "right"
- if (imax == 0)
- {
- return f;
- }
- // set "imax" as actual index
- // (counted one right, see above)
- --imax;
- // counter in "xp"
- size_type ip = 1;
- // fill f[i] for the interior
- for (; i <= imax; ++i)
- {
- // - search next value in "xp"
- while (x[i] > xp[ip])
- {
- ++ip;
- }
- // - distances as doubles
- double dfp = static_cast<double>(fp[ip] - fp[ip - 1]);
- double dxp = static_cast<double>(xp[ip] - xp[ip - 1]);
- double dx = static_cast<double>(x[i] - xp[ip - 1]);
- // - interpolate
- f[i] = fp[ip - 1] + static_cast<value_type>(dfp / dxp * dx);
- }
- return f;
- }
- namespace detail
- {
- template <class E1, class E2>
- auto calculate_discontinuity(E1&& discontinuity, E2&&)
- {
- return discontinuity;
- }
- template <class E2>
- auto calculate_discontinuity(xt::placeholders::xtuph, E2&& period)
- {
- return 0.5 * period;
- }
- template <class E1, class E2>
- auto
- calculate_interval(E2&& period, typename std::enable_if<std::is_integral<E1>::value, E1>::type* = 0)
- {
- auto interval_high = 0.5 * period;
- uint64_t remainder = static_cast<uint64_t>(period) % 2;
- auto boundary_ambiguous = (remainder == 0);
- return std::make_tuple(interval_high, boundary_ambiguous);
- }
- template <class E1, class E2>
- auto
- calculate_interval(E2&& period, typename std::enable_if<std::is_floating_point<E1>::value, E1>::type* = 0)
- {
- auto interval_high = 0.5 * period;
- auto boundary_ambiguous = true;
- return std::make_tuple(interval_high, boundary_ambiguous);
- }
- }
- /**
- * @ingroup basic_functions
- * @brief Unwrap by taking the complement of large deltas with respect to the period
- * @details https://numpy.org/doc/stable/reference/generated/numpy.unwrap.html
- * @param p Input array.
- * @param discontinuity
- * Maximum discontinuity between values, default is `period / 2`.
- * Values below `period / 2` are treated as if they were `period / 2`.
- * To have an effect different from the default, use `discontinuity > period / 2`.
- * @param axis Axis along which unwrap will operate, default: the last axis.
- * @param period Size of the range over which the input wraps. Default: \f$ 2 \pi \f$.
- */
- template <class E1, class E2 = xt::placeholders::xtuph, class E3 = double>
- inline auto unwrap(
- E1&& p,
- E2 discontinuity = xnone(),
- std::ptrdiff_t axis = -1,
- E3 period = 2.0 * xt::numeric_constants<double>::PI
- )
- {
- auto discont = detail::calculate_discontinuity(discontinuity, period);
- using value_type = typename std::decay_t<E1>::value_type;
- std::size_t saxis = normalize_axis(p.dimension(), axis);
- auto dd = diff(p, 1, axis);
- xstrided_slice_vector slice(p.dimension(), all());
- slice[saxis] = range(1, xnone());
- auto interval_tuple = detail::calculate_interval<value_type>(period);
- auto interval_high = std::get<0>(interval_tuple);
- auto boundary_ambiguous = std::get<1>(interval_tuple);
- auto interval_low = -interval_high;
- auto ddmod = xt::eval(xt::fmod(xt::fmod(dd - interval_low, period) + period, period) + interval_low);
- if (boundary_ambiguous)
- {
- // for `mask = (abs(dd) == period/2)`, the above line made
- //`ddmod[mask] == -period/2`. correct these such that
- //`ddmod[mask] == sign(dd[mask])*period/2`.
- auto boolmap = xt::equal(ddmod, interval_low) && (xt::greater(dd, 0.0));
- ddmod = xt::where(boolmap, interval_high, ddmod);
- }
- auto ph_correct = xt::eval(ddmod - dd);
- ph_correct = xt::where(xt::abs(dd) < discont, 0.0, ph_correct);
- E1 up(p);
- strided_view(up, slice) = strided_view(p, slice)
- + xt::cumsum(ph_correct, static_cast<std::ptrdiff_t>(saxis));
- return up;
- }
- /**
- * @ingroup basic_functions
- * @brief Returns the one-dimensional piecewise linear interpolant to a function with given discrete data
- * points (xp, fp), evaluated at x.
- *
- * @param x The x-coordinates at which to evaluate the interpolated values (sorted).
- * @param xp The x-coordinates of the data points (sorted).
- * @param fp The y-coordinates of the data points, same length as xp.
- * @return an one-dimensional xarray, same length as x.
- */
- template <class E1, class E2, class E3>
- inline auto interp(const E1& x, const E2& xp, const E3& fp)
- {
- return interp(x, xp, fp, fp[0], fp[fp.size() - 1]);
- }
- /**
- * @brief Returns the covariance matrix
- *
- * @param x one or two dimensional array
- * @param y optional one-dimensional array to build covariance to x
- */
- template <class E1>
- inline auto cov(const E1& x, const E1& y = E1())
- {
- using value_type = typename E1::value_type;
- if (y.dimension() == 0)
- {
- auto s = x.shape();
- using size_type = std::decay_t<decltype(s[0])>;
- if (x.dimension() == 1)
- {
- auto covar = eval(zeros<value_type>({1, 1}));
- auto x_norm = x - eval(mean(x));
- covar(0, 0) = std::inner_product(x_norm.begin(), x_norm.end(), x_norm.begin(), 0.0)
- / value_type(s[0] - 1);
- return covar;
- }
- XTENSOR_ASSERT(x.dimension() == 2);
- auto covar = eval(zeros<value_type>({s[0], s[0]}));
- auto m = eval(mean(x, {1}));
- m.reshape({m.shape()[0], 1});
- auto x_norm = x - m;
- for (size_type i = 0; i < s[0]; i++)
- {
- auto xi = strided_view(x_norm, {range(i, i + 1), all()});
- for (size_type j = i; j < s[0]; j++)
- {
- auto xj = strided_view(x_norm, {range(j, j + 1), all()});
- covar(j, i) = std::inner_product(xi.begin(), xi.end(), xj.begin(), 0.0)
- / value_type(s[1] - 1);
- }
- }
- return eval(covar + transpose(covar) - diag(diagonal(covar)));
- }
- else
- {
- return cov(eval(stack(xtuple(x, y))));
- }
- }
- /*
- * convolution mode placeholders for selecting the algorithm
- * used in computing a 1D convolution.
- * Same as NumPy's mode parameter.
- */
- namespace convolve_mode
- {
- struct valid
- {
- };
- struct full
- {
- };
- }
- namespace detail
- {
- template <class E1, class E2>
- inline auto convolve_impl(E1&& e1, E2&& e2, convolve_mode::valid)
- {
- using value_type = typename std::decay<E1>::type::value_type;
- const std::size_t na = e1.size();
- const std::size_t nv = e2.size();
- const std::size_t n = na - nv + 1;
- xt::xtensor<value_type, 1> out = xt::zeros<value_type>({n});
- for (std::size_t i = 0; i < n; i++)
- {
- for (std::size_t j = 0; j < nv; j++)
- {
- out(i) += e1(j) * e2(j + i);
- }
- }
- return out;
- }
- template <class E1, class E2>
- inline auto convolve_impl(E1&& e1, E2&& e2, convolve_mode::full)
- {
- using value_type = typename std::decay<E1>::type::value_type;
- const std::size_t na = e1.size();
- const std::size_t nv = e2.size();
- const std::size_t n = na + nv - 1;
- xt::xtensor<value_type, 1> out = xt::zeros<value_type>({n});
- for (std::size_t i = 0; i < n; i++)
- {
- const std::size_t jmn = (i >= nv - 1) ? i - (nv - 1) : 0;
- const std::size_t jmx = (i < na - 1) ? i : na - 1;
- for (std::size_t j = jmn; j <= jmx; ++j)
- {
- out(i) += e1(j) * e2(i - j);
- }
- }
- return out;
- }
- }
- /*
- * @brief computes the 1D convolution between two 1D expressions
- *
- * @param a 1D expression
- * @param v 1D expression
- * @param mode placeholder Select algorithm #convolve_mode
- *
- * @detail the algorithm convolves a with v and will incur a copy overhead
- * should v be longer than a.
- */
- template <class E1, class E2, class E3>
- inline auto convolve(E1&& a, E2&& v, E3 mode)
- {
- if (a.dimension() != 1 || v.dimension() != 1)
- {
- XTENSOR_THROW(std::runtime_error, "Invalid dimentions convolution arguments must be 1D expressions");
- }
- XTENSOR_ASSERT(a.size() > 0 && v.size() > 0);
- // swap them so a is always the longest one
- if (a.size() < v.size())
- {
- return detail::convolve_impl(std::forward<E2>(v), std::forward<E1>(a), mode);
- }
- else
- {
- return detail::convolve_impl(std::forward<E1>(a), std::forward<E2>(v), mode);
- }
- }
- }
- #endif
|