/*****************************************************************************
* Project: RooFit *
* Package: RooFitCore *
* @(#)root/roofitcore:$Id$
* Authors: *
* WV, Wouter Verkerke, UC Santa Barbara, verkerke@slac.stanford.edu *
* DK, David Kirkby, UC Irvine, dkirkby@uci.edu *
* *
* Copyright (c) 2000-2005, Regents of the University of California *
* and Stanford University. All rights reserved. *
* *
* Redistribution and use in source and binary forms, *
* with or without modification, are permitted according to the terms *
* listed in LICENSE (http://roofit.sourceforge.net/license.txt) *
*****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//
// BEGIN_HTML
// RooSuperCategory consolidates several RooAbsCategoryLValue objects into
// a single category. The states of the super category consist of all the permutations
// of the input categories. The super category is an lvalue and requires that
// all input categories are lvalues as well as modification
// of its state will back propagate into a modification of its input categories.
// To define a consolidated category of multiple non-lvalye categories
// use class RooMultiCategory
//
// RooSuperCategory state are automatically defined and updated whenever an input
// category modifies its list of states
// END_HTML
//
#include "RooFit.h"
#include "Riostream.h"
#include "Riostream.h"
#include
#include
#include "TString.h"
#include "TClass.h"
#include "RooSuperCategory.h"
#include "RooStreamParser.h"
#include "RooArgSet.h"
#include "RooMultiCatIter.h"
#include "RooAbsCategoryLValue.h"
#include "RooMsgService.h"
using namespace std;
ClassImp(RooSuperCategory)
;
////////////////////////////////////////////////////////////////////////////////
/// Construct a lvalue product of the given set of input RooAbsCategoryLValues in 'inInputCatList'
/// The state names of this product category are {S1;S2,S3,...Sn} where Si are the state names
/// of the input categories. A RooSuperCategory is an lvalue.
RooSuperCategory::RooSuperCategory(const char *name, const char *title, const RooArgSet& inInputCatList) :
RooAbsCategoryLValue(name, title), _catSet("input","Input category set",this,kTRUE,kTRUE)
{
// Copy category list
TIterator* iter = inInputCatList.createIterator() ;
RooAbsArg* arg ;
while ((arg=(RooAbsArg*)iter->Next())) {
if (!arg->IsA()->InheritsFrom(RooAbsCategoryLValue::Class())) {
coutE(InputArguments) << "RooSuperCategory::RooSuperCategory(" << GetName() << "): input category " << arg->GetName()
<< " is not an lvalue" << endl ;
}
_catSet.add(*arg) ;
}
delete iter ;
_catIter = _catSet.createIterator() ;
updateIndexList() ;
}
////////////////////////////////////////////////////////////////////////////////
/// Copy constructor
RooSuperCategory::RooSuperCategory(const RooSuperCategory& other, const char *name) :
RooAbsCategoryLValue(other,name), _catSet("input",this,other._catSet)
{
_catIter = _catSet.createIterator() ;
updateIndexList() ;
setIndex(other.getIndex()) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Destructor
RooSuperCategory::~RooSuperCategory()
{
delete _catIter ;
}
////////////////////////////////////////////////////////////////////////////////
/// Make an iterator over all state permutations of
/// the input categories of this supercategory
TIterator* RooSuperCategory::MakeIterator() const
{
return new RooMultiCatIter(_catSet) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Update the list of possible states of this super category
void RooSuperCategory::updateIndexList()
{
clearTypes() ;
RooMultiCatIter mcIter(_catSet) ;
TObjString* obj ;
Int_t i(0) ;
while((obj = (TObjString*) mcIter.Next())) {
// Register composite label
defineTypeUnchecked(obj->String(),i++) ;
}
// Renumbering will invalidate cache
setValueDirty() ;
}
////////////////////////////////////////////////////////////////////////////////
/// Return the name of the current state,
/// constructed from the state names of the input categories
TString RooSuperCategory::currentLabel() const
{
_catIter->Reset() ;
// Construct composite label name
TString label ;
RooAbsCategory* cat ;
Bool_t first(kTRUE) ;
while((cat=(RooAbsCategory*) _catIter->Next())) {
label.Append(first?"{":";") ;
label.Append(cat->getLabel()) ;
first=kFALSE ;
}
label.Append("}") ;
return label ;
}
////////////////////////////////////////////////////////////////////////////////
/// Calculate and return the current value
RooCatType RooSuperCategory::evaluate() const
{
if (isShapeDirty()) {
const_cast(this)->updateIndexList() ;
}
const RooCatType* ret = lookupType(currentLabel(),kTRUE) ;
if (!ret) {
coutE(Eval) << "RooSuperCat::evaluate(" << this << ") error: current state not defined: '" << currentLabel() << "'" << endl ;
printStream(ccoutE(Eval),0,kVerbose) ;
return RooCatType() ;
}
return *ret ;
}
////////////////////////////////////////////////////////////////////////////////
/// Set the value of the super category by specifying the state index code
/// by setting the states of the corresponding input category lvalues
Bool_t RooSuperCategory::setIndex(Int_t index, Bool_t /*printError*/)
{
const RooCatType* type = lookupType(index,kTRUE) ;
if (!type) return kTRUE ;
return setType(type) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Set the value of the super category by specifying the state name
/// by setting the state names of the corresponding input category lvalues
Bool_t RooSuperCategory::setLabel(const char* label, Bool_t /*printError*/)
{
const RooCatType* type = lookupType(label,kTRUE) ;
if (!type) return kTRUE ;
return setType(type) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Set the value of the super category by specifying the state object
/// by setting the state names of the corresponding input category lvalues
Bool_t RooSuperCategory::setType(const RooCatType* type, Bool_t /*printError*/)
{
char buf[1024] ;
strlcpy(buf,type->GetName(),1024) ;
RooAbsCategoryLValue* arg ;
Bool_t error(kFALSE) ;
// Parse composite label and set label of components to their values
char* ptr=buf+1 ;
char* token = ptr ;
_catIter->Reset() ;
while ((arg=(RooAbsCategoryLValue*)_catIter->Next())) {
// Delimit name token for this category
if (*ptr=='{') {
// Token is composite itself, terminate at matching '}'
Int_t nBrak(1) ;
while(*(++ptr)) {
if (nBrak==0) {
*ptr = 0 ;
break ;
}
if (*ptr=='{') {
nBrak++ ;
} else if (*ptr=='}') {
nBrak-- ;
}
}
} else {
// Simple token, terminate at next semi-colon
ptr = strtok(ptr,";}") ;
ptr += strlen(ptr) ;
}
error |= arg->setLabel(token) ;
token = ++ptr ;
}
return error ;
}
////////////////////////////////////////////////////////////////////////////////
/// Print the state of this object to the specified output stream.
void RooSuperCategory::printMultiline(ostream& os, Int_t content, Bool_t verbose, TString indent) const
{
RooAbsCategory::printMultiline(os,content,verbose,indent) ;
if (verbose) {
os << indent << "--- RooSuperCategory ---" << endl;
os << indent << " Input category list:" << endl ;
TString moreIndent(indent) ;
os << moreIndent << _catSet << endl ;
}
}
////////////////////////////////////////////////////////////////////////////////
/// Read object contents from given stream
Bool_t RooSuperCategory::readFromStream(istream& /*is*/, Bool_t /*compact*/, Bool_t /*verbose*/)
{
return kTRUE ;
}
////////////////////////////////////////////////////////////////////////////////
/// Write object contents to given stream
void RooSuperCategory::writeToStream(ostream& os, Bool_t compact) const
{
RooAbsCategory::writeToStream(os,compact) ;
}
////////////////////////////////////////////////////////////////////////////////
/// Return true of all of the input category states are in the given range
Bool_t RooSuperCategory::inRange(const char* rangeName) const
{
_catIter->Reset() ;
RooAbsCategoryLValue* cat ;
while((cat = (RooAbsCategoryLValue*)_catIter->Next())) {
if (!cat->inRange(rangeName)) {
return kFALSE ;
}
}
return kTRUE ;
}
////////////////////////////////////////////////////////////////////////////////
/// Return true if any of the input categories has a range
/// named 'rangeName'
Bool_t RooSuperCategory::hasRange(const char* rangeName) const
{
_catIter->Reset() ;
RooAbsCategoryLValue* cat ;
while((cat = (RooAbsCategoryLValue*)_catIter->Next())) {
if (cat->hasRange(rangeName)) return kTRUE ;
}
return kFALSE ;
}