// @(#)root/tmva $Id$
// Author: Tancredi Carli, Dominik Dannheim, Alexander Voigt

/**********************************************************************************
 * Project: TMVA - a Root-integrated toolkit for multivariate data analysis       *
 * Package: TMVA                                                                  *
 * Classes: PDEFoamMultiTarget                                                    *
 * Web    : http://tmva.sourceforge.net                                           *
 *                                                                                *
 * Description:                                                                   *
 *      Implementation.                                                           *
 *                                                                                *
 * Authors (alphabetical):                                                        *
 *      Tancredi Carli   - CERN, Switzerland                                      *
 *      Dominik Dannheim - CERN, Switzerland                                      *
 *      S. Jadach        - Institute of Nuclear Physics, Cracow, Poland           *
 *      Alexander Voigt  - TU Dresden, Germany                                    *
 *      Peter Speckmayer - CERN, Switzerland                                      *
 *                                                                                *
 * Copyright (c) 2008, 2010:                                                      *
 *      CERN, Switzerland                                                         *
 *      MPI-K Heidelberg, Germany                                                 *
 *                                                                                *
 * Redistribution and use in source and binary forms, with or without             *
 * modification, are permitted according to the terms listed in LICENSE           *
 * (http://tmva.sourceforge.net/LICENSE)                                          *
 **********************************************************************************/

//_____________________________________________________________________
//
// PDEFoamMultiTarget
//
// This PDEFoam variant is used to estimate multiple targets by
// creating an event density foam (PDEFoamEvent), which has dimension:
//
//    dimension = number of variables + number targets
//
// This PDEFoam variant stores in every cell the sum of event weights
// and the sum of the squared event weights.  During evaluation for a
// given event, which has only variables and no targets (number of
// event variables is smaller than the foam dimension), the targets
// are estimated by finding all cells, which correspond to this event
// and calculate the Mean (or Mpv, depending on the ETargetSelection)
// cell center weighted by the event density in the cell.
//
// This PDEFoam variant should be booked together with the
// PDEFoamEventDensity density estimator, which returns the event
// weight density at a given phase space point during the foam
// build-up.
//
//_____________________________________________________________________

#ifndef ROOT_TMVA_PDEFoamMultiTarget
#include "TMVA/PDEFoamMultiTarget.h"
#endif

ClassImp(TMVA::PDEFoamMultiTarget)

//_____________________________________________________________________
TMVA::PDEFoamMultiTarget::PDEFoamMultiTarget()
   : PDEFoamEvent()
   , fTargetSelection(kMean)
{
   // Default constructor for streamer, user should not use it.
}

//_____________________________________________________________________
TMVA::PDEFoamMultiTarget::PDEFoamMultiTarget(const TString& name, ETargetSelection ts)
   : PDEFoamEvent(name)
   , fTargetSelection(ts)
{
   // User constructor
   //
   // Parameters:
   //
   // - name - name of PDEFoam object
   //
   // - ts - target selection method used in
   //   GetCellValue(const std::map<Int_t, Float_t>& xvec, ECellValue)
   //   Cadidates are: TMVA::kMean, TMVA::kMpv
   //
   //   - TMVA::kMean - The function GetCellValue() finds all cells
   //     which contain a given event vector 'xvec' and returns the
   //     mean target (for every target variable in the foam).
   //
   //   - TMVA::kMpv - The function GetCellValue() finds all cells
   //     which contain a given event vector 'xvec' and returns the
   //     most probable target (for every target variable in the
   //     foam), that is the target value which corresponds to the
   //     cell with the largest event density.
}

//_____________________________________________________________________
TMVA::PDEFoamMultiTarget::PDEFoamMultiTarget(const PDEFoamMultiTarget &from)
   : PDEFoamEvent(from)
   , fTargetSelection(from.fTargetSelection)
{
   // Copy Constructor  NOT IMPLEMENTED (NEVER USED)
   Log() << kFATAL << "COPY CONSTRUCTOR NOT IMPLEMENTED" << Endl;
}

