/*
	file automatically generated by make_test_files.pl
	Fri Jul  3 11:37:51 2026
*/

/*****************************************************************************
 *                                                                           *
 *          UNU.RAN -- Universal Non-Uniform Random number generator         *
 *                                                                           *
 *****************************************************************************/
    
/**
 ** Tests for MATRIX
 **/
    
/*---------------------------------------------------------------------------*/
#include "testunuran.h"

#ifdef UNUR_URNG_DEFAULT_RNGSTREAM
#include <RngStream.h>
#endif
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
/* global variables                                                          */

static FILE *TESTLOG;               /* test log file                         */
static FILE *UNURANLOG;             /* unuran log file                       */

static int test_ok = TRUE;          /* all tests ok (boolean)                */
static int fullcheck = FALSE;       /* whether all checks are performed      */ 

static TIMER watch;                 /* stop watch                            */

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

void run_verify_generator( FILE *LOG, int line, UNUR_PAR *par );

int unur_matrix_set_verify( UNUR_PAR *par, int verify);


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

void test_new (void);
void test_set (void);
void test_get (void);
void test_chg (void);
void test_init (void);
void test_reinit (void);
void test_sample (void);
void test_validate (void);
void test_special(void);

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



/* header files */
#include<utils/matrix_source.h>
#include<utils/vector_source.h>

/* function prototypes */
void _unur_test_set_matrix_1(int dim, double *M);
void _unur_test_set_matrix_2(int dim, double *M);
int _unur_test_matrix(int dim);

/* dimension of test matrix */
static const int dim_testmatrix = 50;

/* max tolerable absolute error */
static const double error_absolute_max = 1.e-12;

#ifndef M_PI
#define M_PI       3.14159265358979323846264338328      /* pi */
#endif

#define COMPARE_SAMPLE_SIZE   (10000)
#define VIOLATE_SAMPLE_SIZE   (20)





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

#ifndef CHI2_FAILURES_TOLERATED
#  define CHI2_FAILURES_TOLERATED DEFAULT_CHI2_FAILURES_TOLERATED
#endif

/*---------------------------------------------------------------------------*/
/* [verbatim] */



void _unur_test_set_matrix_1(int dim, double *M) {
#define idx1(a,b) ((a-1)*dim+(b-1))
  int i,j,k;
  double p;
  
  /* original derflinger test-matrix */
  p = M_PI/(dim+1);
  for (i=1; i<=dim; i++) {
  for (k=1; k<=i; k++) {
    M[idx1(i,k)]=0.;
    for (j=1; j<=dim; j++) {
      M[idx1(i,k)] += sin(p*i*j)*j*sin(p*j*k);
    }
    M[idx1(k,i)] = M[idx1(i,k)]; 
  }}

#undef idx1
} /* end of _unur_test_set_matrix_1() */

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

void _unur_test_set_matrix_2(int dim, double *M) {
#define idx1(a,b) ((a-1)*dim+(b-1))
  int i,j,k;

  /* another test-matrix */
  for (i=1; i<=dim; i++) {
  for (k=1; k<=i; k++) {
    M[idx1(i,k)]=0.;
    for (j=1; j<=dim; j++) {
      M[idx1(i,k)] = 1./(i+k);
    }
    M[idx1(k,i)] = M[idx1(i,k)]; 
  }}

#undef idx1
} /* end of _unur_test_set_matrix_2() */

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

int _unur_test_matrix(int dim) {
#define idx1(a,b) ((a-1)*dim+(b-1))

  int i, ret;

  double *M;
  double *values;
  double *vectors;

  double error_absolute; 
  double error_relative; 
 
  int error_counter = 0;
  char error_char;

  /* allocate memory */
  M = malloc(dim*dim*sizeof(double));
  values = malloc(dim*sizeof(double));
  vectors = malloc(dim*dim*sizeof(double));

  _unur_test_set_matrix_1(dim, M);
  
  error_counter = 0;
  ret = _unur_matrix_eigensystem(dim, M, values, vectors);
  if (ret == UNUR_SUCCESS) {
    fprintf(TESTLOG, " #   \t   Eigenvalue \t\t   Expected \t\t Abs. Error \t Rel. Error\n"); 
    for (i=0; i<dim; i++) {
      error_absolute = 2.*values[i]/(dim+1) - (i+1) ;  
      error_relative = error_absolute / (i+1.);

      if (error_absolute > error_absolute_max) { 
        /* eigenvalue is not ok */
        error_char = '*';
        error_counter++;
      }
      else
      {
        /* eigenvalue is ok */
        error_char = ' ';
      }

      fprintf(TESTLOG, "%02d : \t%18.15f   \t%18.15f  \t% 8.4e \t% 8.4e  %c\n", 
              i+1,  
              2.*values[i]/(dim+1),  
              (double) (i+1) , 
              error_absolute,
	      error_relative,
	      error_char);
    }
    if (error_counter!=0)
       printf(" failed at %d eigenvalues", error_counter);
  }
  else {
    ++error_counter;
    printf(": init");
  }

  /* free memory */
  free(M); 
  free(values);
  free(vectors);

  /* return number of errors */
  return error_counter;

#undef idx1
} /* end of _unur_test_matrix() */

/*---------------------------------------------------------------------------*/
/* [new] */

