Skip to content

Commit 96be2a4

Browse files
committed
Improve BDT in L1Trigger/L1TMuonEndCap
- fixed memory corruption problems which could lead to double deletes or deletion of random memory locations - memory handling now done via std::unique_ptr - improved const correctness
1 parent eb45085 commit 96be2a4

File tree

6 files changed

+127
-177
lines changed

6 files changed

+127
-177
lines changed

L1Trigger/L1TMuonEndCap/interface/bdt/Forest.h

+11-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#ifndef L1Trigger_L1TMuonEndCap_emtf_Forest
44
#define L1Trigger_L1TMuonEndCap_emtf_Forest
55

6+
#include <memory>
67
#include "Tree.h"
78
#include "LossFunctions.h"
89
#include "CondFormats/L1TObjects/interface/L1TMuonEndCapForest.h"
@@ -14,28 +15,29 @@ namespace emtf {
1415
// Constructor(s)/Destructor
1516
Forest();
1617
Forest(std::vector<Event*>& trainingEvents);
17-
~Forest();
18+
~Forest() = default;
1819

1920
Forest(const Forest& forest);
2021
Forest& operator=(const Forest& forest);
2122
Forest(Forest&& forest) = default;
23+
Forest& operator=(Forest&& forest) = default;
2224

2325
// Get/Set
2426
void setTrainingEvents(std::vector<Event*>& trainingEvents);
2527
std::vector<Event*> getTrainingEvents();
2628

2729
// Returns the number of trees in the forest.
28-
unsigned int size();
30+
unsigned int size() const;
2931

3032
// Get info on variable importance.
31-
void rankVariables(std::vector<int>& rank);
33+
void rankVariables(std::vector<int>& rank) const;
3234

3335
// Output the list of split values used for each variable.
34-
void saveSplitValues(const char* savefilename);
36+
void saveSplitValues(const char* savefilename) const;
3537

3638
// Helpful operations
37-
void listEvents(std::vector<std::vector<Event*> >& e);
38-
void sortEventVectors(std::vector<std::vector<Event*> >& e);
39+
void listEvents(std::vector<std::vector<Event*>>& e) const;
40+
void sortEventVectors(std::vector<std::vector<Event*>>& e) const;
3941
void generate(int numTrainEvents, int numTestEvents, double sigma);
4042
void loadForestFromXML(const char* directory, unsigned int numTrees);
4143
void loadFromCondPayload(const L1TMuonEndCapForest::DForest& payload);
@@ -63,9 +65,9 @@ namespace emtf {
6365
Tree* getTree(unsigned int i);
6466

6567
private:
66-
std::vector<std::vector<Event*> > events;
67-
std::vector<std::vector<Event*> > subSample;
68-
std::vector<Tree*> trees;
68+
std::vector<std::vector<Event*>> events;
69+
std::vector<std::vector<Event*>> subSample;
70+
std::vector<std::unique_ptr<Tree>> trees;
6971
};
7072

7173
} // namespace emtf

L1Trigger/L1TMuonEndCap/interface/bdt/Node.h

+17-13
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <string>
77
#include <vector>
8+
#include <memory>
89
#include "Event.h"
910

