#############################################################################

[main]

[main - data:]

# method (for information only: the program scans the file name)
method: DSTD

[main - header:]

/* prototypes */

int estimate_uerror( UNUR_DISTR *distr, double u_resolution, int samplesize );

double cdf_geom(int k, const UNUR_DISTR *distr);
int invcdf_geom(double u, const UNUR_DISTR *distr);

/* -- constants -- */

/* sample size */
static const int    UERROR_SAMPLESIZE = 100000;
static const double UERROR_RESOLUTION = 1.e-14;

\#define COMPARE_SAMPLE_SIZE   (500)
\#define VIOLATE_SAMPLE_SIZE   (20)

/* \#define SEED   (298346) */

#############################################################################

[new]

[new - invalid NULL ptr: 
   distr = NULL; ]

~( distr );
	--> expected_NULL --> UNUR_ERR_NULL

[new - invalid distribution type:
   distr = unur_distr_cont_new(); ]

~( distr );
	 --> expected_NULL --> UNUR_ERR_DISTR_INVALID

[new - not a standard distribution:
   distr = unur_distr_discr_new(); ]

~( distr );
	--> expected_NULL --> UNUR_ERR_DISTR_REQUIRED

##############################################################################

[set]

[set - invalid NULL ptr: 
   par = NULL; ]

~_variant(par,1);
	--> expected_setfailed --> UNUR_ERR_NULL

[set - invalid parameter object:
   double fpar[1] = {0.5};
   distr = unur_distr_geometric(fpar,1);
   par = unur_dgt_new(distr); ]

~_variant(par,1);
	--> expected_setfailed --> UNUR_ERR_PAR_INVALID

unur_par_free(par);

[set - invalid parameters:
   double fpar[1] = {0.5};
   distr = unur_distr_geometric(fpar,1);
   par = unur_dstd_new(distr); ]

~_variant(par,9999);
	--> expected_setfailed --> UNUR_ERR_PAR_VARIANT

unur_par_free(par);

##############################################################################

# [get]

##############################################################################

[chg]

[chg - invalid generator object:
   double fpar[2] = {10,0.4};
   distr = unur_distr_binomial(fpar,2);
   par = unur_dgt_new(distr);
   unur_set_debug(par,0);
   gen = unur_init( par ); <-- ! NULL ]

~_truncated(gen, 1, 5);
	--> expected_setfailed --> UNUR_ERR_GEN_INVALID

##############################################################################

[init]

[init - invalid NULL ptr: 
   par = NULL; ]

unur_init( par );
	--> expected_NULL --> UNUR_ERR_NULL


##############################################################################

[reinit]

[reinit - does not exist:
   double fpar[2] = {10.,0.63};
   distr = unur_distr_binomial(fpar,2);
   par = unur_dstd_new(distr);
   gen = unur_init( par ); <-- ! NULL ]

unur_reinit( gen );
	--> expected_reinit

##############################################################################

[sample]

[sample - compare clone:
   UNUR_GEN *clone;
   double fpar[] = {10,0.3}; 
   distr = unur_distr_binomial(fpar,2);
   par = NULL;
   gen = NULL; ]

/* original generator object */
par = unur_dstd_new(distr);
gen = unur_init(par);
        -->compare_sequence_gen_start

/* clone */
clone = unur_gen_clone(gen);
unur_free(gen);
gen = clone;
        -->compare_sequence_gen

#.....................................................................

[sample - compare stringparser:
   double fpar[] = {3.};
   distr = NULL;
   par = NULL;
   gen = NULL; ]

distr = unur_distr_poisson(fpar,1);
par = unur_dstd_new(distr);
unur_dstd_set_variant(par,2);
gen = unur_init(par);
	-->compare_sequence_gen_start
	
unur_free(gen); gen = NULL;
unur_distr_free(distr); distr = NULL;
gen = unur_str2gen( "poisson(3.) & method = dstd; variant = 2" );
	-->compare_sequence_gen


##############################################################################

[validate]

[validate - generators:]

# inversion      
par[0] = unur_dstd_new(@distr@);
if (unur_dstd_set_variant(par,UNUR_STDGEN_INVERSION)!=UNUR_SUCCESS) { unur_par_free(par); par = NULL; }

par[1] = unur_dstd_new(@distr@);
if (unur_dstd_set_variant(par,1)!=UNUR_SUCCESS) { unur_par_free(par); par = NULL; }