void test_new (void)
{
        int n_tests_failed;          /* number of failed tests */

	/* start test */
	printf("[new "); fflush(stdout);
	fprintf(TESTLOG,"\n[new]\n");

	/* reset counter */
	n_tests_failed = 0;

	/* set stop watch */
	stopwatch_lap(&watch);
  

	/* timing */
	stopwatch_print(TESTLOG,"\n<*>time = %.3f ms\n\n", stopwatch_lap(&watch));

	/* test finished */
	test_ok &= (n_tests_failed) ? 0 : 1;
	(n_tests_failed) ? printf(" ==> failed] ") : printf(" ==> ok] ");

} /* end of test_new() */

/*---------------------------------------------------------------------------*/
/* [special] */

void test_special (void)
{
	/* set boolean to FALSE */
	int FAILED = 0;





/* start test */
printf("[special "); fflush(stdout);
fprintf(TESTLOG,"\n[special]\n");

/* set stop watch */
stopwatch_lap(&watch);



  printf("\nEigensystem");

  /* run tests */
  FAILED = _unur_test_matrix(dim_testmatrix);



	/* timing */
	stopwatch_print(TESTLOG,"\n<*>time = %.3f ms\n\n", stopwatch_lap(&watch));

	/* test finished */
	test_ok &= (FAILED) ? 0 : 1;
	(FAILED) ? printf(" ==> failed] ") : printf(" ==> ok] ");

} /* end of test_special() */


/*---------------------------------------------------------------------------*/
/* run generator in verifying mode */

void run_verify_generator( FILE *LOG, int line, UNUR_PAR *par )
{
	UNUR_GEN *gen;
	int i;

	/* switch to verifying mode */
	unur_matrix_set_verify(par,1);

	/* initialize generator */
	gen = unur_init( par ); abort_if_NULL(LOG, line, gen);

	/* run generator */
	for (i=0; i<VIOLATE_SAMPLE_SIZE; i++)
		unur_sample_cont(gen);

	/* destroy generator */
	unur_free(gen); 

} /* end of run_verify_generator() */

int unur_matrix_set_verify(UNUR_PAR *par ATTRIBUTE__UNUSED, int verify ATTRIBUTE__UNUSED) {return 0;}

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

int main(void)
{ 
        unsigned long seed;
	char *str_seed, *str_tail;

	/* start stop watch */
	stopwatch_init();
	stopwatch_start(&watch);

        /* open log file for unuran and set output stream for unuran messages */
        UNURANLOG = fopen( "t_util_matrix_unuran.log","w" );
        abort_if_NULL( stderr,-1, UNURANLOG );
        unur_set_stream( UNURANLOG );

        /* open log file for testing */
	TESTLOG = fopen( "t_util_matrix_test.log","w" );
	abort_if_NULL( stderr,-1, TESTLOG );

        /* seed for uniform generators */

	/* seed set by environment */
	str_seed = getenv("SEED");

	if (str_seed != NULL) {
	    seed = strtol(str_seed, &str_tail, 10);
	    if (seed == 0u) 
		seed = 290620;
	}
	else {
#ifdef SEED
	    seed = SEED;
#else
	    seed = 290620;
#endif
	}

        /* seed build-in uniform generators */
        unur_urng_MRG31k3p_seed(NULL,seed);
        unur_urng_fish_seed(NULL,seed);
	unur_urng_mstd_seed(NULL,seed);

	/* seed uniform random number generator */
#ifdef UNUR_URNG_UNURAN
#  ifdef UNUR_URNG_DEFAULT_RNGSTREAM
	{
	        unsigned long sa[6];
	        int i;
	        for (i=0; i<6; i++) sa[i] = seed;
                RngStream_SetPackageSeed(sa);
        }
#  else
	if (unur_urng_seed(NULL,seed) != UNUR_SUCCESS) {
	        fprintf(stderr,"WARNING: Seed could not be set at random\n");
                seed = ~0u;
	}
#  endif  /* UNUR_URNG_DEFAULT_RNGSTREAM */
#endif  /* UNUR_URNG_UNURAN */
 
	/* set default debugging flag */
	unur_set_default_debug(UNUR_DEBUG_ALL);

        /* detect required check mode */
        fullcheck = (getenv("UNURANFULLCHECK")==NULL) ? FALSE : TRUE;

	/* write header into log file */
        print_test_log_header( TESTLOG, seed, fullcheck );

	/* set timer for sending SIGALRM signal */
	set_alarm(TESTLOG);

	/* start test */
	printf("matrix: ");

	/* run tests */
test_new();
test_special();


	/* test finished */
	printf("\n");  fflush(stdout);

	/* close log files */
	fprintf(TESTLOG,"\n====================================================\n\n");
	if (test_ok)
		fprintf(TESTLOG,"All tests PASSED.\n");
	else
		fprintf(TESTLOG,"Test(s) FAILED.\n");

	/* timing */
	stopwatch_print(TESTLOG,"\n<*>total time = %.0f ms\n\n", stopwatch_stop(&watch));

	fclose(UNURANLOG);
	fclose(TESTLOG);

	/* free memory */
	compare_free_memory();
	unur_urng_free(unur_get_default_urng());
	unur_urng_free(unur_get_default_urng_aux());

	/* exit */
	exit( (test_ok) ? EXIT_SUCCESS : EXIT_FAILURE );

} /* end of main */

