// @(#)root/unuran:$Id$
// Authors: L. Moneta, J. Leydold Tue Sep 26 16:25:09 2006

/**********************************************************************
 *                                                                    *
 * Copyright (c) 2006  LCG ROOT Math Team, CERN/PH-SFT                *
 *                                                                    *
 *                                                                    *
 **********************************************************************/

// Implementation file for class TUnuran

#include "TUnuran.h"

#include "TUnuranContDist.h"
#include "TUnuranMultiContDist.h"
#include "TUnuranDiscrDist.h"
#include "TUnuranEmpDist.h"

#include "UnuranRng.h"
#include "UnuranDistrAdapter.h"

#include "TRandom.h"
#include "TSystem.h"

#include "TH1.h"

#include <cassert>


#include <unuran.h>

#include "TError.h"


TUnuran::TUnuran(TRandom * r, unsigned int debugLevel) :
   fGen(0),
   fUdistr(0),
   fUrng(0),
   fRng(r)
{
   // constructor implementation with a ROOT random generator
   // if no generator is given the ROOT default is used
   if (fRng == 0) fRng = gRandom;
   // set debug level at global level
   // (should be in a static  initialization function of the library ? )
   if ( debugLevel > 1)
      unur_set_default_debug(UNUR_DEBUG_ALL);
   else if (debugLevel == 1)
      unur_set_default_debug(UNUR_DEBUG_INIT);
   else
      unur_set_default_debug(UNUR_DEBUG_OFF);

}


TUnuran::~TUnuran()
{
   // Destructor implementation
   if (fGen != 0) unur_free(fGen);
   if (fUrng != 0) unur_urng_free(fUrng);
  // we can delete now the distribution object
   if (fUdistr != 0) unur_distr_free(fUdistr);
}

//private (no impl.)
TUnuran::TUnuran(const TUnuran &)
{
   // Implementation of copy constructor.
}

TUnuran & TUnuran::operator = (const TUnuran &rhs)
{
   // Implementation of assignment operator.
   if (this == &rhs) return *this;  // time saving self-test
   return *this;
}

bool  TUnuran::Init(const std::string & dist, const std::string & method)
{
   // initialize with a string
   std::string s = dist + " & " + method;
   fGen = unur_str2gen(s.c_str() );
   if (fGen == 0) {
      Error("Init","Cannot create generator object");
      return false;
   }
   if (! SetRandomGenerator() ) return false;

   return true;
}

bool TUnuran::Init(const TUnuranContDist & distr, const std::string  & method)
{
   // initialization with a distribution and and generator
   // the distribution object is copied in and managed by this class
   // use auto_ptr to manage previously existing distribution objects
   TUnuranContDist * distNew = distr.Clone();
   fDist = std::auto_ptr< TUnuranBaseDist>(distNew);

   fMethod = method;
   if (! SetContDistribution(*distNew) ) return false;
   if (! SetMethodAndInit() ) return false;
   if (! SetRandomGenerator() ) return false;
   return true;
}


bool TUnuran::Init(const TUnuranMultiContDist & distr, const std::string  & method)
{
   //  initialization with a distribution and method
   // the distribution object is copied in and managed by this class
   // use auto_ptr to manage previously existing distribution objects
   TUnuranMultiContDist * distNew = distr.Clone();
   fDist = std::auto_ptr< TUnuranBaseDist>(distNew);

   fMethod = method;
   if (! SetMultiDistribution(*distNew) ) return false;
   if (! SetMethodAndInit() ) return false;
   if (! SetRandomGenerator() ) return false;
   return true;
}


bool TUnuran::Init(const TUnuranDiscrDist & distr, const std::string & method ) {
   //   initialization with a distribution and and generator
   // the distribution object is copied in and managed by this class
   // use auto_ptr to manage previously existing distribution objects
   TUnuranDiscrDist * distNew = distr.Clone();
   fDist = std::auto_ptr< TUnuranBaseDist>(distNew);

   fMethod = method;
   if (! SetDiscreteDistribution(*distNew) ) return false;
   if (! SetMethodAndInit() ) return false;
   if (! SetRandomGenerator() ) return false;
   return true;
}