par[2] = unur_dstd_new(@distr@);
if (unur_dstd_set_variant(par,2)!=UNUR_SUCCESS) { unur_par_free(par); par = NULL; }

# change domain
par[10] = unur_dstd_new(@distr@);
if (unur_dstd_set_variant(par,UNUR_STDGEN_INVERSION)!=UNUR_SUCCESS) { if (par) unur_par_free(par); par = NULL; }
unur_dstd_chg_truncated(gen,1,4);

# change parameters (use default variant)
{ UNUR_DISTR *dg =NULL;
par[11] = unur_dstd_new(@distr@);
fpm[0] = 0.2;
fpm[1] = 0.5;
dg = unur_get_distr(gen);
unur_distr_discr_set_pmfparams(dg,fpm,2);
unur_reinit(gen); }

# change parameters (use default variant)
{ UNUR_DISTR *dg =NULL;
par[12] = unur_dstd_new(@distr@);
fpm[0] = 20;
fpm[1] = 0.5;
dg = unur_get_distr(gen);
unur_distr_discr_set_pmfparams(dg,fpm,2);
unur_reinit(gen); }

# change parameters (use default variant)
{ UNUR_DISTR *dg =NULL;
par[13] = unur_dstd_new(@distr@);
fpm[0] = 200;
fpm[1] = 50;
dg = unur_get_distr(gen);
unur_distr_discr_set_pmfparams(dg,fpm,2);
unur_reinit(gen); }


[validate - distributions:]

# Binomial distribution
fpm[0] = 50.;
fpm[1] = 0.4;
distr[1] = unur_distr_binomial(fpm,2);

fpm[0] = 100.;
fpm[1] = 0.87;
distr[2] = unur_distr_binomial(fpm,2);

fpm[0] = 100.;
fpm[1] = 0.01;
distr[3] = unur_distr_binomial(fpm,2);

fpm[0] = 10000.;
fpm[1] = 0.7 ;
distr[4] = unur_distr_binomial(fpm,2);


# Geometric disctribution
fpm[0] = 0.5;
distr[0] = unur_distr_geometric(fpm,1);

fpm[0] = 0.001;
distr[11] = unur_distr_geometric(fpm,1);

fpm[0] = 0.999;
distr[12] = unur_distr_geometric(fpm,1);


# Hypergeometric
fpm[0] = 10000.;
fpm[1] = 100. ;
fpm[2] = 50. ;
distr[5] = unur_distr_hypergeometric(fpm,3);

fpm[0] = 10000.;
fpm[1] = 9000. ;
fpm[2] = 50. ;
distr[6] = unur_distr_hypergeometric(fpm,3);

fpm[0] = 10000.;
fpm[1] = 80. ;
fpm[2] = 90. ;
distr[7] = unur_distr_hypergeometric(fpm,3);

fpm[0] = 10000.;
fpm[1] = 1000. ;
fpm[2] = 150. ;
distr[8] = unur_distr_hypergeometric(fpm,3);

fpm[0] = 10000.;
fpm[1] = 9000. ;
fpm[2] = 500. ;
distr[9] = unur_distr_hypergeometric(fpm,3);

fpm[0] = 10000.;
fpm[1] = 9000. ;
fpm[2] = 250. ;
distr[10] = unur_distr_hypergeometric(fpm,3);


# Logarithmic disctribution
fpm[0] = 0.001;
distr[25] = unur_distr_logarithmic(fpm,1);

fpm[0] = 0.01;
distr[13] = unur_distr_logarithmic(fpm,1);

fpm[0] = 0.1;
distr[14] = unur_distr_logarithmic(fpm,1);

fpm[0] = 0.5;
distr[15] = unur_distr_logarithmic(fpm,1);

fpm[0] = 0.9;
distr[16] = unur_distr_logarithmic(fpm,1);

fpm[0] = 0.999;
distr[17] = unur_distr_logarithmic(fpm,1);

# Poisson distribution
fpm[0] = 0.001;
distr[18] = unur_distr_poisson(fpm,1);

fpm[0] = 0.1;
distr[19] = unur_distr_poisson(fpm,1);

fpm[0] = 0.5;
distr[20] = unur_distr_poisson(fpm,1);

fpm[0] = 1.;
distr[21] = unur_distr_poisson(fpm,1);

fpm[0] = 10.;
distr[22] = unur_distr_poisson(fpm,1);

fpm[0] = 1000.;
distr[23] = unur_distr_poisson(fpm,1);

