Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
RDFHelpers.hxx
Go to the documentation of this file.
1 // Author: Enrico Guiraud, Danilo Piparo CERN 02/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 // This header contains helper free functions that slim down RDataFrame's programming model
12 
13 #ifndef ROOT_RDF_HELPERS
14 #define ROOT_RDF_HELPERS
15 
16 #include <ROOT/RDataFrame.hxx>
17 #include <ROOT/RDF/GraphUtils.hxx>
19 #include <ROOT/TypeTraits.hxx>
20 
21 #include <algorithm> // std::transform
22 #include <functional>
23 #include <type_traits>
24 #include <vector>
25 #include <memory>
26 #include <fstream>
27 #include <iostream>
28 
29 namespace ROOT {
30 namespace Internal {
31 namespace RDF {
32 template <typename... ArgTypes, typename F>
33 std::function<bool(ArgTypes...)> NotHelper(ROOT::TypeTraits::TypeList<ArgTypes...>, F &&f)
34 {
35  return std::function<bool(ArgTypes...)>([=](ArgTypes... args) mutable { return !f(args...); });
36 }
37 
38 template <typename... ArgTypes, typename Ret, typename... Args>
39 std::function<bool(ArgTypes...)> NotHelper(ROOT::TypeTraits::TypeList<ArgTypes...>, Ret (*f)(Args...))
40 {
41  return std::function<bool(ArgTypes...)>([=](ArgTypes... args) mutable { return !f(args...); });
42 }
43 
44 template <typename I, typename T, typename F>
45 class PassAsVecHelper;
46 
47 template <std::size_t... N, typename T, typename F>
48 class PassAsVecHelper<std::index_sequence<N...>, T, F> {
49  template <std::size_t Idx>
50  using AlwaysT = T;
51  F fFunc;
52 
53 public:
54  PassAsVecHelper(F &&f) : fFunc(std::forward<F>(f)) {}
55  auto operator()(AlwaysT<N>... args) -> decltype(fFunc({args...})) { return fFunc({args...}); }
56 };
57 
58 template <std::size_t N, typename T, typename F>
59 auto PassAsVec(F &&f) -> PassAsVecHelper<std::make_index_sequence<N>, T, F>
60 {
61  return PassAsVecHelper<std::make_index_sequence<N>, T, F>(std::forward<F>(f));
62 }
63 
64 } // namespace RDF
65 } // namespace Internal
66 
67 namespace RDF {
68 namespace RDFInternal = ROOT::Internal::RDF;
69 
70 
71 // clag-format off
72 /// Given a callable with signature bool(T1, T2, ...) return a callable with same signature that returns the negated result
73 ///
74 /// The callable must have one single non-template definition of operator(). This is a limitation with respect to
75 /// std::not_fn, required for interoperability with RDataFrame.
76 // clang-format on
77 template <typename F,
78  typename Args = typename ROOT::TypeTraits::CallableTraits<typename std::decay<F>::type>::arg_types_nodecay,
79  typename Ret = typename ROOT::TypeTraits::CallableTraits<typename std::decay<F>::type>::ret_type>
80 auto Not(F &&f) -> decltype(RDFInternal::NotHelper(Args(), std::forward<F>(f)))
81 {
82  static_assert(std::is_same<Ret, bool>::value, "RDF::Not requires a callable that returns a bool.");
83  return RDFInternal::NotHelper(Args(), std::forward<F>(f));
84 }
85 
86 // clang-format off
87 /// PassAsVec is a callable generator that allows passing N variables of type T to a function as a single collection.
88 ///
89 /// PassAsVec<N, T>(func) returns a callable that takes N arguments of type T, passes them down to function `func` as
90 /// an initializer list `{t1, t2, t3,..., tN}` and returns whatever f({t1, t2, t3, ..., tN}) returns.
91 ///
92 /// Note that for this to work with RDataFrame the type of all columns that the callable is applied to must be exactly T.
93 /// Example usage together with RDataFrame ("varX" columns must all be `float` variables):
94 /// \code
95 /// bool myVecFunc(std::vector<float> args);
96 /// df.Filter(PassAsVec<3, float>(myVecFunc), {"var1", "var2", "var3"});
97 /// \endcode
98 // clang-format on
99 template <std::size_t N, typename T, typename F>
100 auto PassAsVec(F &&f) -> RDFInternal::PassAsVecHelper<std::make_index_sequence<N>, T, F>
101 {
102  return RDFInternal::PassAsVecHelper<std::make_index_sequence<N>, T, F>(std::forward<F>(f));
103 }
104 template <typename Proxied, typename DataSource>
105 class RInterface;
106 
107 
108 // clang-format off
109 /// Create a graphviz representation of the dataframe computation graph, return it as a string.
110 /// \param[in] node any node of the graph. Called on the head (first) node, it prints the entire graph. Otherwise, only the branch the node belongs to.
111 // clang-format on
112 template <typename NodeType>
113 std::string SaveGraph(NodeType node)
114 {
115  ROOT::Internal::RDF::GraphDrawing::GraphCreatorHelper helper;
116  return helper(node);
117 }
118 
119 // clang-format off
120 /// Create a graphviz representation of the dataframe computation graph, write it to the specified file.
121 /// \param[in] node any node of the graph. Called on the head (first) node, it prints the entire graph. Otherwise, only the branch the node belongs to.
122 /// \param[in] outputFile file where to save the representation.
123 // clang-format on
124 template <typename NodeType>
125 void SaveGraph(NodeType node, const std::string &outputFile)
126 {
127  ROOT::Internal::RDF::GraphDrawing::GraphCreatorHelper helper;
128  std::string dotGraph = helper(node);
129 
130  std::ofstream out(outputFile);
131  if (!out.is_open()) {
132  throw std::runtime_error("Could not open output file \"" + outputFile + "\"for reading");
133  }
134 
135  out << dotGraph;
136  out.close();
137 }
138 
139 // clang-format off
140 /// Cast a RDataFrame node to the common type ROOT::RDF::RNode
141 /// \param[in] Any node of a RDataFrame graph
142 // clang-format on
143 template <typename NodeType>
144 RNode AsRNode(NodeType node)
145 {
146  return node;
147 }
148 
149 } // namespace RDF
150 } // namespace ROOT
151 #endif