bool TUnuran::Init(const TUnuranEmpDist & distr, const std::string & method ) {
   //   initialization with a distribution and and generator
   // the distribution object is copied in and managed by this class
   // use auto_ptr to manage previously existing distribution objects
   TUnuranEmpDist * distNew = distr.Clone();
   fDist = std::auto_ptr< TUnuranBaseDist>(distNew);

   fMethod = method;
   if (distr.IsBinned()) fMethod = "hist";
   else if (distr.NDim() > 1) fMethod = "vempk";
   if (! SetEmpiricalDistribution(*distNew) ) return false;
   if (! SetMethodAndInit() ) return false;
   if (! SetRandomGenerator() ) return false;
   return true;
}


bool  TUnuran::SetRandomGenerator()
{
   // set an external random generator
   if (fRng == 0) return false;
   if (fGen == 0) return false;

   fUrng = unur_urng_new(&UnuranRng<TRandom>::Rndm, fRng );
   if (fUrng == 0) return false;
   unsigned int ret = 0;
   ret |= unur_urng_set_delete(fUrng, &UnuranRng<TRandom>::Delete);
   ret |= unur_urng_set_seed(fUrng, &UnuranRng<TRandom>::Seed);
   if (ret != 0) return false;

   unur_chg_urng( fGen, fUrng);
   return true;
}

bool  TUnuran::SetContDistribution(const TUnuranContDist & dist )
{
   // internal method to set in unuran the function pointer for a continuous univariate distribution
   if (fUdistr != 0)  unur_distr_free(fUdistr);
   fUdistr = unur_distr_cont_new();
   if (fUdistr == 0) return false;
   unsigned int ret = 0;
   ret = unur_distr_set_extobj(fUdistr, &dist);
   if ( ! dist.IsLogPdf() ) {
      ret |= unur_distr_cont_set_pdf(fUdistr, &ContDist::Pdf);
      ret |= unur_distr_cont_set_dpdf(fUdistr, &ContDist::Dpdf);
      if (dist.HasCdf() ) ret |= unur_distr_cont_set_cdf(fUdistr, &ContDist::Cdf);
   }
   else {
      // case user provides log of pdf
      ret |= unur_distr_cont_set_logpdf(fUdistr, &ContDist::Pdf);
      ret |= unur_distr_cont_set_dlogpdf(fUdistr, &ContDist::Dpdf);
   }

   double xmin, xmax = 0;
   if (dist.GetDomain(xmin,xmax) ) {
      ret = unur_distr_cont_set_domain(fUdistr,xmin,xmax);
      if (ret != 0)  {
         Error("SetContDistribution","invalid domain xmin = %g xmax = %g ",xmin,xmax);
         return false;
      }
   }
   if (dist.HasMode() ) {
      ret = unur_distr_cont_set_mode(fUdistr, dist.Mode());
      if (ret != 0)  {
         Error("SetContDistribution","invalid mode given,  mode = %g ",dist.Mode());
         return false;
      }
   }
   if (dist.HasPdfArea() ) {
      ret = unur_distr_cont_set_pdfarea(fUdistr, dist.PdfArea());
      if (ret != 0)  {
         Error("SetContDistribution","invalid area given,  area = %g ",dist.PdfArea());
         return false;
      }
   }

   return (ret ==0) ? true : false;
}