# Zipf
fpm[0] = 2.;
fpm[1] = 3.;
distr[28] = unur_distr_zipf(fpm,2);

fpm[0] = 3.;
fpm[1] = 2.;
distr[29] = unur_distr_zipf(fpm,2);

# negative binomial distribution
fpm[0] = 0.5;
fpm[1] = 10.;
distr[24] = unur_distr_negativebinomial(fpm,2);

# distributions from scratch
distr[26] = unur_distr_discr_new();
unur_distr_set_name( distr[26], "CDF_only" );
unur_distr_discr_set_domain( distr[26], 0, INT_MAX );
unur_distr_discr_set_cdf( distr[26], cdf_geom );

distr[27] = unur_distr_discr_new();
unur_distr_set_name( distr[27], "CDF&invCDF" );
unur_distr_discr_set_domain( distr[27], 0, INT_MAX );
unur_distr_discr_set_cdf( distr[27], cdf_geom );
unur_distr_discr_set_invcdf( distr[27], invcdf_geom );


# number of distributions: 30


[validate - test chi2:]

#  + ... pass test
#  0 ... fail to initialize generator (given variant does not exist)
#  - ... fail test
#  / ... either init fails or test passes
#  . ... do not run test
#  # ... comment
#
# generators:
#   [0]         ... Inversion
#   [1] -- [2]  ... Variants 1 to 9
#   [10]        ... domain changed after initialization
#   [11]        ... change parameters to {0.2, 0.5}  (use default variant)
#   [12]        ... change parameters to {20, 0.5}   (use default variant)
#   [13]        ... change parameters to {200, 50}   (use default variant)
#
#	           1  1  1  1
#gen	0  1  2    0  1  2  3	# distribution
#-------------------------------------------------------------
  <1>	.  +  .    .  .  +  .	# binomial (50, 0.4)
  <2>	.  +  .    .  .  +  .	# binomial (100, 0.87)
  <3>	.  +  .    .  .  +  .	# binomial (100, 0.01)
  <4>	.  +  .    .  .  +  .	# binomial (10000, 0.7)

  <0>	+  .  .    .  +  .  .	# geometric (0.5)
 <11>	+  .  .    .  +  .  .	# geometric (0.01)
 <12>	+  .  .    .  +  .  .	# geometric (0.999)

  <5>	.  +  .    .  .  .  +	# hypergeometric (10000, 100, 50)
  <6>	.  +  .    .  .  .  +	# hypergeometric (10000, 9000, 50)
  <7>	.  +  .    .  .  .  +	# hypergeometric (10000, 80, 90)
  <8>	.  +  .    .  .  .  +	# hypergeometric (10000, 1000, 150)
  <9>	.  +  .    .  .  .  +	# hypergeometric (10000, 9000, 500)
 <10>	.  +  .    .  .  .  +	# hypergeometric (10000, 9000, 5000)

x<25>	.  +  .    .  +  .  .	# logarithmic (0.001)
 <13>	.  +  .    .  +  .  .	# logarithmic (0.01)
 <14>	.  +  .    .  +  .  .	# logarithmic (0.1)
 <15>	.  +  .    .  +  .  .	# logarithmic (0.5)
 <16>	.  +  .    .  +  .  .	# logarithmic (0.9)
 <17>	.  +  .    .  +  .  .	# logarithmic (0.999)

x<18>	.  +  +    .  +  +  .	# poisson (0.001)
 <19>	.  +  +    .  +  +  .	# poisson (0.1)
 <20>	.  +  +    .  +  +  .	# poisson (0.5)
 <21>	.  +  +    .  +  +  .	# poisson (1)
 <22>	.  +  +    .  +  +  .	# poisson (10)
 <23>	.  +  +    .  +  +  .	# poisson (1000)

 <28>	.  +  .    .  .  .  .	# zipf (2,3)
 <29>	.  +  .    .  .  .  .	# zipf (3,2)

#<24>	.  .  .    .  .  .  .	# negativebinomial (0.5, 10)

 <26>	0  .  .    .  .  .  .	# given CDF
 <27>	+  .  .    .  .  .  .	# given CDF + invCDF


##############################################################################
##############################################################################

[special]

## Remark:
## 
## In this section we merely test the existence of inversion.
## A few implementations seem to be rather inaccurate with respect to
## their u-errors.
##