1011
namespace emtf {
@@ -13,43 +14,46 @@ namespace emtf {
1314
public:
1415
Node();
1516
Node(std::string cName);
16-
~Node();
17+
~Node() = default;
1718

1819
Node(Node &&) = default;
1920
Node(const Node &) = delete;
2021
Node &operator=(const Node &) = delete;
2122

22-
std::string getName();
23+
std::string getName() const;
2324
void setName(std::string sName);
2425

25-
double getErrorReduction();
26+
double getErrorReduction() const;
2627
void setErrorReduction(double sErrorReduction);
2728

2829
Node *getLeftDaughter();
29-
void setLeftDaughter(Node *sLeftDaughter);
30+
const Node *getLeftDaughter() const;
31+
void setLeftDaughter(std::unique_ptr<Node> sLeftDaughter);
3032

33+
const Node *getRightDaughter() const;
3134
Node *getRightDaughter();
32-
void setRightDaughter(Node *sLeftDaughter);
35+
void setRightDaughter(std::unique_ptr<Node> sLeftDaughter);
3336

3437
Node *getParent();
38+
const Node *getParent() const;
3539
void setParent(Node *sParent);
3640

37-
double getSplitValue();
41+
double getSplitValue() const;
3842
void setSplitValue(double sSplitValue);
3943

40-
int getSplitVariable();
44+
int getSplitVariable() const;
4145
void setSplitVariable(int sSplitVar);
4246

43-
double getFitValue();
47+
double getFitValue() const;
4448
void setFitValue(double sFitValue);
4549

46-
double getTotalError();
50+
double getTotalError() const;
4751
void setTotalError(double sTotalError);
4852

49-
double getAvgError();
53+
double getAvgError() const;
5054
void setAvgError(double sAvgError);
5155

52-
int getNumEvents();
56+
int getNumEvents() const;
5357
void setNumEvents(int sNumEvents);
5458

5559
std::vector<std::vector<Event *> > &getEvents();
@@ -64,8 +68,8 @@ namespace emtf {
6468
private:
6569
std::string name;
6670

67-
Node *leftDaughter;
68-
Node *rightDaughter;
71+
std::unique_ptr<Node> leftDaughter;
72+
std::unique_ptr<Node> rightDaughter;
6973
Node *parent;
7074

7175
double splitValue;

L1Trigger/L1TMuonEndCap/interface/bdt/Tree.h

+10-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define L1Trigger_L1TMuonEndCap_emtf_Tree
55

66
#include <list>
7+
#include <memory>
78
#include "Node.h"
89
#include "TXMLEngine.h"
910
#include "CondFormats/L1TObjects/interface/L1TMuonEndCapForest.h"
@@ -16,14 +17,15 @@ namespace emtf {
1617
public:
1718
Tree();
1819
Tree(std::vector<std::vector<Event*>>& cEvents);
19-
~Tree();
20+
~Tree() = default;
2021

2122
Tree(const Tree& tree);
2223
Tree& operator=(const Tree& tree);
23-
Tree(Tree&& tree);
24+
Tree(Tree&& tree) = default;
2425

2526
void setRootNode(Node* sRootNode);
2627
Node* getRootNode();
28+
const Node* getRootNode() const;
2729

2830
void setTerminalNodes(std::list<Node*>& sTNodes);
2931
std::list<Node*>& getTerminalNodes();
@@ -48,25 +50,25 @@ namespace emtf {
4850
const L1TMuonEndCapForest::DTreeNode& node,
4951
Node* tnode);
5052

51-
void rankVariables(std::vector<double>& v);
52-
void rankVariablesRecursive(Node* node, std::vector<double>& v);
53+
void rankVariables(std::vector<double>& v) const;
54+
void rankVariablesRecursive(Node* node, std::vector<double>& v) const;
5355

54-
void getSplitValues(std::vector<std::vector<double>>& v);
55-
void getSplitValuesRecursive(Node* node, std::vector<std::vector<double>>& v);
56+
void getSplitValues(std::vector<std::vector<double>>& v) const;
57+
void getSplitValuesRecursive(Node* node, std::vector<std::vector<double>>& v) const;
5658

5759
double getBoostWeight(void) const { return boostWeight; }
5860
void setBoostWeight(double wgt) { boostWeight = wgt; }
5961

6062
private:
61-
Node* rootNode;
63+
std::unique_ptr<Node> rootNode;
6264
std::list<Node*> terminalNodes;
6365
int numTerminalNodes;
6466
double rmsError;
6567
double boostWeight;
6668
unsigned xmlVersion; // affects only XML loading part, save uses an old format and looses the boostWeight
6769

6870
// this is the main recursive workhorse function that compensates for Nodes being non-copyable
69-
Node* copyFrom(const Node* local_root); // no garantees if throws in the process
71+
std::unique_ptr<Node> copyFrom(const Node* local_root); // no garantees if throws in the process
7072
// a dumb DFS tree traversal
7173
void findLeafs(Node* local_root, std::list<Node*>& tn);
7274
};

L1Trigger/L1TMuonEndCap/src/bdt/Forest.cc

+25-48
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,17 @@ Forest::Forest() { events = std::vector<std::vector<Event*>>(1); }
4545

4646
Forest::Forest(std::vector<Event*>& trainingEvents) { setTrainingEvents(trainingEvents); }
4747

48-
/////////////////////////////////////////////////////////////////////////
49-
// _______________________Destructor____________________________________//
50-
//////////////////////////////////////////////////////////////////////////
51-
52-
Forest::~Forest() {
53-
// When the forest is destroyed it will delete the trees as well as the
54-
// events from the training and testing sets.
55-
// The user may want the events to remain after they destroy the forest
56-
// this should be changed in future upgrades.
57-
58-
for (unsigned int i = 0; i < trees.size(); i++) {
59-
if (trees[i])
60-
delete trees[i];
61-
}
62-
}
63-
6448
Forest::Forest(const Forest& forest) {
65-
transform(forest.trees.cbegin(), forest.trees.cend(), back_inserter(trees), [](const Tree* tree) {
66-
return new Tree(*tree);
49+
transform(forest.trees.cbegin(), forest.trees.cend(), back_inserter(trees), [](const std::unique_ptr<Tree>& tree) {
50+
return std::make_unique<Tree>(*tree);
6751
});
6852
}
6953

7054
Forest& Forest::operator=(const Forest& forest) {
71-
for (unsigned int i = 0; i < trees.size(); i++) {
72-
if (trees[i])
73-
delete trees[i];
74-
}
7555
trees.resize(0);
76-
77-
transform(forest.trees.cbegin(), forest.trees.cend(), back_inserter(trees), [](const Tree* tree) {
78-
return new Tree(*tree);
56+
trees.reserve(forest.trees.size());
57+
transform(forest.trees.cbegin(), forest.trees.cend(), back_inserter(trees), [](const std::unique_ptr<Tree>& tree) {
58+
return std::make_unique<Tree>(*tree);
7959
});
8060
return *this;
8161
}
@@ -113,7 +93,7 @@ std::vector<Event*> Forest::getTrainingEvents() { return events[0]; }
11393
// return the ith tree
11494
Tree* Forest::getTree(unsigned int i) {
11595
if (/*i>=0 && */ i < trees.size())
116-
return trees[i];
96+
return trees[i].get();
11797
else {
11898
//std::cout << i << "is an invalid input for getTree. Out of range." << std::endl;
11999
return nullptr;
@@ -124,7 +104,7 @@ Tree* Forest::getTree(unsigned int i) {
124104
// ______________________Various_Helpful_Functions______________________//
125105
//////////////////////////////////////////////////////////////////////////
126106

127-
unsigned int Forest::size() {
107+
unsigned int Forest::size() const {
128108
// Return the number of trees in the forest.
129109
return trees.size();
130110
}
@@ -139,7 +119,7 @@ unsigned int Forest::size() {
139119
// ----------------------------------------------------------------------
140120
//////////////////////////////////////////////////////////////////////////
141121

142-
void Forest::listEvents(std::vector<std::vector<Event*>>& e) {
122+
void Forest::listEvents(std::vector<std::vector<Event*>>& e) const {
143123
// Simply list the events in each event vector. We have multiple copies
144124
// of the events vector. Each copy is sorted according to a different
145125
// determining variable.
@@ -178,7 +158,7 @@ bool compareEventsById(Event* e1, Event* e2) {
178158
// ----------------------------------------------------------------------
179159
//////////////////////////////////////////////////////////////////////////
180160

181-
void Forest::sortEventVectors(std::vector<std::vector<Event*>>& e) {
161+
void Forest::sortEventVectors(std::vector<std::vector<Event*>>& e) const {
182162
// When a node chooses the optimum split point and split variable it needs
183163
// the events to be sorted according to the variable it is considering.
184164

@@ -192,7 +172,7 @@ void Forest::sortEventVectors(std::vector<std::vector<Event*>>& e) {
192172
// ----------------------------------------------------------------------
193173
//////////////////////////////////////////////////////////////////////////
194174

195-
void Forest::rankVariables(std::vector<int>& rank) {
175+
void Forest::rankVariables(std::vector<int>& rank) const {
196176
// This function ranks the determining variables according to their importance
197177
// in determining the fit. Use a low learning rate for better results.
198178
// Separates completely useless variables from useful ones well,
@@ -242,7 +222,7 @@ void Forest::rankVariables(std::vector<int>& rank) {
242222
// ----------------------------------------------------------------------
243223
//////////////////////////////////////////////////////////////////////////
244224

245-
void Forest::saveSplitValues(const char* savefilename) {
225+
void Forest::saveSplitValues(const char* savefilename) const {
246226
// This function gathers all of the split values from the forest and puts them into lists.
247227

248228
std::ofstream splitvaluefile;
@@ -377,8 +357,8 @@ void Forest::doRegression(int nodeLimit,
377357

378358
for (unsigned int i = 0; i < (unsigned)treeLimit; i++) {
379359
// std::cout << "++Building Tree " << i << "... " << std::endl;
380-
Tree* tree = new Tree(events);
381-
trees.push_back(tree);
360+
trees.emplace_back(std::make_unique<Tree>(events));
361+
Tree* tree = trees.back().get();
382362
tree->buildTree(nodeLimit);
383363

384364
// Update the targets for the next tree to fit.
@@ -426,7 +406,7 @@ void Forest::predictEvents(std::vector<Event*>& eventsp, unsigned int numtrees)
426406
void Forest::appendCorrection(std::vector<Event*>& eventsp, int treenum) {
427407
// Update the prediction by appending the next correction.
428408

429-
Tree* tree = trees[treenum];
409+
Tree* tree = trees[treenum].get();
430410
tree->filterEvents(eventsp);
431411

432412
// Update the events with their new prediction.
@@ -463,7 +443,7 @@ void Forest::predictEvent(Event* e, unsigned int numtrees) {
463443
void Forest::appendCorrection(Event* e, int treenum) {
464444
// Update the prediction by appending the next correction.
465445

466-
Tree* tree = trees[treenum];
446+
Tree* tree = trees[treenum].get();
467447
Node* terminalNode = tree->filterEvent(e);
468448

469449
// Update the event with its new prediction.
@@ -478,12 +458,13 @@ void Forest::loadForestFromXML(const char* directory, unsigned int numTrees) {
478458
// Load a forest that has already been created and stored into XML somewhere.
479459

480460
// Initialize the vector of trees.
481-
trees = std::vector<Tree*>(numTrees);
461+
trees.resize(numTrees);
462+
trees.shrink_to_fit();
482463

483464
// Load the Forest.
484465
// std::cout << std::endl << "Loading Forest from XML ... " << std::endl;
485466
for (unsigned int i = 0; i < numTrees; i++) {
486-
trees[i] = new Tree();
467+
trees[i] = std::make_unique<Tree>();
487468

488469
std::stringstream ss;
489470
ss << directory << "/" << i << ".xml";
@@ -499,17 +480,12 @@ void Forest::loadFromCondPayload(const L1TMuonEndCapForest::DForest& forest) {
499480
// Initialize the vector of trees.
500481
unsigned int numTrees = forest.size();
501482

502-
// clean-up leftovers from previous initialization (if any)
503-
for (unsigned int i = 0; i < trees.size(); i++) {
504-
if (trees[i])
505-
delete trees[i];
506-
}
507-
508-
trees = std::vector<Tree*>(numTrees);
483+
trees.resize(numTrees);
484+
trees.shrink_to_fit();
509485

510486
// Load the Forest.
511487
for (unsigned int i = 0; i < numTrees; i++) {
512-
trees[i] = new Tree();
488+
trees[i] = std::make_unique<Tree>();
513489
trees[i]->loadFromCondPayload(forest[i]);
514490
}
515491
}
@@ -556,7 +532,8 @@ void Forest::doStochasticRegression(
556532

557533
// Prepare some things.
558534
sortEventVectors(events);
559-
trees = std::vector<Tree*>(treeLimit);
535+
trees.resize(treeLimit);
536+
trees.shrink_to_fit();
560537

561538
// See how long the regression takes.
562539
TStopwatch timer;
@@ -572,15 +549,15 @@ void Forest::doStochasticRegression(
572549
for (unsigned int i = 0; i < (unsigned)treeLimit; i++) {
573550
// Build the tree using a random subsample.
574551
prepareRandomSubsample(fraction);
575-
trees[i] = new Tree(subSample);
552+
trees[i] = std::make_unique<Tree>(subSample);
576553
trees[i]->buildTree(nodeLimit);
577554

578555
// Fit all of the events based upon the tree we built using
579556
// the subsample of events.
580557
trees[i]->filterEvents(events[0]);
581558

582559
// Update the targets for the next tree to fit.
583-
updateRegTargets(trees[i], learningRate, l);
560+
updateRegTargets(trees[i].get(), learningRate, l);
584561

585562
// Save trees to xml in some directory.
586563
std::ostringstream ss;

0 commit comments

Comments
 (0)