bool  TUnuran::SetMultiDistribution(const TUnuranMultiContDist & dist )
{
   // internal method to set in unuran the function pointer for a multivariate distribution
   if (fUdistr != 0)  unur_distr_free(fUdistr);
   fUdistr = unur_distr_cvec_new(dist.NDim() );
   if (fUdistr == 0) return false;
   unsigned int ret = 0;
   ret |= unur_distr_set_extobj(fUdistr, &dist );
   if ( ! dist.IsLogPdf() ) {
      ret |= unur_distr_cvec_set_pdf(fUdistr, &MultiDist::Pdf);
      ret |= unur_distr_cvec_set_dpdf(fUdistr, &MultiDist::Dpdf);
      ret |= unur_distr_cvec_set_pdpdf(fUdistr, &MultiDist::Pdpdf);
   }
   else {
      ret |= unur_distr_cvec_set_logpdf(fUdistr, &MultiDist::Pdf);
      ret |= unur_distr_cvec_set_dlogpdf(fUdistr, &MultiDist::Dpdf);
      ret |= unur_distr_cvec_set_pdlogpdf(fUdistr, &MultiDist::Pdpdf);
   }

   const double * xmin = dist.GetLowerDomain();
   const double * xmax = dist.GetUpperDomain();
   if ( xmin != 0 || xmax != 0 ) {
      ret = unur_distr_cvec_set_domain_rect(fUdistr,xmin,xmax);
      if (ret != 0)  {
         Error("SetMultiDistribution","invalid domain");
         return false;
      }
#ifdef OLDVERS
      Error("SetMultiDistribution","domain setting not available in UNURAN 0.8.1");
#endif

   }

   const double * xmode = dist.GetMode();
   if (xmode != 0) {
      ret = unur_distr_cvec_set_mode(fUdistr, xmode);
      if (ret != 0)  {
         Error("SetMultiDistribution","invalid mode");
         return false;
      }
   }
   return (ret ==0) ? true : false;
}

bool TUnuran::SetEmpiricalDistribution(const TUnuranEmpDist & dist) {

   // internal method to set in unuran the function pointer for am empiral distribution (from histogram)
   if (fUdistr != 0)  unur_distr_free(fUdistr);
   if (dist.NDim() == 1)
      fUdistr = unur_distr_cemp_new();
   else
      fUdistr = unur_distr_cvemp_new(dist.NDim() );

   if (fUdistr == 0) return false;
   unsigned int ret = 0;


   // get info from histogram
   if (dist.IsBinned() ) {
      int nbins = dist.Data().size();
      double min = dist.LowerBin();
      double max = dist.UpperBin();
      const double * pv = &(dist.Data().front());
      ret |= unur_distr_cemp_set_hist(fUdistr, pv, nbins, min, max);
#ifdef OLDVERS
      Error("SetEmpiricalDistribution","hist method not available in UNURAN 0.8.1");
#endif
   }
   else {
      const double * pv = &dist.Data().front();
      // n is number of points (size/ndim)
      int n = dist.Data().size()/dist.NDim();
      if (dist.NDim() == 1)
         ret |= unur_distr_cemp_set_data(fUdistr, pv, n);
      else
         ret |= unur_distr_cvemp_set_data(fUdistr, pv, n);
   }
   if (ret != 0) {
      Error("SetEmpiricalDistribution","invalid distribution object");
      return false;
   }
   return true;
}