[special - decl:]

  int samplesize = UERROR_SAMPLESIZE;
  double ures = UERROR_RESOLUTION;

  int errorsum = 0;
  double fpar[5];

  UNUR_DISTR *distr;

[special - start:]

  /* test for maximal u-error */
  printf("\n[test maximal u-error for inversion method]\n"); 
  fprintf(TESTLOG,"\n* Test maximal u-error for inversion method *\n"); 

## ----------------------------------------------------

  printf(" binomial");

  fpar[0] = 20;
  fpar[1] = 0.2;
  distr = unur_distr_binomial(fpar,2);
  errorsum += estimate_uerror(distr,ures,samplesize);

  fpar[0] = 10000;
  fpar[1] = 0.2;
  distr = unur_distr_binomial(fpar,2);
  errorsum += estimate_uerror(distr,ures,samplesize);

## ----------------------------------------------------

  printf(" geometric");

  fpar[0] = 0.1;
  distr = unur_distr_geometric(fpar,1);
  errorsum += estimate_uerror(distr,ures,samplesize);

## ----------------------------------------------------

  printf(" hypergeometric");

  fpar[0] = 10000;
  fpar[1] = 1000;
  fpar[2] = 150;
  distr = unur_distr_hypergeometric(fpar,3);
  errorsum += estimate_uerror(distr,ures,samplesize);

## ----------------------------------------------------

  printf(" negativebinomial");

  fpar[0] = 0.2;
  fpar[1] = 20;
  distr = unur_distr_negativebinomial(fpar,2);
  errorsum += estimate_uerror(distr,ures,samplesize);

  fpar[0] = 0.2;
  fpar[1] = 10000;
  distr = unur_distr_negativebinomial(fpar,2);
  errorsum += estimate_uerror(distr,ures,samplesize);

## ----------------------------------------------------

  printf(" poisson");

  fpar[0] = 0.1;
  distr = unur_distr_poisson(fpar,1);
  errorsum += estimate_uerror(distr,ures,samplesize);

  fpar[0] = 10;
  distr = unur_distr_poisson(fpar,1);
  errorsum += estimate_uerror(distr,ures,samplesize);

## ----------------------------------------------------

/*---------------------------------------------------------------------------*/

  /* test finished */
  FAILED = (errorsum < 2) ? 0 : 1;


##############################################################################

[verbatim]

#############################################################################
#
# routines for special tests
#
#############################################################################

int
estimate_uerror( UNUR_DISTR *distr,     /* distribution object */
		 double u_resolution,   /* maximal tolerated u-error */
  		 int samplesize )       /* sample size for error experiment */
/* returns 0 if maxerror < u_resolution, errorcode otherwise */
{
  UNUR_PAR *par;
  UNUR_GEN *gen;
  int i, nfpar;
  const double *fpar;
  double score;

  /* print data about distribution */
  fprintf(TESTLOG,"> %s (",unur_distr_get_name(distr));
  nfpar = unur_distr_discr_get_pmfparams(distr,&fpar);
  for(i=0;i<nfpar;i++) fprintf(TESTLOG,"%s %g", (i?",":""), fpar[i]);
  fprintf(TESTLOG,")\n");

  /* create parameter object for inversion method */
  par = unur_dstd_new(distr);
  if (par==NULL || 
      unur_dstd_set_variant(par,UNUR_STDGEN_INVERSION)!=UNUR_SUCCESS) {
    fprintf(TESTLOG,"\t--> inversion method not implemented !!\n\n");
    printf("0"); fflush(stdout);
    if (par) unur_par_free(par);
    unur_distr_free(distr);
    return 0; 
  }

  /* initialize generator object */
  gen = unur_init(par);

  /* run test */
  score = run_validate_u_error( TESTLOG, gen, distr, u_resolution, samplesize );

  /* clear working space */
  unur_distr_free(distr);
  unur_free(gen);

  /* return */
  fprintf(TESTLOG,"\n");
  return score;

} /* end of estimate_uerror() */


#############################################################################
#
# PDFs and CDF for test distributions
#
#############################################################################

double cdf_geom(int k, const UNUR_DISTR *distr ATTRIBUTE__UNUSED)
{ 
  const double p = 0.3;
  return ((k<0) ? 0. : (1. - pow(1. - p, k+1.)) );
}

int invcdf_geom(double u, const UNUR_DISTR *distr ATTRIBUTE__UNUSED)
{ 
  const double p = 0.3;
  return ((int) (log(u) / log(1.-p)));
}


##############################################################################
