1 /*****************************************************************************
2  *                                                                           *
3  *          UNURAN -- Universal Non-Uniform Random number generator          *
4  *                                                                           *
5  *****************************************************************************
6  *                                                                           *
7  *   FILE:      testroutines.c                                               *
8  *                                                                           *
9  *   Common test routines                                                    *
10  *                                                                           *
11  *****************************************************************************
12  *                                                                           *
13  *   Copyright (c) 2000-2006 Wolfgang Hoermann and Josef Leydold             *
14  *   Department of Statistics and Mathematics, WU Wien, Austria              *
15  *                                                                           *
16  *   This program is free software; you can redistribute it and/or modify    *
17  *   it under the terms of the GNU General Public License as published by    *
18  *   the Free Software Foundation; either version 2 of the License, or       *
19  *   (at your option) any later version.                                     *
20  *                                                                           *
21  *   This program is distributed in the hope that it will be useful,         *
22  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
23  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
24  *   GNU General Public License for more details.                            *
25  *                                                                           *
26  *   You should have received a copy of the GNU General Public License       *
27  *   along with this program; if not, write to the                           *
28  *   Free Software Foundation, Inc.,                                         *
29  *   59 Temple Place, Suite 330, Boston, MA 02111-1307, USA                  *
30  *                                                                           *
31  *****************************************************************************/
32 
33 /*---------------------------------------------------------------------------*/
34 
35 #include "testunuran.h"
36 #include <signal.h>
37 
38 #ifdef HAVE_UNISTD_H
39 #  include <unistd.h>
40 #endif
41 
42 /*---------------------------------------------------------------------------*/
43 /* Compiler switches                                                         */
44 
45 /* whether to test U-errors for inversion method in tails more accurately */
46 #define TEST_INVERROR_TAILS (FALSE)
47 
48 /*---------------------------------------------------------------------------*/
49 /* global switches                                                           */
50 
51 static int stopwatch = FALSE;   /* whether to use a stop watch for checks    */
52 static TIMER vw;                /* timer for particular tests                */
53 
54 /*---------------------------------------------------------------------------*/
55 
56 #if defined(HAVE_ALARM) && defined(HAVE_SIGNAL)
57 
58 /* time limit before SIGALRM is sent to process */
59 int time_limit = 0u;
60 
61 /* handle SIGALRM signals */
62 static void catch_alarm (int sig);
63 
64 /* test log file */
65 static FILE *TESTLOG = NULL;
66 
67 #endif
68 
69 /*---------------------------------------------------------------------------*/
70 
71 /* compare two doubles */
72 static int compare_doubles ( double x1, double x2 );
73 
74 /* compare double sequences generated by generator */
75 static int compare_double_sequence_gen_start ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
76 static int compare_double_sequence_gen       ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
77 
78 /* compare int sequences generated by generator    */
79 static int compare_int_sequence_gen_start    ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
80 static int compare_int_sequence_gen          ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
81 
82 /* compare sequences of double vectors generated by generator */
83 static int compare_cvec_sequence_gen_start   ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
84 static int compare_cvec_sequence_gen         ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
85 
86 /* compare sequences of double matrices generated by generator */
87 static int compare_matr_sequence_gen_start   ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
88 static int compare_matr_sequence_gen         ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size );
89 
90 /*---------------------------------------------------------------------------*/
91 /* check whether unur_urng_reset() works                                     */
92 
93 static int
cannot_compare_sequence(FILE * LOG)94 cannot_compare_sequence ( FILE *LOG )
95 {
96   fprintf (LOG,"\nURNG cannot be reset. Cannot compare sequences. (Skip)\n");
97   printf ("URNG cannot be reset. Cannot compare sequences. (Skip)\n");
98 
99   return UNUR_SUCCESS; /* indicate as "not failed" for practical reasons */
100 } /* end of cannot_compare_sequence() */
101 
102 /*---------------------------------------------------------------------------*/
103 /* stop watch                                                                */
104 
stopwatch_start(TIMER * t)105 void stopwatch_start(TIMER *t)
106 /* start stop watch */
107 {
108   t->stop = stopwatch_get_time(t->tv);
109   t->interim = t->stop;
110   t->start = t->stop;
111 }
112 
stopwatch_lap(TIMER * t)113 double stopwatch_lap(TIMER *t)
114 /* return elapsed time (in ms) since last call to stopwatch_start(),
115    stopwatch_stop(), or stopwatch_lap() */
116 {
117   double etime;
118 
119   t->stop = stopwatch_get_time(t->tv);
120   etime = t->stop - t->interim;
121 
122   t->interim = t->stop;
123 
124   return etime;
125 }
126 
stopwatch_stop(TIMER * t)127 double stopwatch_stop(TIMER *t)
128 /* return elapsed time (in ms) since last call to stopwatch_start()
129    or stopwatch_stop() */
130 {
131   double etime;
132 
133   t->stop = stopwatch_get_time(t->tv);
134   etime = t->stop - t->start;
135 
136   t->interim = t->stop;
137   t->start = t->stop;
138 
139   return etime;
140 }
141 
stopwatch_init(void)142 void stopwatch_init(void)
143 /* initialize watch */
144 {
145   /* detect whether stopwatch should be used */
146   stopwatch = (getenv("UNURANSTOPWATCH")==NULL) ? FALSE : TRUE;
147   stopwatch_start(&vw);
148 }
149 
stopwatch_print(FILE * LOG,const char * format,double etime)150 void stopwatch_print( FILE *LOG, const char *format, double etime )
151 /* print time depending whether watch is enabled or not */
152 {
153   if (stopwatch)
154     fprintf(LOG,format,etime);
155 }
156 
157 /*---------------------------------------------------------------------------*/
158 /* exit with FAIL when run time exceeds limit                                */
159 
160 #if defined(HAVE_ALARM) && defined(HAVE_SIGNAL)
161 
catch_alarm(int sig ATTRIBUTE__UNUSED)162 void catch_alarm (int sig ATTRIBUTE__UNUSED)
163 {
164   fprintf(stdout," aborted! time limit of %d seconds exceeded ...\n",time_limit);
165   fprintf(TESTLOG,"\n\n=== ABORTED! ===\ntime limit of %d seconds exceeded ...\n\n",time_limit);
166   exit (EXIT_FAILURE);
167 }
168 
set_alarm(FILE * LOG)169 void set_alarm(FILE *LOG)
170 {
171   char *read_timer;
172 
173   /* file handle for test log file */
174   TESTLOG = LOG;
175 
176   /* read time limit from environment */
177   read_timer = getenv("UNURANTIMER");
178   time_limit = (read_timer!=NULL) ? atoi(read_timer) : 0;
179 
180   /* alarm is only set when environment variable is defined */
181   if (time_limit<=0) return;
182 
183   /* Establish a handler for SIGALRM signals. */
184   signal(SIGALRM, catch_alarm);
185 
186   /* set in alarm in 'time' seconds */
187   alarm((unsigned)time_limit);
188 
189   /* print message into test log file */
190   fprintf(TESTLOG,"Send alarm in %d seconds\n",time_limit);
191   fprintf(TESTLOG,"\n====================================================\n\n");
192 
193 }
194 
195 #else
196 
set_alarm(FILE * LOG ATTRIBUTE__UNUSED)197 void set_alarm(FILE *LOG ATTRIBUTE__UNUSED) {;}
198 
199 #endif
200 
201 /*---------------------------------------------------------------------------*/
202 /* print header for test log file                                            */
203 
print_test_log_header(FILE * LOG,unsigned long seed,int fullcheck)204 void print_test_log_header( FILE *LOG, unsigned long seed, int fullcheck )
205 {
206   time_t started;
207 
208   /* Title */
209   fprintf(LOG,"\nUNU.RAN - Universal Non-Uniform RANdom number generator\n\n");
210   if (time( &started ) != -1)
211     fprintf(LOG,"%s",ctime(&started));
212   fprintf(LOG,"\n=======================================================\n\n");
213 
214   /* version */
215   fprintf(LOG,"UNU.RAN version:        %s\n", PACKAGE_STRING);
216 
217   /* deprecated code */
218   fprintf(LOG,"Use deprecated code:    %s\n",
219 #ifdef USE_DEPRECATED_CODE
220 	  "yes"
221 #else
222 	  "no"
223 #endif
224 	  );
225 
226   /* runtime checks */
227   fprintf(LOG,"Enable runtime checks:  %s\n",
228 #if defined(UNUR_ENABLE_CHECKNULL) || defined(UNUR_COOKIES)
229 	  "yes"
230 #else
231 	  "no"
232 #endif
233 	  );
234 
235   /* printing debugging info into log file */
236   fprintf(LOG,"Enable logging of data: %s\n",
237 #ifdef UNUR_ENABLE_LOGGING
238 	  "yes"
239 #else
240 	  "no"
241 #endif
242 	  );
243 
244   /* creating info string */
245   fprintf(LOG,"Enable info routine:    %s\n",
246 #ifdef UNUR_ENABLE_INFO
247 	  "yes"
248 #else
249 	  "no"
250 #endif
251 	  );
252 
253   fprintf(LOG,"\n");
254 
255   /* Uniform random number generator */
256   fprintf(LOG,"Uniform random number generator: %s\n",
257 #ifdef UNUR_URNG_DEFAULT_RNGSTREAM
258 	  "RngStreams"
259 #else
260 	  "[default]  (built-in or user supplied)"
261 #endif
262 	  );
263 
264   /* seed */
265   if (seed != ~0u)
266     fprintf(LOG,"SEED = %lu\n",seed);
267   else
268     fprintf(LOG,"SEED = (not set)\n");
269 
270   fprintf(LOG,"\n");
271 
272   /* whether all checks are performed */
273   fprintf(LOG,"check mode: %s\n",
274 	  fullcheck ? "fullcheck" : "installation");
275 
276   /* end */
277   fprintf(LOG,"\n=======================================================\n\n");
278 
279 } /* end of print_test_log_header() */
280 
281 /*---------------------------------------------------------------------------*/
282 /* check for invalid NULL pointer, that should not happen in this program */
283 
abort_if_NULL(FILE * LOG,int line,const void * ptr)284 void abort_if_NULL( FILE *LOG, int line, const void *ptr )
285 {
286   if (ptr) return; /* o.k. */
287 
288   /*
289      There must not be a NULL pointer.
290      Since we do not expect a NULL pointer something serious has
291      happend. So it is better to abort the tests.
292   */
293   fprintf(LOG,"line %4d: Unexpected NULL pointer. Panik --> Abort tests!!\n\n",line);
294   printf(" Panik --> Tests aborted\n"); fflush(stdout);
295 
296   /* test finished */
297   printf("\n");  fflush(stdout);
298 
299   /* close log files and exit */
300   fclose(LOG);
301   exit(EXIT_FAILURE);
302 
303 } /* abort_if_NULL() */
304 
305 /*---------------------------------------------------------------------------*/
306 /* compare error code */
307 
check_errorcode(FILE * LOG,int line,int errno_exp)308 int check_errorcode( FILE *LOG, int line, int errno_exp )
309 {
310   int errno_obs = unur_get_errno();
311 
312   fprintf(LOG,"line %4d: Error code ...\t\t",line);
313 
314   if (errno_obs != errno_exp) {
315     fprintf(LOG," Failed");
316     fprintf(LOG," (observed = %#x, expected = %#x)\n",errno_obs,errno_exp);
317     fflush(LOG);
318     return UNUR_FAILURE;
319   }
320 
321   else {
322     fprintf(LOG," ok\n");
323     fflush(LOG);
324     return UNUR_SUCCESS;
325   }
326 } /* end of check_errorcode() */
327 
328 /*---------------------------------------------------------------------------*/
329 /* check for expected NULL pointer */
330 
do_check_expected_NULL(FILE * LOG,int line,int is_NULL)331 int do_check_expected_NULL( FILE *LOG, int line, int is_NULL )
332 {
333   fprintf(LOG,"line %4d: NULL pointer expected ...\t",line);
334 
335   if (is_NULL) {
336     fprintf(LOG," ok\n");
337     fflush(LOG);
338     return UNUR_SUCCESS;
339   }
340 
341   else {
342     fprintf(LOG," Failed\n");
343     fflush(LOG);
344     return UNUR_FAILURE;
345   }
346 
347 } /* end of check_expected_NULL() */
348 
349 /*---------------------------------------------------------------------------*/
350 /* check for "set failed" */
351 
check_expected_setfailed(FILE * LOG,int line,int rcode)352 int check_expected_setfailed( FILE *LOG, int line, int rcode )
353 {
354   fprintf(LOG,"line %4d: `failed' expected ...\t",line);
355   if (rcode==UNUR_SUCCESS) {
356     fprintf(LOG," Failed\n");
357     fflush(LOG);
358     return UNUR_FAILURE;
359   }
360 
361   else {
362     fprintf(LOG," ok\n");
363     fflush(LOG);
364     return UNUR_SUCCESS;
365   }
366 } /* end of check_expected_setfailed() */
367 
368 /*---------------------------------------------------------------------------*/
369 /* check for O (zero) */
370 
check_expected_zero(FILE * LOG,int line,int k)371 int check_expected_zero( FILE *LOG, int line, int k )
372 {
373   fprintf(LOG,"line %4d: 0 (zero) expected ...\t",line);
374 
375   if (k != 0) {
376     fprintf(LOG," Failed\n");
377     fflush(LOG);
378     return UNUR_FAILURE;
379   }
380 
381   else {
382     fprintf(LOG," ok\n");
383     fflush(LOG);
384     return UNUR_SUCCESS;
385   }
386 } /* end of check_expected_zero() */
387 
388 /*---------------------------------------------------------------------------*/
389 /* check for INFINITY */
390 
check_expected_INFINITY(FILE * LOG,int line,double x)391 int check_expected_INFINITY( FILE *LOG, int line, double x )
392 {
393   fprintf(LOG,"line %4d: INFINITY expected ...\t",line);
394 
395   if (x < UNUR_INFINITY) {
396     fprintf(LOG," Failed\n");
397     fflush(LOG);
398     return UNUR_FAILURE;
399   }
400 
401   else {
402     fprintf(LOG," ok\n");
403     fflush(LOG);
404     return UNUR_SUCCESS;
405   }
406 } /* end of check_expected_INFINITY() */
407 
check_expected_negINFINITY(FILE * LOG,int line,double x)408 int check_expected_negINFINITY( FILE *LOG, int line, double x )
409 {
410   fprintf(LOG,"line %4d: -INFINITY expected ...\t",line);
411 
412   if (x > -UNUR_INFINITY) {
413     fprintf(LOG," Failed\n");
414     fflush(LOG);
415     return UNUR_FAILURE;
416   }
417 
418   else {
419     fprintf(LOG," ok\n");
420     fflush(LOG);
421     return UNUR_SUCCESS;
422   }
423 } /* end of check_expected_negINFINITY() */
424 
check_expected_INTMAX(FILE * LOG,int line,int k)425 int check_expected_INTMAX( FILE *LOG, int line, int k )
426 {
427   fprintf(LOG,"line %4d: INT_MAX expected ...\t",line);
428 
429   if (k < INT_MAX) {
430     fprintf(LOG," Failed\n");
431     fflush(LOG);
432     return UNUR_FAILURE;
433   }
434 
435   else {
436     fprintf(LOG," ok\n");
437     fflush(LOG);
438     return UNUR_SUCCESS;
439   }
440 } /* end of check_expected_INTMAX() */
441 
442 /*---------------------------------------------------------------------------*/
443 /* check for reinit */
444 
check_expected_reinit(FILE * LOG,int line,int rcode)445 int check_expected_reinit( FILE *LOG, int line, int rcode )
446 {
447   fprintf(LOG,"line %4d: reinit ...\t\t\t",line);
448 
449   if (rcode!=UNUR_SUCCESS) {
450     fprintf(LOG," Failed\n");
451     fflush(LOG);
452     return UNUR_FAILURE;
453   }
454 
455   else {
456     fprintf(LOG," ok\n");
457     fflush(LOG);
458     return UNUR_SUCCESS;
459   }
460 } /* end of check_expected_reinit() */
461 
462 /*---------------------------------------------------------------------------*/
463 /* check for non existing reinit */
464 
check_expected_no_reinit(FILE * LOG,int line,int rcode)465 int check_expected_no_reinit( FILE *LOG, int line, int rcode )
466 {
467   fprintf(LOG,"line %4d: no reinit ...\t\t",line);
468 
469   if (rcode==UNUR_SUCCESS) {
470     fprintf(LOG," Failed\n");
471     fflush(LOG);
472     return UNUR_FAILURE;
473   }
474 
475   else {
476     fprintf(LOG," ok\n");
477     fflush(LOG);
478     return UNUR_SUCCESS;
479   }
480 } /* end of check_expected_no_reinit() */
481 
482 /*---------------------------------------------------------------------------*/
483 /* compare two doubles */
484 
485 int
compare_doubles(double x1,double x2)486 compare_doubles ( double x1, double x2 )
487 {
488   if (_unur_FP_approx(x1,x2))
489     return TRUE;
490   else if (fabs(x1-x2) < UNUR_EPSILON)
491     return TRUE;
492   else
493     return FALSE;
494 } /* end of compare_doubles() */
495 
496 /*---------------------------------------------------------------------------*/
497 /* compare sequences generated by generator                                  */
498 
499 int
compare_sequence_gen_start(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)500 compare_sequence_gen_start( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
501 {
502 
503   if (gen == NULL) return UNUR_FAILURE;
504 
505   /* reset uniform RNG */
506   if (unur_urng_reset(unur_get_urng(gen)) != UNUR_SUCCESS)
507     return UNUR_SUCCESS;
508 
509   switch( unur_distr_get_type(unur_get_distr(gen)) ) {
510 
511   case UNUR_DISTR_CONT:
512   case UNUR_DISTR_CEMP:
513   case 0:  /* method UNIF */
514     return compare_double_sequence_gen_start(LOG,line,gen,sample_size );
515 
516   case UNUR_DISTR_CVEC:
517   case UNUR_DISTR_CVEMP:
518     return compare_cvec_sequence_gen_start(LOG,line,gen,sample_size );
519 
520   case UNUR_DISTR_DISCR:
521     return compare_int_sequence_gen_start(LOG,line,gen,sample_size );
522 
523   case UNUR_DISTR_MATR:
524     return compare_matr_sequence_gen_start(LOG,line,gen,sample_size );
525 
526   default:
527     fprintf(stderr,"\ncannot handle distribution type! ... aborted\n");
528     exit (EXIT_FAILURE);
529   }
530 
531 } /* end of compare_sequence_gen_start() */
532 
533 int
compare_sequence_gen(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)534 compare_sequence_gen ( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
535 {
536   if (gen == NULL) return UNUR_FAILURE;
537 
538   /* reset uniform RNG */
539   if (unur_urng_reset(unur_get_urng(gen)) != UNUR_SUCCESS)
540     return cannot_compare_sequence(LOG);
541 
542   switch( unur_distr_get_type(unur_get_distr(gen)) ) {
543 
544   case UNUR_DISTR_CONT:
545   case UNUR_DISTR_CEMP:
546   case 0:  /* method UNIF */
547     return compare_double_sequence_gen(LOG,line,gen,sample_size );
548 
549   case UNUR_DISTR_CVEC:
550   case UNUR_DISTR_CVEMP:
551     return compare_cvec_sequence_gen(LOG,line,gen,sample_size );
552 
553   case UNUR_DISTR_DISCR:
554     return compare_int_sequence_gen(LOG,line,gen,sample_size );
555 
556   case UNUR_DISTR_MATR:
557     return compare_matr_sequence_gen(LOG,line,gen,sample_size );
558 
559   default:
560     fprintf(stderr,"\ncannot handle distribution type! ... aborted\n");
561     exit (EXIT_FAILURE);
562   }
563 } /* end of compare_sequence_gen() */
564 
565 /*---------------------------------------------------------------------------*/
566 
567 int
compare_sequence_par_start(FILE * LOG,int line,UNUR_PAR * par,int sample_size)568 compare_sequence_par_start( FILE *LOG, int line, UNUR_PAR *par, int sample_size )
569 {
570   UNUR_GEN *gen;
571   int result;
572 
573   /* reset uniform RNG */
574   if (unur_urng_reset(unur_get_default_urng()) != UNUR_SUCCESS) {
575     if (par) free(par); return UNUR_SUCCESS;
576   }
577 
578   /* init generator */
579   gen = unur_init( par ); abort_if_NULL(LOG,line,gen);
580 
581   /* run test */
582   result = compare_sequence_gen_start(LOG,line,gen,sample_size);
583 
584   unur_free(gen);
585   return result;
586 
587 } /* end of compare_sequence_par_start() */
588 
589 int
compare_sequence_par(FILE * LOG,int line,UNUR_PAR * par,int sample_size)590 compare_sequence_par ( FILE *LOG, int line, UNUR_PAR *par, int sample_size )
591 {
592   UNUR_GEN *gen;
593   int result;
594 
595   /* reset uniform RNG */
596   if (unur_urng_reset(unur_get_default_urng()) != UNUR_SUCCESS) {
597     if (par) free(par); return cannot_compare_sequence(LOG);
598   }
599 
600   /* init generator */
601   gen = unur_init( par ); abort_if_NULL(LOG, line,gen);
602 
603   /* run test */
604   result = compare_sequence_gen(LOG,line,gen,sample_size);
605 
606   unur_free(gen);
607 
608   return result;
609 
610 } /* end of compare_sequence_par() */
611 
612 /*---------------------------------------------------------------------------*/
613 /* compare double sequences generated by generator */
614 /* only when when we can reset the uniform RNG     */
615 
616 static double *double_sequence_A = NULL;
617 
compare_sequence_urng_start(FILE * LOG,int line,int sample_size)618 int compare_sequence_urng_start( FILE *LOG, int line, int sample_size )
619 {
620   int i;
621   UNUR_URNG *urng = unur_get_default_urng();
622 
623   /* allocate memory for storing sequence */
624   if (double_sequence_A == NULL) {
625     double_sequence_A = malloc( sample_size * sizeof(double) );
626     abort_if_NULL(LOG, line, double_sequence_A);
627   }
628 
629   /* reset uniform RNG */
630   if (unur_urng_reset(urng) != UNUR_SUCCESS)
631     return UNUR_SUCCESS;
632 
633   /* generate sequence */
634   for (i=0; i<sample_size; i++)
635     double_sequence_A[i] = unur_urng_sample(urng);
636 
637   /* there cannot be a failure */
638   return UNUR_SUCCESS;
639 
640 } /* end of compare_sequence_urng_start() */
641 
642 /*...........................................................................*/
643 
compare_double_sequence_gen_start(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)644 int compare_double_sequence_gen_start( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
645 {
646   int i;
647 
648   /* check generator object */
649   if (gen==NULL) {
650     /* error */
651     if (double_sequence_A) free (double_sequence_A);
652     double_sequence_A = NULL;
653     return UNUR_FAILURE;
654   }
655 
656   /* allocate memory for storing sequence */
657   if (double_sequence_A == NULL) {
658     double_sequence_A = malloc( sample_size * sizeof(double) );
659     abort_if_NULL(LOG,line, double_sequence_A);
660   }
661 
662   /* generate sequence */
663   for (i=0; i<sample_size; i++)
664     double_sequence_A[i] = unur_sample_cont(gen);
665 
666   /* there cannot be a failure */
667   return UNUR_SUCCESS;
668 
669 } /* end of compare_double_sequence_gen_start() */
670 
671 /*...........................................................................*/
672 
compare_double_sequence_gen(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)673 int compare_double_sequence_gen( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
674 {
675   int i;
676   int ok = TRUE;
677   double x = 0.;
678   int failed = 0;
679 
680   /* check generator object and stored sequence */
681   if (gen==NULL || double_sequence_A==NULL) {
682     /* error */
683     return UNUR_FAILURE;
684   }
685 
686   /* compare sequence */
687   for (i=0; i<sample_size; i++) {
688     x = unur_sample_cont(gen);
689     if (!compare_doubles(double_sequence_A[i], x)) {
690 /*     if ( !_unur_FP_approx(double_sequence_A[i], x)) { */
691       ok = FALSE;
692       break;
693     }
694   }
695 
696   /* print result */
697   fprintf(LOG,"line %4d: random seqences ...\t\t",line);
698   if (!ok) {
699     failed = 1;
700     fprintf(LOG," Failed\n");
701     fprintf(LOG,"\tx[1] = %g, x[2] = %g, diff = %g\n",double_sequence_A[i],x,double_sequence_A[i]-x);
702   }
703   else
704     fprintf(LOG," ok\n");
705 
706   fflush(LOG);
707   return (failed ? UNUR_FAILURE : UNUR_SUCCESS);
708 
709 } /* end of compare_double_sequence_gen() */
710 
711 /*---------------------------------------------------------------------------*/
712 /* compare int sequences generated by generator    */
713 /* only when when we can reset the uniform RNG     */
714 
715 static int *int_sequence_A = NULL;
716 
compare_int_sequence_gen_start(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)717 int compare_int_sequence_gen_start( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
718 {
719   int i;
720 
721   /* check generator object */
722   if (gen==NULL) {
723     /* error */
724     if (int_sequence_A) free (int_sequence_A);
725     int_sequence_A = NULL;
726     return UNUR_FAILURE;
727   }
728 
729   /* allocate memory for storing sequence */
730   if (int_sequence_A == NULL) {
731     int_sequence_A = malloc( sample_size * sizeof(int) );
732     abort_if_NULL(LOG, line, int_sequence_A);
733   }
734 
735   /* generate sequence */
736   for (i=0; i<sample_size; i++)
737     int_sequence_A[i] = unur_sample_discr(gen);
738 
739   /* there cannot be a failure */
740   return UNUR_SUCCESS;
741 
742 } /* end of compare_int_sequence_gen_start() */
743 
744 /*...........................................................................*/
745 
compare_int_sequence_gen(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)746 int compare_int_sequence_gen( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
747 {
748   int i;
749   int ok = TRUE;
750   int failed = 0;
751 
752   /* check generator object and stored sequence */
753   if (gen==NULL || int_sequence_A==NULL) {
754     /* error */
755     return UNUR_FAILURE;
756   }
757 
758   /* compare sequence */
759   for (i=0; i<sample_size; i++)
760     if (int_sequence_A[i] != unur_sample_discr(gen)) {
761       ok = FALSE;
762       break;
763     }
764 
765   /* print result */
766   fprintf(LOG,"line %4d: random seqences ...\t\t",line);
767   if (!ok) {
768     failed = 1;
769     fprintf(LOG," Failed\n");
770   }
771   else
772     fprintf(LOG," ok\n");
773 
774   fflush(LOG);
775   return (failed ? UNUR_FAILURE : UNUR_SUCCESS);
776 
777 } /* end of compare_int_sequence_gen() */
778 
779 /*---------------------------------------------------------------------------*/
780 /* compare sequences of double vectors generated by generator */
781 /* only when when we can reset the uniform RNG                */
782 
783 static double *cvec_sequence_A = NULL;
784 
compare_cvec_sequence_gen_start(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)785 int compare_cvec_sequence_gen_start( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
786 {
787   int i;
788   int dim;
789 
790   /* free sequence */
791   if (cvec_sequence_A) {
792     free (cvec_sequence_A);
793     cvec_sequence_A = NULL;
794   }
795 
796   /* check generator object */
797   if (gen==NULL) {
798     /* error */
799     return UNUR_FAILURE;
800   }
801 
802   /* get dimension */
803   dim = unur_get_dimension (gen);
804 
805   /* allocate memory for storing sequence */
806   if (cvec_sequence_A == NULL) {
807     cvec_sequence_A = malloc( dim * sample_size * sizeof(double) );
808     abort_if_NULL(LOG,line, cvec_sequence_A);
809   }
810 
811   /* generate sequence */
812   for (i=0; i<sample_size; i++)
813     unur_sample_vec( gen, cvec_sequence_A+(i*dim) );
814 
815   /* there cannot be a failure */
816   return UNUR_SUCCESS;
817 
818 } /* end of compare_cvec_sequence_gen_start() */
819 
820 /*...........................................................................*/
821 
compare_cvec_sequence_gen(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)822 int compare_cvec_sequence_gen( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
823 {
824   int i,k;
825   int ok = TRUE;
826   double *x;
827   int failed = 0;
828   int dim;
829 
830   /* check generator object and stored sequence */
831   if (gen==NULL || cvec_sequence_A==NULL) {
832     /* error */
833     return UNUR_FAILURE;
834   }
835 
836   /* get dimension */
837   dim = unur_get_dimension (gen);
838 
839   /* need space for sampling result */
840   x = malloc( dim * sizeof(double) );
841   abort_if_NULL(LOG,line, x);
842 
843   /* compare sequence */
844   for (i=0; i<sample_size; i++) {
845     unur_sample_vec( gen, x );
846     for (k=0; k<dim; k++) {
847       if ( _unur_FP_cmp(cvec_sequence_A[i*dim+k], x[k], 100.*UNUR_SQRT_DBL_EPSILON) !=0 ) {
848 	/* multivariate random variates are more sensitive against rounding effects */
849 	ok = FALSE;
850 	break;
851       }
852     }
853     if (!ok) break;
854   }
855 
856   /* print result */
857   fprintf(LOG,"line %4d: random seqences ...\t\t",line);
858   if (!ok) {
859     failed = 1;
860     fprintf(LOG," Failed\n");
861     fprintf(LOG,"\tx[1] = (");
862     for (k=0; k<dim; k++)
863       fprintf(LOG," %g",cvec_sequence_A[i*dim+k]);
864     fprintf(LOG,"),\tx[2] = (");
865     for (k=0; k<dim; k++)
866       fprintf(LOG," %g",x[k]);
867     fprintf(LOG,"),\tdiff = (");
868     for (k=0; k<dim; k++)
869       fprintf(LOG," %g",cvec_sequence_A[i*dim+k]-x[k]);
870     fprintf(LOG,")\n");
871   }
872   else
873     fprintf(LOG," ok\n");
874 
875   fflush(LOG);
876   free (x);
877   return (failed ? UNUR_FAILURE : UNUR_SUCCESS);
878 
879 } /* end of compare_cvec_sequence_gen() */
880 
881 /*---------------------------------------------------------------------------*/
882 /* compare sequences of double matrices generated by generator */
883 /* only when when we can reset the uniform RNG                */
884 
885 static double *matr_sequence_A = NULL;
886 
compare_matr_sequence_gen_start(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)887 int compare_matr_sequence_gen_start( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
888 {
889   int i;
890   int dim;
891 
892   /* free sequence */
893   if (matr_sequence_A) {
894     free (matr_sequence_A);
895     matr_sequence_A = NULL;
896   }
897 
898   /* check generator object */
899   if (gen==NULL) {
900     /* error */
901     return UNUR_FAILURE;
902   }
903 
904   /* get dimension */
905   dim = unur_get_dimension (gen);
906 
907   /* allocate memory for storing sequence */
908   if (matr_sequence_A == NULL) {
909     matr_sequence_A = malloc( dim * sample_size * sizeof(double) );
910     abort_if_NULL(LOG,line, matr_sequence_A);
911   }
912 
913   /* generate sequence */
914   for (i=0; i<sample_size; i++)
915     unur_sample_matr( gen, matr_sequence_A+(i*dim) );
916 
917   /* there cannot be a failure */
918   return UNUR_SUCCESS;
919 
920 } /* end of compare_matr_sequence_gen_start() */
921 
922 /*...........................................................................*/
923 
compare_matr_sequence_gen(FILE * LOG,int line,UNUR_GEN * gen,int sample_size)924 int compare_matr_sequence_gen( FILE *LOG, int line, UNUR_GEN *gen, int sample_size )
925 {
926   int i,k;
927   int ok = TRUE;
928   double *x;
929   int failed = 0;
930   int dim;
931 
932   /* check generator object and stored sequence */
933   if (gen==NULL || matr_sequence_A==NULL) {
934     /* error */
935     return UNUR_FAILURE;
936   }
937 
938   /* get dimension */
939   dim = unur_get_dimension (gen);
940 
941   /* need space for sampling result */
942   x = malloc( dim * sizeof(double) );
943   abort_if_NULL(LOG,line, x);
944 
945   /* compare sequence */
946   for (i=0; i<sample_size; i++) {
947     unur_sample_matr( gen, x );
948     for (k=0; k<dim; k++) {
949       if ( !compare_doubles(matr_sequence_A[i*dim+k], x[k])) {
950 /*       if ( !_unur_FP_approx(matr_sequence_A[i*dim+k], x[k])) { */
951 	ok = FALSE;
952 	break;
953       }
954     }
955     if (!ok) break;
956   }
957 
958   /* print result */
959   fprintf(LOG,"line %4d: random seqences ...\t\t",line);
960   if (!ok) {
961     failed = 1;
962     fprintf(LOG," Failed\n");
963     fprintf(LOG,"\tx[1] = (");
964     for (k=0; k<dim; k++)
965       fprintf(LOG," %g",matr_sequence_A[i*dim+k]);
966     fprintf(LOG,"),\tx[2] = (");
967     for (k=0; k<dim; k++)
968       fprintf(LOG," %g",x[k]);
969     fprintf(LOG,"),\tdiff = (");
970     for (k=0; k<dim; k++)
971       fprintf(LOG," %g",matr_sequence_A[i*dim+k]-x[k]);
972     fprintf(LOG,")\n");
973   }
974   else
975     fprintf(LOG," ok\n");
976 
977   fflush(LOG);
978   free (x);
979   return (failed ? UNUR_FAILURE : UNUR_SUCCESS);
980 
981 } /* end of compare_matr_sequence_gen() */
982 
983 /*---------------------------------------------------------------------------*/
984 /* free memory used for comparing sequences                                  */
985 
compare_free_memory(void)986 void compare_free_memory( void )
987 {
988   if (double_sequence_A) free (double_sequence_A);
989   if (int_sequence_A)    free (int_sequence_A);
990   if (cvec_sequence_A)   free (cvec_sequence_A);
991   if (matr_sequence_A)   free (matr_sequence_A);
992 } /* end of compare_free_memory */
993 
994 /*---------------------------------------------------------------------------*/
995 /* print name of distribution */
996 
print_distr_name(FILE * LOG,const UNUR_DISTR * distr,const char * genid)997 void print_distr_name( FILE *LOG, const UNUR_DISTR *distr, const char *genid )
998 {
999   int i,n_fpar;
1000   const double *fpar;
1001 
1002   /* print name of distribution */
1003   if (genid)
1004     fprintf(LOG,"%s: ",genid);
1005   fprintf(LOG,"%s ",unur_distr_get_name(distr));
1006 
1007   /* get parameters */
1008   n_fpar = 0;
1009   if ( unur_distr_is_cont(distr) )
1010     /* continuous distribution */
1011     n_fpar = unur_distr_cont_get_pdfparams( distr, &fpar );
1012   else if ( unur_distr_is_discr(distr) )
1013     /* discrete distribution */
1014     n_fpar = unur_distr_discr_get_pmfparams( distr, &fpar );
1015 
1016   /* print parameter list */
1017   fprintf(LOG,"(");
1018   if (n_fpar) {
1019     fprintf(LOG,"%g",fpar[0]);
1020     for (i=1; i<n_fpar; i++)
1021       fprintf(LOG,", %g",fpar[i]);
1022   }
1023   fprintf(LOG,")");
1024 
1025 } /* end of print_distr_name() */
1026 
1027 /*---------------------------------------------------------------------------*/
1028 /* check p-value of statistical test and print result */
1029 
print_pval(FILE * LOG,UNUR_GEN * gen,const UNUR_DISTR * distr,double pval,int trial,int todo)1030 int print_pval( FILE *LOG, UNUR_GEN *gen, const UNUR_DISTR *distr,
1031 		double pval, int trial, int todo )
1032 {
1033   int failed = 0;
1034   double pval_corrected;
1035   int dim;
1036   int l;
1037 
1038   /* Correct p-value.   */
1039   /* For multivariate distributions unur_test_chi2() runs chi^2 tests on the   */
1040   /* multivariate distribution itself as well as on all marginal distibutions. */
1041   /* It returns the minimum of all p-palues. Thus we have to adjust this       */
1042   /* value and multiply it with (dim+1) before deciding about the significance */
1043   /* of the result.                                                            */
1044   dim = unur_distr_get_dim(distr);
1045   pval_corrected = (dim>1) ? pval : pval*(dim+1);
1046 
1047 
1048   if (pval < -1.5) {
1049     /* was not able to run test (CDF missing) */
1050 
1051     fprintf(LOG,"   not performed (missing data)\t");
1052     /* print distribution name */
1053     print_distr_name( LOG, distr, gen ? unur_get_genid(gen):"???\t" );
1054     fprintf(LOG,"\n");
1055 
1056     printf("X");
1057 
1058     fflush(stdout);
1059     fflush(LOG);
1060 
1061     /* test failed */
1062     return UNUR_FAILURE;
1063   }
1064 
1065   if (pval < 0.) {
1066     fprintf(LOG,"   setup failed\t\t");
1067   }
1068   else {
1069     fprintf(LOG,"   pval = %8.6f   ",pval);
1070     l = _unur_isnan(pval_corrected)
1071       ? 10000
1072       : -(int) ((pval_corrected > 1e-6) ? (log(pval_corrected) / M_LN10) : 6.);
1073     switch (l) {
1074     case 0:
1075       fprintf(LOG,"      "); break;
1076     case 1:
1077       fprintf(LOG,".     "); break;
1078     case 2:
1079       fprintf(LOG,"**    "); break;
1080     case 3:
1081       fprintf(LOG,"XXX   "); break;
1082     case 4:
1083       fprintf(LOG,"XXXX  "); break;
1084     case 5:
1085       fprintf(LOG,"XXXXX "); break;
1086     default:
1087       fprintf(LOG,"######"); break;
1088     }
1089   }
1090 
1091   switch (todo) {
1092   case '+':
1093     if (pval_corrected >= PVAL_LIMIT) {
1094       fprintf(LOG,"\t ok");
1095       printf("+");
1096     }
1097     else {
1098       failed = 1;
1099       if (trial > 2) {
1100 	fprintf(LOG,"\t Failed");
1101 	printf("(!+)");
1102       }
1103       else {
1104 	fprintf(LOG,"\t Try again");
1105 	printf("?");
1106       }
1107     }
1108     break;
1109   case '0':
1110   case '/':
1111     fprintf(LOG,"\t ok (expected to fail)");
1112     printf("0");
1113     break;
1114   case '-':
1115     if (pval_corrected < PVAL_LIMIT) {
1116       /* in this case it is expected to fail */
1117       failed = 0;
1118       fprintf(LOG,"\t ok (expected to fail)");
1119       printf("-");
1120     }
1121     else {
1122       /* the test has failed which was not what we have expected */
1123       failed = 1;
1124       fprintf(LOG,"\t Not ok (expected to fail)");
1125       printf("(!-)");
1126     }
1127     break;
1128   default:
1129     fprintf(stderr, "%s:%d: invalid test symbol\n", __FILE__, __LINE__);
1130     exit (-1);
1131   }
1132 
1133   /* timing */
1134   stopwatch_print(LOG,"\ttime=%.1f ms ", stopwatch_lap(&vw));
1135 
1136   /* print distribution name */
1137   fprintf(LOG,"\t");
1138   print_distr_name( LOG, distr, gen ? unur_get_genid(gen):"???\t" );
1139   fprintf(LOG,"\n");
1140 
1141   fflush(stdout);
1142   fflush(LOG);
1143   return (failed ? UNUR_FAILURE : UNUR_SUCCESS);
1144 
1145 } /* end of print_pval() */
1146 
1147 /*---------------------------------------------------------------------------*/
1148 /* run chi2 test */
1149 
run_validate_chi2(FILE * LOG,int line ATTRIBUTE__UNUSED,UNUR_GEN * gen,const UNUR_DISTR * distr,int todo)1150 int run_validate_chi2( FILE *LOG, int line ATTRIBUTE__UNUSED,
1151 		       UNUR_GEN *gen, const UNUR_DISTR *distr, int todo )
1152      /*   UNUR_SUCCESS    ... on success                                        */
1153      /*   UNUR_ERR_SILENT ... test failed only once                             */
1154      /*   UNUR_FAILURE    ... serious failure                                   */
1155 {
1156 #define BUFSIZE 128
1157   const char *distr_name;
1158   static char last_distr_name[BUFSIZE] = "";
1159   unsigned int type;
1160   int i;
1161   double pval;
1162   int failed = 0;
1163 
1164   /* check input */
1165   if (distr == NULL) {
1166     printf(" [!!no distribution!!] "); fflush(stdout);
1167     return UNUR_FAILURE;
1168   }
1169 
1170   /* timer */
1171   stopwatch_lap(&vw);
1172 
1173   /* get name of distribution */
1174   distr_name = unur_distr_get_name( distr );
1175 
1176   /* get type of distribution */
1177   type = unur_distr_get_type( distr );
1178 
1179   if ( strcmp(distr_name,last_distr_name) ) {
1180     /* different distributions */
1181     strncpy(last_distr_name,distr_name,(size_t)BUFSIZE);
1182     last_distr_name[BUFSIZE-1] = '\0';
1183     printf(" %s",distr_name); fflush(stdout);
1184   }
1185 
1186   if (todo == '.') {
1187     /* nothing to do */
1188     printf(".");  fflush(stdout);
1189     return UNUR_SUCCESS;
1190   }
1191 
1192   if (todo == '0') {
1193     /* initialization of generator is expected to fail */
1194     if (gen == NULL) {
1195       printf("0");  fflush(stdout);
1196       return UNUR_SUCCESS;
1197     }
1198     else {
1199       /* error */
1200       printf("(!0)");  fflush(stdout);
1201       return UNUR_FAILURE;
1202     }
1203   }
1204 
1205   if (gen == NULL) {
1206     if (todo == '-') {
1207       print_pval(LOG,gen,distr,-0.5,10,todo);
1208       return UNUR_SUCCESS;
1209     }
1210     else if (todo == '/') {
1211       printf("/");  fflush(stdout);
1212       return UNUR_SUCCESS;
1213     }
1214     else {
1215       /* initialization failed --> cannot run test */
1216       print_pval(LOG,gen,distr,-0.5,10,todo);
1217       return UNUR_FAILURE;
1218     }
1219   }
1220 
1221   /* init successful */
1222   if ( todo == '/' ) todo = '+';
1223 
1224   /* run chi^2 test */
1225   for (i=1; i<=3; i++) {
1226     /* we run the test up to three times when it fails */
1227 
1228     switch (type) {
1229     case UNUR_DISTR_DISCR:
1230       pval = unur_test_chi2( gen, CHI_TEST_INTERVALS, 100000, 20, CHI_TEST_VERBOSITY, LOG);
1231       break;
1232     case UNUR_DISTR_CONT:
1233     case UNUR_DISTR_CEMP:
1234       pval = unur_test_chi2( gen, CHI_TEST_INTERVALS, 0, 20, CHI_TEST_VERBOSITY, LOG);
1235       break;
1236     case UNUR_DISTR_CVEC:
1237     case UNUR_DISTR_CVEMP:
1238       pval = unur_test_chi2( gen, CHI_TEST_INTERVALS, 0, 20, CHI_TEST_VERBOSITY, LOG);
1239       break;
1240     default:
1241       fprintf(stderr, "\n%s:%d: run_validate_chi2: this should not happen\n", __FILE__, __LINE__);
1242       exit (EXIT_FAILURE);
1243     }
1244 
1245     if ( print_pval(LOG,gen,distr,pval,i,todo) != UNUR_SUCCESS )
1246       /* test failed */
1247       failed++;
1248     else
1249       /* test ok */
1250       break;
1251   }
1252 
1253   return (failed==0 ? UNUR_SUCCESS : (failed<=2 ? UNUR_ERR_SILENT : UNUR_FAILURE));
1254 
1255 #undef BUFSIZE
1256 } /* end of run_validate_chi2() */
1257 
1258 /*---------------------------------------------------------------------------*/
1259 /* run verify hat test */
1260 
1261 #define VERIFYHAT_SAMPLESIZE 10000
1262 
run_validate_verifyhat(FILE * LOG,int line,UNUR_GEN * gen,const UNUR_DISTR * distr,int todo)1263 int run_validate_verifyhat( FILE *LOG, int line, UNUR_GEN *gen,
1264 			    const UNUR_DISTR *distr, int todo )
1265 {
1266 #define BUFSIZE 128
1267   const char *distr_name;
1268   static char last_distr_name[BUFSIZE] = "";
1269   unsigned int type;
1270   int i;
1271   int failed = 0;
1272   int dim;
1273   double *x = NULL;
1274   int errno_obs;
1275 
1276   /* check input */
1277   if (distr == NULL) {
1278     printf(" [!!no distribution!!]" ); fflush(stdout);
1279     return UNUR_FAILURE;
1280   }
1281 
1282   /* timer */
1283   stopwatch_lap(&vw);
1284 
1285   /* get name of distribution */
1286   distr_name = unur_distr_get_name( distr );
1287 
1288   /* get type of distribution */
1289   type = unur_distr_get_type( distr );
1290 
1291   if (strcmp(distr_name,last_distr_name) ) {
1292     /* different distributions */
1293     strncpy(last_distr_name,distr_name,(size_t)BUFSIZE);
1294     last_distr_name[BUFSIZE-1] = '\0';
1295     printf(" %s",distr_name); fflush(stdout);
1296   }
1297 
1298   if (todo == '.') {
1299     /* nothing to do */
1300     printf(".");  fflush(stdout);
1301     return UNUR_SUCCESS;
1302   }
1303 
1304   if (todo == '0') {
1305     /* initialization of generator is expected to fail */
1306     if (gen == NULL) {
1307       printf("0");  fflush(stdout);
1308       print_verifyhat_result(LOG,gen,distr,-1,todo);
1309       return UNUR_SUCCESS;
1310     }
1311     else {
1312       /* error */
1313       printf("(!0)");  fflush(stdout);
1314       return UNUR_FAILURE;
1315     }
1316   }
1317 
1318   if (gen == NULL) {
1319     if (todo == '-') {
1320       printf("-");  fflush(stdout);
1321       print_verifyhat_result(LOG,gen,distr,-1,todo);
1322       return UNUR_SUCCESS;
1323     }
1324     else {
1325       /* initialization failed --> cannot run test */
1326       printf("(!+)");  fflush(stdout);
1327       print_verifyhat_result(LOG,gen,distr,-1,todo);
1328       return UNUR_FAILURE;
1329     }
1330   }
1331 
1332   /* get dimension of distribution */
1333   dim = unur_get_dimension (gen);
1334 
1335   /* allocate working space */
1336   if (dim > 0) {
1337     x = malloc( dim * sizeof(double) );
1338     abort_if_NULL(LOG, line, x);
1339   }
1340 
1341   /* run verify hat test */
1342   for (i=0; i<VERIFYHAT_SAMPLESIZE; i++) {
1343 
1344     unur_reset_errno();
1345     switch (type) {
1346     case UNUR_DISTR_DISCR:
1347       unur_sample_discr(gen);
1348       break;
1349     case UNUR_DISTR_CONT:
1350     case UNUR_DISTR_CEMP:
1351       unur_sample_cont(gen);
1352       break;
1353     case UNUR_DISTR_CVEC:
1354       unur_sample_vec(gen,x);
1355       break;
1356     default:
1357       fprintf(stderr, "\n%s:%d: run_validate_verifyhat: this should not happen\n", __FILE__, __LINE__);
1358       exit (EXIT_FAILURE);
1359     }
1360 
1361     if ((errno_obs = unur_get_errno())) {
1362       /* error */
1363       if (errno_obs == UNUR_ERR_GEN_CONDITION)
1364 	failed++;
1365       unur_reset_errno();
1366     }
1367 
1368   }
1369 
1370   /* free working space */
1371   if (x!=NULL) free(x);
1372 
1373   return print_verifyhat_result(LOG,gen,distr,failed,todo);
1374 
1375 } /* end of run_validate_verifyhat() */
1376 
1377 /*---------------------------------------------------------------------------*/
1378 /* print result of verify hat test */
1379 
print_verifyhat_result(FILE * LOG,UNUR_GEN * gen,const UNUR_DISTR * distr,int failed,int todo)1380 int print_verifyhat_result( FILE *LOG, UNUR_GEN *gen, const UNUR_DISTR *distr,
1381 			    int failed, int todo )
1382 {
1383   int failed_test = 0;
1384   double failed_ratio = ((double)failed) / VERIFYHAT_SAMPLESIZE;
1385 
1386   if (failed >= 0) {
1387     fprintf(LOG,"   failures = %d (%g%%)  ",failed, 100. * failed_ratio);
1388     switch (todo) {
1389     case '+':
1390       if (failed > 0) {
1391 	fprintf(LOG,"\t Failed");
1392 	printf("(!+)");
1393 	failed_test = 1;
1394       }
1395       else {
1396 	fprintf(LOG,"\t ok");
1397 	printf("+");
1398       }
1399       break;
1400     case '~':
1401       if (failed == 0) {
1402 	fprintf(LOG,"\t ok");
1403 	printf("+");
1404       }
1405       else if (failed_ratio <= 0.01) {
1406 	fprintf(LOG,"\t tolerated");
1407 	printf("(~+)");
1408       }
1409       else {
1410 	fprintf(LOG,"\t Failed");
1411 	printf("(!~+)");
1412 	failed_test = 1;
1413       }
1414       break;
1415     case '-':
1416       if (failed_ratio > 0.01) {
1417 	/* in this case it is expected to fail */
1418 	fprintf(LOG,"\t ok (expected to fail)");
1419 	printf("-");
1420       }
1421       else {
1422 	/* the test has failed which was not what we have expected */
1423 	fprintf(LOG,"\t Not ok (expected to fail)");
1424 	printf("(!-)");
1425 	failed_test = 1;
1426       }
1427       break;
1428     default:
1429       fprintf(stderr,"%s:%d: invalid test symbol\n", __FILE__, __LINE__);
1430       exit (EXIT_FAILURE);
1431     }
1432   }
1433 
1434   else {
1435     fprintf(LOG,"   setup failed\t");
1436     switch (todo) {
1437     case '0':
1438     case '-':
1439       fprintf(LOG,"\t ok (expected to fail)");
1440       break;
1441     default:
1442       fprintf(LOG,"\t Failed");
1443     }
1444   }
1445 
1446   /* timing */
1447   stopwatch_print(LOG,"\ttime=%.1f ms ", stopwatch_lap(&vw));
1448 
1449   /* print distribution name */
1450   fprintf(LOG,"\t");
1451   print_distr_name( LOG, distr, gen ? unur_get_genid(gen):"???\t" );
1452   fprintf(LOG,"\n");
1453 
1454   fflush(stdout);
1455   fflush(LOG);
1456 
1457   return (failed_test ? UNUR_ERR_SILENT : UNUR_SUCCESS);
1458 
1459 } /* end of print_verifyhat_result() */
1460 #undef VERIFYHAT_SAMPLESIZE
1461 
1462 /*---------------------------------------------------------------------------*/
1463 /* print result of timings */
1464 
print_timing_results(FILE * LOG,int line ATTRIBUTE__UNUSED,const UNUR_DISTR * distr,double * timing_setup,double * timing_marginal,int n_results)1465 void print_timing_results( FILE *LOG, int line ATTRIBUTE__UNUSED, const UNUR_DISTR *distr,
1466 			   double *timing_setup, double *timing_marginal, int n_results )
1467 {
1468   const char *distr_name;
1469   static const char *last_distr_name = "";
1470   int i;
1471 
1472   /* get name of distribution */
1473   distr_name = unur_distr_get_name( distr );
1474 
1475   if (strcmp(distr_name,last_distr_name) ) {
1476     /* different distributions */
1477     last_distr_name = distr_name;
1478     printf(" %s=",distr_name); fflush(stdout);
1479   }
1480   else {
1481     printf("="); fflush(stdout);
1482   }
1483 
1484   /* print timings into log file */
1485   for (i=0; i<n_results; i++)
1486     if (timing_marginal[i] < 0.)
1487       /* no test */
1488       fprintf(LOG, "      /        ");
1489     else
1490       fprintf(LOG, "%5.0f /%7.2f ", timing_setup[i], timing_marginal[i]);
1491 
1492   /* print name of distribution into log file */
1493   fprintf(LOG,"\t");
1494   print_distr_name( LOG, distr, NULL );
1495   fprintf(LOG,"\n");
1496 
1497 } /* end of print_timing_results() */
1498 
1499 /*---------------------------------------------------------------------------*/
1500 /* run test for u-error of inversion method and print results                */
1501 
run_validate_u_error(FILE * LOG,UNUR_GEN * gen,const UNUR_DISTR * distr,double u_resolution,int samplesize)1502 int run_validate_u_error( FILE *LOG, UNUR_GEN *gen, const UNUR_DISTR *distr,
1503 			  double u_resolution, int samplesize )
1504 {
1505   double maxerror, MAE;  /* maximum observed and mean absolute u-error */
1506   double score;          /* penalty score of inversion error test */
1507   const char *genid;
1508 
1509   /* check objectst */
1510   if (gen == NULL || distr == NULL) {
1511     fprintf(LOG,"test_inverror:   ERROR: generator not initialized\n");
1512     printf("(!!+)"); fflush(stdout);
1513     return 1000;
1514   }
1515 
1516   /* get generator id */
1517   genid = unur_get_genid(gen);
1518 
1519   /* run test */
1520   score = unur_test_u_error(gen, &maxerror, &MAE, u_resolution, samplesize,
1521 			     FALSE, TEST_INVERROR_TAILS, TRUE, LOG);
1522 
1523   /* check score */
1524   if (score < 0.) {
1525     /* an error has occured */
1526     fprintf(LOG,"%s:   ERROR: could not run test\n",genid);
1527     printf("(!!+)"); fflush(stdout);
1528     return 3;
1529   }
1530 
1531   /* print result into log file */
1532   fprintf(LOG,"%s:   result: max u-error = %g, MAE = %g  ",genid,maxerror,MAE);
1533   if (maxerror > u_resolution) {
1534      fprintf(LOG,"(NOT <= %g)\n",u_resolution);
1535      fprintf(LOG,"%s: Warning: precision problem, maxerror > u_resolution\n",genid);
1536   }
1537   else {
1538      fprintf(LOG,"(<= %g)\n",u_resolution);
1539   }
1540 
1541   fprintf(LOG,"%s:           score = %5.2f %%\t--> %s\n", genid,
1542 	  score*100, (score<0.001) ? "passed" : "failed");
1543 
1544   /* print result of test on screen and return result */
1545   if (score == 0.) {
1546     printf("+"); fflush(stdout);
1547     return 0;
1548   }
1549   if (score < 0.001) {
1550     printf("(?+)"); fflush(stdout);
1551     return 1;
1552   }
1553   else {
1554     printf("(!+)"); fflush(stdout);
1555     return 2;
1556   }
1557 
1558 } /* end of run_validate_u_error() */
1559 
1560 /*---------------------------------------------------------------------------*/
1561