Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
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_RVEC
16 #define ROOT_RVEC
17 
18 #ifdef _WIN32
19  #define _VECOPS_USE_EXTERN_TEMPLATES false
20 #else
21  #define _VECOPS_USE_EXTERN_TEMPLATES true
22 #endif
23 
24 #include <ROOT/RAdoptAllocator.hxx>
26 #include <ROOT/RStringView.hxx>
27 #include <TError.h> // R__ASSERT
28 #include <ROOT/TypeTraits.hxx>
29 
30 #include <algorithm>
31 #include <cmath>
32 #include <numeric> // for inner_product
33 #include <sstream>
34 #include <stdexcept>
35 #include <type_traits>
36 #include <vector>
37 #include <utility>
38 
39 #define _USE_MATH_DEFINES // enable definition of M_PI
40 #ifdef _WIN32
41 // cmath does not expose M_PI on windows
42 #include <math.h>
43 #else
44 #include <cmath>
45 #endif
46 
47 #ifdef R__HAS_VDT
48 #include <vdt/vdtMath.h>
49 #endif
50 
51 
52 namespace ROOT {
53 namespace VecOps {
54 template<typename T>
55 class RVec;
56 }
57 
58 namespace Detail {
59 namespace VecOps {
60 
61 template<typename T>
62 using RVec = ROOT::VecOps::RVec<T>;
63 
64 template <typename... T>
65 std::size_t GetVectorsSize(std::string_view id, const RVec<T> &... vs)
66 {
67  constexpr const auto nArgs = sizeof...(T);
68  const std::size_t sizes[] = {vs.size()...};
69  if (nArgs > 1) {
70  for (auto i = 1UL; i < nArgs; i++) {
71  if (sizes[0] == sizes[i])
72  continue;
73  std::string msg(id);
74  msg += ": input RVec instances have different lengths!";
75  throw std::runtime_error(msg);
76  }
77  }
78  return sizes[0];
79 }
80 
81 template <typename F, typename... T>
82 auto MapImpl(F &&f, const RVec<T> &... vs) -> RVec<decltype(f(vs[0]...))>
83 {
84  const auto size = GetVectorsSize("Map", vs...);
85  RVec<decltype(f(vs[0]...))> ret(size);
86 
87  for (auto i = 0UL; i < size; i++)
88  ret[i] = f(vs[i]...);
89 
90  return ret;
91 }
92 
93 template <typename Tuple_t, std::size_t... Is>
94 auto MapFromTuple(Tuple_t &&t, std::index_sequence<Is...>)
95  -> decltype(MapImpl(std::get<std::tuple_size<Tuple_t>::value - 1>(t), std::get<Is>(t)...))
96 {
97  constexpr const auto tupleSizeM1 = std::tuple_size<Tuple_t>::value - 1;
98  return MapImpl(std::get<tupleSizeM1>(t), std::get<Is>(t)...);
99 }
100 
101 }
102 }
103 
104 namespace Internal {
105 namespace VecOps {
106 
107 // We use this helper to workaround a limitation of compilers such as
108 // gcc 4.8 amd clang on osx 10.14 for which std::vector<bool>::emplace_back
109 // is not defined.
110 template <typename T, typename... Args>
111 void EmplaceBack(T &v, Args &&... args)
112 {
113  v.emplace_back(std::forward<Args>(args)...);
114 }
115 
116 template <typename... Args>
117 void EmplaceBack(std::vector<bool> &v, Args &&... args)
118 {
119  v.push_back(std::forward<Args>(args)...);
120 }
121 
122 } // End of VecOps NS
123 } // End of Internal NS
124 
125 namespace VecOps {
126 // clang-format off
127 /**
128 \class ROOT::VecOps::RVec
129 \ingroup vecops
130 \brief A "std::vector"-like collection of values implementing handy operation to analyse them
131 \tparam T The type of the contained objects
132 
133 A RVec is a container designed to make analysis of values' collections fast and easy.
134 Its storage is contiguous in memory and its interface is designed such to resemble to the one
135 of the stl vector. In addition the interface features methods and external functions to ease
136 the manipulation and analysis of the data in the RVec.
137 
138 \htmlonly
139 <a href="https://doi.org/10.5281/zenodo.1253756"><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.1253756.svg" alt="DOI"></a>
140 \endhtmlonly
141 
142 ## Table of Contents
143 - [Example](#example)
144 - [Owning and adopting memory](#owningandadoptingmemory)
145 - [Sorting and manipulation of indices](#sorting)
146 - [Usage in combination with RDataFrame](#usagetdataframe)
147 - [Reference for the RVec class](#RVecdoxyref)
148 
149 Also see the [reference for RVec helper functions](https://root.cern/doc/master/namespaceROOT_1_1VecOps.html).
150 
151 ## <a name="example"></a>Example
152 Suppose to have an event featuring a collection of muons with a certain pseudorapidity,
153 momentum and charge, e.g.:
154 ~~~{.cpp}
155 std::vector<short> mu_charge {1, 1, -1, -1, -1, 1, 1, -1};
156 std::vector<float> mu_pt {56, 45, 32, 24, 12, 8, 7, 6.2};
157 std::vector<float> mu_eta {3.1, -.2, -1.1, 1, 4.1, 1.6, 2.4, -.5};
158 ~~~
159 Suppose you want to extract the transverse momenta of the muons satisfying certain
160 criteria, for example consider only negatively charged muons with a pseudorapidity
161 smaller or equal to 2 and with a transverse momentum greater than 10 GeV.
162 Such a selection would require, among the other things, the management of an explicit
163 loop, for example:
164 ~~~{.cpp}
165 std::vector<float> goodMuons_pt;
166 const auto size = mu_charge.size();
167 for (size_t i=0; i < size; ++i) {
168  if (mu_pt[i] > 10 && abs(mu_eta[i]) <= 2. && mu_charge[i] == -1) {
169  goodMuons_pt.emplace_back(mu_pt[i]);
170  }
171 }
172 ~~~
173 These operations become straightforward with RVec - we just need to *write what
174 we mean*:
175 ~~~{.cpp}
176 auto goodMuons_pt = mu_pt[ (mu_pt > 10.f && abs(mu_eta) <= 2.f && mu_charge == -1) ]
177 ~~~
178 Now the clean collection of transverse momenta can be used within the rest of the data analysis, for
179 example to fill a histogram.
180 
181 ## <a name="owningandadoptingmemory"></a>Owning and adopting memory
182 RVec has contiguous memory associated to it. It can own it or simply adopt it. In the latter case,
183 it can be constructed with the address of the memory associated to it and its length. For example:
184 ~~~{.cpp}
185 std::vector<int> myStlVec {1,2,3};
186 RVec<int> myRVec(myStlVec.data(), myStlVec.size());
187 ~~~
188 In this case, the memory associated to myStlVec and myRVec is the same, myRVec simply "adopted it".
189 If any method which implies a re-allocation is called, e.g. *emplace_back* or *resize*, the adopted
190 memory is released and new one is allocated. The previous content is copied in the new memory and
191 preserved.
192 
193 ## <a name="#sorting"></a>Sorting and manipulation of indices
194 
195 ### Sorting
196 RVec complies to the STL interfaces when it comes to iterations. As a result, standard algorithms
197 can be used, for example sorting:
198 ~~~{.cpp}
199 RVec<double> v{6., 4., 5.};
200 std::sort(v.begin(), v.end());
201 ~~~
202 
203 For convinience, helpers are provided too:
204 ~~~{.cpp}
205 auto sorted_v = Sort(v);
206 auto reversed_v = Reverse(v);
207 ~~~
208 
209 ### Manipulation of indices
210 
211 It is also possible to manipulated the RVecs acting on their indices. For example,
212 the following syntax
213 ~~~{.cpp}
214 RVec<double> v0 {9., 7., 8.};
215 auto v1 = Take(v0, {1, 2, 0});
216 ~~~
217 will yield a new RVec<double> the content of which is the first, second and zeroth element of
218 v0, i.e. `{7., 8., 9.}`.
219 
220 The `Argsort` helper extracts the indices which order the content of a `RVec`. For example,
221 this snippet accomplish in a more expressive way what we just achieved:
222 ~~~{.cpp}
223 auto v1_indices = Argsort(v0); // The content of v1_indices is {1, 2, 0}.
224 v1 = Take(v0, v1_indices);
225 ~~~
226 
227 The `Take` utility allows to extract portions of the `RVec`. The content to be *taken*
228 can be specified with an `RVec` of indices or an integer. If the integer is negative,
229 elements will be picked starting from the end of the container:
230 ~~~{.cpp}
231 RVec<float> vf {1.f, 2.f, 3.f, 4.f};
232 auto vf_1 = Take(vf, {1, 3}); // The content is {2.f, 4.f}
233 auto vf_2 = Take(vf, 2); // The content is {1.f, 2.f}
234 auto vf_3 = Take(vf, -3); // The content is {2.f, 3.f, 4.f}
235 ~~~
236 
237 ## <a name="usagetdataframe"></a>Usage in combination with RDataFrame
238 RDataFrame leverages internally RVecs. Suppose to have a dataset stored in a
239 TTree which holds these columns (here we choose C arrays to represent the
240 collections, they could be as well std::vector instances):
241 ~~~{.bash}
242  nPart "nPart/I" An integer representing the number of particles
243  px "px[nPart]/D" The C array of the particles' x component of the momentum
244  py "py[nPart]/D" The C array of the particles' y component of the momentum
245  E "E[nPart]/D" The C array of the particles' Energy
246 ~~~
247 Suppose you'd like to plot in a histogram the transverse momenta of all particles
248 for which the energy is greater than 200 MeV.
249 The code required would just be:
250 ~~~{.cpp}
251 RDataFrame d("mytree", "myfile.root");
252 using doubles = RVec<double>;
253 auto cutPt = [](doubles &pxs, doubles &pys, doubles &Es) {
254  auto all_pts = sqrt(pxs * pxs + pys * pys);
255  auto good_pts = all_pts[Es > 200.];
256  return good_pts;
257  };
258 
259 auto hpt = d.Define("pt", cutPt, {"px", "py", "E"})
260  .Histo1D("pt");
261 hpt->Draw();
262 ~~~
263 And if you'd like to express your selection as a string:
264 ~~~{.cpp}
265 RDataFrame d("mytree", "myfile.root");
266 auto hpt = d.Define("pt", "sqrt(pxs * pxs + pys * pys)[E>200]")
267  .Histo1D("pt");
268 hpt->Draw();
269 ~~~
270 <a name="RVecdoxyref"></a>
271 **/
272 // clang-format on
273 template <typename T>
274 class RVec {
275  // Here we check if T is a bool. This is done in order to decide what type
276  // to use as a storage. If T is anything but bool, we use a vector<T, RAdoptAllocator<T>>.
277  // If T is a bool, we opt for a plain vector<bool> otherwise we'll not be able
278  // to write the data type given the shortcomings of TCollectionProxy design.
279  static constexpr const auto IsVecBool = std::is_same<bool, T>::value;
280 public:
281  using Impl_t = typename std::conditional<IsVecBool, std::vector<bool>, std::vector<T, ::ROOT::Detail::VecOps::RAdoptAllocator<T>>>::type;
282  using value_type = typename Impl_t::value_type;
283  using size_type = typename Impl_t::size_type;
284  using difference_type = typename Impl_t::difference_type;
285  using reference = typename Impl_t::reference;
286  using const_reference = typename Impl_t::const_reference;
287  using pointer = typename Impl_t::pointer;
288  using const_pointer = typename Impl_t::const_pointer;
289  // The data_t and const_data_t types are chosen to be void in case T is a bool.
290  // This way we can as elegantly as in the STL return void upon calling the data() method.
291  using data_t = typename std::conditional<IsVecBool, void, typename Impl_t::pointer>::type;
292  using const_data_t = typename std::conditional<IsVecBool, void, typename Impl_t::const_pointer>::type;
293  using iterator = typename Impl_t::iterator;
294  using const_iterator = typename Impl_t::const_iterator;
295  using reverse_iterator = typename Impl_t::reverse_iterator;
296  using const_reverse_iterator = typename Impl_t::const_reverse_iterator;
297 
298 private:
299  Impl_t fData;
300 
301 public:
302  // constructors
303  RVec() {}
304 
305  explicit RVec(size_type count) : fData(count) {}
306 
307  RVec(size_type count, const T &value) : fData(count, value) {}
308 
309  RVec(const RVec<T> &v) : fData(v.fData) {}
310 
311  RVec(RVec<T> &&v) : fData(std::move(v.fData)) {}
312 
313  RVec(const std::vector<T> &v) : fData(v.cbegin(), v.cend()) {}
314 
315  RVec(pointer p, size_type n) : fData(n, T(), ROOT::Detail::VecOps::RAdoptAllocator<T>(p)) {}
316 
317  template <class InputIt>
318  RVec(InputIt first, InputIt last) : fData(first, last) {}
319 
320  RVec(std::initializer_list<T> init) : fData(init) {}
321 
322  // assignment
323  RVec<T> &operator=(const RVec<T> &v)
324  {
325  fData = v.fData;
326  return *this;
327  }
328 
329  RVec<T> &operator=(RVec<T> &&v)
330  {
331  std::swap(fData, v.fData);
332  return *this;
333  }
334 
335  RVec<T> &operator=(std::initializer_list<T> ilist)
336  {
337  fData = ilist;
338  return *this;
339  }
340 
341  // conversion
342  template <typename U, typename = std::enable_if<std::is_convertible<T, U>::value>>
343  operator RVec<U>() const
344  {
345  RVec<U> ret(size());
346  std::copy(begin(), end(), ret.begin());
347  return ret;
348  }
349 
350  const Impl_t &AsVector() const { return fData; }
351  Impl_t &AsVector() { return fData; }
352 
353  // accessors
354  reference at(size_type pos) { return fData.at(pos); }
355  const_reference at(size_type pos) const { return fData.at(pos); }
356  /// No exception thrown. The user specifies the desired value in case the RVec is shorter than `pos`.
357  value_type at(size_type pos, value_type fallback) { return pos < fData.size() ? fData[pos] : fallback; }
358  /// No exception thrown. The user specifies the desired value in case the RVec is shorter than `pos`.
359  value_type at(size_type pos, value_type fallback) const { return pos < fData.size() ? fData[pos] : fallback; }
360  reference operator[](size_type pos) { return fData[pos]; }
361  const_reference operator[](size_type pos) const { return fData[pos]; }
362 
363  template <typename V, typename = std::enable_if<std::is_convertible<V, bool>::value>>
364  RVec operator[](const RVec<V> &conds) const
365  {
366  const size_type n = conds.size();
367 
368  if (n != size())
369  throw std::runtime_error("Cannot index RVec with condition vector of different size");
370 
371  RVec<T> ret;
372  ret.reserve(n);
373  for (size_type i = 0; i < n; ++i)
374  if (conds[i])
375  ret.emplace_back(fData[i]);
376  return ret;
377  }
378 
379  reference front() { return fData.front(); }
380  const_reference front() const { return fData.front(); }
381  reference back() { return fData.back(); }
382  const_reference back() const { return fData.back(); }
383  data_t data() noexcept { return fData.data(); }
384  const_data_t data() const noexcept { return fData.data(); }
385  // iterators
386  iterator begin() noexcept { return fData.begin(); }
387  const_iterator begin() const noexcept { return fData.begin(); }
388  const_iterator cbegin() const noexcept { return fData.cbegin(); }
389  iterator end() noexcept { return fData.end(); }
390  const_iterator end() const noexcept { return fData.end(); }
391  const_iterator cend() const noexcept { return fData.cend(); }
392  reverse_iterator rbegin() noexcept { return fData.rbegin(); }
393  const_reverse_iterator rbegin() const noexcept { return fData.rbegin(); }
394  const_reverse_iterator crbegin() const noexcept { return fData.crbegin(); }
395  reverse_iterator rend() noexcept { return fData.rend(); }
396  const_reverse_iterator rend() const noexcept { return fData.rend(); }
397  const_reverse_iterator crend() const noexcept { return fData.crend(); }
398  // capacity
399  bool empty() const noexcept { return fData.empty(); }
400  size_type size() const noexcept { return fData.size(); }
401  size_type max_size() const noexcept { return fData.size(); }
402  void reserve(size_type new_cap) { fData.reserve(new_cap); }
403  size_type capacity() const noexcept { return fData.capacity(); }
404  void shrink_to_fit() { fData.shrink_to_fit(); };
405  // modifiers
406  void clear() noexcept { fData.clear(); }
407  iterator erase(iterator pos) { return fData.erase(pos); }
408  iterator erase(iterator first, iterator last) { return fData.erase(first, last); }
409  void push_back(T &&value) { fData.push_back(std::forward<T>(value)); }
410  void push_back(const value_type& value) { fData.push_back(value); };
411  template <class... Args>
412  reference emplace_back(Args &&... args)
413  {
414  ROOT::Internal::VecOps::EmplaceBack(fData, std::forward<Args>(args)...);
415  return fData.back();
416  }
417  /// This method is intended only for arithmetic types unlike the std::vector
418  /// corresponding one which is generic.
419  template<typename U = T, typename std::enable_if<std::is_arithmetic<U>::value, int>* = nullptr>
420  iterator emplace(const_iterator pos, U value)
421  {
422  return fData.emplace(pos, value);
423  }
424  void pop_back() { fData.pop_back(); }
425  void resize(size_type count) { fData.resize(count); }
426  void resize(size_type count, const value_type &value) { fData.resize(count, value); }
427  void swap(RVec<T> &other) { std::swap(fData, other.fData); }
428 };
429 
430 ///@name RVec Unary Arithmetic Operators
431 ///@{
432 
433 #define RVEC_UNARY_OPERATOR(OP) \
434 template <typename T> \
435 RVec<T> operator OP(const RVec<T> &v) \
436 { \
437  RVec<T> ret(v); \
438  for (auto &x : ret) \
439  x = OP x; \
440 return ret; \
441 } \
442 
443 RVEC_UNARY_OPERATOR(+)
444 RVEC_UNARY_OPERATOR(-)
445 RVEC_UNARY_OPERATOR(~)
446 RVEC_UNARY_OPERATOR(!)
447 #undef RVEC_UNARY_OPERATOR
448 
449 ///@}
450 ///@name RVec Binary Arithmetic Operators
451 ///@{
452 
453 #define ERROR_MESSAGE(OP) \
454  "Cannot call operator " #OP " on vectors of different sizes."
455 
456 #define RVEC_BINARY_OPERATOR(OP) \
457 template <typename T0, typename T1> \
458 auto operator OP(const RVec<T0> &v, const T1 &y) \
459  -> RVec<decltype(v[0] OP y)> \
460 { \
461  RVec<decltype(v[0] OP y)> ret(v.size()); \
462  auto op = [&y](const T0 &x) { return x OP y; }; \
463  std::transform(v.begin(), v.end(), ret.begin(), op); \
464  return ret; \
465 } \
466  \
467 template <typename T0, typename T1> \
468 auto operator OP(const T0 &x, const RVec<T1> &v) \
469  -> RVec<decltype(x OP v[0])> \
470 { \
471  RVec<decltype(x OP v[0])> ret(v.size()); \
472  auto op = [&x](const T1 &y) { return x OP y; }; \
473  std::transform(v.begin(), v.end(), ret.begin(), op); \
474  return ret; \
475 } \
476  \
477 template <typename T0, typename T1> \
478 auto operator OP(const RVec<T0> &v0, const RVec<T1> &v1) \
479  -> RVec<decltype(v0[0] OP v1[0])> \
480 { \
481  if (v0.size() != v1.size()) \
482  throw std::runtime_error(ERROR_MESSAGE(OP)); \
483  \
484  RVec<decltype(v0[0] OP v1[0])> ret(v0.size()); \
485  auto op = [](const T0 &x, const T1 &y) { return x OP y; }; \
486  std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), op); \
487  return ret; \
488 } \
489 
490 RVEC_BINARY_OPERATOR(+)
491 RVEC_BINARY_OPERATOR(-)
492 RVEC_BINARY_OPERATOR(*)
493 RVEC_BINARY_OPERATOR(/)
494 RVEC_BINARY_OPERATOR(%)
495 RVEC_BINARY_OPERATOR(^)
496 RVEC_BINARY_OPERATOR(|)
497 RVEC_BINARY_OPERATOR(&)
498 #undef RVEC_BINARY_OPERATOR
499 
500 ///@}
501 ///@name RVec Assignment Arithmetic Operators
502 ///@{
503 
504 #define RVEC_ASSIGNMENT_OPERATOR(OP) \
505 template <typename T0, typename T1> \
506 RVec<T0>& operator OP(RVec<T0> &v, const T1 &y) \
507 { \
508  auto op = [&y](T0 &x) { return x OP y; }; \
509  std::transform(v.begin(), v.end(), v.begin(), op); \
510  return v; \
511 } \
512  \
513 template <typename T0, typename T1> \
514 RVec<T0>& operator OP(RVec<T0> &v0, const RVec<T1> &v1) \
515 { \
516  if (v0.size() != v1.size()) \
517  throw std::runtime_error(ERROR_MESSAGE(OP)); \
518  \
519  auto op = [](T0 &x, const T1 &y) { return x OP y; }; \
520  std::transform(v0.begin(), v0.end(), v1.begin(), v0.begin(), op); \
521  return v0; \
522 } \
523 
524 RVEC_ASSIGNMENT_OPERATOR(+=)
525 RVEC_ASSIGNMENT_OPERATOR(-=)
526 RVEC_ASSIGNMENT_OPERATOR(*=)
527 RVEC_ASSIGNMENT_OPERATOR(/=)
528 RVEC_ASSIGNMENT_OPERATOR(%=)
529 RVEC_ASSIGNMENT_OPERATOR(^=)
530 RVEC_ASSIGNMENT_OPERATOR(|=)
531 RVEC_ASSIGNMENT_OPERATOR(&=)
532 RVEC_ASSIGNMENT_OPERATOR(>>=)
533 RVEC_ASSIGNMENT_OPERATOR(<<=)
534 #undef RVEC_ASSIGNMENT_OPERATOR
535 
536 ///@}
537 ///@name RVec Comparison and Logical Operators
538 ///@{
539 
540 #define RVEC_LOGICAL_OPERATOR(OP) \
541 template <typename T0, typename T1> \
542 auto operator OP(const RVec<T0> &v, const T1 &y) \
543  -> RVec<int> /* avoid std::vector<bool> */ \
544 { \
545  RVec<int> ret(v.size()); \
546  auto op = [y](const T0 &x) -> int { return x OP y; }; \
547  std::transform(v.begin(), v.end(), ret.begin(), op); \
548  return ret; \
549 } \
550  \
551 template <typename T0, typename T1> \
552 auto operator OP(const T0 &x, const RVec<T1> &v) \
553  -> RVec<int> /* avoid std::vector<bool> */ \
554 { \
555  RVec<int> ret(v.size()); \
556  auto op = [x](const T1 &y) -> int { return x OP y; }; \
557  std::transform(v.begin(), v.end(), ret.begin(), op); \
558  return ret; \
559 } \
560  \
561 template <typename T0, typename T1> \
562 auto operator OP(const RVec<T0> &v0, const RVec<T1> &v1) \
563  -> RVec<int> /* avoid std::vector<bool> */ \
564 { \
565  if (v0.size() != v1.size()) \
566  throw std::runtime_error(ERROR_MESSAGE(OP)); \
567  \
568  RVec<int> ret(v0.size()); \
569  auto op = [](const T0 &x, const T1 &y) -> int { return x OP y; }; \
570  std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), op); \
571  return ret; \
572 } \
573 
574 RVEC_LOGICAL_OPERATOR(<)
575 RVEC_LOGICAL_OPERATOR(>)
576 RVEC_LOGICAL_OPERATOR(==)
577 RVEC_LOGICAL_OPERATOR(!=)
578 RVEC_LOGICAL_OPERATOR(<=)
579 RVEC_LOGICAL_OPERATOR(>=)
580 RVEC_LOGICAL_OPERATOR(&&)
581 RVEC_LOGICAL_OPERATOR(||)
582 #undef RVEC_LOGICAL_OPERATOR
583 
584 ///@}
585 ///@name RVec Standard Mathematical Functions
586 ///@{
587 
588 /// \cond
589 template <typename T> struct PromoteTypeImpl;
590 
591 template <> struct PromoteTypeImpl<float> { using Type = float; };
592 template <> struct PromoteTypeImpl<double> { using Type = double; };
593 template <> struct PromoteTypeImpl<long double> { using Type = long double; };
594 
595 template <typename T> struct PromoteTypeImpl { using Type = double; };
596 
597 template <typename T>
598 using PromoteType = typename PromoteTypeImpl<T>::Type;
599 
600 template <typename U, typename V>
601 using PromoteTypes = decltype(PromoteType<U>() + PromoteType<V>());
602 
603 /// \endcond
604 
605 #define RVEC_UNARY_FUNCTION(NAME, FUNC) \
606  template <typename T> \
607  RVec<PromoteType<T>> NAME(const RVec<T> &v) \
608  { \
609  RVec<PromoteType<T>> ret(v.size()); \
610  auto f = [](const T &x) { return FUNC(x); }; \
611  std::transform(v.begin(), v.end(), ret.begin(), f); \
612  return ret; \
613  }
614 
615 #define RVEC_BINARY_FUNCTION(NAME, FUNC) \
616  template <typename T0, typename T1> \
617  RVec<PromoteTypes<T0, T1>> NAME(const T0 &x, const RVec<T1> &v) \
618  { \
619  RVec<PromoteTypes<T0, T1>> ret(v.size()); \
620  auto f = [&x](const T1 &y) { return FUNC(x, y); }; \
621  std::transform(v.begin(), v.end(), ret.begin(), f); \
622  return ret; \
623  } \
624  \
625  template <typename T0, typename T1> \
626  RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &v, const T1 &y) \
627  { \
628  RVec<PromoteTypes<T0, T1>> ret(v.size()); \
629  auto f = [&y](const T1 &x) { return FUNC(x, y); }; \
630  std::transform(v.begin(), v.end(), ret.begin(), f); \
631  return ret; \
632  } \
633  \
634  template <typename T0, typename T1> \
635  RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &v0, const RVec<T1> &v1) \
636  { \
637  if (v0.size() != v1.size()) \
638  throw std::runtime_error(ERROR_MESSAGE(NAME)); \
639  \
640  RVec<PromoteTypes<T0, T1>> ret(v0.size()); \
641  auto f = [](const T0 &x, const T1 &y) { return FUNC(x, y); }; \
642  std::transform(v0.begin(), v0.end(), v1.begin(), ret.begin(), f); \
643  return ret; \
644  } \
645 
646 #define RVEC_STD_UNARY_FUNCTION(F) RVEC_UNARY_FUNCTION(F, std::F)
647 #define RVEC_STD_BINARY_FUNCTION(F) RVEC_BINARY_FUNCTION(F, std::F)
648 
649 RVEC_STD_UNARY_FUNCTION(abs)
650 RVEC_STD_BINARY_FUNCTION(fdim)
651 RVEC_STD_BINARY_FUNCTION(fmod)
652 RVEC_STD_BINARY_FUNCTION(remainder)
653 
654 RVEC_STD_UNARY_FUNCTION(exp)
655 RVEC_STD_UNARY_FUNCTION(exp2)
656 RVEC_STD_UNARY_FUNCTION(expm1)
657 
658 RVEC_STD_UNARY_FUNCTION(log)
659 RVEC_STD_UNARY_FUNCTION(log10)
660 RVEC_STD_UNARY_FUNCTION(log2)
661 RVEC_STD_UNARY_FUNCTION(log1p)
662 
663 RVEC_STD_BINARY_FUNCTION(pow)
664 RVEC_STD_UNARY_FUNCTION(sqrt)
665 RVEC_STD_UNARY_FUNCTION(cbrt)
666 RVEC_STD_BINARY_FUNCTION(hypot)
667 
668 RVEC_STD_UNARY_FUNCTION(sin)
669 RVEC_STD_UNARY_FUNCTION(cos)
670 RVEC_STD_UNARY_FUNCTION(tan)
671 RVEC_STD_UNARY_FUNCTION(asin)
672 RVEC_STD_UNARY_FUNCTION(acos)
673 RVEC_STD_UNARY_FUNCTION(atan)
674 RVEC_STD_BINARY_FUNCTION(atan2)
675 
676 RVEC_STD_UNARY_FUNCTION(sinh)
677 RVEC_STD_UNARY_FUNCTION(cosh)
678 RVEC_STD_UNARY_FUNCTION(tanh)
679 RVEC_STD_UNARY_FUNCTION(asinh)
680 RVEC_STD_UNARY_FUNCTION(acosh)
681 RVEC_STD_UNARY_FUNCTION(atanh)
682 
683 RVEC_STD_UNARY_FUNCTION(floor)
684 RVEC_STD_UNARY_FUNCTION(ceil)
685 RVEC_STD_UNARY_FUNCTION(trunc)
686 RVEC_STD_UNARY_FUNCTION(round)
687 RVEC_STD_UNARY_FUNCTION(lround)
688 RVEC_STD_UNARY_FUNCTION(llround)
689 
690 RVEC_STD_UNARY_FUNCTION(erf)
691 RVEC_STD_UNARY_FUNCTION(erfc)
692 RVEC_STD_UNARY_FUNCTION(lgamma)
693 RVEC_STD_UNARY_FUNCTION(tgamma)
694 #undef RVEC_STD_UNARY_FUNCTION
695 
696 ///@}
697 ///@name RVec Fast Mathematical Functions with Vdt
698 ///@{
699 
700 #ifdef R__HAS_VDT
701 #define RVEC_VDT_UNARY_FUNCTION(F) RVEC_UNARY_FUNCTION(F, vdt::F)
702 
703 RVEC_VDT_UNARY_FUNCTION(fast_expf)
704 RVEC_VDT_UNARY_FUNCTION(fast_logf)
705 RVEC_VDT_UNARY_FUNCTION(fast_sinf)
706 RVEC_VDT_UNARY_FUNCTION(fast_cosf)
707 RVEC_VDT_UNARY_FUNCTION(fast_tanf)
708 RVEC_VDT_UNARY_FUNCTION(fast_asinf)
709 RVEC_VDT_UNARY_FUNCTION(fast_acosf)
710 RVEC_VDT_UNARY_FUNCTION(fast_atanf)
711 
712 RVEC_VDT_UNARY_FUNCTION(fast_exp)
713 RVEC_VDT_UNARY_FUNCTION(fast_log)
714 RVEC_VDT_UNARY_FUNCTION(fast_sin)
715 RVEC_VDT_UNARY_FUNCTION(fast_cos)
716 RVEC_VDT_UNARY_FUNCTION(fast_tan)
717 RVEC_VDT_UNARY_FUNCTION(fast_asin)
718 RVEC_VDT_UNARY_FUNCTION(fast_acos)
719 RVEC_VDT_UNARY_FUNCTION(fast_atan)
720 #undef RVEC_VDT_UNARY_FUNCTION
721 
722 #endif // R__HAS_VDT
723 
724 #undef RVEC_UNARY_FUNCTION
725 
726 ///@}
727 
728 /// Inner product
729 ///
730 /// Example code, at the ROOT prompt:
731 /// ~~~{.cpp}
732 /// using namespace ROOT::VecOps;
733 /// RVec<float> v1 {1., 2., 3.};
734 /// RVec<float> v2 {4., 5., 6.};
735 /// auto v1_dot_v2 = Dot(v1, v2);
736 /// v1_dot_v2
737 /// // (float) 32.f
738 /// ~~~
739 template <typename T, typename V>
740 auto Dot(const RVec<T> &v0, const RVec<V> &v1) -> decltype(v0[0] * v1[0])
741 {
742  if (v0.size() != v1.size())
743  throw std::runtime_error("Cannot compute inner product of vectors of different sizes");
744  return std::inner_product(v0.begin(), v0.end(), v1.begin(), decltype(v0[0] * v1[0])(0));
745 }
746 
747 /// Sum elements of an RVec
748 ///
749 /// Example code, at the ROOT prompt:
750 /// ~~~{.cpp}
751 /// using namespace ROOT::VecOps;
752 /// RVec<float> v {1.f, 2.f, 3.f};
753 /// auto v_sum = Sum(v);
754 /// v_sum
755 /// // (float) 6.f
756 /// ~~~
757 template <typename T>
758 T Sum(const RVec<T> &v)
759 {
760  return std::accumulate(v.begin(), v.end(), T(0));
761 }
762 
763 /// Get the mean of the elements of an RVec
764 ///
765 /// The return type is a double precision floating point number.
766 /// Example code, at the ROOT prompt:
767 /// ~~~{.cpp}
768 /// using namespace ROOT::VecOps;
769 /// RVec<float> v {1.f, 2.f, 4.f};
770 /// auto v_mean = Mean(v);
771 /// v_mean
772 /// // (double) 2.3333333
773 /// ~~~
774 template <typename T>
775 double Mean(const RVec<T> &v)
776 {
777  if (v.empty()) return 0.;
778  return double(Sum(v)) / v.size();
779 }
780 
781 /// Get the greatest element of an RVec
782 ///
783 /// Example code, at the ROOT prompt:
784 /// ~~~~{.cpp}
785 /// using namespace ROOT::VecOps;
786 /// RVec<float> v {1.f, 2.f, 4.f};
787 /// auto v_max = Max(v)
788 /// v_max
789 /// (float) 4.f
790 /// ~~~~
791 template <typename T>
792 T Max(const RVec<T> &v)
793 {
794  return *std::max_element(v.begin(), v.end());
795 }
796 
797 /// Get the smallest element of an RVec
798 ///
799 /// Example code, at the ROOT prompt:
800 /// ~~~~{.cpp}
801 /// using namespace ROOT::VecOps;
802 /// RVec<float> v {1.f, 2.f, 4.f};
803 /// auto v_min = Min(v)
804 /// v_min
805 /// (float) 1.f
806 /// ~~~~
807 template <typename T>
808 T Min(const RVec<T> &v)
809 {
810  return *std::min_element(v.begin(), v.end());
811 }
812 
813 /// Get the index of the greatest element of an RVec
814 /// In case of multiple occurrences of the maximum values,
815 /// the index corresponding to the first occurrence is returned.
816 ///
817 /// Example code, at the ROOT prompt:
818 /// ~~~~{.cpp}
819 /// using namespace ROOT::VecOps;
820 /// RVec<float> v {1.f, 2.f, 4.f};
821 /// auto v_argmax = ArgMax(v);
822 /// v_argmax
823 /// // (int) 2
824 /// ~~~~
825 template <typename T>
826 std::size_t ArgMax(const RVec<T> &v)
827 {
828  return std::distance(v.begin(), std::max_element(v.begin(), v.end()));
829 }
830 
831 /// Get the index of the smallest element of an RVec
832 /// In case of multiple occurrences of the minimum values,
833 /// the index corresponding to the first occurrence is returned.
834 ///
835 /// Example code, at the ROOT prompt:
836 /// ~~~~{.cpp}
837 /// using namespace ROOT::VecOps;
838 /// RVec<float> v {1.f, 2.f, 4.f};
839 /// auto v_argmin = ArgMin(v);
840 /// v_argmin
841 /// // (int) 0
842 /// ~~~~
843 template <typename T>
844 std::size_t ArgMin(const RVec<T> &v)
845 {
846  return std::distance(v.begin(), std::min_element(v.begin(), v.end()));
847 }
848 
849 /// Get the variance of the elements of an RVec
850 ///
851 /// The return type is a double precision floating point number.
852 /// Example code, at the ROOT prompt:
853 /// ~~~{.cpp}
854 /// using namespace ROOT::VecOps;
855 /// RVec<float> v {1.f, 2.f, 4.f};
856 /// auto v_var = Var(v);
857 /// v_var
858 /// // (double) 2.3333333
859 /// ~~~
860 template <typename T>
861 double Var(const RVec<T> &v)
862 {
863  const std::size_t size = v.size();
864  if (size < std::size_t(2)) return 0.;
865  T sum_squares(0), squared_sum(0);
866  auto pred = [&sum_squares, &squared_sum](const T& x) {sum_squares+=x*x; squared_sum+=x;};
867  std::for_each(v.begin(), v.end(), pred);
868  squared_sum *= squared_sum;
869  const auto dsize = (double) size;
870  return 1. / (dsize - 1.) * (sum_squares - squared_sum / dsize );
871 }
872 
873 /// Get the standard deviation of the elements of an RVec
874 ///
875 /// The return type is a double precision floating point number.
876 /// Example code, at the ROOT prompt:
877 /// ~~~{.cpp}
878 /// using namespace ROOT::VecOps;
879 /// RVec<float> v {1.f, 2.f, 4.f};
880 /// auto v_sd = StdDev(v);
881 /// v_sd
882 /// // (double) 1.5275252
883 /// ~~~
884 template <typename T>
885 double StdDev(const RVec<T> &v)
886 {
887  return std::sqrt(Var(v));
888 }
889 
890 /// Create new collection applying a callable to the elements of the input collection
891 ///
892 /// Example code, at the ROOT prompt:
893 /// ~~~{.cpp}
894 /// using namespace ROOT::VecOps;
895 /// RVec<float> v {1.f, 2.f, 4.f};
896 /// auto v_square = Map(v, [](float f){return f* 2.f;});
897 /// v_square
898 /// // (ROOT::VecOps::RVec<float> &) { 2.00000f, 4.00000f, 8.00000f }
899 ///
900 /// RVec<float> x({1.f, 2.f, 3.f});
901 /// RVec<float> y({4.f, 5.f, 6.f});
902 /// RVec<float> z({7.f, 8.f, 9.f});
903 /// auto mod = [](float x, float y, float z) { return sqrt(x * x + y * y + z * z); };
904 /// auto v_mod = Map(x, y, z, mod);
905 /// v_mod
906 /// // (ROOT::VecOps::RVec<float> &) { 8.12404f, 9.64365f, 11.2250f }
907 /// ~~~
908 template <typename... Args>
909 auto Map(Args &&... args)
910  -> decltype(ROOT::Detail::VecOps::MapFromTuple(std::forward_as_tuple(args...),
911  std::make_index_sequence<sizeof...(args) - 1>()))
912 {
913  /*
914  Here the strategy in order to generalise the previous implementation of Map, i.e.
915  `RVec Map(RVec, F)`, here we need to move the last parameter of the pack in first
916  position in order to be able to invoke the Map function with automatic type deduction.
917  This is achieved in two steps:
918  1. Forward as tuple the pack to MapFromTuple
919  2. Invoke the MapImpl helper which has the signature `template<...T, F> RVec MapImpl(F &&f, RVec<T>...)`
920  NOTA BENE: the signature is very heavy but it is one of the lightest ways to manage in C++11
921  to build the return type based on the template args.
922  */
923  return ROOT::Detail::VecOps::MapFromTuple(std::forward_as_tuple(args...),
924  std::make_index_sequence<sizeof...(args) - 1>());
925 }
926 
927 /// Create a new collection with the elements passing the filter expressed by the predicate
928 ///
929 /// Example code, at the ROOT prompt:
930 /// ~~~{.cpp}
931 /// using namespace ROOT::VecOps;
932 /// RVec<int> v {1, 2, 4};
933 /// auto v_even = Filter(v, [](int i){return 0 == i%2;});
934 /// v_even
935 /// // (ROOT::VecOps::RVec<int> &) { 2, 4 }
936 /// ~~~
937 template <typename T, typename F>
938 RVec<T> Filter(const RVec<T> &v, F &&f)
939 {
940  const auto thisSize = v.size();
941  RVec<T> w;
942  w.reserve(thisSize);
943  for (auto &&val : v) {
944  if (f(val))
945  w.emplace_back(val);
946  }
947  return w;
948 }
949 
950 /// Return true if any of the elements equates to true, return false otherwise.
951 ///
952 /// Example code, at the ROOT prompt:
953 /// ~~~{.cpp}
954 /// using namespace ROOT::VecOps;
955 /// RVec<int> v {0, 1, 0};
956 /// auto anyTrue = Any(v);
957 /// anyTrue
958 /// // (bool) true
959 /// ~~~
960 template <typename T>
961 auto Any(const RVec<T> &v) -> decltype(v[0] == true)
962 {
963  for (auto &&e : v)
964  if (e == true)
965  return true;
966  return false;
967 }
968 
969 /// Return true if all of the elements equate to true, return false otherwise.
970 ///
971 /// Example code, at the ROOT prompt:
972 /// ~~~{.cpp}
973 /// using namespace ROOT::VecOps;
974 /// RVec<int> v {0, 1, 0};
975 /// auto allTrue = All(v);
976 /// allTrue
977 /// // (bool) false
978 /// ~~~
979 template <typename T>
980 auto All(const RVec<T> &v) -> decltype(v[0] == false)
981 {
982  for (auto &&e : v)
983  if (e == false)
984  return false;
985  return true;
986 }
987 
988 template <typename T>
989 void swap(RVec<T> &lhs, RVec<T> &rhs)
990 {
991  lhs.swap(rhs);
992 }
993 
994 /// Return an RVec of indices that sort the input RVec
995 ///
996 /// Example code, at the ROOT prompt:
997 /// ~~~{.cpp}
998 /// using namespace ROOT::VecOps;
999 /// RVec<double> v {2., 3., 1.};
1000 /// auto sortIndices = Argsort(v);
1001 /// sortIndices
1002 /// // (ROOT::VecOps::RVec<unsigned long> &) { 2, 0, 1 }
1003 /// ~~~
1004 template <typename T>
1005 RVec<typename RVec<T>::size_type> Argsort(const RVec<T> &v)
1006 {
1007  using size_type = typename RVec<T>::size_type;
1008  RVec<size_type> i(v.size());
1009  std::iota(i.begin(), i.end(), 0);
1010  std::sort(i.begin(), i.end(), [&v](size_type i1, size_type i2) { return v[i1] < v[i2]; });
1011  return i;
1012 }
1013 
1014 /// Return elements of a vector at given indices
1015 ///
1016 /// Example code, at the ROOT prompt:
1017 /// ~~~{.cpp}
1018 /// using namespace ROOT::VecOps;
1019 /// RVec<double> v {2., 3., 1.};
1020 /// auto vTaken = Take(v, {0,2});
1021 /// vTaken
1022 /// // (ROOT::VecOps::RVec<double>) { 2.0000000, 1.0000000 }
1023 /// ~~~
1024 template <typename T>
1025 RVec<T> Take(const RVec<T> &v, const RVec<typename RVec<T>::size_type> &i)
1026 {
1027  using size_type = typename RVec<T>::size_type;
1028  const size_type isize = i.size();
1029  RVec<T> r(isize);
1030  for (size_type k = 0; k < isize; k++)
1031  r[k] = v[i[k]];
1032  return r;
1033 }
1034 
1035 /// Return first or last `n` elements of an RVec
1036 ///
1037 /// if `n > 0` and last elements if `n < 0`.
1038 ///
1039 /// Example code, at the ROOT prompt:
1040 /// ~~~{.cpp}
1041 /// using namespace ROOT::VecOps;
1042 /// RVec<double> v {2., 3., 1.};
1043 /// auto firstTwo = Take(v, 2);
1044 /// firstTwo
1045 /// // (ROOT::VecOps::RVec<double>) { 2.0000000, 3.0000000 }
1046 /// auto lastOne = Take(v, -1);
1047 /// lastOne
1048 /// // (ROOT::VecOps::RVec<double>) { 1.0000000 }
1049 /// ~~~
1050 template <typename T>
1051 RVec<T> Take(const RVec<T> &v, const int n)
1052 {
1053  using size_type = typename RVec<T>::size_type;
1054  const size_type size = v.size();
1055  const size_type absn = std::abs(n);
1056  if (absn > size) {
1057  std::stringstream ss;
1058  ss << "Try to take " << absn << " elements but vector has only size " << size << ".";
1059  throw std::runtime_error(ss.str());
1060  }
1061  RVec<T> r(absn);
1062  if (n < 0) {
1063  for (size_type k = 0; k < absn; k++)
1064  r[k] = v[size - absn + k];
1065  } else {
1066  for (size_type k = 0; k < absn; k++)
1067  r[k] = v[k];
1068  }
1069  return r;
1070 }
1071 
1072 /// Return copy of reversed vector
1073 ///
1074 /// Example code, at the ROOT prompt:
1075 /// ~~~{.cpp}
1076 /// using namespace ROOT::VecOps;
1077 /// RVec<double> v {2., 3., 1.};
1078 /// auto v_reverse = Reverse(v);
1079 /// v_reverse
1080 /// // (ROOT::VecOps::RVec<double>) { 1.0000000, 3.0000000, 2.0000000 }
1081 /// ~~~
1082 template <typename T>
1083 RVec<T> Reverse(const RVec<T> &v)
1084 {
1085  RVec<T> r(v);
1086  std::reverse(r.begin(), r.end());
1087  return r;
1088 }
1089 
1090 /// Return copy of RVec with elements sorted in ascending order
1091 ///
1092 /// This helper is different from ArgSort since it does not return an RVec of indices,
1093 /// but an RVec of values.
1094 ///
1095 /// Example code, at the ROOT prompt:
1096 /// ~~~{.cpp}
1097 /// using namespace ROOT::VecOps;
1098 /// RVec<double> v {2., 3., 1.};
1099 /// auto v_sorted = Sort(v);
1100 /// v_sorted
1101 /// // (ROOT::VecOps::RVec<double>) { 1.0000000, 2.0000000, 3.0000000 }
1102 /// ~~~
1103 template <typename T>
1104 RVec<T> Sort(const RVec<T> &v)
1105 {
1106  RVec<T> r(v);
1107  std::sort(r.begin(), r.end());
1108  return r;
1109 }
1110 
1111 /// Return copy of RVec with elements sorted based on a comparison operator
1112 ///
1113 /// The comparison operator has to fullfill the same requirements of the
1114 /// predicate of by std::sort.
1115 ///
1116 ///
1117 /// This helper is different from ArgSort since it does not return an RVec of indices,
1118 /// but an RVec of values.
1119 ///
1120 /// Example code, at the ROOT prompt:
1121 /// ~~~{.cpp}
1122 /// using namespace ROOT::VecOps;
1123 /// RVec<double> v {2., 3., 1.};
1124 /// auto v_sorted = Sort(v, [](double x, double y) {return 1/x < 1/y;});
1125 /// v_sorted
1126 /// // (ROOT::VecOps::RVec<double>) { 3.0000000, 2.0000000, 1.0000000 }
1127 /// ~~~
1128 template <typename T, typename Compare>
1129 RVec<T> Sort(const RVec<T> &v, Compare &&c)
1130 {
1131  RVec<T> r(v);
1132  std::sort(r.begin(), r.end(), std::forward<Compare>(c));
1133  return r;
1134 }
1135 
1136 /// Return the indices that represent all combinations of the elements of two
1137 /// RVecs.
1138 ///
1139 /// The type of the return value is an RVec of two RVecs containing indices.
1140 ///
1141 /// Example code, at the ROOT prompt:
1142 /// ~~~{.cpp}
1143 /// using namespace ROOT::VecOps;
1144 /// auto comb_idx = Combinations(3, 2);
1145 /// comb_idx
1146 /// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 1, 1, 2, 2 }, { 0, 1, 0, 1, 0, 1 } }
1147 /// ~~~
1148 inline RVec<RVec<std::size_t>> Combinations(const std::size_t size1, const std::size_t size2)
1149 {
1150  using size_type = std::size_t;
1151  RVec<RVec<size_type>> r(2);
1152  r[0].resize(size1*size2);
1153  r[1].resize(size1*size2);
1154  size_type c = 0;
1155  for(size_type i=0; i<size1; i++) {
1156  for(size_type j=0; j<size2; j++) {
1157  r[0][c] = i;
1158  r[1][c] = j;
1159  c++;
1160  }
1161  }
1162  return r;
1163 }
1164 
1165 /// Return the indices that represent all combinations of the elements of two
1166 /// RVecs.
1167 ///
1168 /// The type of the return value is an RVec of two RVecs containing indices.
1169 ///
1170 /// Example code, at the ROOT prompt:
1171 /// ~~~{.cpp}
1172 /// using namespace ROOT::VecOps;
1173 /// RVec<double> v1 {1., 2., 3.};
1174 /// RVec<double> v2 {-4., -5.};
1175 /// auto comb_idx = Combinations(v1, v2);
1176 /// comb_idx
1177 /// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 1, 1, 2, 2 }, { 0, 1,
1178 /// 0, 1, 0, 1 } }
1179 /// ~~~
1180 template <typename T1, typename T2>
1181 RVec<RVec<typename RVec<T1>::size_type>> Combinations(const RVec<T1> &v1, const RVec<T2> &v2)
1182 {
1183  return Combinations(v1.size(), v2.size());
1184 }
1185 
1186 /// Return the indices that represent all unique combinations of the
1187 /// elements of a given RVec.
1188 ///
1189 /// ~~~{.cpp}
1190 /// using namespace ROOT::VecOps;
1191 /// RVec<double> v {1., 2., 3., 4.};
1192 /// auto v_1 = Combinations(v, 1);
1193 /// v_1
1194 /// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 1, 2, 3 } }
1195 /// auto v_2 = Combinations(v, 2);
1196 /// auto v_2
1197 /// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 0, 1, 1, 2 }, { 1, 2, 3, 2, 3, 3 } }
1198 /// auto v_3 = Combinations(v, 3);
1199 /// v_3
1200 /// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0, 0, 0, 1 }, { 1, 1, 2, 2 }, { 2, 3, 3, 3 } }
1201 /// auto v_4 = Combinations(v, 4);
1202 /// v_4
1203 /// (ROOT::VecOps::RVec<ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type> >) { { 0 }, { 1 }, { 2 }, { 3 } }
1204 /// ~~~
1205 template <typename T>
1206 RVec<RVec<typename RVec<T>::size_type>> Combinations(const RVec<T>& v, const typename RVec<T>::size_type n)
1207 {
1208  using size_type = typename RVec<T>::size_type;
1209  const size_type s = v.size();
1210  if (n > s) {
1211  std::stringstream ss;
1212  ss << "Cannot make unique combinations of size " << n << " from vector of size " << s << ".";
1213  throw std::runtime_error(ss.str());
1214  }
1215  RVec<size_type> indices(s);
1216  for(size_type k=0; k<s; k++)
1217  indices[k] = k;
1218  RVec<RVec<size_type>> c(n);
1219  for(size_type k=0; k<n; k++)
1220  c[k].emplace_back(indices[k]);
1221  while (true) {
1222  bool run_through = true;
1223  long i = n - 1;
1224  for (; i>=0; i--) {
1225  if (indices[i] != i + s - n){
1226  run_through = false;
1227  break;
1228  }
1229  }
1230  if (run_through) {
1231  return c;
1232  }
1233  indices[i]++;
1234  for (long j=i+1; j<(long)n; j++)
1235  indices[j] = indices[j-1] + 1;
1236  for(size_type k=0; k<n; k++)
1237  c[k].emplace_back(indices[k]);
1238  }
1239 }
1240 
1241 /// Return the indices of the elements which are not zero
1242 ///
1243 /// Example code, at the ROOT prompt:
1244 /// ~~~{.cpp}
1245 /// using namespace ROOT::VecOps;
1246 /// RVec<double> v {2., 0., 3., 0., 1.};
1247 /// auto nonzero_idx = Nonzero(v);
1248 /// nonzero_idx
1249 /// // (ROOT::VecOps::RVec<ROOT::VecOps::RVec<double>::size_type>) { 0, 2, 4 }
1250 /// ~~~
1251 template <typename T>
1252 RVec<typename RVec<T>::size_type> Nonzero(const RVec<T> &v)
1253 {
1254  using size_type = typename RVec<T>::size_type;
1255  RVec<size_type> r;
1256  const auto size = v.size();
1257  r.reserve(size);
1258  for(size_type i=0; i<size; i++) {
1259  if(v[i] != 0) {
1260  r.emplace_back(i);
1261  }
1262  }
1263  return r;
1264 }
1265 
1266 /// Return the intersection of elements of two RVecs.
1267 ///
1268 /// Each element of v1 is looked up in v2 and added to the returned vector if
1269 /// found. Following, the order of v1 is preserved. If v2 is already sorted, the
1270 /// optional argument v2_is_sorted can be used to toggle of the internal sorting
1271 /// step, therewith optimising runtime.
1272 ///
1273 /// Example code, at the ROOT prompt:
1274 /// ~~~{.cpp}
1275 /// using namespace ROOT::VecOps;
1276 /// RVec<double> v1 {1., 2., 3.};
1277 /// RVec<double> v2 {-4., -5., 2., 1.};
1278 /// auto v1_intersect_v2 = Intersect(v1, v2);
1279 /// v1_intersect_v2
1280 /// // (ROOT::VecOps::RVec<double>) { 1.0000000, 2.0000000 }
1281 /// ~~~
1282 template <typename T>
1283 RVec<T> Intersect(const RVec<T>& v1, const RVec<T>& v2, bool v2_is_sorted = false)
1284 {
1285  RVec<T> v2_sorted;
1286  if (!v2_is_sorted) v2_sorted = Sort(v2);
1287  const auto v2_begin = v2_is_sorted ? v2.begin() : v2_sorted.begin();
1288  const auto v2_end = v2_is_sorted ? v2.end() : v2_sorted.end();
1289  RVec<T> r;
1290  const auto size = v1.size();
1291  r.reserve(size);
1292  using size_type = typename RVec<T>::size_type;
1293  for(size_type i=0; i<size; i++) {
1294  if (std::binary_search(v2_begin, v2_end, v1[i])) {
1295  r.emplace_back(v1[i]);
1296  }
1297  }
1298  return r;
1299 }
1300 
1301 /// Return the elements of v1 if the condition c is true and v2 if the
1302 /// condition c is false.
1303 ///
1304 /// Example code, at the ROOT prompt:
1305 /// ~~~{.cpp}
1306 /// using namespace ROOT::VecOps;
1307 /// RVec<double> v1 {1., 2., 3.};
1308 /// RVec<double> v2 {-1., -2., -3.};
1309 /// auto c = v1 > 1;
1310 /// c
1311 /// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
1312 /// auto if_c_v1_else_v2 = Where(c, v1, v2);
1313 /// if_c_v1_else_v2
1314 /// // (ROOT::VecOps::RVec<double> &) { -1.0000000, 2.0000000, 3.0000000 }
1315 /// ~~~
1316 template <typename T>
1317 RVec<T> Where(const RVec<int>& c, const RVec<T>& v1, const RVec<T>& v2)
1318 {
1319  using size_type = typename RVec<T>::size_type;
1320  const size_type size = c.size();
1321  RVec<T> r;
1322  r.reserve(size);
1323  for (size_type i=0; i<size; i++) {
1324  r.emplace_back(c[i] != 0 ? v1[i] : v2[i]);
1325  }
1326  return r;
1327 }
1328 
1329 /// Return the elements of v1 if the condition c is true and sets the value v2
1330 /// if the condition c is false.
1331 ///
1332 /// Example code, at the ROOT prompt:
1333 /// ~~~{.cpp}
1334 /// using namespace ROOT::VecOps;
1335 /// RVec<double> v1 {1., 2., 3.};
1336 /// double v2 = 4.;
1337 /// auto c = v1 > 1;
1338 /// c
1339 /// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
1340 /// auto if_c_v1_else_v2 = Where(c, v1, v2);
1341 /// if_c_v1_else_v2
1342 /// // (ROOT::VecOps::RVec<double>) { 4.0000000, 2.0000000, 3.0000000 }
1343 /// ~~~
1344 template <typename T>
1345 RVec<T> Where(const RVec<int>& c, const RVec<T>& v1, T v2)
1346 {
1347  using size_type = typename RVec<T>::size_type;
1348  const size_type size = c.size();
1349  RVec<T> r;
1350  r.reserve(size);
1351  for (size_type i=0; i<size; i++) {
1352  r.emplace_back(c[i] != 0 ? v1[i] : v2);
1353  }
1354  return r;
1355 }
1356 
1357 /// Return the elements of v2 if the condition c is false and sets the value v1
1358 /// if the condition c is true.
1359 ///
1360 /// Example code, at the ROOT prompt:
1361 /// ~~~{.cpp}
1362 /// using namespace ROOT::VecOps;
1363 /// double v1 = 4.;
1364 /// RVec<double> v2 {1., 2., 3.};
1365 /// auto c = v2 > 1;
1366 /// c
1367 /// // (ROOT::VecOps::RVec<int> &) { 0, 1, 1 }
1368 /// auto if_c_v1_else_v2 = Where(c, v1, v2);
1369 /// if_c_v1_else_v2
1370 /// // (ROOT::VecOps::RVec<double>) { 1.0000000, 4.0000000, 4.0000000 }
1371 /// ~~~
1372 template <typename T>
1373 RVec<T> Where(const RVec<int>& c, T v1, const RVec<T>& v2)
1374 {
1375  using size_type = typename RVec<T>::size_type;
1376  const size_type size = c.size();
1377  RVec<T> r;
1378  r.reserve(size);
1379  for (size_type i=0; i<size; i++) {
1380  r.emplace_back(c[i] != 0 ? v1 : v2[i]);
1381  }
1382  return r;
1383 }
1384 
1385 /// Return a vector with the value v2 if the condition c is false and sets the
1386 /// value v1 if the condition c is true.
1387 ///
1388 /// Example code, at the ROOT prompt:
1389 /// ~~~{.cpp}
1390 /// using namespace ROOT::VecOps;
1391 /// double v1 = 4.;
1392 /// double v2 = 2.;
1393 /// RVec<int> c {0, 1, 1};
1394 /// auto if_c_v1_else_v2 = Where(c, v1, v2);
1395 /// if_c_v1_else_v2
1396 /// // (ROOT::VecOps::RVec<double>) { 2.0000000, 4.0000000, 4.0000000 }
1397 /// ~~~
1398 template <typename T>
1399 RVec<T> Where(const RVec<int>& c, T v1, T v2)
1400 {
1401  using size_type = typename RVec<T>::size_type;
1402  const size_type size = c.size();
1403  RVec<T> r;
1404  r.reserve(size);
1405  for (size_type i=0; i<size; i++) {
1406  r.emplace_back(c[i] != 0 ? v1 : v2);
1407  }
1408  return r;
1409 }
1410 
1411 /// Return the concatenation of two RVecs.
1412 ///
1413 /// Example code, at the ROOT prompt:
1414 /// ~~~{.cpp}
1415 /// using namespace ROOT::VecOps;
1416 /// RVec<float> rvf {0.f, 1.f, 2.f};
1417 /// RVec<int> rvi {7, 8, 9};
1418 /// Concatenate(rvf, rvi);
1419 /// // (ROOT::VecOps::RVec<float>) { 2.0000000, 4.0000000, 4.0000000 }
1420 /// ~~~
1421 template <typename T0, typename T1, typename Common_t = typename std::common_type<T0, T1>::type>
1422 RVec<Common_t> Concatenate(const RVec<T0> &v0, const RVec<T1> &v1)
1423 {
1424  RVec<Common_t> res;
1425  res.reserve(v0.size() + v1.size());
1426  auto &resAsVect = res.AsVector();
1427  auto &v0AsVect = v0.AsVector();
1428  auto &v1AsVect = v1.AsVector();
1429  resAsVect.insert(resAsVect.begin(), v0AsVect.begin(), v0AsVect.end());
1430  resAsVect.insert(resAsVect.end(), v1AsVect.begin(), v1AsVect.end());
1431  return res;
1432 }
1433 
1434 /// Return the angle difference \f$\Delta \phi\f$ of two scalars.
1435 ///
1436 /// The function computes the closest angle from v1 to v2 with sign and is
1437 /// therefore in the range \f$[-\pi, \pi]\f$.
1438 /// The computation is done per default in radians \f$c = \pi\f$ but can be switched
1439 /// to degrees \f$c = 180\f$.
1440 template <typename T>
1441 T DeltaPhi(T v1, T v2, const T c = M_PI)
1442 {
1443  static_assert(std::is_floating_point<T>::value,
1444  "DeltaPhi must be called with floating point values.");
1445  auto r = std::fmod(v2 - v1, 2.0 * c);
1446  if (r < -c) {
1447  r += 2.0 * c;
1448  }
1449  else if (r > c) {
1450  r -= 2.0 * c;
1451  }
1452  return r;
1453 }
1454 
1455 /// Return the angle difference \f$\Delta \phi\f$ in radians of two vectors.
1456 ///
1457 /// The function computes the closest angle from v1 to v2 with sign and is
1458 /// therefore in the range \f$[-\pi, \pi]\f$.
1459 /// The computation is done per default in radians \f$c = \pi\f$ but can be switched
1460 /// to degrees \f$c = 180\f$.
1461 template <typename T>
1462 RVec<T> DeltaPhi(const RVec<T>& v1, const RVec<T>& v2, const T c = M_PI)
1463 {
1464  using size_type = typename RVec<T>::size_type;
1465  const size_type size = v1.size();
1466  auto r = RVec<T>(size);
1467  for (size_type i = 0; i < size; i++) {
1468  r[i] = DeltaPhi(v1[i], v2[i], c);
1469  }
1470  return r;
1471 }
1472 
1473 /// Return the angle difference \f$\Delta \phi\f$ in radians of a vector and a scalar.
1474 ///
1475 /// The function computes the closest angle from v1 to v2 with sign and is
1476 /// therefore in the range \f$[-\pi, \pi]\f$.
1477 /// The computation is done per default in radians \f$c = \pi\f$ but can be switched
1478 /// to degrees \f$c = 180\f$.
1479 template <typename T>
1480 RVec<T> DeltaPhi(const RVec<T>& v1, T v2, const T c = M_PI)
1481 {
1482  using size_type = typename RVec<T>::size_type;
1483  const size_type size = v1.size();
1484  auto r = RVec<T>(size);
1485  for (size_type i = 0; i < size; i++) {
1486  r[i] = DeltaPhi(v1[i], v2, c);
1487  }
1488  return r;
1489 }
1490 
1491 /// Return the angle difference \f$\Delta \phi\f$ in radians of a scalar and a vector.
1492 ///
1493 /// The function computes the closest angle from v1 to v2 with sign and is
1494 /// therefore in the range \f$[-\pi, \pi]\f$.
1495 /// The computation is done per default in radians \f$c = \pi\f$ but can be switched
1496 /// to degrees \f$c = 180\f$.
1497 template <typename T>
1498 RVec<T> DeltaPhi(T v1, const RVec<T>& v2, const T c = M_PI)
1499 {
1500  using size_type = typename RVec<T>::size_type;
1501  const size_type size = v2.size();
1502  auto r = RVec<T>(size);
1503  for (size_type i = 0; i < size; i++) {
1504  r[i] = DeltaPhi(v1, v2[i], c);
1505  }
1506  return r;
1507 }
1508 
1509 /// Return the square of the distance on the \f$\eta\f$-\f$\phi\f$ plane (\f$\Delta R\f$) from
1510 /// the collections eta1, eta2, phi1 and phi2.
1511 ///
1512 /// The function computes \f$\Delta R^2 = (\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2\f$
1513 /// of the given collections eta1, eta2, phi1 and phi2. The angle \f$\phi\f$ can
1514 /// be set to radian or degrees using the optional argument c, see the documentation
1515 /// of the DeltaPhi helper.
1516 template <typename T>
1517 RVec<T> DeltaR2(const RVec<T>& eta1, const RVec<T>& eta2, const RVec<T>& phi1, const RVec<T>& phi2, const T c = M_PI)
1518 {
1519  const auto dphi = DeltaPhi(phi1, phi2, c);
1520  return (eta1 - eta2) * (eta1 - eta2) + dphi * dphi;
1521 }
1522 
1523 /// Return the distance on the \f$\eta\f$-\f$\phi\f$ plane (\f$\Delta R\f$) from
1524 /// the collections eta1, eta2, phi1 and phi2.
1525 ///
1526 /// The function computes \f$\Delta R = \sqrt{(\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2}\f$
1527 /// of the given collections eta1, eta2, phi1 and phi2. The angle \f$\phi\f$ can
1528 /// be set to radian or degrees using the optional argument c, see the documentation
1529 /// of the DeltaPhi helper.
1530 template <typename T>
1531 RVec<T> DeltaR(const RVec<T>& eta1, const RVec<T>& eta2, const RVec<T>& phi1, const RVec<T>& phi2, const T c = M_PI)
1532 {
1533  return sqrt(DeltaR2(eta1, eta2, phi1, phi2, c));
1534 }
1535 
1536 /// Return the distance on the \f$\eta\f$-\f$\phi\f$ plane (\f$\Delta R\f$) from
1537 /// the scalars eta1, eta2, phi1 and phi2.
1538 ///
1539 /// The function computes \f$\Delta R = \sqrt{(\eta_1 - \eta_2)^2 + (\phi_1 - \phi_2)^2}\f$
1540 /// of the given scalars eta1, eta2, phi1 and phi2. The angle \f$\phi\f$ can
1541 /// be set to radian or degrees using the optional argument c, see the documentation
1542 /// of the DeltaPhi helper.
1543 template <typename T>
1544 T DeltaR(T eta1, T eta2, T phi1, T phi2, const T c = M_PI)
1545 {
1546  const auto dphi = DeltaPhi(phi1, phi2, c);
1547  return std::sqrt((eta1 - eta2) * (eta1 - eta2) + dphi * dphi);
1548 }
1549 
1550 /// Return the invariant mass of two particles given the collections of the quantities
1551 /// transverse momentum (pt), rapidity (eta), azimuth (phi) and mass.
1552 ///
1553 /// The function computes the invariant mass of two particles with the four-vectors
1554 /// (pt1, eta2, phi1, mass1) and (pt2, eta2, phi2, mass2).
1555 template <typename T>
1556 RVec<T> InvariantMasses(
1557  const RVec<T>& pt1, const RVec<T>& eta1, const RVec<T>& phi1, const RVec<T>& mass1,
1558  const RVec<T>& pt2, const RVec<T>& eta2, const RVec<T>& phi2, const RVec<T>& mass2)
1559 {
1560  std::size_t size = pt1.size();
1561 
1562  R__ASSERT(eta1.size() == size && phi1.size() == size && mass1.size() == size);
1563  R__ASSERT(pt2.size() == size && phi2.size() == size && mass2.size() == size);
1564 
1565  RVec<T> inv_masses(size);
1566 
1567  for (std::size_t i = 0u; i < size; ++i) {
1568  // Conversion from (pt, eta, phi, mass) to (x, y, z, e) coordinate system
1569  const auto x1 = pt1[i] * std::cos(phi1[i]);
1570  const auto y1 = pt1[i] * std::sin(phi1[i]);
1571  const auto z1 = pt1[i] * std::sinh(eta1[i]);
1572  const auto e1 = std::sqrt(x1 * x1 + y1 * y1 + z1 * z1 + mass1[i] * mass1[i]);
1573 
1574  const auto x2 = pt2[i] * std::cos(phi2[i]);
1575  const auto y2 = pt2[i] * std::sin(phi2[i]);
1576  const auto z2 = pt2[i] * std::sinh(eta2[i]);
1577  const auto e2 = std::sqrt(x2 * x2 + y2 * y2 + z2 * z2 + mass2[i] * mass2[i]);
1578 
1579  // Addition of particle four-vector elements
1580  const auto e = e1 + e2;
1581  const auto x = x1 + x2;
1582  const auto y = y1 + y2;
1583  const auto z = z1 + z2;
1584 
1585  inv_masses[i] = std::sqrt(e * e - x * x - y * y - z * z);
1586  }
1587 
1588  // Return invariant mass with (+, -, -, -) metric
1589  return inv_masses;
1590 }
1591 
1592 /// Return the invariant mass of multiple particles given the collections of the
1593 /// quantities transverse momentum (pt), rapidity (eta), azimuth (phi) and mass.
1594 ///
1595 /// The function computes the invariant mass of multiple particles with the
1596 /// four-vectors (pt, eta, phi, mass).
1597 template <typename T>
1598 T InvariantMass(const RVec<T>& pt, const RVec<T>& eta, const RVec<T>& phi, const RVec<T>& mass)
1599 {
1600  const std::size_t size = pt.size();
1601 
1602  R__ASSERT(eta.size() == size && phi.size() == size && mass.size() == size);
1603 
1604  T x_sum = 0.;
1605  T y_sum = 0.;
1606  T z_sum = 0.;
1607  T e_sum = 0.;
1608 
1609  for (std::size_t i = 0u; i < size; ++ i) {
1610  // Convert to (e, x, y, z) coordinate system and update sums
1611  const auto x = pt[i] * std::cos(phi[i]);
1612  x_sum += x;
1613  const auto y = pt[i] * std::sin(phi[i]);
1614  y_sum += y;
1615  const auto z = pt[i] * std::sinh(eta[i]);
1616  z_sum += z;
1617  const auto e = std::sqrt(x * x + y * y + z * z + mass[i] * mass[i]);
1618  e_sum += e;
1619  }
1620 
1621  // Return invariant mass with (+, -, -, -) metric
1622  return std::sqrt(e_sum * e_sum - x_sum * x_sum - y_sum * y_sum - z_sum * z_sum);
1623 }
1624 
1625 ////////////////////////////////////////////////////////////////////////////
1626 /// \brief Build an RVec of objects starting from RVecs of input to their constructors.
1627 /// \tparam T Type of the objects contained in the created RVec.
1628 /// \tparam Args_t Pack of types templating the input RVecs.
1629 /// \param[in] args The RVecs containing the values used to initialise the output objects.
1630 /// \return The RVec of objects initialised with the input parameters.
1631 ///
1632 /// Example code, at the ROOT prompt:
1633 /// ~~~{.cpp}
1634 /// using namespace ROOT::VecOps;
1635 /// RVec<float> etas {.3f, 2.2f, 1.32f};
1636 /// RVec<float> phis {.1f, 3.02f, 2.2f};
1637 /// RVec<float> pts {15.5f, 34.32f, 12.95f};
1638 /// RVec<float> masses {105.65f, 105.65f, 105.65f};
1639 /// Construct<ROOT::Math::PtEtaPhiMVector> fourVects(etas, phis, pts, masses);
1640 /// cout << fourVects << endl;
1641 /// // { (15.5,0.3,0.1,105.65), (34.32,2.2,3.02,105.65), (12.95,1.32,2.2,105.65) }
1642 /// ~~~
1643 template <typename T, typename... Args_t>
1644 RVec<T> Construct(const RVec<Args_t> &... args)
1645 {
1646  const auto size = ::ROOT::Detail::VecOps::GetVectorsSize("Construct", args...);
1647  RVec<T> ret;
1648  ret.reserve(size);
1649  for (auto i = 0UL; i < size; ++i) {
1650  ret.emplace_back(args[i]...);
1651  }
1652  return ret;
1653 }
1654 
1655 ////////////////////////////////////////////////////////////////////////////////
1656 /// Print a RVec at the prompt:
1657 template <class T>
1658 std::ostream &operator<<(std::ostream &os, const RVec<T> &v)
1659 {
1660  // In order to print properly, convert to 64 bit int if this is a char
1661  constexpr bool mustConvert = std::is_same<char, T>::value || std::is_same<signed char, T>::value ||
1662  std::is_same<unsigned char, T>::value || std::is_same<wchar_t, T>::value ||
1663  std::is_same<char16_t, T>::value || std::is_same<char32_t, T>::value;
1664  using Print_t = typename std::conditional<mustConvert, long long int, T>::type;
1665  os << "{ ";
1666  auto size = v.size();
1667  if (size) {
1668  for (std::size_t i = 0; i < size - 1; ++i) {
1669  os << (Print_t)v[i] << ", ";
1670  }
1671  os << (Print_t)v[size - 1];
1672  }
1673  os << " }";
1674  return os;
1675 }
1676 
1677 #if (_VECOPS_USE_EXTERN_TEMPLATES)
1678 
1679 #define RVEC_EXTERN_UNARY_OPERATOR(T, OP) \
1680  extern template RVec<T> operator OP<T>(const RVec<T> &);
1681 
1682 #define RVEC_EXTERN_BINARY_OPERATOR(T, OP) \
1683  extern template auto operator OP<T, T>(const T &x, const RVec<T> &v) \
1684  -> RVec<decltype(x OP v[0])>; \
1685  extern template auto operator OP<T, T>(const RVec<T> &v, const T &y) \
1686  -> RVec<decltype(v[0] OP y)>; \
1687  extern template auto operator OP<T, T>(const RVec<T> &v0, const RVec<T> &v1)\
1688  -> RVec<decltype(v0[0] OP v1[0])>;
1689 
1690 #define RVEC_EXTERN_ASSIGN_OPERATOR(T, OP) \
1691  extern template RVec<T> &operator OP<T, T>(RVec<T> &, const T &); \
1692  extern template RVec<T> &operator OP<T, T>(RVec<T> &, const RVec<T> &);
1693 
1694 #define RVEC_EXTERN_LOGICAL_OPERATOR(T, OP) \
1695  extern template RVec<int> operator OP<T, T>(const RVec<T> &, const T &); \
1696  extern template RVec<int> operator OP<T, T>(const T &, const RVec<T> &); \
1697  extern template RVec<int> operator OP<T, T>(const RVec<T> &, const RVec<T> &);
1698 
1699 #define RVEC_EXTERN_FLOAT_TEMPLATE(T) \
1700  extern template class RVec<T>; \
1701  RVEC_EXTERN_UNARY_OPERATOR(T, +) \
1702  RVEC_EXTERN_UNARY_OPERATOR(T, -) \
1703  RVEC_EXTERN_UNARY_OPERATOR(T, !) \
1704  RVEC_EXTERN_BINARY_OPERATOR(T, +) \
1705  RVEC_EXTERN_BINARY_OPERATOR(T, -) \
1706  RVEC_EXTERN_BINARY_OPERATOR(T, *) \
1707  RVEC_EXTERN_BINARY_OPERATOR(T, /) \
1708  RVEC_EXTERN_ASSIGN_OPERATOR(T, +=) \
1709  RVEC_EXTERN_ASSIGN_OPERATOR(T, -=) \
1710  RVEC_EXTERN_ASSIGN_OPERATOR(T, *=) \
1711  RVEC_EXTERN_ASSIGN_OPERATOR(T, /=) \
1712  RVEC_EXTERN_LOGICAL_OPERATOR(T, <) \
1713  RVEC_EXTERN_LOGICAL_OPERATOR(T, >) \
1714  RVEC_EXTERN_LOGICAL_OPERATOR(T, ==) \
1715  RVEC_EXTERN_LOGICAL_OPERATOR(T, !=) \
1716  RVEC_EXTERN_LOGICAL_OPERATOR(T, <=) \
1717  RVEC_EXTERN_LOGICAL_OPERATOR(T, >=) \
1718  RVEC_EXTERN_LOGICAL_OPERATOR(T, &&) \
1719  RVEC_EXTERN_LOGICAL_OPERATOR(T, ||)
1720 
1721 #define RVEC_EXTERN_INTEGER_TEMPLATE(T) \
1722  extern template class RVec<T>; \
1723  RVEC_EXTERN_UNARY_OPERATOR(T, +) \
1724  RVEC_EXTERN_UNARY_OPERATOR(T, -) \
1725  RVEC_EXTERN_UNARY_OPERATOR(T, ~) \
1726  RVEC_EXTERN_UNARY_OPERATOR(T, !) \
1727  RVEC_EXTERN_BINARY_OPERATOR(T, +) \
1728  RVEC_EXTERN_BINARY_OPERATOR(T, -) \
1729  RVEC_EXTERN_BINARY_OPERATOR(T, *) \
1730  RVEC_EXTERN_BINARY_OPERATOR(T, /) \
1731  RVEC_EXTERN_BINARY_OPERATOR(T, %) \
1732  RVEC_EXTERN_BINARY_OPERATOR(T, &) \
1733  RVEC_EXTERN_BINARY_OPERATOR(T, |) \
1734  RVEC_EXTERN_BINARY_OPERATOR(T, ^) \
1735  RVEC_EXTERN_ASSIGN_OPERATOR(T, +=) \
1736  RVEC_EXTERN_ASSIGN_OPERATOR(T, -=) \
1737  RVEC_EXTERN_ASSIGN_OPERATOR(T, *=) \
1738  RVEC_EXTERN_ASSIGN_OPERATOR(T, /=) \
1739  RVEC_EXTERN_ASSIGN_OPERATOR(T, %=) \
1740  RVEC_EXTERN_ASSIGN_OPERATOR(T, &=) \
1741  RVEC_EXTERN_ASSIGN_OPERATOR(T, |=) \
1742  RVEC_EXTERN_ASSIGN_OPERATOR(T, ^=) \
1743  RVEC_EXTERN_ASSIGN_OPERATOR(T, >>=) \
1744  RVEC_EXTERN_ASSIGN_OPERATOR(T, <<=) \
1745  RVEC_EXTERN_LOGICAL_OPERATOR(T, <) \
1746  RVEC_EXTERN_LOGICAL_OPERATOR(T, >) \
1747  RVEC_EXTERN_LOGICAL_OPERATOR(T, ==) \
1748  RVEC_EXTERN_LOGICAL_OPERATOR(T, !=) \
1749  RVEC_EXTERN_LOGICAL_OPERATOR(T, <=) \
1750  RVEC_EXTERN_LOGICAL_OPERATOR(T, >=) \
1751  RVEC_EXTERN_LOGICAL_OPERATOR(T, &&) \
1752  RVEC_EXTERN_LOGICAL_OPERATOR(T, ||)
1753 
1754 RVEC_EXTERN_INTEGER_TEMPLATE(char)
1755 RVEC_EXTERN_INTEGER_TEMPLATE(short)
1756 RVEC_EXTERN_INTEGER_TEMPLATE(int)
1757 RVEC_EXTERN_INTEGER_TEMPLATE(long)
1758 //RVEC_EXTERN_INTEGER_TEMPLATE(long long)
1759 
1760 RVEC_EXTERN_INTEGER_TEMPLATE(unsigned char)
1761 RVEC_EXTERN_INTEGER_TEMPLATE(unsigned short)
1762 RVEC_EXTERN_INTEGER_TEMPLATE(unsigned int)
1763 RVEC_EXTERN_INTEGER_TEMPLATE(unsigned long)
1764 //RVEC_EXTERN_INTEGER_TEMPLATE(unsigned long long)
1765 
1766 RVEC_EXTERN_FLOAT_TEMPLATE(float)
1767 RVEC_EXTERN_FLOAT_TEMPLATE(double)
1768 
1769 #undef RVEC_EXTERN_UNARY_OPERATOR
1770 #undef RVEC_EXTERN_BINARY_OPERATOR
1771 #undef RVEC_EXTERN_ASSIGN_OPERATOR
1772 #undef RVEC_EXTERN_LOGICAL_OPERATOR
1773 #undef RVEC_EXTERN_INTEGER_TEMPLATE
1774 #undef RVEC_EXTERN_FLOAT_TEMPLATE
1775 
1776 #define RVEC_EXTERN_UNARY_FUNCTION(T, NAME, FUNC) \
1777  extern template RVec<PromoteType<T>> NAME(const RVec<T> &);
1778 
1779 #define RVEC_EXTERN_STD_UNARY_FUNCTION(T, F) RVEC_EXTERN_UNARY_FUNCTION(T, F, std::F)
1780 
1781 #define RVEC_EXTERN_BINARY_FUNCTION(T0, T1, NAME, FUNC) \
1782  extern template RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &, const T1 &); \
1783  extern template RVec<PromoteTypes<T0, T1>> NAME(const T0 &, const RVec<T1> &); \
1784  extern template RVec<PromoteTypes<T0, T1>> NAME(const RVec<T0> &, const RVec<T1> &);
1785 
1786 #define RVEC_EXTERN_STD_BINARY_FUNCTION(T, F) RVEC_EXTERN_BINARY_FUNCTION(T, T, F, std::F)
1787 
1788 #define RVEC_EXTERN_STD_FUNCTIONS(T) \
1789  RVEC_EXTERN_STD_UNARY_FUNCTION(T, abs) \
1790  RVEC_EXTERN_STD_BINARY_FUNCTION(T, fdim) \
1791  RVEC_EXTERN_STD_BINARY_FUNCTION(T, fmod) \
1792  RVEC_EXTERN_STD_BINARY_FUNCTION(T, remainder) \
1793  RVEC_EXTERN_STD_UNARY_FUNCTION(T, exp) \
1794  RVEC_EXTERN_STD_UNARY_FUNCTION(T, exp2) \
1795  RVEC_EXTERN_STD_UNARY_FUNCTION(T, expm1) \
1796  RVEC_EXTERN_STD_UNARY_FUNCTION(T, log) \
1797  RVEC_EXTERN_STD_UNARY_FUNCTION(T, log10) \
1798  RVEC_EXTERN_STD_UNARY_FUNCTION(T, log2) \
1799  RVEC_EXTERN_STD_UNARY_FUNCTION(T, log1p) \
1800  RVEC_EXTERN_STD_BINARY_FUNCTION(T, pow) \
1801  RVEC_EXTERN_STD_UNARY_FUNCTION(T, sqrt) \
1802  RVEC_EXTERN_STD_UNARY_FUNCTION(T, cbrt) \
1803  RVEC_EXTERN_STD_BINARY_FUNCTION(T, hypot) \
1804  RVEC_EXTERN_STD_UNARY_FUNCTION(T, sin) \
1805  RVEC_EXTERN_STD_UNARY_FUNCTION(T, cos) \
1806  RVEC_EXTERN_STD_UNARY_FUNCTION(T, tan) \
1807  RVEC_EXTERN_STD_UNARY_FUNCTION(T, asin) \
1808  RVEC_EXTERN_STD_UNARY_FUNCTION(T, acos) \
1809  RVEC_EXTERN_STD_UNARY_FUNCTION(T, atan) \
1810  RVEC_EXTERN_STD_BINARY_FUNCTION(T, atan2) \
1811  RVEC_EXTERN_STD_UNARY_FUNCTION(T, sinh) \
1812  RVEC_EXTERN_STD_UNARY_FUNCTION(T, cosh) \
1813  RVEC_EXTERN_STD_UNARY_FUNCTION(T, tanh) \
1814  RVEC_EXTERN_STD_UNARY_FUNCTION(T, asinh) \
1815  RVEC_EXTERN_STD_UNARY_FUNCTION(T, acosh) \
1816  RVEC_EXTERN_STD_UNARY_FUNCTION(T, atanh) \
1817  RVEC_EXTERN_STD_UNARY_FUNCTION(T, floor) \
1818  RVEC_EXTERN_STD_UNARY_FUNCTION(T, ceil) \
1819  RVEC_EXTERN_STD_UNARY_FUNCTION(T, trunc) \
1820  RVEC_EXTERN_STD_UNARY_FUNCTION(T, round) \
1821  RVEC_EXTERN_STD_UNARY_FUNCTION(T, erf) \
1822  RVEC_EXTERN_STD_UNARY_FUNCTION(T, erfc) \
1823  RVEC_EXTERN_STD_UNARY_FUNCTION(T, lgamma) \
1824  RVEC_EXTERN_STD_UNARY_FUNCTION(T, tgamma) \
1825 
1826 RVEC_EXTERN_STD_FUNCTIONS(float)
1827 RVEC_EXTERN_STD_FUNCTIONS(double)
1828 #undef RVEC_EXTERN_STD_UNARY_FUNCTION
1829 #undef RVEC_EXTERN_STD_BINARY_FUNCTION
1830 #undef RVEC_EXTERN_STD_UNARY_FUNCTIONS
1831 
1832 #ifdef R__HAS_VDT
1833 
1834 #define RVEC_EXTERN_VDT_UNARY_FUNCTION(T, F) RVEC_EXTERN_UNARY_FUNCTION(T, F, vdt::F)
1835 
1836 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_expf)
1837 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_logf)
1838 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_sinf)
1839 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_cosf)
1840 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_tanf)
1841 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_asinf)
1842 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_acosf)
1843 RVEC_EXTERN_VDT_UNARY_FUNCTION(float, fast_atanf)
1844 
1845 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_exp)
1846 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_log)
1847 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_sin)
1848 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_cos)
1849 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_tan)
1850 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_asin)
1851 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_acos)
1852 RVEC_EXTERN_VDT_UNARY_FUNCTION(double, fast_atan)
1853 
1854 #endif // R__HAS_VDT
1855 
1856 #endif // _VECOPS_USE_EXTERN_TEMPLATES
1857 
1858 } // End of VecOps NS
1859 
1860 // Allow to use RVec as ROOT::RVec
1861 using ROOT::VecOps::RVec;
1862 
1863 } // End of ROOT NS
1864 
1865 #endif // ROOT_RVEC