LArMvaHelper.h
Go to the documentation of this file.
1 /**
2  * @file larpandoracontent/include/LArHelpers/LArMvaHelper.h
3  *
4  * @brief Header file for the lar mva helper class.
5  *
6  * $Log: $
7  */
8 #ifndef LAR_MVA_HELPER_H
9 #define LAR_MVA_HELPER_H 1
10 
12 
13 #include "Pandora/AlgorithmTool.h"
14 #include "Pandora/StatusCodes.h"
15 
16 #include <chrono>
17 #include <ctime>
18 #include <fstream>
19 
20 namespace lar_content
21 {
22 
23 /**
24  * @brief MvaFeatureTool class template
25  */
26 template <typename... Ts>
27 class MvaFeatureTool : public pandora::AlgorithmTool
28 {
29 public:
31 
32  /**
33  * @brief Default constructor.
34  */
35  MvaFeatureTool() = default;
36 
37  /**
38  * @brief Run the algorithm tool
39  *
40  * @param featureVector the vector of features to append
41  * @param args arguments to pass to the tool
42  */
43  virtual void Run(MvaTypes::MvaFeatureVector &featureVector, Ts... args) = 0;
44 };
45 
46 template <typename... Ts>
48 
49 //------------------------------------------------------------------------------------------------------------------------------------------
50 
51 /**
52  * @brief LArMvaHelper class
53  */
55 {
56 public:
59 
60  /**
61  * @brief Produce a training example with the given features and result
62  *
63  * @param trainingOutputFile the file to which to append the example
64  * @param featureLists the lists of features
65  *
66  * @return success
67  */
68  template <typename... TLISTS>
69  static pandora::StatusCode ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TLISTS &&... featureLists);
70 
71  /**
72  * @brief Use the trained classifier to predict the boolean class of an example
73  *
74  * @param classifier the classifier
75  * @param featureLists the lists of features
76  *
77  * @return the predicted boolean class of the example
78  */
79  template <typename... TLISTS>
80  static bool Classify(const MvaInterface &classifier, TLISTS &&... featureLists);
81 
82  /**
83  * @brief Use the trained classifer to calculate the classification score of an example (>0 means boolean class true)
84  *
85  * @param classifier the classifier
86  * @param featureLists the lists of features
87  *
88  * @return the classification score
89  */
90  template <typename... TLISTS>
91  static double CalculateClassificationScore(const MvaInterface &classifier, TLISTS &&... featureLists);
92 
93  /**
94  * @brief Use the trained mva to calculate a classification probability for an example
95  *
96  * @param classifier the classifier
97  * @param featureLists the lists of features
98  *
99  * @return the classification probability
100  */
101  template <typename... TLISTS>
102  static double CalculateProbability(const MvaInterface &classifier, TLISTS &&... featureLists);
103 
104  /**
105  * @brief Calculate the features in a given feature tool vector
106  *
107  * @param featureToolVector the feature tool vector
108  * @param args arguments to pass to the tool
109  *
110  * @return the vector of features
111  */
112  template <typename... Ts, typename... TARGS>
113  static MvaFeatureVector CalculateFeatures(const MvaFeatureToolVector<Ts...> &featureToolVector, TARGS &&... args);
114 
115  /**
116  * @brief Calculate the features of a given derived feature tool type in a feature tool vector
117  *
118  * @param featureToolVector the feature tool vector
119  * @param args arguments to pass to the tool
120  *
121  * @return the vector of features
122  */
123  template <typename T, typename... Ts, typename... TARGS>
124  static MvaFeatureVector CalculateFeaturesOfType(const MvaFeatureToolVector<Ts...> &featureToolVector, TARGS &&... args);
125 
126  /**
127  * @brief Add a feature tool to a vector of feature tools
128  *
129  * @param pFeatureTool the feature tool
130  * @param featureToolVector the vector to append
131  *
132  * @return success
133  */
134  template <typename... Ts>
135  static pandora::StatusCode AddFeatureToolToVector(pandora::AlgorithmTool *const pFeatureTool, MvaFeatureToolVector<Ts...> &featureToolVector);
136 
137 private:
138  /**
139  * @brief Get a timestamp string for this point in time
140  *
141  * @return a timestamp string
142  */
143  static std::string GetTimestampString();
144 
145  /**
146  * @brief Recursively write the features of the given lists to file
147  *
148  * @param outfile the std::ofstream object to use
149  * @param delimiter the delimiter string
150  * @param featureList a list of features to write
151  * @param featureLists optional further lists of features to write
152  *
153  * @return success
154  */
155  template <typename TLIST, typename... TLISTS>
156  static pandora::StatusCode WriteFeaturesToFile(std::ofstream &outfile, const std::string &delimiter, TLIST &&featureList, TLISTS &&... featureLists);
157 
158  /**
159  * @brief Recursively write the features of the given lists to file (terminating method)
160  *
161  * @return success
162  */
163  static pandora::StatusCode WriteFeaturesToFile(std::ofstream &, const std::string &);
164 
165  /**
166  * @brief Write the features of the given list to file (implementation method)
167  *
168  * @param outfile the std::ofstream object to use
169  * @param delimiter the delimiter string
170  * @param featureList a list of features to write
171  *
172  * @return success
173  */
174  template <typename TLIST>
175  static pandora::StatusCode WriteFeaturesToFileImpl(std::ofstream &outfile, const std::string &delimiter, TLIST &&featureList);
176 
177  /**
178  * @brief Recursively concatenate vectors of features
179  *
180  * @param featureList a list of features
181  * @param featureLists optional further lists of features
182  *
183  * @return the concatenated vector of features
184  */
185  template <typename TLIST, typename... TLISTS>
186  static MvaFeatureVector ConcatenateFeatureLists(TLIST &&featureList, TLISTS &&... featureLists);
187 
188  /**
189  * @brief Recursively concatenate vectors of features (terminating method)
190  */
191  static MvaFeatureVector ConcatenateFeatureLists();
192 };
193 
194 //------------------------------------------------------------------------------------------------------------------------------------------
195 
196 template <typename... TLISTS>
197 pandora::StatusCode LArMvaHelper::ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TLISTS &&... featureLists)
198 {
199  std::ofstream outfile;
200  outfile.open(trainingOutputFile, std::ios_base::app); // always append to the output file
201 
202  if (!outfile.is_open())
203  {
204  std::cout << "LArMvaHelper: could not open file for training examples at " << trainingOutputFile << std::endl;
205  return pandora::STATUS_CODE_FAILURE;
206  }
207 
208  std::string delimiter(",");
209  outfile << GetTimestampString() << delimiter;
210 
211  PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, WriteFeaturesToFile(outfile, delimiter, featureLists...));
212  outfile << static_cast<int>(result) << '\n';
213 
214  return pandora::STATUS_CODE_SUCCESS;
215 }
216 
217 //------------------------------------------------------------------------------------------------------------------------------------------
218 
219 template <typename... TLISTS>
220 bool LArMvaHelper::Classify(const MvaInterface &classifier, TLISTS &&... featureLists)
221 {
222  return classifier.Classify(ConcatenateFeatureLists(std::forward<TLISTS>(featureLists)...));
223 }
224 
225 //------------------------------------------------------------------------------------------------------------------------------------------
226 
227 template <typename... TLISTS>
228 double LArMvaHelper::CalculateClassificationScore(const MvaInterface &classifier, TLISTS &&... featureLists)
229 {
230  return classifier.CalculateClassificationScore(ConcatenateFeatureLists(std::forward<TLISTS>(featureLists)...));
231 }
232 
233 //------------------------------------------------------------------------------------------------------------------------------------------
234 
235 template <typename... TLISTS>
236 double LArMvaHelper::CalculateProbability(const MvaInterface &classifier, TLISTS &&... featureLists)
237 {
238  return classifier.CalculateProbability(ConcatenateFeatureLists(std::forward<TLISTS>(featureLists)...));
239 }
240 
241 //------------------------------------------------------------------------------------------------------------------------------------------
242 
243 template <typename... Ts, typename... TARGS>
245 {
246  LArMvaHelper::MvaFeatureVector featureVector;
247 
248  for (MvaFeatureTool<Ts...> *const pFeatureTool : featureToolVector)
249  pFeatureTool->Run(featureVector, std::forward<TARGS>(args)...);
250 
251  return featureVector;
252 }
253 
254 //------------------------------------------------------------------------------------------------------------------------------------------
255 
256 template <typename T, typename... Ts, typename... TARGS>
258 {
259  using TD = typename std::decay<T>::type;
260  LArMvaHelper::MvaFeatureVector featureVector;
261 
262  for (MvaFeatureTool<Ts...> *const pFeatureTool : featureToolVector)
263  {
264  if (TD *const pCastFeatureTool = dynamic_cast<TD *const>(pFeatureTool))
265  pCastFeatureTool->Run(featureVector, std::forward<TARGS>(args)...);
266  }
267 
268  return featureVector;
269 }
270 
271 //------------------------------------------------------------------------------------------------------------------------------------------
272 
273 template <typename... Ts>
274 pandora::StatusCode LArMvaHelper::AddFeatureToolToVector(pandora::AlgorithmTool *const pFeatureTool, MvaFeatureToolVector<Ts...> &featureToolVector)
275 {
276  if (MvaFeatureTool<Ts...> *const pCastFeatureTool = dynamic_cast<MvaFeatureTool<Ts...> *const>(pFeatureTool))
277  {
278  featureToolVector.push_back(pCastFeatureTool);
279  return pandora::STATUS_CODE_SUCCESS;
280  }
281 
282  return pandora::STATUS_CODE_FAILURE;
283 }
284 
285 //------------------------------------------------------------------------------------------------------------------------------------------
286 
288 {
289  std::time_t timestampNow = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
290 
291  struct tm *pTimeInfo(NULL);
292  char buffer[80];
293 
294  pTimeInfo = localtime(&timestampNow);
295  strftime(buffer, 80, "%x_%X", pTimeInfo);
296 
297  std::string timeString(buffer);
298 
299  if (!timeString.empty() && timeString.back() == '\n') // last char is always a newline
300  timeString.pop_back();
301 
302  return timeString;
303 }
304 
305 //------------------------------------------------------------------------------------------------------------------------------------------
306 
307 template <typename TLIST, typename... TLISTS>
308 inline pandora::StatusCode LArMvaHelper::WriteFeaturesToFile(
309  std::ofstream &outfile, const std::string &delimiter, TLIST &&featureList, TLISTS &&... featureLists)
310 {
311  static_assert(std::is_same<typename std::decay<TLIST>::type, LArMvaHelper::MvaFeatureVector>::value,
312  "LArMvaHelper: Could not write training set example because a passed parameter was not a vector of MvaFeatures");
313 
314  PANDORA_RETURN_RESULT_IF(pandora::STATUS_CODE_SUCCESS, !=, WriteFeaturesToFileImpl(outfile, delimiter, featureList));
315  return WriteFeaturesToFile(outfile, delimiter, featureLists...);
316 }
317 
318 //------------------------------------------------------------------------------------------------------------------------------------------
319 
320 inline pandora::StatusCode LArMvaHelper::WriteFeaturesToFile(std::ofstream &, const std::string &)
321 {
322  return pandora::STATUS_CODE_SUCCESS;
323 }
324 
325 //------------------------------------------------------------------------------------------------------------------------------------------
326 
327 template <typename TLIST>
328 pandora::StatusCode LArMvaHelper::WriteFeaturesToFileImpl(std::ofstream &outfile, const std::string &delimiter, TLIST &&featureList)
329 {
330  for (const MvaFeature &feature : featureList)
331  outfile << feature.Get() << delimiter;
332 
333  return pandora::STATUS_CODE_SUCCESS;
334 }
335 
336 //------------------------------------------------------------------------------------------------------------------------------------------
337 
338 template <typename TLIST, typename... TLISTS>
339 LArMvaHelper::MvaFeatureVector LArMvaHelper::ConcatenateFeatureLists(TLIST &&featureList, TLISTS &&... featureLists)
340 {
341  static_assert(std::is_same<typename std::decay<TLIST>::type, LArMvaHelper::MvaFeatureVector>::value,
342  "LArMvaHelper: Could not concatenate feature lists because one or more lists was not a vector of MvaFeatures");
343 
344  LArMvaHelper::MvaFeatureVector featureVector;
345 
346  for (const MvaFeature &feature : featureList)
347  featureVector.push_back(feature);
348 
349  LArMvaHelper::MvaFeatureVector newFeatureVector = ConcatenateFeatureLists(std::forward<TLISTS>(featureLists)...);
350  featureVector.insert(featureVector.end(), newFeatureVector.begin(), newFeatureVector.end());
351 
352  return featureVector;
353 }
354 
355 //------------------------------------------------------------------------------------------------------------------------------------------
356 
358 {
360 }
361 
362 } // namespace lar_content
363 
364 #endif // #ifndef LAR_MVA_HELPER_H
static double CalculateProbability(const MvaInterface &classifier, TLISTS &&...featureLists)
Use the trained mva to calculate a classification probability for an example.
Definition: LArMvaHelper.h:236
static pandora::StatusCode WriteFeaturesToFileImpl(std::ofstream &outfile, const std::string &delimiter, TLIST &&featureList)
Write the features of the given list to file (implementation method)
Definition: LArMvaHelper.h:328
MvaTypes::MvaFeatureVector MvaFeatureVector
Definition: LArMvaHelper.h:58
static QCString result
std::string string
Definition: nybbler.cc:12
MvaFeatureTool()=default
Default constructor.
virtual void Run(MvaTypes::MvaFeatureVector &featureVector, Ts...args)=0
Run the algorithm tool.
static std::string GetTimestampString()
Get a timestamp string for this point in time.
Definition: LArMvaHelper.h:287
struct vector vector
static pandora::StatusCode WriteFeaturesToFile(std::ofstream &outfile, const std::string &delimiter, TLIST &&featureList, TLISTS &&...featureLists)
Recursively write the features of the given lists to file.
Definition: LArMvaHelper.h:308
MvaInterface class.
static bool Classify(const MvaInterface &classifier, TLISTS &&...featureLists)
Use the trained classifier to predict the boolean class of an example.
Definition: LArMvaHelper.h:220
std::vector< MvaFeatureTool< Ts... > * > MvaFeatureToolVector
Definition: LArMvaHelper.h:47
static QCString args
Definition: declinfo.cpp:674
tm
Definition: demo.py:21
MvaTypes::MvaFeature MvaFeature
Definition: LArMvaHelper.h:57
static double CalculateClassificationScore(const MvaInterface &classifier, TLISTS &&...featureLists)
Use the trained classifer to calculate the classification score of an example (>0 means boolean class...
Definition: LArMvaHelper.h:228
static pandora::StatusCode ProduceTrainingExample(const std::string &trainingOutputFile, const bool result, TLISTS &&...featureLists)
Produce a training example with the given features and result.
Definition: LArMvaHelper.h:197
virtual bool Classify(const MvaTypes::MvaFeatureVector &features) const =0
Classify the set of input features based on the trained model.
static MvaFeatureVector CalculateFeaturesOfType(const MvaFeatureToolVector< Ts... > &featureToolVector, TARGS &&...args)
Calculate the features of a given derived feature tool type in a feature tool vector.
Definition: LArMvaHelper.h:257
InitializedDouble class used to define mva features.
static pandora::StatusCode AddFeatureToolToVector(pandora::AlgorithmTool *const pFeatureTool, MvaFeatureToolVector< Ts... > &featureToolVector)
Add a feature tool to a vector of feature tools.
Definition: LArMvaHelper.h:274
LArMvaHelper class.
Definition: LArMvaHelper.h:54
virtual double CalculateProbability(const MvaTypes::MvaFeatureVector &features) const =0
Calculate the classification probability for a set of input features, based on the trained model...
std::vector< MvaFeatureTool< Ts... > * > FeatureToolVector
Definition: LArMvaHelper.h:30
virtual double CalculateClassificationScore(const MvaTypes::MvaFeatureVector &features) const =0
Calculate the classification score for a set of input features, based on the trained model...
static QCString type
Definition: declinfo.cpp:672
static MvaFeatureVector CalculateFeatures(const MvaFeatureToolVector< Ts... > &featureToolVector, TARGS &&...args)
Calculate the features in a given feature tool vector.
Definition: LArMvaHelper.h:244
static MvaFeatureVector ConcatenateFeatureLists()
Recursively concatenate vectors of features (terminating method)
Definition: LArMvaHelper.h:357
MvaFeatureTool class template.
Definition: LArMvaHelper.h:27
std::vector< MvaFeature > MvaFeatureVector
Header file for the lar multivariate analysis interface class.
QTextStream & endl(QTextStream &s)