00001 #include <iostream>
00002 #include <sstream>
00003 #include <fstream>
00004 #include <algorithm>
00005 #include <iterator>
00006 #include <cstddef>
00007 #include <cstring>
00008 #include <vector>
00009 #include <set>
00010
00011
00012 #include <RVersion.h>
00013
00014 #include <TBufferFile.h>
00015 #include <TClass.h>
00016
00017 #include "FWCore/Utilities/interface/Exception.h"
00018
00019 #include "PhysicsTools/MVAComputer/interface/zstream.h"
00020
00021 #include "PhysicsTools/MVAComputer/interface/MVAComputer.h"
00022 #include "PhysicsTools/MVAComputer/interface/VarProcessor.h"
00023 #include "PhysicsTools/MVAComputer/interface/Calibration.h"
00024 #include "PhysicsTools/MVAComputer/interface/Variable.h"
00025 #include "PhysicsTools/MVAComputer/interface/AtomicId.h"
00026
00027
00028
00029 #ifdef DEBUG_EVAL
00030 # include <Reflex/Tools.h>
00031 #endif
00032
00033 #define STANDALONE_HEADER "MVAComputer calibration\n"
00034
00035 namespace PhysicsTools {
00036
00037 MVAComputer::MVAComputer(const Calibration::MVAComputer *calib) :
00038 nVars(0), output(0)
00039 {
00040 setup(calib);
00041 }
00042
00043 MVAComputer::MVAComputer(Calibration::MVAComputer *calib, bool owned) :
00044 nVars(0), output(0)
00045 {
00046 if (owned)
00047 this->owned.reset(calib);
00048 setup(calib);
00049 }
00050
00051 MVAComputer::MVAComputer(const char *filename) :
00052 nVars(0), output(0), owned(readCalibration(filename))
00053 {
00054 setup(owned.get());
00055 }
00056
00057 MVAComputer::MVAComputer(std::istream &is) :
00058 nVars(0), output(0), owned(readCalibration(is))
00059 {
00060 setup(owned.get());
00061 }
00062
00063 void MVAComputer::setup(const Calibration::MVAComputer *calib)
00064 {
00065 nVars = calib->inputSet.size();
00066 output = calib->output;
00067
00068 std::vector<Variable::Flags> flags(nVars, Variable::FLAG_ALL);
00069 const TrainMVAComputerCalibration *trainCalib =
00070 dynamic_cast<const TrainMVAComputerCalibration*>(calib);
00071 if (trainCalib)
00072 trainCalib->initFlags(flags);
00073
00074 VarProcessor::ConfigCtx config(flags);
00075 std::vector<Calibration::VarProcessor*> processors =
00076 calib->getProcessors();
00077
00078 for(std::vector<Calibration::VarProcessor*>::const_iterator iter =
00079 processors.begin();
00080 iter != processors.end(); ++iter) {
00081 std::string name = (*iter)->getInstanceName();
00082 VarProcessor *processor =
00083 VarProcessor::create(name.c_str(), *iter, this);
00084 if (!processor)
00085 throw cms::Exception("UnknownProcessor")
00086 << name << " could not be instantiated."
00087 << std::endl;
00088
00089 VarProcessor::ConfigCtx::iterator::difference_type pos =
00090 config.end() - config.begin();
00091 processor->configure(config);
00092 unsigned int nOutput = (config.end() - config.begin()) - pos;
00093 if (!nOutput)
00094 throw cms::Exception("InvalidProcessor")
00095 << name << " rejected input variable "
00096 "configuration" << std::endl;
00097
00098 varProcessors.push_back(Processor(processor, nOutput));
00099 }
00100
00101 for(VarProcessor::ConfigCtx::iterator iter = config.begin() + nVars;
00102 iter != config.end(); iter++) {
00103 VarProcessor::Config *origin = &config[iter->origin];
00104 if (iter->origin >= nVars)
00105 iter->origin = origin->origin;
00106
00107 if (iter->mask & Variable::FLAG_MULTIPLE) {
00108 iter->mask = (Variable::Flags)(iter->mask &
00109 origin->mask);
00110 config[iter->origin].origin++;
00111 }
00112 }
00113
00114 nVars = config.size();
00115
00116 if (output >= nVars)
00117
00118 throw cms::Exception("InvalidOutput")
00119 << "Output variable at index " << output
00120 << " invalid." << std::endl;
00121
00122 std::set<InputVar> variables;
00123 unsigned int i = 0;
00124 for(std::vector<Calibration::Variable>::const_iterator iter =
00125 calib->inputSet.begin(); iter != calib->inputSet.end();
00126 ++iter, i++) {
00127 InputVar var;
00128 var.var = Variable(iter->name, config[i].mask);
00129 var.index = i;
00130 variables.insert(var);
00131 }
00132
00133 inputVariables.resize(i);
00134 std::copy(variables.begin(), variables.end(),
00135 inputVariables.begin());
00136
00137 for(unsigned int j = 0; j < i; j++)
00138 inputVariables[j].multiplicity = config[j].origin;
00139 }
00140
00141 MVAComputer::~MVAComputer()
00142 {
00143 }
00144
00145 unsigned int MVAComputer::getVariableId(AtomicId name) const
00146 {
00147 std::vector<InputVar>::const_iterator pos =
00148 std::lower_bound(inputVariables.begin(), inputVariables.end(),
00149 name);
00150
00151 if (pos == inputVariables.end() || pos->var.getName() != name)
00152 throw cms::Exception("InvalidVariable")
00153 << "Input variable " << (const char*)name
00154 << " not found." << std::endl;
00155
00156 return pos->index;
00157 }
00158
00159 template<class T>
00160 void MVAComputer::evalInternal(T &ctx) const
00161 {
00162 double *output = ctx.values() + ctx.n();
00163 int *outConf = ctx.conf() + inputVariables.size();
00164
00165 #ifdef DEBUG_EVAL
00166 std::cout << "Input" << std::endl;
00167 double *v = ctx.values();
00168 for(int *o = ctx.conf(); o < outConf; o++) {
00169 std::cout << "\tVar " << (o - ctx.conf()) << std::endl;
00170 for(int i = o[0]; i < o[1]; i++)
00171 std::cout << "\t\t" << *v++ << std::endl;
00172 }
00173 #endif
00174 std::vector<Processor>::const_iterator iter = varProcessors.begin();
00175 while(iter != varProcessors.end()) {
00176 std::vector<Processor>::const_iterator loop = iter;
00177 int *loopOutConf = outConf;
00178 int *loopStart = 0;
00179 double *loopOutput = output;
00180
00181 VarProcessor::LoopStatus status = VarProcessor::kNext;
00182 unsigned int offset = 0;
00183 while(status != VarProcessor::kStop) {
00184 std::vector<Processor>::const_iterator next = iter + 1;
00185 unsigned int nextOutput = (next != varProcessors.end())
00186 ? next->nOutput : 0;
00187
00188 #ifdef DEBUG_EVAL
00189 std::cout << ROOT::Reflex::Tools::Demangle(
00190 typeid(*iter->processor)) << std::endl;
00191 #endif
00192 if (status != VarProcessor::kSkip)
00193 ctx.eval(&*iter->processor, outConf, output,
00194 loopStart ? loopStart : loopOutConf,
00195 offset, iter->nOutput);
00196
00197 #ifdef DEBUG_EVAL
00198 for(unsigned int i = 0; i < iter->nOutput;
00199 i++, outConf++) {
00200 std::cout << "\tVar " << (outConf - ctx.conf())
00201 << std::endl;
00202 for(int j = outConf[0]; j < outConf[1]; j++)
00203 std::cout << "\t\t" << *output++
00204 << std::endl;
00205 }
00206 #else
00207 int orig = *outConf;
00208 outConf += iter->nOutput;
00209 output += *outConf - orig;
00210 #endif
00211
00212 status = loop->processor->loop(output, outConf,
00213 nextOutput, offset);
00214
00215 if (status == VarProcessor::kReset) {
00216 outConf = loopOutConf;
00217 output = loopOutput;
00218 loopStart = 0;
00219 offset = 0;
00220 iter = loop;
00221 } else {
00222 if (loop == iter)
00223 loopStart = outConf;
00224 iter = next;
00225 }
00226 }
00227 }
00228 }
00229
00230 Calibration::MVAComputer *MVAComputer::readCalibration(const char *filename)
00231 {
00232 std::ifstream file(filename);
00233 return readCalibration(file);
00234 }
00235
00236 Calibration::MVAComputer *MVAComputer::readCalibration(std::istream &is)
00237 {
00238 if (!is.good())
00239 throw cms::Exception("InvalidFileState")
00240 << "Stream passed to MVAComputer::readCalibration "
00241 "has an invalid state." << std::endl;
00242
00243 char header[sizeof STANDALONE_HEADER - 1] = { 0, };
00244 if (is.readsome(header, sizeof header) != sizeof header ||
00245 std::memcmp(header, STANDALONE_HEADER, sizeof header) != 0)
00246 throw cms::Exception("InvalidFileFormat")
00247 << "Stream passed to MVAComputer::readCalibration "
00248 "is not a valid calibration file." << std::endl;
00249
00250 TClass *rootClass =
00251 TClass::GetClass("PhysicsTools::Calibration::MVAComputer");
00252 if (!rootClass)
00253 throw cms::Exception("DictionaryMissing")
00254 << "CondFormats dictionary for "
00255 "PhysicsTools::Calibration::MVAComputer missing"
00256 << std::endl;
00257
00258 ext::izstream izs(&is);
00259 std::ostringstream ss;
00260 ss << izs.rdbuf();
00261 std::string buf = ss.str();
00262
00263 TBufferFile buffer(TBuffer::kRead, buf.size(), const_cast<void*>(
00264 static_cast<const void*>(buf.c_str())), kFALSE);
00265 buffer.InitMap();
00266
00267 std::auto_ptr<Calibration::MVAComputer> calib(
00268 new Calibration::MVAComputer());
00269 buffer.StreamObject(static_cast<void*>(calib.get()), rootClass);
00270
00271 return calib.release();
00272 }
00273
00274 void MVAComputer::writeCalibration(const char *filename,
00275 const Calibration::MVAComputer *calib)
00276 {
00277 std::ofstream file(filename);
00278 writeCalibration(file, calib);
00279 }
00280
00281 void MVAComputer::writeCalibration(std::ostream &os,
00282 const Calibration::MVAComputer *calib)
00283 {
00284 if (!os.good())
00285 throw cms::Exception("InvalidFileState")
00286 << "Stream passed to MVAComputer::writeCalibration "
00287 "has an invalid state." << std::endl;
00288
00289 os << STANDALONE_HEADER;
00290
00291 TClass *rootClass =
00292 TClass::GetClass("PhysicsTools::Calibration::MVAComputer");
00293 if (!rootClass)
00294 throw cms::Exception("DictionaryMissing")
00295 << "CondFormats dictionary for "
00296 "PhysicsTools::Calibration::MVAComputer missing"
00297 << std::endl;
00298
00299 TBufferFile buffer(TBuffer::kWrite);
00300 buffer.StreamObject(const_cast<void*>(static_cast<const void*>(calib)),
00301 rootClass);
00302
00303 ext::ozstream ozs(&os);
00304 ozs.write(buffer.Buffer(), buffer.Length());
00305 ozs.flush();
00306 }
00307
00308
00309
00310 void MVAComputer::DerivContext::eval(
00311 const VarProcessor *proc, int *outConf, double *output,
00312 int *loop, unsigned int offset, unsigned int out) const
00313 {
00314 proc->deriv(values(), conf(), output, outConf,
00315 loop, offset, n(), out, deriv_);
00316 }
00317
00318 double MVAComputer::DerivContext::output(unsigned int output,
00319 std::vector<double> &derivs) const
00320 {
00321 derivs.clear();
00322 derivs.reserve(n_);
00323
00324 int pos = conf_[output];
00325 if (pos >= (int)n_)
00326 std::copy(&deriv_.front() + n_ * (pos - n_),
00327 &deriv_.front() + n_ * (pos - n_ + 1),
00328 std::back_inserter(derivs));
00329 else {
00330 derivs.resize(n_);
00331 derivs[pos] = 1.;
00332 }
00333
00334 return values_[pos];
00335 }
00336
00337 template void MVAComputer::evalInternal(EvalContext &ctx) const;
00338 template void MVAComputer::evalInternal(DerivContext &ctx) const;
00339
00340 }