#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),
fRng(r)
{
if (fRng == 0) fRng = gRandom;
if ( debugLevel > 2)
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()
{
if (fGen != 0) unur_free(fGen);
if (fUdistr != 0) unur_distr_free(fUdistr);
}
TUnuran::TUnuran(const TUnuran &)
{
}
TUnuran & TUnuran::operator = (const TUnuran &rhs)
{
if (this == &rhs) return *this;
return *this;
}
bool TUnuran::Init(const std::string & dist, const std::string & method)
{
std::string s = dist + " & " + method;
fGen = unur_str2gen(s.c_str() );
if (fGen == 0) {
Error("Init","Cannot create generator object");
return false;
}
SetRandomGenerator();
return true;
}
bool TUnuran::Init(const TUnuranContDist & distr, const std::string & method)
{
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)
{
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 ) {
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 ) {
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()
{
if (fRng == 0) return false;
UNUR_URNG * rng = unur_urng_new(&UnuranRng<TRandom>::Rndm, fRng );
if (rng == 0) return false;
unsigned int ret = 0;
ret |= unur_urng_set_delete(rng, &UnuranRng<TRandom>::Delete);
ret |= unur_urng_set_seed(rng, &UnuranRng<TRandom>::Seed);
if (fGen == 0) return false;
unur_chg_urng( fGen, rng);
return (ret ==0) ? true : false;
}
bool TUnuran::SetContDistribution(const TUnuranContDist & dist )
{
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 {
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 )
{
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) {
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;
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();
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)
{
if (fUdistr != 0) unur_distr_free(fUdistr);
fUdistr = unur_distr_discr_new();
if (fUdistr == 0) return false;
unsigned int ret = 0;
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 {
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 = %g xmax = %g ",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 = %g ",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() {
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");
return false;
}
unur_set_use_distr_privatecopy (par, false);
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()
{
assert(fGen != 0);
return unur_sample_discr(fGen);
}
double TUnuran::Sample()
{
assert(fGen != 0);
return unur_sample_cont(fGen);
}
bool TUnuran::SampleMulti(double * x)
{
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 > 2)
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) {
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 ) {
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) {
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);
}