//_____________________________________________________________________
std::vector<Float_t> TMVA::PDEFoamMultiTarget::GetCellValue(const std::map<Int_t, Float_t>& xvec, ECellValue /*cv*/)
{
   // This function is overridden from PDFEFoam.  It returns all
   // regression targets (in order), given an untransformed event
   // vector 'xvec'.  The key of 'xvec' is the dimension and the value
   // (Float_t) is the coordinate.
   //
   // Note: number of foam dimensions = number of variables + number
   // of targets
   //
   // Parameters:
   // - xvec - map of event variables (no targets!)
   // - cv - cell value to return (ignored!)
   //
   // Return:
   // Targets, ordered by missing dimensions in 'xvec'.
   // The size of the returned vector = foam dimension - size of xvec.

   // transform event vector
   std::map<Int_t, Float_t> txvec; // transformed event vector
   for (std::map<Int_t, Float_t>::const_iterator it = xvec.begin();
        it != xvec.end(); ++it) {
      Float_t coordinate = it->second; // event coordinate
      Int_t dim = it->first;           // dimension
      // checkt whether coordinate is within foam borders. if not,
      // push event coordinate into foam
      if (coordinate <= fXmin[dim])
         coordinate = fXmin[dim] + std::numeric_limits<float>::epsilon();
      else if (coordinate >= fXmax[dim])
         coordinate = fXmax[dim] - std::numeric_limits<float>::epsilon();
      // transform event
      txvec.insert(std::pair<Int_t, Float_t>(dim, VarTransform(dim, coordinate)));
   }

   // map of targets
   std::map<Int_t, Float_t> target;

   // find cells, which fit txvec
   std::vector<PDEFoamCell*> cells = FindCells(txvec);
   if (cells.empty()) {
      // return empty target vector (size = dimension of foam -
      // number of variables)
      return std::vector<Float_t>(GetTotDim() - xvec.size(), 0);
   }

   // initialize the target map
   for (Int_t idim = 0; idim < GetTotDim(); ++idim) {
      // is idim a target dimension, i.e. is idim missing in txvec?
      if (txvec.find(idim) == txvec.end())
         target.insert(std::pair<Int_t, Float_t>(idim, 0));
   }

   switch (fTargetSelection) {
   case kMean:
      CalculateMean(target, cells);
      break;
   case kMpv:
      CalculateMpv(target, cells);
      break;
   default:
      Log() << "<PDEFoamMultiTarget::GetCellValue>: "
            << "unknown target selection type!" << Endl;
      break;
   }

   // copy targets to result vector
   std::vector<Float_t> result;
   result.reserve(target.size());
   for (std::map<Int_t, Float_t>::const_iterator it = target.begin();
        it != target.end(); ++it)
      result.push_back(it->second);

   return result;
}

void TMVA::PDEFoamMultiTarget::CalculateMpv(std::map<Int_t, Float_t>& target, const std::vector<PDEFoamCell*>& cells)
{
   // This function calculates the most probable target value from a
   // given number of cells.  The most probable target is defined to
   // be the coordinates of the cell which has the biggest event
   // density.
   //
   // Parameters:
   //
   // - target - map of targets, where the key is the dimension and
   //   the value is the target value.  It is assumed that this map is
   //   initialized such that there is a map entry for every target.
   //
   // - cells - vector of PDEFoam cells to pick the most probable
   //   target from

   Double_t max_dens = 0.0;            // maximum cell density

   // loop over all cells and find cell with maximum event density
   for (std::vector<PDEFoamCell*>::const_iterator cell_it = cells.begin();
        cell_it != cells.end(); ++cell_it) {

      // get event density of cell
      const Double_t cell_density = GetCellValue(*cell_it, kValueDensity);

      // has this cell a larger event density?
      if (cell_density > max_dens) {
         // get cell position and size
         PDEFoamVect  cellPosi(GetTotDim()), cellSize(GetTotDim());
         (*cell_it)->GetHcub(cellPosi, cellSize);

         // save new maximum density
         max_dens = cell_density;

         // calculate new target values
         for (std::map<Int_t, Float_t>::iterator target_it = target.begin();
              target_it != target.end(); ++target_it) {
            const Int_t dim = target_it->first; // target dimension
            target_it->second =
               VarTransformInvers(dim, cellPosi[dim] + 0.5 * cellSize[dim]);
         }
      }
   }
}