bool  TUnuran::SetDiscreteDistribution(const TUnuranDiscrDist & dist)
{
   // internal method to set in unuran the function pointer for a discrete univariate distribution
   if (fUdistr != 0)  unur_distr_free(fUdistr);
   fUdistr = unur_distr_discr_new();
   if (fUdistr == 0) return false;
   unsigned int ret = 0;
   // if a probability mesh function is provided
   if (dist.ProbVec().size() == 0) {
      ret = unur_distr_set_extobj(fUdistr, &dist );
      ret |= unur_distr_discr_set_pmf(fUdistr, &DiscrDist::Pmf);
      if (dist.HasCdf() ) ret |= unur_distr_discr_set_cdf(fUdistr, &DiscrDist::Cdf);

   }
   else {
      // case user provides vector of probabilities
      ret |= unur_distr_discr_set_pv(fUdistr, &dist.ProbVec().front(), dist.ProbVec().size() );
   }

   int xmin, xmax = 0;
   if (dist.GetDomain(xmin,xmax) ) {
      ret = unur_distr_discr_set_domain(fUdistr,xmin,xmax);
      if (ret != 0)  {
         Error("SetDiscrDistribution","invalid domain xmin = %d xmax = %d ",xmin,xmax);
         return false;
      }
   }
   if (dist.HasMode() ) {
      ret = unur_distr_discr_set_mode(fUdistr, dist.Mode());
      if (ret != 0)  {
         Error("SetContDistribution","invalid mode given,  mode = %d ",dist.Mode());
         return false;
      }
   }
   if (dist.HasProbSum() ) {
      ret = unur_distr_discr_set_pmfsum(fUdistr, dist.ProbSum());
      if (ret != 0)  {
         Error("SetContDistribution","invalid sum given,  mode = %g ",dist.ProbSum());
         return false;
      }
   }

   return (ret ==0) ? true : false;
}


//bool TUnuran::SetMethodAndInit(const std::string & s) {
bool TUnuran::SetMethodAndInit() {

   // internal function to set a method from a distribution and
   // initialize unuran with the given distribution.
   if (fUdistr == 0) return false;

   struct unur_slist *mlist = NULL;

   UNUR_PAR * par = _unur_str2par(fUdistr, fMethod.c_str(), &mlist);
   if (par == 0) {
      Error("SetMethod","missing distribution information or syntax error");
      if (mlist != 0)  _unur_slist_free(mlist);
      return false;
   }


   // set unuran to not use a private copy of the distribution object
   unur_set_use_distr_privatecopy (par, false);

   // need to free fGen if already existing ?
   if (fGen != 0 )  unur_free(fGen);
   fGen = unur_init(par);
   _unur_slist_free(mlist);
   if (fGen == 0) {
      Error("SetMethod","initializing Unuran: condition for method violated");
      return false;
   }
   return true;
 }


int TUnuran::SampleDiscr()
{
   // sample one-dimensional distribution
   assert(fGen != 0);
   return unur_sample_discr(fGen);
}

double TUnuran::Sample()
{
   // sample one-dimensional distribution
   assert(fGen != 0);
   return unur_sample_cont(fGen);
}

bool TUnuran::SampleMulti(double * x)
{
   // sample multidimensional distribution
   if (fGen == 0) return false;
   unur_sample_vec(fGen,x);
   return true;
}

void TUnuran::SetSeed(unsigned int seed) {
   return fRng->SetSeed(seed);
}

bool  TUnuran::SetLogLevel(unsigned int debugLevel)
{
   if (fGen == 0) return false;
   int ret = 0;
   if ( debugLevel > 1)
      ret |= unur_chg_debug(fGen, UNUR_DEBUG_ALL);
   else if (debugLevel == 1)
      ret |= unur_chg_debug(fGen, UNUR_DEBUG_ALL);
   else
      ret |= unur_chg_debug(fGen, UNUR_DEBUG_OFF);

   return (ret ==0) ? true : false;

}

bool TUnuran::InitPoisson(double mu, const std::string & method) {
   // initializaton for a Poisson
   double p[1];
   p[0] = mu;

   fUdistr = unur_distr_poisson(p,1);

   fMethod = method;
   if (fUdistr == 0) return false;
   if (! SetMethodAndInit() ) return false;
   if (! SetRandomGenerator() ) return false;
   return true;
}


bool TUnuran::InitBinomial(unsigned int ntot, double prob, const std::string & method ) {
   // initializaton for a Binomial
   double par[2];
   par[0] = ntot;
   par[1] = prob;
   fUdistr = unur_distr_binomial(par,2);

   fMethod = method;
   if (fUdistr == 0) return false;
   if (! SetMethodAndInit() ) return false;
   if (! SetRandomGenerator() ) return false;
   return true;
}


