Logo ROOT   6.16/01
Reference Guide
RVec.hxx
Go to the documentation of this file.
1// Author: Enrico Guiraud, Enric Tejedor, Danilo Piparo CERN 01/2018
2
3/*************************************************************************
4 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11/**
12 \defgroup vecops VecOps
13*/
14
15#ifndef ROOT_TVEC
16#define ROOT_TVEC
17
18#ifdef _WIN32
19 #define _VECOPS_USE_EXTERN_TEMPLATES false
20#else
21 #define _VECOPS_USE_EXTERN_TEMPLATES true
22#endif
23
25#include <ROOT/TypeTraits.hxx>
26
27#include <algorithm>
28#include <cmath>
29#include <numeric> // for inner_product
30#include <sstream>
31#include <stdexcept>
32#include <type_traits>
33#include <vector>
34#include <utility>
35
36#ifdef R__HAS_VDT
37#include <vdt/vdtMath.h>
38#endif
39
40namespace ROOT {
41namespace VecOps {
42template<typename T>
43class RVec;
44}
45namespace Internal {
46namespace VecOps {
47
48// We use this helper to workaround a limitation of compilers such as
49// gcc 4.8 amd clang on osx 10.14 for which std::vector<bool>::emplace_back
50// is not defined.
51// We have the template for all types and a partial specialisation
52// for T == bool, which uses push_back.
53template<typename T, typename... Args>
55static void EmplaceBack(T &v, Args &&... args)
56{
57 v.emplace_back(std::forward<Args>(args)...);
58}
59};
60
61template<typename... Args>
62struct REmplaceBackHelper<std::vector<bool>, Args...>{
63static void EmplaceBack(std::vector<bool> &v, Args &&... args)
64{
65 v.push_back(std::forward<Args>(args)...);
66}
67};
68
69} // End of VecOps NS
70} // End of Internal NS
71
72namespace VecOps {
73// clang-format off
74/**
75\class ROOT::VecOps::RVec
76\ingroup vecops
77\brief A "std::vector"-like collection of values implementing handy operation to analyse them
78\tparam T The type of the contained objects
79
80A RVec is a container designed to make analysis of values' collections fast and easy.
81Its storage is contiguous in memory and its interface is designed such to resemble to the one
82of the stl vector. In addition the interface features methods and external functions to ease
83the manipulation and analysis of the data in the RVec.
84
85\htmlonly
86<a href="https://doi.org/10.5281/zenodo.1253756"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.1253756.svg" alt="DOI"></a>
87\endhtmlonly
88
89## Table of Contents
90- [Example](#example)
91- [Owning and adopting memory](#owningandadoptingmemory)
92- [Sorting and manipulation of indices](#sorting)
93- [Usage in combination with RDataFrame](#usagetdataframe)
94- [Reference for the RVec class](#RVecdoxyref)
95
96Also see the [reference for RVec helper functions](https://root.cern/doc/master/namespaceROOT_1_1VecOps.html).
97
98## <a name="example"></a>Example
99Suppose to have an event featuring a collection of muons with a certain pseudorapidity,
100momentum and charge, e.g.:
101~~~{.cpp}
102std::vector<short> mu_charge {1, 1, -1, -1, -1, 1, 1, -1};
103std::vector<float> mu_pt {56, 45, 32, 24, 12, 8, 7, 6.2};
104std::vector<float> mu_eta {3.1, -.2, -1.1, 1, 4.1, 1.6, 2.4, -.5};
105~~~
106Suppose you want to extract the transverse momenta of the muons satisfying certain
107criteria, for example consider only negatively charged muons with a pseudorapidity
108smaller or equal to 2 and with a transverse momentum greater than 10 GeV.
109Such a selection would require, among the other things, the management of an explicit
110loop, for example:
111~~~{.cpp}
112std::vector<float> goodMuons_pt;
113const auto size = mu_charge.size();
114for (size_t i=0; i < size; ++i) {
115 if (mu_pt[i] > 10 && abs(mu_eta[i]) <= 2. && mu_charge[i] == -1) {
116 goodMuons_pt.emplace_back(mu_pt[i]);
117 }
118}
119~~~
120These operations become straightforward with RVec - we just need to *write what
121we mean*:
122~~~{.cpp}
123auto goodMuons_pt = mu_pt[ (mu_pt > 10.f && abs(mu_eta) <= 2.f && mu_charge == -1) ]
124~~~
125Now the clean collection of transverse momenta can be used within the rest of the data analysis, for
126example to fill a histogram.
127
128## <a name="owningandadoptingmemory"></a>Owning and adopting memory
129RVec has contiguous memory associated to it. It can own it or simply adopt it. In the latter case,
130it can be constructed with the address of the memory associated to it and its length. For example:
131~~~{.cpp}
132std::vector<int> myStlVec {1,2,3};
133RVec<int> myRVec(myStlVec.data(), myStlVec.size());
134~~~
135In this case, the memory associated to myStlVec and myRVec is the same, myRVec simply "adopted it".
136If any method which implies a re-allocation is called, e.g. *emplace_back* or *resize*, the adopted
137memory is released and new one is allocated. The previous content is copied in the new memory and
138preserved.
139
140## <a name="#sorting"></a>Sorting and manipulation of indices
141
142### Sorting
143RVec complies to the STL interfaces when it comes to iterations. As a result, standard algorithms
144can be used, for example sorting:
145~~~{.cpp}
146RVec<double> v{6., 4., 5.};
147std::sort(v.begin(), v.end());
148~~~
149
150For convinience, helpers are provided too:
151~~~{.cpp}
152auto sorted_v = Sort(v);
153auto reversed_v = Reverse(v);
154~~~
155
156### Manipulation of indices
157
158It is also possible to manipulated the RVecs acting on their indices. For example,
159the following syntax
160~~~{.cpp}
161RVec<double> v0 {9., 7., 8.};
162auto v1 = Take(v0, {1, 2, 0});
163~~~
164will yield a new RVec<double> the content of which is the first, second and zeroth element of
165v0, i.e. `{7., 8., 9.}`.
166
167The `Argsort` helper extracts the indices which order the content of a `RVec`. For example,
168this snippet accomplish in a more expressive way what we just achieved:
169~~~{.cpp}
170auto v1_indices = Argsort(v0); // The content of v1_indices is {1, 2, 0}.
171v1 = Take(v0, v1_indices);
172~~~
173
174The `Take` utility allows to extract portions of the `RVec`. The content to be *taken*
175can be specified with an `RVec` of indices or an integer. If the integer is negative,
176elements will be picked starting from the end of the container:
177~~~{.cpp}
178RVec<float> vf {1.f, 2.f, 3.f, 4.f};
179auto vf_1 = Take(vf, {1, 3}); // The content is {2.f, 4.f}
180auto vf_2 = Take(vf, 2); // The content is {1.f, 2.f}
181auto vf_3 = Take(vf, -3); // The content is {2.f, 3.f, 4.f}
182~~~
183
184## <a name="usagetdataframe"></a>Usage in combination with RDataFrame
185RDataFrame leverages internally RVecs. Suppose to have a dataset stored in a
186TTree which holds these columns (here we choose C arrays to represent the
187collections, they could be as well std::vector instances):
188~~~{.bash}
189 nPart "nPart/I" An integer representing the number of particles
190 px "px[nPart]/D" The C array of the particles' x component of the momentum
191 py "py[nPart]/D" The C array of the particles' y component of the momentum
192 E "E[nPart]/D" The C array of the particles' Energy
193~~~
194Suppose you'd like to plot in a histogram the transverse momenta of all particles
195for which the energy is greater than 200 MeV.
196The code required would just be:
197~~~{.cpp}
198RDataFrame d("mytree", "myfile.root");
199using doubles = RVec<double>;
200auto cutPt = [](doubles &pxs, doubles &pys, doubles &Es) {
201 auto all_pts = sqrt(pxs * pxs + pys * pys);
202 auto good_pts = all_pts[Es > 200.];
203 return good_pts;
204 };
205
206auto hpt = d.Define("pt", cutPt, {"px", "py", "E"})
207 .Histo1D("pt");
208hpt->Draw();
209~~~
210And if you'd like to express your selection as a string:
211~~~{.cpp}
212RDataFrame d("mytree", "myfile.root");
213auto hpt = d.Define("pt", "sqrt(pxs * pxs + pys * pys)[E>200]")
214 .Histo1D("pt");
215hpt->Draw();
216~~~
217<a name="RVecdoxyref"></a>
218**/
219// clang-format on
220template <typename T>
221class RVec {
222 // Here we check if T is a bool. This is done in order to decide what type
223 // to use as a storage. If T is anything but bool, we use a vector<T, RAdoptAllocator<T>>.
224 // If T is a bool, we opt for a plain vector<bool> otherwise we'll not be able
225 // to write the data type given the shortcomings of TCollectionProxy design.
226 static constexpr const auto IsVecBool = std::is_same<bool, T>::value;
227public:
228 using Impl_t = typename std::conditional<IsVecBool, std::vector<bool>, std::vector<T, ::ROOT::Detail::VecOps::RAdoptAllocator<T>>>::type;
229 using value_type = typename Impl_t::value_type;
230 using size_type = typename Impl_t::size_type;
231 using difference_type = typename Impl_t::difference_type;
232 using reference = typename Impl_t::reference;
233 using const_reference = typename Impl_t::const_reference;
234 using pointer = typename Impl_t::pointer;
235 using const_pointer = typename Impl_t::const_pointer;
236 // The data_t and const_data_t types are chosen to be void in case T is a bool.
237 // This way we can as elegantly as in the STL return void upon calling the data() method.
240 using iterator = typename Impl_t::iterator;
241 using const_iterator = typename Impl_t::const_iterator;
242 using reverse_iterator = typename Impl_t::reverse_iterator;
243 using const_reverse_iterator = typename Impl_t::const_reverse_iterator;
244
245private:
247
248public:
249 // constructors
250 RVec() {}
251
252 explicit RVec(size_type count) : fData(count) {}
253
254 RVec(size_type count, const T &value) : fData(count, value) {}
255
256 RVec(const RVec<T> &v) : fData(v.fData) {}
257
258 RVec(RVec<T> &&v) : fData(std::move(v.fData)) {}
259
260 RVec(const std::vector<T> &v) : fData(v.cbegin(), v.cend()) {}
261
262 RVec(pointer p, size_type n) : fData(n, T(), ROOT::Detail::VecOps::RAdoptAllocator<T>(p)) {}
263
264 template <class InputIt>
265 RVec(InputIt first, InputIt last) : fData(first, last) {}
266
267 RVec(std::initializer_list<T> init) : fData(init) {}
268
269 // assignment
271 {
272 fData = v.fData;
273 return *this;
274 }
275
277 {
278 std::swap(fData, v.fData);
279 return *this;
280 }
281
282 RVec<T> &operator=(std::initializer_list<T> ilist)
283 {
284 fData = ilist;
285 return *this;
286 }
287
288 // conversion
289 template <typename U, typename = std::enable_if<std::is_convertible<T, U>::value>>
290 operator RVec<U>() const
291 {
292 RVec<U> ret(size());
293 std::copy(begin(), end(), ret.begin());
294 return ret;
295 }
296
297 const Impl_t &AsVector() const { return fData; }
298 Impl_t &AsVector() { return fData; }
299
300 // accessors
301 reference at(size_type pos) { return fData.at(pos); }
302 const_reference at(size_type pos) const { return fData.at(pos); }
303 reference operator[](size_type pos) { return fData[pos]; }
304 const_reference operator[](size_type pos) const { return fData[pos]; }
305
306 template <typename V, typename = std::enable_if<std::is_convertible<V, bool>::value>>
307 RVec operator[](const RVec<V> &conds) const
308 {
309 const size_type n = conds.size();
310
311 if (n != size())
312 throw std::runtime_error("Cannot index RVec with condition vector of different size");
313
314 RVec<T> ret;
315 ret.reserve(n);
316 for (size_type i = 0; i < n; ++i)
317 if (conds[i])
318 ret.emplace_back(fData[i]);
319 return ret;
320 }
321
322 reference front() { return fData.front(); }
323 const_reference front() const { return fData.front(); }
324 reference back() { return fData.back(); }
325 const_reference back() const { return fData.back(); }
326 data_t data() noexcept { return fData.data(); }
327 const_data_t data() const noexcept { return fData.data(); }
328 // iterators
329 iterator begin() noexcept { return fData.begin(); }
330 const_iterator begin() const noexcept { return fData.begin(); }
331 const_iterator cbegin() const noexcept { return fData.cbegin(); }
332 iterator end() noexcept { return fData.end(); }
333 const_iterator end() const noexcept { return fData.end(); }
334 const_iterator cend() const noexcept { return fData.cend(); }
335 reverse_iterator rbegin() noexcept { return fData.rbegin(); }
336 const_reverse_iterator rbegin() const noexcept { return fData.rbegin(); }
337 const_reverse_iterator crbegin() const noexcept { return fData.crbegin(); }
338 reverse_iterator rend() noexcept { return fData.rend(); }
339 const_reverse_iterator rend() const noexcept { return fData.rend(); }
340 const_reverse_iterator crend() const noexcept { return fData.crend(); }
341 // capacity
342 bool empty() const noexcept { return fData.empty(); }
343 size_type size() const noexcept { return fData.size(); }
344 size_type max_size() const noexcept { return fData.size(); }
345 void reserve(size_type new_cap) { fData.reserve(new_cap); }
346 size_type capacity() const noexcept { return fData.capacity(); }
347 void shrink_to_fit() { fData.shrink_to_fit(); };
348 // modifiers
349 void clear() noexcept { fData.clear(); }
350 iterator erase(iterator pos) { return fData.erase(pos); }
351 iterator erase(iterator first, iterator last) { return fData.erase(first, last); }
352 void push_back(T &&value) { fData.push_back(std::forward<T>(value)); }
353 void push_back(const value_type& value) { fData.push_back(value); };
354 template <class... Args>
355 reference emplace_back(Args &&... args)
356 {
357 using EBHelper_t = ROOT::Internal::VecOps::REmplaceBackHelper<Impl_t, Args...>;
358 EBHelper_t::EmplaceBack(fData, std::forward<Args>(args)...);
359 return fData.back();
360 }
361 /// This method is intended only for arithmetic types unlike the std::vector
362 /// corresponding one which is generic.
363 template<typename U = T, typename std::enable_if<std::is_arithmetic<U>::value, int>* = nullptr>
365 {
366 return fData.emplace(pos, value);
367 }
368 void pop_back() { fData.pop_back(); }
369 void resize(size_type count) { fData.resize(count); }
370 void resize(size_type count, const value_type &value) { fData.resize(count, value); }
371 void swap(RVec<T> &other) { std::swap(fData, other.fData); }
372};
373
374///@name RVec Unary Arithmetic Operators
375///@{
376
377#define TVEC_UNARY_OPERATOR(OP) \
378template <typename T> \
379RVec<T> operator OP(const RVec<T> &v) \
380{ \
381 RVec<T> ret(v); \
382 for (auto &x : ret) \
383 x = OP x; \
384return ret; \
385} \
386
391#undef TVEC_UNARY_OPERATOR
392
393///@}
394///@name RVec Binary Arithmetic Operators
395///@{
396
397#define ERROR_MESSAGE(OP) \
398 "Cannot call operator " #OP " on vectors of different sizes."
399
400#define TVEC_BINARY_OPERATOR(OP) \
401template <typename T0, typename T1> \
402auto operator OP(const RVec<T0> &v, const T1 &y) \
403 -> RVec<decltype(v[0] OP y)> \
404{ \
405 RVec<decltype(v[0] OP y)> ret(v.size()); \
406 auto op = [&y](const T0 &x) { return x OP y; }; \
407 std::transform(v.begin(), v.end(), ret.begin(), op); \
408 return ret; \
409} \
410 \
411template <typename T0, typename T1> \
412auto operator OP(const T0 &x, const RVec<T1> &v) \
413 -> RVec<decltype(x OP v[0])> \
414{ \
415 RVec<decltype(x OP v[0])> ret(v.size()); \
416 auto op = [&x](const T1 &y) { return x OP y; }; \
417 std::transform(v.begin(), v.end(), ret.begin(), op); \
418 return ret; \
419} \
420 \
421template <typename T0, typename T1> \
422auto operator OP(const RVec<T0> &v0, const RVec<T1> &v1) \
423 -> RVec<decltype(v0[0] OP v1[0])> \
424{ \
425 if (v0.size() != v1.size()) \
426 throw std::runtime_error(ERROR_MESSAGE(OP)); \
427 \
428 RVec<decltype(v0[0] OP v1[0])> ret(v0.size()); \
429 auto op = [](const T0 &x, const T1 &y) { return x OP y; }; \
430 std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), op); \
431 return ret; \
432} \
433
442#undef TVEC_BINARY_OPERATOR
443
444///@}
445///@name RVec Assignment Arithmetic Operators
446///@{
447
448#define TVEC_ASSIGNMENT_OPERATOR(OP) \
449template <typename T0, typename T1> \
450RVec<T0>& operator OP(RVec<T0> &v, const T1 &y) \
451{ \
452 auto op = [&y](T0 &x) { return x OP y; }; \
453 std::transform(v.begin(), v.end(), v.begin(), op); \
454 return v; \
455} \
456 \
457template <typename T0, typename T1> \
458RVec<T0>& operator OP(RVec<T0> &v0, const RVec<T1> &v1) \
459{ \
460 if (v0.size() != v1.size()) \
461 throw std::runtime_error(ERROR_MESSAGE(OP)); \
462 \
463 auto op = [](T0 &x, const T1 &y) { return x OP y; }; \
464 std::transform(v0.begin(), v0.end(), v1.begin(), v0.begin(), op); \
465 return v0; \
466} \
467
478#undef TVEC_ASSIGNMENT_OPERATOR
479
480///@}
481///@name RVec Comparison and Logical Operators
482///@{
483
484#define TVEC_LOGICAL_OPERATOR(OP) \
485template <typename T0, typename T1> \
486auto operator OP(const RVec<T0> &v, const T1 &y) \
487 -> RVec<int> /* avoid std::vector<bool> */ \
488{ \
489 RVec<int> ret(v.size()); \
490 auto op = [y](const T0 &x) -> int { return x OP y; }; \
491 std::transform(v.begin(), v.end(), ret.begin(), op); \
492 return ret; \
493} \
494 \
495template <typename T0, typename T1> \
496auto operator OP(const T0 &x, const RVec<T1> &v) \
497 -> RVec<int> /* avoid std::vector<bool> */ \
498{ \
499 RVec<int> ret(v.size()); \
500 auto op = [x](const T1 &y) -> int { return x OP y; }; \
501 std::transform(v.begin(), v.end(), ret.begin(), op); \
502 return ret; \
503} \
504 \
505template <typename T0, typename T1> \
506auto operator OP(const RVec<T0> &v0, const RVec<T1> &v1) \
507 -> RVec<int> /* avoid std::vector<bool> */ \
508{ \
509 if (v0.size() != v1.size()) \
510 throw std::runtime_error(ERROR_MESSAGE(OP)); \
511 \
512 RVec<int> ret(v0.size()); \
513 auto op = [](const T0 &x, const T1 &y) -> int { return x OP y; }; \
514 std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), op); \
515 return ret; \
516} \
517
526#undef TVEC_LOGICAL_OPERATOR
527
528///@}
529///@name RVec Standard Mathematical Functions
530///@{
531
532/// \cond
533template <typename T> struct PromoteTypeImpl;
534
535template <> struct PromoteTypeImpl<float> { using Type = float; };
536template <> struct PromoteTypeImpl<double> { using Type = double; };
537template <> struct PromoteTypeImpl<long double> { using Type = long double; };
538
539template <typename T> struct PromoteTypeImpl { using Type = double; };
540
541template <typename T>
542using PromoteType = typename PromoteTypeImpl<T>::Type;
543
544template <typename U, typename V>
545using PromoteTypes = decltype(PromoteType<U>() + PromoteType<V>());
546
547/// \endcond
548
549#define TVEC_UNARY_FUNCTION(NAME, FUNC) \
550 template <typename T> \
551 RVec<PromoteType<T>> NAME(const RVec<T> &v) \
552 { \
553 RVec<PromoteType<T>> ret(v.size()); \
554 auto f = [](const T &x) { return FUNC(x); }; \
555 std::transform(v.begin(), v.end(), ret.begin(), f); \
556 return ret; \
557 }
558
559#define TVEC_BINARY_FUNCTION(NAME, FUNC) \
560 template <typename T0, typename T1> \
561 RVec<PromoteTypes<T0, T1>> NAME(const T0 &x, const RVec<T1> &v) \
562 { \
563 RVec<PromoteTypes<T0, T1>> ret(v.size()); \
564 auto f = [&x](const T1 &y) { return FUNC(x, y); }; \
565 std::transform(v.begin(), v.end(), ret.begin(), f); \
566 return ret; \
567 } \
568 \
569 template <typename T0, typename T1> \
570 RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &v, const T1 &y) \
571 { \
572 RVec<PromoteTypes<T0, T1>> ret(v.size()); \
573 auto f = [&y](const T1 &x) { return FUNC(x, y); }; \
574 std::transform(v.begin(), v.end(), ret.begin(), f); \
575 return ret; \
576 } \
577 \
578 template <typename T0, typename T1> \
579 RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &v0, const RVec<T1> &v1) \
580 { \
581 if (v0.size() != v1.size()) \
582 throw std::runtime_error(ERROR_MESSAGE(NAME)); \
583 \
584 RVec<PromoteTypes<T0, T1>> ret(v0.size()); \
585 auto f = [](const T0 &x, const T1 &y) { return FUNC(x, y); }; \
586 std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), f); \
587 return ret; \
588 } \
589
590#define TVEC_STD_UNARY_FUNCTION(F) TVEC_UNARY_FUNCTION(F, std::F)
591#define TVEC_STD_BINARY_FUNCTION(F) TVEC_BINARY_FUNCTION(F, std::F)
592
597
601
606
611
619
626
633
638#undef TVEC_STD_UNARY_FUNCTION
639
640///@}
641///@name RVec Fast Mathematical Functions with Vdt
642///@{
643
644#ifdef R__HAS_VDT
645#define TVEC_VDT_UNARY_FUNCTION(F) TVEC_UNARY_FUNCTION(F, vdt::F)
646
647TVEC_VDT_UNARY_FUNCTION(fast_expf)
648TVEC_VDT_UNARY_FUNCTION(fast_logf)
649TVEC_VDT_UNARY_FUNCTION(fast_sinf)
650TVEC_VDT_UNARY_FUNCTION(fast_cosf)
651TVEC_VDT_UNARY_FUNCTION(fast_tanf)
652TVEC_VDT_UNARY_FUNCTION(fast_asinf)
653TVEC_VDT_UNARY_FUNCTION(fast_acosf)
654TVEC_VDT_UNARY_FUNCTION(fast_atanf)
655
656TVEC_VDT_UNARY_FUNCTION(fast_exp)
657TVEC_VDT_UNARY_FUNCTION(fast_log)
658TVEC_VDT_UNARY_FUNCTION(fast_sin)
659TVEC_VDT_UNARY_FUNCTION(fast_cos)
660TVEC_VDT_UNARY_FUNCTION(fast_tan)
661TVEC_VDT_UNARY_FUNCTION(fast_asin)
662TVEC_VDT_UNARY_FUNCTION(fast_acos)
663TVEC_VDT_UNARY_FUNCTION(fast_atan)
664#undef TVEC_VDT_UNARY_FUNCTION
665
666#endif // R__HAS_VDT
667
668#undef TVEC_UNARY_FUNCTION
669
670///@}
671
672/// Inner product
673///
674/// Example code, at the ROOT prompt:
675/// ~~~{.cpp}
676/// using namespace ROOT::VecOps;
677/// RVec<float> v1 {1., 2., 3.};
678/// RVec<float> v2 {4., 5., 6.};
679/// auto v1_dot_v2 = Dot(v1, v2);
680/// v1_dot_v2
681/// // (float) 32.f
682/// ~~~
683template <typename T, typename V>
684auto Dot(const RVec<T> &v0, const RVec<V> &v1) -> decltype(v0[0] * v1[0])
685{
686 if (v0.size() != v1.size())
687 throw std::runtime_error("Cannot compute inner product of vectors of different sizes");
688 return std::inner_product(v0.begin(), v0.end(), v1.begin(), decltype(v0[0] * v1[0])(0));
689}
690
691/// Sum elements of an RVec
692///
693/// Example code, at the ROOT prompt:
694/// ~~~{.cpp}
695/// using namespace ROOT::VecOps;
696/// RVec<float> v {1.f, 2.f, 3.f};
697/// auto v_sum = Sum(v);
698/// v_sum
699/// // (float) 6.f
700/// ~~~
701template <typename T>
702T Sum(const RVec<T> &v)
703{
704 return std::accumulate(v.begin(), v.end(), T(0));
705}
706
707/// Get the mean of the elements of an RVec
708///
709/// The return type is a double precision floating point number.
710/// Example code, at the ROOT prompt:
711/// ~~~{.cpp}
712/// using namespace ROOT::VecOps;
713/// RVec<float> v {1.f, 2.f, 4.f};
714/// auto v_mean = Mean(v);
715/// v_mean
716/// // (double) 2.3333333
717/// ~~~
718template <typename T>
719double Mean(const RVec<T> &v)
720{
721 if (v.empty()) return 0.;
722 return double(Sum(v)) / v.size();
723}
724
725/// Get the variance of the elements of an RVec
726///
727/// The return type is a double precision floating point number.
728/// Example code, at the ROOT prompt:
729/// ~~~{.cpp}
730/// using namespace ROOT::VecOps;
731/// RVec<float> v {1.f, 2.f, 4.f};
732/// auto v_var = Var(v);
733/// v_var
734/// // (double) 2.3333333
735/// ~~~
736template <typename T>
737double Var(const RVec<T> &v)
738{
739 const std::size_t size = v.size();
740 if (size < std::size_t(2)) return 0.;
741 T sum_squares(0), squared_sum(0);
742 auto pred = [&sum_squares, &squared_sum](const T& x) {sum_squares+=x*x; squared_sum+=x;};
743 std::for_each(v.begin(), v.end(), pred);
744 squared_sum *= squared_sum;
745 const auto dsize = (double) size;
746 return 1. / (dsize - 1.) * (sum_squares - squared_sum / dsize );
747}
748
749/// Get the standard deviation of the elements of an RVec
750///
751/// The return type is a double precision floating point number.
752/// Example code, at the ROOT prompt:
753/// ~~~{.cpp}
754/// using namespace ROOT::VecOps;
755/// RVec<float> v {1.f, 2.f, 4.f};
756/// auto v_sd = StdDev(v);
757/// v_sd
758/// // (double) 1.5275252
759/// ~~~
760template <typename T>
761double StdDev(const RVec<T> &v)
762{
763 return std::sqrt(Var(v));
764}
765
766/// Create new collection applying a callable to the elements of the input collection
767///
768/// Example code, at the ROOT prompt:
769/// ~~~{.cpp}
770/// using namespace ROOT::VecOps;
771/// RVec<float> v {1.f, 2.f, 4.f};
772/// auto v_square = Map(v, [](float f){return f* 2.f;});
773/// v_square
774/// // (ROOT::VecOps::RVec<float> &) { 2.00000f, 4.00000f, 8.00000f }
775/// ~~~
776template <typename T, typename F>
777auto Map(const RVec<T> &v, F &&f) -> RVec<decltype(f(v[0]))>
778{
779 RVec<decltype(f(v[0]))> ret(v.size());
780 std::transform(v.begin(), v.end(), ret.begin(), f);
781 return ret;
782}
783
784/// Create a new collection with the elements passing the filter expressed by the predicate
785///
786/// Example code, at the ROOT prompt:
787/// ~~~{.cpp}
788/// using namespace ROOT::VecOps;
789/// RVec<int> v {1, 2, 4};
790/// auto v_even = Filter(v, [](int i){return 0 == i%2;});
791/// v_even
792/// // (ROOT::VecOps::RVec<int> &) { 2, 4 }
793/// ~~~
794template <typename T, typename F>
796{
797 const auto thisSize = v.size();
798 RVec<T> w;
799 w.reserve(thisSize);
800 for (auto &&val : v) {
801 if (f(val))
802 w.emplace_back(val);
803 }
804 return w;
805}
806
807/// Return true if any of the elements equates to true, return false otherwise.
808///
809/// Example code, at the ROOT prompt:
810/// ~~~{.cpp}
811/// using namespace ROOT::VecOps;
812/// RVec<int> v {0, 1, 0};
813/// auto anyTrue = Any(v);
814/// anyTrue
815/// // (bool) true
816/// ~~~
817template <typename T>
818auto Any(const RVec<T> &v) -> decltype(v[0] == true)
819{
820 for (auto &&e : v)
821 if (e == true)
822 return true;
823 return false;
824}
825
826/// Return true if all of the elements equate to true, return false otherwise.
827///
828/// Example code, at the ROOT prompt:
829/// ~~~{.cpp}
830/// using namespace ROOT::VecOps;
831/// RVec<int> v {0, 1, 0};
832/// auto allTrue = All(v);
833/// allTrue
834/// // (bool) false
835/// ~~~
836template <typename T>
837auto All(const RVec<T> &v) -> decltype(v[0] == false)
838{
839 for (auto &&e : v)
840 if (e == false)
841 return false;
842 return true;
843}
844
845template <typename T>
846void swap(RVec<T> &lhs, RVec<T> &rhs)
847{
848 lhs.swap(rhs);
849}
850
851/// Return an RVec of indices that sort the input RVec
852///
853/// Example code, at the ROOT prompt:
854/// ~~~{.cpp}
855/// using namespace ROOT::VecOps;
856/// RVec<double> v {2., 3., 1.};
857/// auto sortIndices = Argsort(v);
858/// sortIndices
859/// // (ROOT::VecOps::RVec<unsigned long> &) { 2, 0, 1 }
860/// ~~~
861template <typename T>
863{
864 using size_type = typename RVec<T>::size_type;
865 RVec<size_type> i(v.size());
866 std::iota(i.begin(), i.end(), 0);
867 std::sort(i.begin(), i.end(), [&v](size_type i1, size_type i2) { return v[i1] < v[i2]; });
868 return i;
869}
870
871/// Return elements of a vector at given indices
872///
873/// Example code, at the ROOT prompt:
874/// ~~~{.cpp}
875/// using namespace ROOT::VecOps;
876/// RVec<double> v {2., 3., 1.};
877/// auto vTaken = Take(v, {0,2});
878/// vTaken
879/// // (ROOT::VecOps::RVec<double>) { 2.0000000, 1.0000000 }
880/// ~~~
881template <typename T>
882RVec<T> Take(const RVec<T> &v, const RVec<typename RVec<T>::size_type> &i)
883{
884 using size_type = typename RVec<T>::size_type;
885 const size_type isize = i.size();
886 RVec<T> r(isize);
887 for (size_type k = 0; k < isize; k++)
888 r[k] = v[i[k]];
889 return r;
890}
891
892/// Return first or last `n` elements of an RVec
893///
894/// if `n > 0` and last elements if `n < 0`.
895///
896/// Example code, at the ROOT prompt:
897/// ~~~{.cpp}
898/// using namespace ROOT::VecOps;
899/// RVec<double> v {2., 3., 1.};
900/// auto firstTwo = Take(v, 2);
901/// firstTwo
902/// // (ROOT::VecOps::RVec<double>) { 2.0000000, 3.0000000 }
903/// auto lastOne = Take(v, -1);
904/// lastOne
905/// // (ROOT::VecOps::RVec<double>) { 1.0000000 }
906/// ~~~
907template <typename T>
908RVec<T> Take(const RVec<T> &v, const int n)
909{
910 using size_type = typename RVec<T>::size_type;
911 const size_type size = v.size();
912 const size_type absn = std::abs(n);
913 if (absn > size) {
914 std::stringstream ss;
915 ss << "Try to take " << absn << " elements but vector has only size " << size << ".";
916 throw std::runtime_error(ss.str());
917 }
918 RVec<T> r(absn);
919 if (n < 0) {
920 for (size_type k = 0; k < absn; k++)
921 r[k] = v[size - absn + k];
922 } else {
923 for (size_type k = 0; k < absn; k++)
924 r[k] = v[k];
925 }
926 return r;
927}
928
929/// Return copy of reversed vector
930///
931/// Example code, at the ROOT prompt:
932/// ~~~{.cpp}
933/// using namespace ROOT::VecOps;
934/// RVec<double> v {2., 3., 1.};
935/// auto v_reverse = Reverse(v);
936/// v_reverse
937/// // (ROOT::VecOps::RVec<double>) { 1.0000000, 3.0000000, 2.0000000 }
938/// ~~~
939template <typename T>
941{
942 RVec<T> r(v);
943 std::reverse(r.begin(), r.end());
944 return r;
945}
946
947/// Return copy of RVec with elements sorted in ascending order
948///
949/// This helper is different from ArgSort since it does not return an RVec of indices,
950/// but an RVec of values.
951///
952/// Example code, at the ROOT prompt:
953/// ~~~{.cpp}
954/// using namespace ROOT::VecOps;
955/// RVec<double> v {2., 3., 1.};
956/// auto v_sorted = Sort(v);
957/// v_sorted
958/// // (ROOT::VecOps::RVec<double>) { 1.0000000, 2.0000000, 3.0000000 }
959/// ~~~
960template <typename T>
962{
963 RVec<T> r(v);
964 std::sort(r.begin(), r.end());
965 return r;
966}
967
968/// Return copy of RVec with elements sorted based on a comparison operator
969///
970/// The comparison operator has to fullfill the same requirements of the
971/// predicate of by std::sort.
972///
973///
974/// This helper is different from ArgSort since it does not return an RVec of indices,
975/// but an RVec of values.
976///
977/// Example code, at the ROOT prompt:
978/// ~~~{.cpp}
979/// using namespace ROOT::VecOps;
980/// RVec<double> v {2., 3., 1.};
981/// auto v_sorted = Sort(v, [](double x, double y) {return 1/x < 1/y;});
982/// v_sorted
983/// // (ROOT::VecOps::RVec<double>) { 3.0000000, 2.0000000, 1.0000000 }
984/// ~~~
985template <typename T, typename Compare>
987{
988 RVec<T> r(v);
989 std::sort(r.begin(), r.end(), std::forward<Compare>(c));
990 return r;
991}
992
993/// Return the indices that represent all combinations of the elements of two
994/// RVecs.
995///
996/// The type of the return value is an RVec of two RVecs containing indices.
997///
998/// Example code, at the ROOT prompt:
999/// ~~~{.cpp}
1000/// using namespace ROOT::VecOps;
1001/// RVec<double> v1 {1., 2., 3.};
1002/// RVec<double> v2 {-4., -5.};
1003/// auto comb_idx = Combinations(v1, v2);
1004/// comb_idx
1005/// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 1, 1, 2, 2 }, { 0, 1, 0, 1, 0, 1 } }
1006/// ~~~
1007template <typename T1, typename T2>
1009{
1010 using size_type = typename RVec<T1>::size_type;
1011 size_type size1 = v1.size();
1012 size_type size2 = v2.size();
1014 r[0].resize(size1*size2);
1015 r[1].resize(size1*size2);
1016 size_type c = 0;
1017 for(size_type i=0; i<size1; i++) {
1018 for(size_type j=0; j<size2; j++) {
1019 r[0][c] = i;
1020 r[1][c] = j;
1021 c++;
1022 }
1023 }
1024 return r;
1025}
1026
1027/// Return the indices that represent all unique combinations of the
1028/// elements of a given RVec.
1029///
1030/// ~~~{.cpp}
1031/// using namespace ROOT::VecOps;
1032/// RVec<double> v {1., 2., 3., 4.};
1033/// auto v_1 = Combinations(v, 1);
1034/// v_1
1035/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 1, 2, 3 } }
1036/// auto v_2 = Combinations(v, 2);
1037/// auto v_2
1038/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 0, 1, 1, 2 }, { 1, 2, 3, 2, 3, 3 } }
1039/// auto v_3 = Combinations(v, 3);
1040/// v_3
1041/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 0, 1 }, { 1, 1, 2, 2 }, { 2, 3, 3, 3 } }
1042/// auto v_4 = Combinations(v, 4);
1043/// v_4
1044/// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0 }, { 1 }, { 2 }, { 3 } }
1045/// ~~~
1046template <typename T>
1048{
1049 using size_type = typename RVec<T>::size_type;
1050 const size_type s = v.size();
1051 if (n > s) {
1052 std::stringstream ss;
1053 ss << "Cannot make unique combinations of size " << n << " from vector of size " << s << ".";
1054 throw std::runtime_error(ss.str());
1055 }
1057 for(size_type k=0; k<s; k++)
1058 indices[k] = k;
1060 for(size_type k=0; k<n; k++)
1061 c[k].emplace_back(indices[k]);
1062 while (true) {
1063 bool run_through = true;
1064 long i = n - 1;
1065 for (; i>=0; i--) {
1066 if (indices[i] != i + s - n){
1067 run_through = false;
1068 break;
1069 }
1070 }
1071 if (run_through) {
1072 return c;
1073 }
1074 indices[i]++;
1075 for (long j=i+1; j<(long)n; j++)
1076 indices[j] = indices[j-1] + 1;
1077 for(size_type k=0; k<n; k++)
1078 c[k].emplace_back(indices[k]);
1079 }
1080}
1081
1082/// Return the indices of the elements which are not zero
1083///
1084/// Example code, at the ROOT prompt:
1085/// ~~~{.cpp}
1086/// using namespace ROOT::VecOps;
1087/// RVec<double> v {2., 0., 3., 0., 1.};
1088/// auto nonzero_idx = Nonzero(v);
1089/// nonzero_idx
1090/// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type>) { 0, 2, 4 }
1091/// ~~~
1092template <typename T>
1094{
1095 using size_type = typename RVec<T>::size_type;
1097 const auto size = v.size();
1098 r.reserve(size);
1099 for(size_type i=0; i<size; i++) {
1100 if(v[i] != 0) {
1101 r.emplace_back(i);
1102 }
1103 }
1104 return r;
1105}
1106
1107/// Return the intersection of elements of two RVecs.
1108///
1109/// Each element of v1 is looked up in v2 and added to the returned vector if
1110/// found. Following, the order of v1 is preserved. If v2 is already sorted, the
1111/// optional argument v2_is_sorted can be used to toggle of the internal sorting
1112/// step, therewith optimising runtime.
1113///
1114/// Example code, at the ROOT prompt:
1115/// ~~~{.cpp}
1116/// using namespace ROOT::VecOps;
1117/// RVec<double> v1 {1., 2., 3.};
1118/// RVec<double> v2 {-4., -5., 2., 1.};
1119/// auto v1_intersect_v2 = Intersect(v1, v2);
1120/// v1_intersect_v2
1121/// // (ROOT::VecOps::RVec<double>) { 1.0000000, 2.0000000 }
1122/// ~~~
1123template <typename T>
1124RVec<T> Intersect(const RVec<T>& v1, const RVec<T>& v2, bool v2_is_sorted = false)
1125{
1126 RVec<T> v2_sorted;
1127 if (!v2_is_sorted) v2_sorted = Sort(v2);
1128 const auto v2_begin = v2_is_sorted ? v2.begin() : v2_sorted.begin();
1129 const auto v2_end = v2_is_sorted ? v2.end() : v2_sorted.end();
1130 RVec<T> r;
1131 const auto size = v1.size();
1132 r.reserve(size);
1133 using size_type = typename RVec<T>::size_type;
1134 for(size_type i=0; i<size; i++) {
1135 if (std::binary_search(v2_begin, v2_end, v1[i])) {
1136 r.emplace_back(v1[i]);
1137 }
1138 }
1139 return r;
1140}
1141
1142/// Return the elements of v1 if the condition c is true and v2 if the
1143/// condition c is false.
1144///
1145/// Example code, at the ROOT prompt:
1146/// ~~~{.cpp}
1147/// using namespace ROOT::VecOps;
1148/// RVec<double> v1 {1., 2., 3.};
1149/// RVec<double> v2 {-1., -2., -3.};
1150/// auto c = v1 > 1;
1151/// c
1152/// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
1153/// auto if_c_v1_else_v2 = Where(c, v1, v2);
1154/// if_c_v1_else_v2
1155/// // (ROOT::VecOps::RVec<double> &) { -1.0000000, 2.0000000, 3.0000000 }
1156/// ~~~
1157template <typename T>
1158RVec<T> Where(const RVec<int>& c, const RVec<T>& v1, const RVec<T>& v2)
1159{
1160 using size_type = typename RVec<T>::size_type;
1161 const size_type size = c.size();
1162 RVec<T> r;
1163 r.reserve(size);
1164 for (size_type i=0; i<size; i++) {
1165 r.emplace_back(c[i] != 0 ? v1[i] : v2[i]);
1166 }
1167 return r;
1168}
1169
1170/// Return the elements of v1 if the condition c is true and sets the value v2
1171/// if the condition c is false.
1172///
1173/// Example code, at the ROOT prompt:
1174/// ~~~{.cpp}
1175/// using namespace ROOT::VecOps;
1176/// RVec<double> v1 {1., 2., 3.};
1177/// double v2 = 4.;
1178/// auto c = v1 > 1;
1179/// c
1180/// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
1181/// auto if_c_v1_else_v2 = Where(c, v1, v2);
1182/// if_c_v1_else_v2
1183/// // (ROOT::VecOps::RVec<double>) { 4.0000000, 2.0000000, 3.0000000 }
1184/// ~~~
1185template <typename T>
1186RVec<T> Where(const RVec<int>& c, const RVec<T>& v1, T v2)
1187{
1188 using size_type = typename RVec<T>::size_type;
1189 const size_type size = c.size();
1190 RVec<T> r;
1191 r.reserve(size);
1192 for (size_type i=0; i<size; i++) {
1193 r.emplace_back(c[i] != 0 ? v1[i] : v2);
1194 }
1195 return r;
1196}
1197
1198/// Return the elements of v2 if the condition c is false and sets the value v1
1199/// if the condition c is true.
1200///
1201/// Example code, at the ROOT prompt:
1202/// ~~~{.cpp}
1203/// using namespace ROOT::VecOps;
1204/// double v1 = 4.;
1205/// RVec<double> v2 {1., 2., 3.};
1206/// auto c = v2 > 1;
1207/// c
1208/// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
1209/// auto if_c_v1_else_v2 = Where(c, v1, v2);
1210/// if_c_v1_else_v2
1211/// // (ROOT::VecOps::RVec<double>) { 1.0000000, 4.0000000, 4.0000000 }
1212/// ~~~
1213template <typename T>
1214RVec<T> Where(const RVec<int>& c, T v1, const RVec<T>& v2)
1215{
1216 using size_type = typename RVec<T>::size_type;
1217 const size_type size = c.size();
1218 RVec<T> r;
1219 r.reserve(size);
1220 for (size_type i=0; i<size; i++) {
1221 r.emplace_back(c[i] != 0 ? v1 : v2[i]);
1222 }
1223 return r;
1224}
1225
1226/// Return a vector with the value v2 if the condition c is false and sets the
1227/// value v1 if the condition c is true.
1228///
1229/// Example code, at the ROOT prompt:
1230/// ~~~{.cpp}
1231/// using namespace ROOT::VecOps;
1232/// double v1 = 4.;
1233/// double v2 = 2.;
1234/// RVec<int> c {0, 1, 1};
1235/// auto if_c_v1_else_v2 = Where(c, v1, v2);
1236/// if_c_v1_else_v2
1237/// // (ROOT::VecOps::RVec<double>) { 2.0000000, 4.0000000, 4.0000000 }
1238/// ~~~
1239template <typename T>
1240RVec<T> Where(const RVec<int>& c, T v1, T v2)
1241{
1242 using size_type = typename RVec<T>::size_type;
1243 const size_type size = c.size();
1244 RVec<T> r;
1245 r.reserve(size);
1246 for (size_type i=0; i<size; i++) {
1247 r.emplace_back(c[i] != 0 ? v1 : v2);
1248 }
1249 return r;
1250}
1251
1252////////////////////////////////////////////////////////////////////////////////
1253/// Print a RVec at the prompt:
1254template <class T>
1255std::ostream &operator<<(std::ostream &os, const RVec<T> &v)
1256{
1257 // In order to print properly, convert to 64 bit int if this is a char
1258 constexpr bool mustConvert = std::is_same<char, T>::value || std::is_same<signed char, T>::value ||
1259 std::is_same<unsigned char, T>::value || std::is_same<wchar_t, T>::value ||
1260 std::is_same<char16_t, T>::value || std::is_same<char32_t, T>::value;
1262 os << "{ ";
1263 auto size = v.size();
1264 if (size) {
1265 for (std::size_t i = 0; i < size - 1; ++i) {
1266 os << (Print_t)v[i] << ", ";
1267 }
1268 os << (Print_t)v[size - 1];
1269 }
1270 os << " }";
1271 return os;
1272}
1273
1274#if (_VECOPS_USE_EXTERN_TEMPLATES)
1275
1276#define TVEC_EXTERN_UNARY_OPERATOR(T, OP) \
1277 extern template RVec<T> operator OP<T>(const RVec<T> &);
1278
1279#define TVEC_EXTERN_BINARY_OPERATOR(T, OP) \
1280 extern template auto operator OP<T, T>(const T &x, const RVec<T> &v) \
1281 -> RVec<decltype(x OP v[0])>; \
1282 extern template auto operator OP<T, T>(const RVec<T> &v, const T &y) \
1283 -> RVec<decltype(v[0] OP y)>; \
1284 extern template auto operator OP<T, T>(const RVec<T> &v0, const RVec<T> &v1)\
1285 -> RVec<decltype(v0[0] OP v1[0])>;
1286
1287#define TVEC_EXTERN_ASSIGN_OPERATOR(T, OP) \
1288 extern template RVec<T> &operator OP<T, T>(RVec<T> &, const T &); \
1289 extern template RVec<T> &operator OP<T, T>(RVec<T> &, const RVec<T> &);
1290
1291#define TVEC_EXTERN_LOGICAL_OPERATOR(T, OP) \
1292 extern template RVec<int> operator OP<T, T>(const RVec<T> &, const T &); \
1293 extern template RVec<int> operator OP<T, T>(const T &, const RVec<T> &); \
1294 extern template RVec<int> operator OP<T, T>(const RVec<T> &, const RVec<T> &);
1295
1296#define TVEC_EXTERN_FLOAT_TEMPLATE(T) \
1297 extern template class RVec<T>; \
1298 TVEC_EXTERN_UNARY_OPERATOR(T, +) \
1299 TVEC_EXTERN_UNARY_OPERATOR(T, -) \
1300 TVEC_EXTERN_UNARY_OPERATOR(T, !) \
1301 TVEC_EXTERN_BINARY_OPERATOR(T, +) \
1302 TVEC_EXTERN_BINARY_OPERATOR(T, -) \
1303 TVEC_EXTERN_BINARY_OPERATOR(T, *) \
1304 TVEC_EXTERN_BINARY_OPERATOR(T, /) \
1305 TVEC_EXTERN_ASSIGN_OPERATOR(T, +=) \
1306 TVEC_EXTERN_ASSIGN_OPERATOR(T, -=) \
1307 TVEC_EXTERN_ASSIGN_OPERATOR(T, *=) \
1308 TVEC_EXTERN_ASSIGN_OPERATOR(T, /=) \
1309 TVEC_EXTERN_LOGICAL_OPERATOR(T, <) \
1310 TVEC_EXTERN_LOGICAL_OPERATOR(T, >) \
1311 TVEC_EXTERN_LOGICAL_OPERATOR(T, ==) \
1312 TVEC_EXTERN_LOGICAL_OPERATOR(T, !=) \
1313 TVEC_EXTERN_LOGICAL_OPERATOR(T, <=) \
1314 TVEC_EXTERN_LOGICAL_OPERATOR(T, >=) \
1315 TVEC_EXTERN_LOGICAL_OPERATOR(T, &&) \
1316 TVEC_EXTERN_LOGICAL_OPERATOR(T, ||)
1317
1318#define TVEC_EXTERN_INTEGER_TEMPLATE(T) \
1319 extern template class RVec<T>; \
1320 TVEC_EXTERN_UNARY_OPERATOR(T, +) \
1321 TVEC_EXTERN_UNARY_OPERATOR(T, -) \
1322 TVEC_EXTERN_UNARY_OPERATOR(T, ~) \
1323 TVEC_EXTERN_UNARY_OPERATOR(T, !) \
1324 TVEC_EXTERN_BINARY_OPERATOR(T, +) \
1325 TVEC_EXTERN_BINARY_OPERATOR(T, -) \
1326 TVEC_EXTERN_BINARY_OPERATOR(T, *) \
1327 TVEC_EXTERN_BINARY_OPERATOR(T, /) \
1328 TVEC_EXTERN_BINARY_OPERATOR(T, %) \
1329 TVEC_EXTERN_BINARY_OPERATOR(T, &) \
1330 TVEC_EXTERN_BINARY_OPERATOR(T, |) \
1331 TVEC_EXTERN_BINARY_OPERATOR(T, ^) \
1332 TVEC_EXTERN_ASSIGN_OPERATOR(T, +=) \
1333 TVEC_EXTERN_ASSIGN_OPERATOR(T, -=) \
1334 TVEC_EXTERN_ASSIGN_OPERATOR(T, *=) \
1335 TVEC_EXTERN_ASSIGN_OPERATOR(T, /=) \
1336 TVEC_EXTERN_ASSIGN_OPERATOR(T, %=) \
1337 TVEC_EXTERN_ASSIGN_OPERATOR(T, &=) \
1338 TVEC_EXTERN_ASSIGN_OPERATOR(T, |=) \
1339 TVEC_EXTERN_ASSIGN_OPERATOR(T, ^=) \
1340 TVEC_EXTERN_ASSIGN_OPERATOR(T, >>=) \
1341 TVEC_EXTERN_ASSIGN_OPERATOR(T, <<=) \
1342 TVEC_EXTERN_LOGICAL_OPERATOR(T, <) \
1343 TVEC_EXTERN_LOGICAL_OPERATOR(T, >) \
1344 TVEC_EXTERN_LOGICAL_OPERATOR(T, ==) \
1345 TVEC_EXTERN_LOGICAL_OPERATOR(T, !=) \
1346 TVEC_EXTERN_LOGICAL_OPERATOR(T, <=) \
1347 TVEC_EXTERN_LOGICAL_OPERATOR(T, >=) \
1348 TVEC_EXTERN_LOGICAL_OPERATOR(T, &&) \
1349 TVEC_EXTERN_LOGICAL_OPERATOR(T, ||)
1350
1351TVEC_EXTERN_INTEGER_TEMPLATE(char)
1352TVEC_EXTERN_INTEGER_TEMPLATE(short)
1353TVEC_EXTERN_INTEGER_TEMPLATE(int)
1354TVEC_EXTERN_INTEGER_TEMPLATE(long)
1355//TVEC_EXTERN_INTEGER_TEMPLATE(long long)
1356
1357TVEC_EXTERN_INTEGER_TEMPLATE(unsigned char)
1358TVEC_EXTERN_INTEGER_TEMPLATE(unsigned short)
1359TVEC_EXTERN_INTEGER_TEMPLATE(unsigned int)
1360TVEC_EXTERN_INTEGER_TEMPLATE(unsigned long)
1361//TVEC_EXTERN_INTEGER_TEMPLATE(unsigned long long)
1362
1363TVEC_EXTERN_FLOAT_TEMPLATE(float)
1364TVEC_EXTERN_FLOAT_TEMPLATE(double)
1365
1366#undef TVEC_EXTERN_UNARY_OPERATOR
1367#undef TVEC_EXTERN_BINARY_OPERATOR
1368#undef TVEC_EXTERN_ASSIGN_OPERATOR
1369#undef TVEC_EXTERN_LOGICAL_OPERATOR
1370#undef TVEC_EXTERN_INTEGER_TEMPLATE
1371#undef TVEC_EXTERN_FLOAT_TEMPLATE
1372
1373#define TVEC_EXTERN_UNARY_FUNCTION(T, NAME, FUNC) \
1374 extern template RVec<PromoteType<T>> NAME(const RVec<T> &);
1375
1376#define TVEC_EXTERN_STD_UNARY_FUNCTION(T, F) TVEC_EXTERN_UNARY_FUNCTION(T, F, std::F)
1377
1378#define TVEC_EXTERN_BINARY_FUNCTION(T0, T1, NAME, FUNC) \
1379 extern template RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &, const T1 &); \
1380 extern template RVec<PromoteTypes<T0, T1>> NAME(const T0 &, const RVec<T1> &); \
1381 extern template RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &, const RVec<T1> &);
1382
1383#define TVEC_EXTERN_STD_BINARY_FUNCTION(T, F) TVEC_EXTERN_BINARY_FUNCTION(T, T, F, std::F)
1384
1385#define TVEC_EXTERN_STD_FUNCTIONS(T) \
1386 TVEC_EXTERN_STD_UNARY_FUNCTION(T, abs) \
1387 TVEC_EXTERN_STD_BINARY_FUNCTION(T, fdim) \
1388 TVEC_EXTERN_STD_BINARY_FUNCTION(T, fmod) \
1389 TVEC_EXTERN_STD_BINARY_FUNCTION(T, remainder) \
1390 TVEC_EXTERN_STD_UNARY_FUNCTION(T, exp) \
1391 TVEC_EXTERN_STD_UNARY_FUNCTION(T, exp2) \
1392 TVEC_EXTERN_STD_UNARY_FUNCTION(T, expm1) \
1393 TVEC_EXTERN_STD_UNARY_FUNCTION(T, log) \
1394 TVEC_EXTERN_STD_UNARY_FUNCTION(T, log10) \
1395 TVEC_EXTERN_STD_UNARY_FUNCTION(T, log2) \
1396 TVEC_EXTERN_STD_UNARY_FUNCTION(T, log1p) \
1397 TVEC_EXTERN_STD_BINARY_FUNCTION(T, pow) \
1398 TVEC_EXTERN_STD_UNARY_FUNCTION(T, sqrt) \
1399 TVEC_EXTERN_STD_UNARY_FUNCTION(T, cbrt) \
1400 TVEC_EXTERN_STD_BINARY_FUNCTION(T, hypot) \
1401 TVEC_EXTERN_STD_UNARY_FUNCTION(T, sin) \
1402 TVEC_EXTERN_STD_UNARY_FUNCTION(T, cos) \
1403 TVEC_EXTERN_STD_UNARY_FUNCTION(T, tan) \
1404 TVEC_EXTERN_STD_UNARY_FUNCTION(T, asin) \
1405 TVEC_EXTERN_STD_UNARY_FUNCTION(T, acos) \
1406 TVEC_EXTERN_STD_UNARY_FUNCTION(T, atan) \
1407 TVEC_EXTERN_STD_BINARY_FUNCTION(T, atan2) \
1408 TVEC_EXTERN_STD_UNARY_FUNCTION(T, sinh) \
1409 TVEC_EXTERN_STD_UNARY_FUNCTION(T, cosh) \
1410 TVEC_EXTERN_STD_UNARY_FUNCTION(T, tanh) \
1411 TVEC_EXTERN_STD_UNARY_FUNCTION(T, asinh) \
1412 TVEC_EXTERN_STD_UNARY_FUNCTION(T, acosh) \
1413 TVEC_EXTERN_STD_UNARY_FUNCTION(T, atanh) \
1414 TVEC_EXTERN_STD_UNARY_FUNCTION(T, floor) \
1415 TVEC_EXTERN_STD_UNARY_FUNCTION(T, ceil) \
1416 TVEC_EXTERN_STD_UNARY_FUNCTION(T, trunc) \
1417 TVEC_EXTERN_STD_UNARY_FUNCTION(T, round) \
1418 TVEC_EXTERN_STD_UNARY_FUNCTION(T, erf) \
1419 TVEC_EXTERN_STD_UNARY_FUNCTION(T, erfc) \
1420 TVEC_EXTERN_STD_UNARY_FUNCTION(T, lgamma) \
1421 TVEC_EXTERN_STD_UNARY_FUNCTION(T, tgamma) \
1422
1423TVEC_EXTERN_STD_FUNCTIONS(float)
1424TVEC_EXTERN_STD_FUNCTIONS(double)
1425#undef TVEC_EXTERN_STD_UNARY_FUNCTION
1426#undef TVEC_EXTERN_STD_BINARY_FUNCTION
1427#undef TVEC_EXTERN_STD_UNARY_FUNCTIONS
1428
1429#ifdef R__HAS_VDT
1430
1431#define TVEC_EXTERN_VDT_UNARY_FUNCTION(T, F) TVEC_EXTERN_UNARY_FUNCTION(T, F, vdt::F)
1432
1433TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_expf)
1434TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_logf)
1435TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_sinf)
1436TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_cosf)
1437TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_tanf)
1438TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_asinf)
1439TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_acosf)
1440TVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_atanf)
1441
1442TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_exp)
1443TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_log)
1444TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_sin)
1445TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_cos)
1446TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_tan)
1447TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_asin)
1448TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_acos)
1449TVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_atan)
1450
1451#endif // R__HAS_VDT
1452
1453#endif // _VECOPS_USE_EXTERN_TEMPLATES
1454
1455} // End of VecOps NS
1456
1457// Allow to use RVec as ROOT::RVec
1458using ROOT::VecOps::RVec;
1459
1460} // End of ROOT NS
1461
1462#endif
SVector< double, 2 > v
Definition: Dict.h:5
ROOT::R::TRInterface & r
Definition: Object.C:4
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
#define e(i)
Definition: RSha256.hxx:103
#define TVEC_STD_UNARY_FUNCTION(F)
Definition: RVec.hxx:590
#define TVEC_UNARY_OPERATOR(OP)
Definition: RVec.hxx:377
#define TVEC_BINARY_OPERATOR(OP)
Definition: RVec.hxx:400
#define TVEC_STD_BINARY_FUNCTION(F)
Definition: RVec.hxx:591
#define TVEC_ASSIGNMENT_OPERATOR(OP)
Definition: RVec.hxx:448
#define TVEC_LOGICAL_OPERATOR(OP)
Definition: RVec.hxx:484
static Int_t init()
Int_t Compare(const void *item1, const void *item2)
int type
Definition: TGX11.cxx:120
double atan2(double, double)
double tanh(double)
double cosh(double)
double ceil(double)
double acos(double)
double sinh(double)
double cos(double)
double pow(double, double)
double log10(double)
double floor(double)
double atan(double)
double tan(double)
double sqrt(double)
double sin(double)
double asin(double)
double exp(double)
double log(double)
A "std::vector"-like collection of values implementing handy operation to analyse them.
Definition: RVec.hxx:221
typename std::conditional< IsVecBool, std::vector< bool >, std::vector< T, ::ROOT::Detail::VecOps::RAdoptAllocator< T > > >::type Impl_t
Definition: RVec.hxx:228
typename Impl_t::iterator iterator
Definition: RVec.hxx:240
static constexpr const auto IsVecBool
Definition: RVec.hxx:226
const_iterator begin() const noexcept
Definition: RVec.hxx:330
RVec(const RVec< T > &v)
Definition: RVec.hxx:256
reverse_iterator rbegin() noexcept
Definition: RVec.hxx:335
const_iterator cbegin() const noexcept
Definition: RVec.hxx:331
typename Impl_t::value_type value_type
Definition: RVec.hxx:229
reference operator[](size_type pos)
Definition: RVec.hxx:303
void clear() noexcept
Definition: RVec.hxx:349
iterator erase(iterator pos)
Definition: RVec.hxx:350
RVec< T > & operator=(std::initializer_list< T > ilist)
Definition: RVec.hxx:282
typename Impl_t::const_pointer const_pointer
Definition: RVec.hxx:235
RVec(std::initializer_list< T > init)
Definition: RVec.hxx:267
void resize(size_type count)
Definition: RVec.hxx:369
void push_back(T &&value)
Definition: RVec.hxx:352
const_reference back() const
Definition: RVec.hxx:325
typename Impl_t::difference_type difference_type
Definition: RVec.hxx:231
const_reverse_iterator crbegin() const noexcept
Definition: RVec.hxx:337
RVec operator[](const RVec< V > &conds) const
Definition: RVec.hxx:307
iterator erase(iterator first, iterator last)
Definition: RVec.hxx:351
RVec< T > & operator=(RVec< T > &&v)
Definition: RVec.hxx:276
const_reverse_iterator crend() const noexcept
Definition: RVec.hxx:340
const_reference at(size_type pos) const
Definition: RVec.hxx:302
typename Impl_t::const_iterator const_iterator
Definition: RVec.hxx:241
bool empty() const noexcept
Definition: RVec.hxx:342
reference back()
Definition: RVec.hxx:324
typename Impl_t::reference reference
Definition: RVec.hxx:232
void push_back(const value_type &value)
Definition: RVec.hxx:353
iterator end() noexcept
Definition: RVec.hxx:332
size_type size() const noexcept
Definition: RVec.hxx:343
RVec(size_type count, const T &value)
Definition: RVec.hxx:254
const_iterator end() const noexcept
Definition: RVec.hxx:333
iterator emplace(const_iterator pos, U value)
This method is intended only for arithmetic types unlike the std::vector corresponding one which is g...
Definition: RVec.hxx:364
typename Impl_t::const_reference const_reference
Definition: RVec.hxx:233
const_iterator cend() const noexcept
Definition: RVec.hxx:334
RVec(RVec< T > &&v)
Definition: RVec.hxx:258
RVec(size_type count)
Definition: RVec.hxx:252
typename Impl_t::const_reverse_iterator const_reverse_iterator
Definition: RVec.hxx:243
const_reference front() const
Definition: RVec.hxx:323
void reserve(size_type new_cap)
Definition: RVec.hxx:345
reference at(size_type pos)
Definition: RVec.hxx:301
const_reverse_iterator rend() const noexcept
Definition: RVec.hxx:339
typename std::conditional< IsVecBool, void, typename Impl_t::pointer >::type data_t
Definition: RVec.hxx:238
reference front()
Definition: RVec.hxx:322
typename Impl_t::reverse_iterator reverse_iterator
Definition: RVec.hxx:242
const_reference operator[](size_type pos) const
Definition: RVec.hxx:304
typename Impl_t::pointer pointer
Definition: RVec.hxx:234
size_type capacity() const noexcept
Definition: RVec.hxx:346
reverse_iterator rend() noexcept
Definition: RVec.hxx:338
RVec< T > & operator=(const RVec< T > &v)
Definition: RVec.hxx:270
typename std::conditional< IsVecBool, void, typename Impl_t::const_pointer >::type const_data_t
Definition: RVec.hxx:239
void shrink_to_fit()
Definition: RVec.hxx:347
const Impl_t & AsVector() const
Definition: RVec.hxx:297
iterator begin() noexcept
Definition: RVec.hxx:329
Impl_t & AsVector()
Definition: RVec.hxx:298
const_reverse_iterator rbegin() const noexcept
Definition: RVec.hxx:336
typename Impl_t::size_type size_type
Definition: RVec.hxx:230
void resize(size_type count, const value_type &value)
Definition: RVec.hxx:370
reference emplace_back(Args &&... args)
Definition: RVec.hxx:355
const_data_t data() const noexcept
Definition: RVec.hxx:327
RVec(const std::vector< T > &v)
Definition: RVec.hxx:260
data_t data() noexcept
Definition: RVec.hxx:326
void swap(RVec< T > &other)
Definition: RVec.hxx:371
RVec(InputIt first, InputIt last)
Definition: RVec.hxx:265
RVec(pointer p, size_type n)
Definition: RVec.hxx:262
void pop_back()
Definition: RVec.hxx:368
size_type max_size() const noexcept
Definition: RVec.hxx:344
Type
enumeration specifying the integration types.
double erfc(double x)
Complementary error function.
double tgamma(double x)
The gamma function is defined to be the extension of the factorial to real numbers.
double lgamma(double x)
Calculates the logarithm of the gamma function.
double erf(double x)
Error function encountered in integrating the normal distribution.
Double_t x[n]
Definition: legend1.C:17
const Int_t n
Definition: legend1.C:16
#define F(x, y, z)
double T(double x)
Definition: ChebyshevPol.h:34
double log1p(double x)
declarations for functions which are not implemented by some compilers
Definition: Math.h:100
double expm1(double x)
exp(x) -1 with error cancellation when x is small
Definition: Math.h:112
double inner_product(const LAVector &, const LAVector &)
RVec< T > Reverse(const RVec< T > &v)
Return copy of reversed vector.
Definition: RVec.hxx:940
RVec< T > Intersect(const RVec< T > &v1, const RVec< T > &v2, bool v2_is_sorted=false)
Return the intersection of elements of two RVecs.
Definition: RVec.hxx:1124
auto All(const RVec< T > &v) -> decltype(v[0]==false)
Return true if all of the elements equate to true, return false otherwise.
Definition: RVec.hxx:837
T Sum(const RVec< T > &v)
Sum elements of an RVec.
Definition: RVec.hxx:702
RVec< typename RVec< T >::size_type > Nonzero(const RVec< T > &v)
Return the indices of the elements which are not zero.
Definition: RVec.hxx:1093
RVec< T > Sort(const RVec< T > &v)
Return copy of RVec with elements sorted in ascending order.
Definition: RVec.hxx:961
std::ostream & operator<<(std::ostream &os, const RVec< T > &v)
Print a RVec at the prompt:
Definition: RVec.hxx:1255
double Mean(const RVec< T > &v)
Get the mean of the elements of an RVec.
Definition: RVec.hxx:719
RVec< RVec< typename RVec< T1 >::size_type > > Combinations(const RVec< T1 > &v1, const RVec< T2 > &v2)
Return the indices that represent all combinations of the elements of two RVecs.
Definition: RVec.hxx:1008
RVec< T > Take(const RVec< T > &v, const RVec< typename RVec< T >::size_type > &i)
Return elements of a vector at given indices.
Definition: RVec.hxx:882
void swap(RVec< T > &lhs, RVec< T > &rhs)
Definition: RVec.hxx:846
auto Dot(const RVec< T > &v0, const RVec< V > &v1) -> decltype(v0[0] *v1[0])
Inner product.
Definition: RVec.hxx:684
RVec< T > Where(const RVec< int > &c, const RVec< T > &v1, const RVec< T > &v2)
Return the elements of v1 if the condition c is true and v2 if the condition c is false.
Definition: RVec.hxx:1158
double StdDev(const RVec< T > &v)
Get the standard deviation of the elements of an RVec.
Definition: RVec.hxx:761
auto Any(const RVec< T > &v) -> decltype(v[0]==true)
Return true if any of the elements equates to true, return false otherwise.
Definition: RVec.hxx:818
auto Map(const RVec< T > &v, F &&f) -> RVec< decltype(f(v[0]))>
Create new collection applying a callable to the elements of the input collection.
Definition: RVec.hxx:777
RVec< typename RVec< T >::size_type > Argsort(const RVec< T > &v)
Return an RVec of indices that sort the input RVec.
Definition: RVec.hxx:862
double Var(const RVec< T > &v)
Get the variance of the elements of an RVec.
Definition: RVec.hxx:737
RVec< T > Filter(const RVec< T > &v, F &&f)
Create a new collection with the elements passing the filter expressed by the predicate.
Definition: RVec.hxx:795
Namespace for new ROOT classes and functions.
Definition: StringConv.hxx:21
static constexpr double s
Definition: first.py:1
STL namespace.
void swap(nlohmann::json &j1, nlohmann::json &j2) noexcept(is_nothrow_move_constructible< nlohmann::json >::value and is_nothrow_move_assignable< nlohmann::json >::value)
exchanges the values of two JSON objects
Definition: json.hpp:12929
static void EmplaceBack(std::vector< bool > &v, Args &&... args)
Definition: RVec.hxx:63
static void EmplaceBack(T &v, Args &&... args)
Definition: RVec.hxx:55