void TMVA::PDEFoamMultiTarget::CalculateMean(std::map<Int_t, Float_t>& target, const std::vector<PDEFoamCell*>& cells)
{
   // This function calculates the mean target value from a given
   // number of cells.  As weight the event density of the cell is
   // used.
   //
   // Parameters:
   //
   // - target - map of targets, where the key is the dimension and
   //   the value is the target value.  It is assumed that this map is
   //   initialized such that there is a map entry for every target
   //   with all target values set to zero.
   //
   // - cells - vector of PDEFoam cells to pick the most probable
   //   target from

   // normalization
   std::map<Int_t, Float_t> norm;

   // loop over all cells and find cell with maximum event density
   for (std::vector<PDEFoamCell*>::const_iterator cell_it = cells.begin();
        cell_it != cells.end(); ++cell_it) {

      // get event density of cell
      const Double_t cell_density = GetCellValue(*cell_it, kValueDensity);

      // get cell position and size
      PDEFoamVect  cellPosi(GetTotDim()), cellSize(GetTotDim());
      (*cell_it)->GetHcub(cellPosi, cellSize);

      // accumulate weighted target values
      for (std::map<Int_t, Float_t>::iterator target_it = target.begin();
           target_it != target.end(); ++target_it) {
         const Int_t dim = target_it->first; // target dimension
         target_it->second += cell_density *
            VarTransformInvers(dim, cellPosi[dim] + 0.5 * cellSize[dim]);
         norm[dim] += cell_density;
      }
   }

   // normalize the targets
   for (std::map<Int_t, Float_t>::iterator target_it = target.begin();
        target_it != target.end(); ++target_it) {

      // get target dimension
      const Int_t dim = target_it->first;

      // normalize target in dimension 'dim'
      if (norm[dim] > std::numeric_limits<Float_t>::epsilon()) {
         target[dim] /= norm[dim];
      } else {
         // normalisation factor is too small -> return approximate
         // target value
         target[dim] = (fXmax[dim] - fXmin[dim]) / 2.;
      }
   }
}
 PDEFoamMultiTarget.cxx:1
 PDEFoamMultiTarget.cxx:2
 PDEFoamMultiTarget.cxx:3
 PDEFoamMultiTarget.cxx:4
 PDEFoamMultiTarget.cxx:5
 PDEFoamMultiTarget.cxx:6
 PDEFoamMultiTarget.cxx:7
 PDEFoamMultiTarget.cxx:8
 PDEFoamMultiTarget.cxx:9
 PDEFoamMultiTarget.cxx:10
 PDEFoamMultiTarget.cxx:11
 PDEFoamMultiTarget.cxx:12
 PDEFoamMultiTarget.cxx:13
 PDEFoamMultiTarget.cxx:14
 PDEFoamMultiTarget.cxx:15
 PDEFoamMultiTarget.cxx:16
 PDEFoamMultiTarget.cxx:17
 PDEFoamMultiTarget.cxx:18
 PDEFoamMultiTarget.cxx:19
 PDEFoamMultiTarget.cxx:20
 PDEFoamMultiTarget.cxx:21
 PDEFoamMultiTarget.cxx:22
 PDEFoamMultiTarget.cxx:23
 PDEFoamMultiTarget.cxx:24
 PDEFoamMultiTarget.cxx:25
 PDEFoamMultiTarget.cxx:26
 PDEFoamMultiTarget.cxx:27
 PDEFoamMultiTarget.cxx:28
 PDEFoamMultiTarget.cxx:29
 PDEFoamMultiTarget.cxx:30
 PDEFoamMultiTarget.cxx:31
 PDEFoamMultiTarget.cxx:32
 PDEFoamMultiTarget.cxx:33
 PDEFoamMultiTarget.cxx:34
 PDEFoamMultiTarget.cxx:35
 PDEFoamMultiTarget.cxx:36
 PDEFoamMultiTarget.cxx:37
 PDEFoamMultiTarget.cxx:38
 PDEFoamMultiTarget.cxx:39
 PDEFoamMultiTarget.cxx:40
 PDEFoamMultiTarget.cxx:41
 PDEFoamMultiTarget.cxx:42
 PDEFoamMultiTarget.cxx:43
 PDEFoamMultiTarget.cxx:44
 PDEFoamMultiTarget.cxx:45
 PDEFoamMultiTarget.cxx:46
 PDEFoamMultiTarget.cxx:47
 PDEFoamMultiTarget.cxx:48
 PDEFoamMultiTarget.cxx:49
 PDEFoamMultiTarget.cxx:50
 PDEFoamMultiTarget.cxx:51
 PDEFoamMultiTarget.cxx:52
 PDEFoamMultiTarget.cxx:53
 PDEFoamMultiTarget.cxx:54
 PDEFoamMultiTarget.cxx:55
 PDEFoamMultiTarget.cxx:56
 PDEFoamMultiTarget.cxx:57
 PDEFoamMultiTarget.cxx:58
 PDEFoamMultiTarget.cxx:59
 PDEFoamMultiTarget.cxx:60
 PDEFoamMultiTarget.cxx:61
 PDEFoamMultiTarget.cxx:62
 PDEFoamMultiTarget.cxx:63
 PDEFoamMultiTarget.cxx:64
 PDEFoamMultiTarget.cxx:65
 PDEFoamMultiTarget.cxx:66
 PDEFoamMultiTarget.cxx:67
 PDEFoamMultiTarget.cxx:68
 PDEFoamMultiTarget.cxx:69
 PDEFoamMultiTarget.cxx:70
 PDEFoamMultiTarget.cxx:71
 PDEFoamMultiTarget.cxx:72
 PDEFoamMultiTarget.cxx:73
 PDEFoamMultiTarget.cxx:74
 PDEFoamMultiTarget.cxx:75
 PDEFoamMultiTarget.cxx:76
 PDEFoamMultiTarget.cxx:77
 PDEFoamMultiTarget.cxx:78
 PDEFoamMultiTarget.cxx:79
 PDEFoamMultiTarget.cxx:80
 PDEFoamMultiTarget.cxx:81
 PDEFoamMultiTarget.cxx:82
 PDEFoamMultiTarget.cxx:83
 PDEFoamMultiTarget.cxx:84
 PDEFoamMultiTarget.cxx:85
 PDEFoamMultiTarget.cxx:86
 PDEFoamMultiTarget.cxx:87
 PDEFoamMultiTarget.cxx:88
 PDEFoamMultiTarget.cxx:89
 PDEFoamMultiTarget.cxx:90
 PDEFoamMultiTarget.cxx:91
 PDEFoamMultiTarget.cxx:92
 PDEFoamMultiTarget.cxx:93
 PDEFoamMultiTarget.cxx:94
 PDEFoamMultiTarget.cxx:95
 PDEFoamMultiTarget.cxx:96
 PDEFoamMultiTarget.cxx:97
 PDEFoamMultiTarget.cxx:98
 PDEFoamMultiTarget.cxx:99
 PDEFoamMultiTarget.cxx:100
 PDEFoamMultiTarget.cxx:101
 PDEFoamMultiTarget.cxx:102
 PDEFoamMultiTarget.cxx:103
 PDEFoamMultiTarget.cxx:104
 PDEFoamMultiTarget.cxx:105
 PDEFoamMultiTarget.cxx:106
 PDEFoamMultiTarget.cxx:107
 PDEFoamMultiTarget.cxx:108
 PDEFoamMultiTarget.cxx:109
 PDEFoamMultiTarget.cxx:110
 PDEFoamMultiTarget.cxx:111
 PDEFoamMultiTarget.cxx:112
 PDEFoamMultiTarget.cxx:113
 PDEFoamMultiTarget.cxx:114
 PDEFoamMultiTarget.cxx:115
 PDEFoamMultiTarget.cxx:116
 PDEFoamMultiTarget.cxx:117
 PDEFoamMultiTarget.cxx:118
 PDEFoamMultiTarget.cxx:119
 PDEFoamMultiTarget.cxx:120
 PDEFoamMultiTarget.cxx:121
 PDEFoamMultiTarget.cxx:122
 PDEFoamMultiTarget.cxx:123
 PDEFoamMultiTarget.cxx:124
 PDEFoamMultiTarget.cxx:125
 PDEFoamMultiTarget.cxx:126
 PDEFoamMultiTarget.cxx:127
 PDEFoamMultiTarget.cxx:128
 PDEFoamMultiTarget.cxx:129
 PDEFoamMultiTarget.cxx:130
 PDEFoamMultiTarget.cxx:131
 PDEFoamMultiTarget.cxx:132
 PDEFoamMultiTarget.cxx:133
 PDEFoamMultiTarget.cxx:134
 PDEFoamMultiTarget.cxx:135
 PDEFoamMultiTarget.cxx:136
 PDEFoamMultiTarget.cxx:137
 PDEFoamMultiTarget.cxx:138
 PDEFoamMultiTarget.cxx:139
 PDEFoamMultiTarget.cxx:140
 PDEFoamMultiTarget.cxx:141
 PDEFoamMultiTarget.cxx:142
 PDEFoamMultiTarget.cxx:143
 PDEFoamMultiTarget.cxx:144
 PDEFoamMultiTarget.cxx:145
 PDEFoamMultiTarget.cxx:146
 PDEFoamMultiTarget.cxx:147
 PDEFoamMultiTarget.cxx:148
 PDEFoamMultiTarget.cxx:149
 PDEFoamMultiTarget.cxx:150
 PDEFoamMultiTarget.cxx:151
 PDEFoamMultiTarget.cxx:152
 PDEFoamMultiTarget.cxx:153
 PDEFoamMultiTarget.cxx:154
 PDEFoamMultiTarget.cxx:155
 PDEFoamMultiTarget.cxx:156
 PDEFoamMultiTarget.cxx:157
 PDEFoamMultiTarget.cxx:158
 PDEFoamMultiTarget.cxx:159
 PDEFoamMultiTarget.cxx:160
 PDEFoamMultiTarget.cxx:161
 PDEFoamMultiTarget.cxx:162
 PDEFoamMultiTarget.cxx:163
 PDEFoamMultiTarget.cxx:164
 PDEFoamMultiTarget.cxx:165
 PDEFoamMultiTarget.cxx:166
 PDEFoamMultiTarget.cxx:167
 PDEFoamMultiTarget.cxx:168
 PDEFoamMultiTarget.cxx:169
 PDEFoamMultiTarget.cxx:170
 PDEFoamMultiTarget.cxx:171
 PDEFoamMultiTarget.cxx:172
 PDEFoamMultiTarget.cxx:173
 PDEFoamMultiTarget.cxx:174
 PDEFoamMultiTarget.cxx:175
 PDEFoamMultiTarget.cxx:176
 PDEFoamMultiTarget.cxx:177
 PDEFoamMultiTarget.cxx:178
 PDEFoamMultiTarget.cxx:179
 PDEFoamMultiTarget.cxx:180
 PDEFoamMultiTarget.cxx:181
 PDEFoamMultiTarget.cxx:182
 PDEFoamMultiTarget.cxx:183
 PDEFoamMultiTarget.cxx:184
 PDEFoamMultiTarget.cxx:185
 PDEFoamMultiTarget.cxx:186
 PDEFoamMultiTarget.cxx:187
 PDEFoamMultiTarget.cxx:188
 PDEFoamMultiTarget.cxx:189
 PDEFoamMultiTarget.cxx:190
 PDEFoamMultiTarget.cxx:191
 PDEFoamMultiTarget.cxx:192
 PDEFoamMultiTarget.cxx:193
 PDEFoamMultiTarget.cxx:194
 PDEFoamMultiTarget.cxx:195
 PDEFoamMultiTarget.cxx:196
 PDEFoamMultiTarget.cxx:197
 PDEFoamMultiTarget.cxx:198
 PDEFoamMultiTarget.cxx:199
 PDEFoamMultiTarget.cxx:200
 PDEFoamMultiTarget.cxx:201
 PDEFoamMultiTarget.cxx:202
 PDEFoamMultiTarget.cxx:203
 PDEFoamMultiTarget.cxx:204
 PDEFoamMultiTarget.cxx:205
 PDEFoamMultiTarget.cxx:206
 PDEFoamMultiTarget.cxx:207
 PDEFoamMultiTarget.cxx:208
 PDEFoamMultiTarget.cxx:209
 PDEFoamMultiTarget.cxx:210
 PDEFoamMultiTarget.cxx:211
 PDEFoamMultiTarget.cxx:212
 PDEFoamMultiTarget.cxx:213
 PDEFoamMultiTarget.cxx:214
 PDEFoamMultiTarget.cxx:215
 PDEFoamMultiTarget.cxx:216
 PDEFoamMultiTarget.cxx:217
 PDEFoamMultiTarget.cxx:218
 PDEFoamMultiTarget.cxx:219
 PDEFoamMultiTarget.cxx:220
 PDEFoamMultiTarget.cxx:221
 PDEFoamMultiTarget.cxx:222
 PDEFoamMultiTarget.cxx:223
 PDEFoamMultiTarget.cxx:224
 PDEFoamMultiTarget.cxx:225
 PDEFoamMultiTarget.cxx:226
 PDEFoamMultiTarget.cxx:227
 PDEFoamMultiTarget.cxx:228
 PDEFoamMultiTarget.cxx:229
 PDEFoamMultiTarget.cxx:230
 PDEFoamMultiTarget.cxx:231
 PDEFoamMultiTarget.cxx:232
 PDEFoamMultiTarget.cxx:233
 PDEFoamMultiTarget.cxx:234
 PDEFoamMultiTarget.cxx:235
 PDEFoamMultiTarget.cxx:236
 PDEFoamMultiTarget.cxx:237
 PDEFoamMultiTarget.cxx:238
 PDEFoamMultiTarget.cxx:239
 PDEFoamMultiTarget.cxx:240
 PDEFoamMultiTarget.cxx:241
 PDEFoamMultiTarget.cxx:242
 PDEFoamMultiTarget.cxx:243
 PDEFoamMultiTarget.cxx:244
 PDEFoamMultiTarget.cxx:245
 PDEFoamMultiTarget.cxx:246
 PDEFoamMultiTarget.cxx:247
 PDEFoamMultiTarget.cxx:248
 PDEFoamMultiTarget.cxx:249
 PDEFoamMultiTarget.cxx:250
 PDEFoamMultiTarget.cxx:251
 PDEFoamMultiTarget.cxx:252
 PDEFoamMultiTarget.cxx:253
 PDEFoamMultiTarget.cxx:254
 PDEFoamMultiTarget.cxx:255
 PDEFoamMultiTarget.cxx:256
 PDEFoamMultiTarget.cxx:257
 PDEFoamMultiTarget.cxx:258
 PDEFoamMultiTarget.cxx:259
 PDEFoamMultiTarget.cxx:260
 PDEFoamMultiTarget.cxx:261
 PDEFoamMultiTarget.cxx:262
 PDEFoamMultiTarget.cxx:263
 PDEFoamMultiTarget.cxx:264
 PDEFoamMultiTarget.cxx:265
 PDEFoamMultiTarget.cxx:266
 PDEFoamMultiTarget.cxx:267
 PDEFoamMultiTarget.cxx:268
 PDEFoamMultiTarget.cxx:269
 PDEFoamMultiTarget.cxx:270
 PDEFoamMultiTarget.cxx:271
 PDEFoamMultiTarget.cxx:272
 PDEFoamMultiTarget.cxx:273
 PDEFoamMultiTarget.cxx:274
 PDEFoamMultiTarget.cxx:275
 PDEFoamMultiTarget.cxx:276
 PDEFoamMultiTarget.cxx:277
 PDEFoamMultiTarget.cxx:278
 PDEFoamMultiTarget.cxx:279