bool TUnuran::ReInitDiscrDist(unsigned int npar, double * par) {
   // re-initialization of UNURAN without freeing and creating a new fGen object
   // works only for pre-defined distribution by changing their parameters
   if (!fGen ) return false;
   if (!fUdistr) return false;
   unur_distr_discr_set_pmfparams(fUdistr,par,npar);
   int iret = unur_reinit(fGen);
   if (iret) Warning("ReInitDiscrDist","re-init failed - a full initizialization must be performed");
   return (!iret);
}

 TUnuran.cxx:1
 TUnuran.cxx:2
 TUnuran.cxx:3
 TUnuran.cxx:4
 TUnuran.cxx:5
 TUnuran.cxx:6
 TUnuran.cxx:7
 TUnuran.cxx:8
 TUnuran.cxx:9
 TUnuran.cxx:10
 TUnuran.cxx:11
 TUnuran.cxx:12
 TUnuran.cxx:13
 TUnuran.cxx:14
 TUnuran.cxx:15
 TUnuran.cxx:16
 TUnuran.cxx:17
 TUnuran.cxx:18
 TUnuran.cxx:19
 TUnuran.cxx:20
 TUnuran.cxx:21
 TUnuran.cxx:22
 TUnuran.cxx:23
 TUnuran.cxx:24
 TUnuran.cxx:25
 TUnuran.cxx:26
 TUnuran.cxx:27
 TUnuran.cxx:28
 TUnuran.cxx:29
 TUnuran.cxx:30
 TUnuran.cxx:31
 TUnuran.cxx:32
 TUnuran.cxx:33
 TUnuran.cxx:34
 TUnuran.cxx:35
 TUnuran.cxx:36
 TUnuran.cxx:37
 TUnuran.cxx:38
 TUnuran.cxx:39
 TUnuran.cxx:40
 TUnuran.cxx:41
 TUnuran.cxx:42
 TUnuran.cxx:43
 TUnuran.cxx:44
 TUnuran.cxx:45
 TUnuran.cxx:46
 TUnuran.cxx:47
 TUnuran.cxx:48
 TUnuran.cxx:49
 TUnuran.cxx:50
 TUnuran.cxx:51
 TUnuran.cxx:52
 TUnuran.cxx:53
 TUnuran.cxx:54
 TUnuran.cxx:55
 TUnuran.cxx:56
 TUnuran.cxx:57
 TUnuran.cxx:58
 TUnuran.cxx:59
 TUnuran.cxx:60
 TUnuran.cxx:61
 TUnuran.cxx:62
 TUnuran.cxx:63
 TUnuran.cxx:64
 TUnuran.cxx:65
 TUnuran.cxx:66
 TUnuran.cxx:67
 TUnuran.cxx:68
 TUnuran.cxx:69
 TUnuran.cxx:70
 TUnuran.cxx:71
 TUnuran.cxx:72
 TUnuran.cxx:73
 TUnuran.cxx:74
 TUnuran.cxx:75
 TUnuran.cxx:76
 TUnuran.cxx:77
 TUnuran.cxx:78
 TUnuran.cxx:79
 TUnuran.cxx:80
 TUnuran.cxx:81
 TUnuran.cxx:82
 TUnuran.cxx:83
 TUnuran.cxx:84
 TUnuran.cxx:85
 TUnuran.cxx:86
 TUnuran.cxx:87
 TUnuran.cxx:88
 TUnuran.cxx:89
 TUnuran.cxx:90
 TUnuran.cxx:91
 TUnuran.cxx:92
 TUnuran.cxx:93
 TUnuran.cxx:94
 TUnuran.cxx:95
 TUnuran.cxx:96
 TUnuran.cxx:97
 TUnuran.cxx:98
 TUnuran.cxx:99
 TUnuran.cxx:100
 TUnuran.cxx:101
 TUnuran.cxx:102
 TUnuran.cxx:103
 TUnuran.cxx:104
 TUnuran.cxx:105
 TUnuran.cxx:106
 TUnuran.cxx:107
 TUnuran.cxx:108
 TUnuran.cxx:109
 TUnuran.cxx:110
 TUnuran.cxx:111
 TUnuran.cxx:112
 TUnuran.cxx:113
 TUnuran.cxx:114
 TUnuran.cxx:115
 TUnuran.cxx:116
 TUnuran.cxx:117
 TUnuran.cxx:118
 TUnuran.cxx:119
 TUnuran.cxx:120
 TUnuran.cxx:121
 TUnuran.cxx:122
 TUnuran.cxx:123
 TUnuran.cxx:124
 TUnuran.cxx:125
 TUnuran.cxx:126
 TUnuran.cxx:127
 TUnuran.cxx:128
 TUnuran.cxx:129
 TUnuran.cxx:130
 TUnuran.cxx:131
 TUnuran.cxx:132
 TUnuran.cxx:133
 TUnuran.cxx:134
 TUnuran.cxx:135
 TUnuran.cxx:136
 TUnuran.cxx:137
 TUnuran.cxx:138
 TUnuran.cxx:139
 TUnuran.cxx:140
 TUnuran.cxx:141
 TUnuran.cxx:142
 TUnuran.cxx:143
 TUnuran.cxx:144
 TUnuran.cxx:145
 TUnuran.cxx:146
 TUnuran.cxx:147
 TUnuran.cxx:148
 TUnuran.cxx:149
 TUnuran.cxx:150
 TUnuran.cxx:151
 TUnuran.cxx:152
 TUnuran.cxx:153
 TUnuran.cxx:154
 TUnuran.cxx:155
 TUnuran.cxx:156
 TUnuran.cxx:157
 TUnuran.cxx:158
 TUnuran.cxx:159
 TUnuran.cxx:160
 TUnuran.cxx:161
 TUnuran.cxx:162
 TUnuran.cxx:163
 TUnuran.cxx:164
 TUnuran.cxx:165
 TUnuran.cxx:166
 TUnuran.cxx:167
 TUnuran.cxx:168
 TUnuran.cxx:169
 TUnuran.cxx:170
 TUnuran.cxx:171
 TUnuran.cxx:172
 TUnuran.cxx:173
 TUnuran.cxx:174
 TUnuran.cxx:175
 TUnuran.cxx:176
 TUnuran.cxx:177
 TUnuran.cxx:178
 TUnuran.cxx:179
 TUnuran.cxx:180
 TUnuran.cxx:181
 TUnuran.cxx:182
 TUnuran.cxx:183
 TUnuran.cxx:184
 TUnuran.cxx:185
 TUnuran.cxx:186
 TUnuran.cxx:187
 TUnuran.cxx:188
 TUnuran.cxx:189
 TUnuran.cxx:190
 TUnuran.cxx:191
 TUnuran.cxx:192
 TUnuran.cxx:193
 TUnuran.cxx:194
 TUnuran.cxx:195
 TUnuran.cxx:196
 TUnuran.cxx:197
 TUnuran.cxx:198
 TUnuran.cxx:199
 TUnuran.cxx:200
 TUnuran.cxx:201
 TUnuran.cxx:202
 TUnuran.cxx:203
 TUnuran.cxx:204
 TUnuran.cxx:205
 TUnuran.cxx:206
 TUnuran.cxx:207
 TUnuran.cxx:208
 TUnuran.cxx:209
 TUnuran.cxx:210
 TUnuran.cxx:211
 TUnuran.cxx:212
 TUnuran.cxx:213
 TUnuran.cxx:214
 TUnuran.cxx:215
 TUnuran.cxx:216
 TUnuran.cxx:217
 TUnuran.cxx:218
 TUnuran.cxx:219
 TUnuran.cxx:220
 TUnuran.cxx:221
 TUnuran.cxx:222
 TUnuran.cxx:223
 TUnuran.cxx:224
 TUnuran.cxx:225
 TUnuran.cxx:226
 TUnuran.cxx:227
 TUnuran.cxx:228
 TUnuran.cxx:229
 TUnuran.cxx:230
 TUnuran.cxx:231
 TUnuran.cxx:232
 TUnuran.cxx:233
 TUnuran.cxx:234
 TUnuran.cxx:235
 TUnuran.cxx:236
 TUnuran.cxx:237
 TUnuran.cxx:238
 TUnuran.cxx:239
 TUnuran.cxx:240
 TUnuran.cxx:241
 TUnuran.cxx:242
 TUnuran.cxx:243
 TUnuran.cxx:244
 TUnuran.cxx:245
 TUnuran.cxx:246
 TUnuran.cxx:247
 TUnuran.cxx:248
 TUnuran.cxx:249
 TUnuran.cxx:250
 TUnuran.cxx:251
 TUnuran.cxx:252
 TUnuran.cxx:253
 TUnuran.cxx:254
 TUnuran.cxx:255
 TUnuran.cxx:256
 TUnuran.cxx:257
 TUnuran.cxx:258
 TUnuran.cxx:259
 TUnuran.cxx:260
 TUnuran.cxx:261
 TUnuran.cxx:262
 TUnuran.cxx:263
 TUnuran.cxx:264
 TUnuran.cxx:265
 TUnuran.cxx:266
 TUnuran.cxx:267
 TUnuran.cxx:268
 TUnuran.cxx:269
 TUnuran.cxx:270
 TUnuran.cxx:271
 TUnuran.cxx:272
 TUnuran.cxx:273
 TUnuran.cxx:274
 TUnuran.cxx:275
 TUnuran.cxx:276
 TUnuran.cxx:277
 TUnuran.cxx:278
 TUnuran.cxx:279
 TUnuran.cxx:280
 TUnuran.cxx:281
 TUnuran.cxx:282
 TUnuran.cxx:283
 TUnuran.cxx:284
 TUnuran.cxx:285
 TUnuran.cxx:286
 TUnuran.cxx:287
 TUnuran.cxx:288
 TUnuran.cxx:289
 TUnuran.cxx:290
 TUnuran.cxx:291
 TUnuran.cxx:292
 TUnuran.cxx:293
 TUnuran.cxx:294
 TUnuran.cxx:295
 TUnuran.cxx:296
 TUnuran.cxx:297
 TUnuran.cxx:298
 TUnuran.cxx:299
 TUnuran.cxx:300
 TUnuran.cxx:301
 TUnuran.cxx:302
 TUnuran.cxx:303
 TUnuran.cxx:304
 TUnuran.cxx:305
 TUnuran.cxx:306
 TUnuran.cxx:307
 TUnuran.cxx:308
 TUnuran.cxx:309
 TUnuran.cxx:310
 TUnuran.cxx:311
 TUnuran.cxx:312
 TUnuran.cxx:313
 TUnuran.cxx:314
 TUnuran.cxx:315
 TUnuran.cxx:316
 TUnuran.cxx:317
 TUnuran.cxx:318
 TUnuran.cxx:319
 TUnuran.cxx:320
 TUnuran.cxx:321
 TUnuran.cxx:322
 TUnuran.cxx:323
 TUnuran.cxx:324
 TUnuran.cxx:325
 TUnuran.cxx:326
 TUnuran.cxx:327
 TUnuran.cxx:328
 TUnuran.cxx:329
 TUnuran.cxx:330
 TUnuran.cxx:331
 TUnuran.cxx:332
 TUnuran.cxx:333
 TUnuran.cxx:334
 TUnuran.cxx:335
 TUnuran.cxx:336
 TUnuran.cxx:337
 TUnuran.cxx:338
 TUnuran.cxx:339
 TUnuran.cxx:340
 TUnuran.cxx:341
 TUnuran.cxx:342
 TUnuran.cxx:343
 TUnuran.cxx:344
 TUnuran.cxx:345
 TUnuran.cxx:346
 TUnuran.cxx:347
 TUnuran.cxx:348
 TUnuran.cxx:349
 TUnuran.cxx:350
 TUnuran.cxx:351
 TUnuran.cxx:352
 TUnuran.cxx:353
 TUnuran.cxx:354
 TUnuran.cxx:355
 TUnuran.cxx:356
 TUnuran.cxx:357
 TUnuran.cxx:358
 TUnuran.cxx:359
 TUnuran.cxx:360
 TUnuran.cxx:361
 TUnuran.cxx:362
 TUnuran.cxx:363
 TUnuran.cxx:364
 TUnuran.cxx:365
 TUnuran.cxx:366
 TUnuran.cxx:367
 TUnuran.cxx:368
 TUnuran.cxx:369
 TUnuran.cxx:370
 TUnuran.cxx:371
 TUnuran.cxx:372
 TUnuran.cxx:373
 TUnuran.cxx:374
 TUnuran.cxx:375
 TUnuran.cxx:376
 TUnuran.cxx:377
 TUnuran.cxx:378
 TUnuran.cxx:379
 TUnuran.cxx:380
 TUnuran.cxx:381
 TUnuran.cxx:382
 TUnuran.cxx:383
 TUnuran.cxx:384
 TUnuran.cxx:385
 TUnuran.cxx:386
 TUnuran.cxx:387
 TUnuran.cxx:388
 TUnuran.cxx:389
 TUnuran.cxx:390
 TUnuran.cxx:391
 TUnuran.cxx:392
 TUnuran.cxx:393
 TUnuran.cxx:394
 TUnuran.cxx:395
 TUnuran.cxx:396
 TUnuran.cxx:397
 TUnuran.cxx:398
 TUnuran.cxx:399
 TUnuran.cxx:400
 TUnuran.cxx:401
 TUnuran.cxx:402
 TUnuran.cxx:403
 TUnuran.cxx:404
 TUnuran.cxx:405
 TUnuran.cxx:406
 TUnuran.cxx:407
 TUnuran.cxx:408
 TUnuran.cxx:409
 TUnuran.cxx:410
 TUnuran.cxx:411
 TUnuran.cxx:412
 TUnuran.cxx:413
 TUnuran.cxx:414
 TUnuran.cxx:415
 TUnuran.cxx:416
 TUnuran.cxx:417
 TUnuran.cxx:418
 TUnuran.cxx:419
 TUnuran.cxx:420
 TUnuran.cxx:421
 TUnuran.cxx:422
 TUnuran.cxx:423
 TUnuran.cxx:424
 TUnuran.cxx:425
 TUnuran.cxx:426
 TUnuran.cxx:427
 TUnuran.cxx:428
 TUnuran.cxx:429
 TUnuran.cxx:430
 TUnuran.cxx:431
 TUnuran.cxx:432
 TUnuran.cxx:433
 TUnuran.cxx:434
 TUnuran.cxx:435
 TUnuran.cxx:436
 TUnuran.cxx:437
 TUnuran.cxx:438
 TUnuran.cxx:439
 TUnuran.cxx:440
 TUnuran.cxx:441
 TUnuran.cxx:442
 TUnuran.cxx:443
 TUnuran.cxx:444
 TUnuran.cxx:445
 TUnuran.cxx:446
 TUnuran.cxx:447
 TUnuran.cxx:448
 TUnuran.cxx:449
 TUnuran.cxx:450
 TUnuran.cxx:451
 TUnuran.cxx:452
 TUnuran.cxx:453
 TUnuran.cxx:454
 TUnuran.cxx:455
 TUnuran.cxx:456
 TUnuran.cxx:457
 TUnuran.cxx:458
 TUnuran.cxx:459
 TUnuran.cxx:460
 TUnuran.cxx:461
 TUnuran.cxx:462
 TUnuran.cxx:463