#ifndef __LLVUTILS_H__
#define __LLVUTILS_H__ 1

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <gsl/gsl_cdf.h>

#include "constants.h"
#include "struct.h"
#include "EOBNRv2HMROMstruct.h"
#include "EOBNRv2HMROM.h"
#include "wip.h"
#include "likelihood.h"
#include "splinecoeffs.h"
#include "LLVFDresponse.h"
#include "LLVnoise.h"

/***************** Structures for parameters *****************/

/* Parameters for the generation of a LLV waveform (in the form of a list of modes) */
typedef struct tagLLVParams {
  double tRef;               /* reference time (s) - GPS time at the frequency representing coalescence */
  double phiRef;             /* reference phase (rad) - phase at the frequency representing coalescence (or at fRef if specified) */
  double m1;                 /* mass of companion 1 (solar masses) */
  double m2;                 /* mass of companion 2 (solar masses) */
  double distance;           /* distance of source (Mpc) */
  double ra;                 /* right ascension of the source (rad) */
  double dec;                /* declination of the source (rad) */
  double inclination;        /* inclination of L relative to line of sight (rad) */
  double polarization;       /* polarization angle (rad) */
  int nbmode;                /* number of modes to generate (starting with 22) - defaults to 5 (all modes) */
} LLVParams;

/* Global parameters for the waveform generation and overlap computation */
typedef struct tagLLVGlobalParams {
  double fRef;               /* reference frequency (Hz, default 0 which is interpreted as Mf=0.14) */
  double minf;               /* Minimal frequency (Hz) - when set to 0 (default), use the first frequency covered by the noise data of the detector */
  double maxf;               /* Maximal frequency (Hz) - when set to 0 (default), use the last frequency covered by the noise data of the detector */
  int setphiRefatfRef;       /* Flag for adjusting the FD phase at phiRef at the given fRef, which depends also on tRef - if false, treat phiRef simply as an orbital phase shift (minus an observer phase shift) (default=1) */
  int nbmodeinj;             /* number of modes to include in the injection (starting with 22) - defaults to 5 (all modes) */
  int nbmodetemp;            /* number of modes to include in the templates (starting with 22) - defaults to 5 (all modes) */
  int tagint;                /* Tag choosing the integrator: 0 for wip (default), 1 for linear integration */
  int tagnetwork;            /* Tag choosing the network of detectors to use */
  int nbptsoverlap;          /* Number of points to use in loglinear overlaps (default 32768) */
  int constL;                /* set all logLikelihood to 0 - allows to sample from the prior for testing */
} LLVGlobalParams;

typedef struct tagLLVPrior {
	double deltaT;             /* width of time prior centered on injected value (s) (default 0.1) */
	double comp_min;           /* minimum component mass (solar masses) (default 4) */
	double comp_max;           /* maximum component mass (solar masses) (default 50) */
	double mtot_min;           /* minimum total mass (solar masses) (default 8) */
	double mtot_max;           /* maximum total mass (solar masses) (default 100) */
	double qmax;               /* maximum asymmetric mass ratio (>=1) (default 12) */
	double dist_min;           /* minimum distance of source (Mpc) (default 1) */
	double dist_max;           /* maximum distance of source (Mpc) (default 1e4) */
  double ra_min;            /* minimum ra (rad, default 0) - for testing */
  double ra_max;            /* maximum ra (rad, default 2pi) - for testing */
  double dec_min;           /* minimum dec (rad, default 0) - for testing */
  double dec_max;           /* maximum dec (rad, default pi) - for testing */
  double phase_min;          /* minimum phase (rad, default 0) - for testing */
  double phase_max;          /* maximum phase (rad, default 2pi) - for testing */
  double pol_min;            /* minimum polarization (rad, default 0) - for testing */
  double pol_max;            /* maximum polarization (rad, default 2pi) - for testing */
  double inc_min;            /* minimum inclination (rad, default 0) - for testing */
  double inc_max;            /* maximum inclination (rad, default pi) - for testing */
  double fix_m1;
  double fix_m2;
  double fix_time;
  double fix_ra;
  double fix_dec;
  double fix_phase;
  double fix_pol;
  double fix_dist;
  double fix_inc;
  int pin_m1;
  int pin_m2;
  int pin_time;
  int pin_ra;
  int pin_dec;
  int pin_phase;
  int pin_pol;
  int pin_dist;
  int pin_inc;
  double snr_target;
  int rescale_distprior;
  int flat_distprior;
} LLVPrior;

typedef struct tagLLVRunParams {
	double eff;                /* target efficiency (default 0.1) */
	double tol;                /* logZ tolerance (default 0.5) */
	int    nlive;              /* number of live points (default 1000) */
	char   outroot[200];       /* output root (default "chains/LLVinference_") */
	int    bambi;              /* run BAMBI? (default 0) */
	int    resume;             /* resume form previous run? (default 0) */
	int    maxiter;            /* max number of iterations (default 0 - ignore) */
	char   netfile[200];       /* NN settings file (default "LLVinference.inp") */
  int    mmodal;             /* use multimodal decomposition ? */
  int    maxcls;             /* max number of modes in multimodal decomposition */
  int    nclspar;            /* number of parameters to use for multimodal decomposition - in the order of the cube */
  double ztol;               /* in multimodal decomposition, modes with lnZ lower than Ztol are ignored */
  int    seed;               /* seed the inference by setting one of the live points to the injection ? */
} LLVRunParams;

/************ Structures for signals and injections ************/

// typedef struct tagLLVSignal
// {
//   struct tagListmodesCAmpPhaseFrequencySeries* LHOSignal;   /* Signal in LHO, in the form of a list of the contribution of each mode */
//   struct tagListmodesCAmpPhaseFrequencySeries* LLOSignal;   /* Signal in LLO, in the form of a list of the contribution of each mode */
//   struct tagListmodesCAmpPhaseFrequencySeries* VIRGOSignal; /* Signal in VIRGO, in the form of a list of the contribution of each mode */
//   double LHOhh;                                             /* Inner product (h|h) for LHO */
//   double LLOhh;                                             /* Inner product (h|h) for LLO */
//   double VIRGOhh;                                           /* Inner product (h|h) for VIRGO */
// } LLVSignal;

typedef struct tagLLVSignalCAmpPhase
{
  struct tagListmodesCAmpPhaseFrequencySeries* LHOSignal;   /* Signal in LHO, in the form of a list of the contribution of each mode */
  struct tagListmodesCAmpPhaseFrequencySeries* LLOSignal;   /* Signal in LLO, in the form of a list of the contribution of each mode */
  struct tagListmodesCAmpPhaseFrequencySeries* VIRGOSignal; /* Signal in VIRGO, in the form of a list of the contribution of each mode */
  double LLVhh;                                             /* Combined Inner product (h|h) for dectectors LHV */
} LLVSignalCAmpPhase;

typedef struct tagLLVInjectionCAmpPhase
{
  struct tagListmodesCAmpPhaseSpline* LHOSplines;   /* Signal in LHO, in the form of a list of splines for the contribution of each mode */
  struct tagListmodesCAmpPhaseSpline* LLOSplines;   /* Signal in LLO, in the form of a list of splines for the contribution of each mode */
  struct tagListmodesCAmpPhaseSpline* VIRGOSplines;   /* Signal in VIRGO, in the form of a list of splines for the contribution of each mode */
  double LLVss;                                   /* Combined Inner product (s|s) for dectectors LHV */
} LLVInjectionCAmpPhase;

typedef struct tagLLVSignalReIm /* We don't store the SNRs here, as we will use -1/2(h-s|h-s) for the likelihood */
{
  struct tagReImFrequencySeries* LHOSignal;   /* Signal in LHO, in the form of a Re/Im frequency series where the modes have been summed */
  struct tagReImFrequencySeries* LLOSignal;   /* Signal in LLO, in the form of a Re/Im frequency series where the modes have been summed */
  struct tagReImFrequencySeries* VIRGOSignal;   /* Signal in VIRGO, in the form of a Re/Im frequency series where the modes have been summed */
} LLVSignalReIm;

typedef struct tagLLVInjectionReIm /* Storing the vectors of frequencies and noise values - We don't store the SNRs here, as we will use -1/2(h-s|h-s) for the likelihood */
{
  struct tagReImFrequencySeries* LHOSignal;   /* Signal in LHO, in the form of a Re/Im frequency series where the modes have been summed */
  struct tagReImFrequencySeries* LLOSignal;   /* Signal in LLO, in the form of a Re/Im frequency series where the modes have been summed */
  struct tagReImFrequencySeries* VIRGOSignal;   /* Signal in VIRGO, in the form of a Re/Im frequency series where the modes have been summed */
  gsl_vector* freq;                            /* Vector of frequencies of the injection (assumed to be the same for LHO, LLO, VIRGO) */
  gsl_vector* noisevaluesLHO;                    /* Vector of noise values on freq LHO */
  gsl_vector* noisevaluesLLO;                    /* Vector of noise values on freq LLO */
  gsl_vector* noisevaluesVIRGO;                  /* Vector of noise values on freq VIRGO */
} LLVInjectionReIm;

/************ Functions for LLV parameters, injection, likelihood, prior ************/

/* Parsing parameters for the generation of a LLV waveform, from the command line */
/* Masses are input in solar masses and distances in Mpc - converted in SI for the internals */
void parse_args_LLV(ssize_t argc, char **argv,
    LLVParams* params,
    LLVGlobalParams* globalparams,
    LLVPrior* prior,
    LLVRunParams* run,
    LLVParams* addparams);

/* Functions to print the parameters of the run in files for reference */
int print_parameters_to_file_LLV(
  LLVParams* params,
  LLVGlobalParams* globalparams,
  LLVPrior* prior,
  LLVRunParams* run);
int print_rescaleddist_to_file_LLV(
  LLVParams* params,
  LLVGlobalParams* globalparams,
  LLVPrior* prior,
  LLVRunParams* run);

/* Initialization and clean-up for LLVSignal structures */
void LLVSignalCAmpPhase_Cleanup(LLVSignalCAmpPhase* signal);
void LLVSignalCAmpPhase_Init(LLVSignalCAmpPhase** signal);
void LLVInjectionCAmpPhase_Cleanup(LLVInjectionCAmpPhase* signal);
void LLVInjectionCAmpPhase_Init(LLVInjectionCAmpPhase** signal);
void LLVSignalReIm_Cleanup(LLVSignalReIm* signal);
void LLVSignalReIm_Init(LLVSignalReIm** signal);
void LLVInjectionReIm_Cleanup(LLVInjectionReIm* signal);
void LLVInjectionReIm_Init(LLVInjectionReIm** signal);

/* Function generating a LLV signal as a list of modes in CAmp/Phase form, from LLV parameters */
int LLVGenerateSignalCAmpPhase(
  struct tagLLVParams* params,                 /* Input: set of LLV parameters of the signal */
  struct tagLLVSignalCAmpPhase* signal);  /* Output: structure for the generated signal */
/* Function generating a LLV injection as a list of modes, given as preinterpolated splines, from LLV parameters */
int LLVGenerateInjectionCAmpPhase(
  struct tagLLVParams* injectedparams,    /* Input: set of LLV parameters of the signal */
  struct tagLLVInjectionCAmpPhase* signal);  /* Output: structure for the generated signal */
/* Function generating a LLV signal as a frequency series in Re/Im form where the modes have been summed, from LLV parameters - takes as argument the frequencies on which to evaluate */
int LLVGenerateSignalReIm(
  struct tagLLVParams* params,       /* Input: set of LLV parameters of the template */
  gsl_vector* freq,                   /* Input: frequencies on which evaluating the waveform (from the injection) */
  struct tagLLVSignalReIm* signal);  /* Output: structure for the generated signal */
/* Function generating a LLV injection as a frequency series in Re/Im form where the modes have been summed, from LLV parameters - frequencies on which to evaluate are to be determined internally */
int LLVGenerateInjectionReIm(
  struct tagLLVParams* injectedparams,       /* Input: set of LLV parameters of the injection */
  double fLow,                                /* Input: starting frequency (from argument minf) */
  double fHigh,                               /* Input: upper frequency (from argument maxf) */
  int nbpts,                                  /* Input: number of frequency samples */
  int tagsampling,                            /* Input: tag for using linear (0) or logarithmic (1) sampling */
  struct tagLLVInjectionReIm* signal);       /* Output: structure for the generated signal */

// checks prior boundaires
int PriorBoundaryCheck(LLVPrior *prior, double *Cube);

// Prior functions from Cube to physical parameters
// x1 is min, x2 is max when specified
// r is Cube value
double CubeToFlatPrior(double r, double x1, double x2);
double CubeToLogFlatPrior(double r, double x1, double x2);
double CubeToPowerPrior(double p, double r, double x1, double x2);
double CubeToGaussianPrior(double r, double mean, double sigma);
double CubeToSinPrior(double r, double x1, double x2);
double CubeToCosPrior(double r, double x1, double x2);

/* Prior functions from physical parameters to Cube
   x1 is min, x2 is max when specified
   y is physical value */
double FlatPriorToCube(double y, double x1, double x2);
double LogFlatPriorToCube(double y, double x1, double x2);
double PowerPriorToCube(double p, double y, double x1, double x2);
double SinPriorToCube(double y, double x1, double x2);
double CosPriorToCube(double y, double x1, double x2);

/* log-Likelihood functions */
double CalculateLogLCAmpPhase(LLVParams *params, LLVInjectionCAmpPhase* injection);
double CalculateLogLReIm(LLVParams *params, LLVInjectionReIm* injection);

/************ Global Parameters ************/

extern LLVParams* injectedparams;
extern LLVGlobalParams* globalparams;
extern LLVPrior* priorParams;
double logZdata;

#endif


#include <gsl/gsl_test.h>
#include <gsl/gsl_ieee_utils.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_cblas.h>

#include "tests.h"

void
test_trsv (void) {
const double flteps = 1e-4, dbleps = 1e-6;
  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.349749f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1150)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.348f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1151)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.349749f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1152)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.348f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1153)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.349749f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1154)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.348f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1155)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.349749f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1156)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.995f };
   float X[] = { 0.348f };
   int incX = -1;
   float x_expected[] = { 0.348f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1157)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.42623f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1158)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.338f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1159)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.42623f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1160)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.338f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1161)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.42623f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1162)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.338f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1163)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.42623f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1164)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.793f };
   float X[] = { 0.338f };
   int incX = -1;
   float x_expected[] = { 0.338f };
   cblas_strsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], flteps, "strsv(case 1165)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { -2.25238095238 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1166)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { 0.473 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1167)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { -2.25238095238 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1168)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { 0.473 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1169)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { -2.25238095238 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1170)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { 0.473 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1171)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { -2.25238095238 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1172)");
     }
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { -0.21 };
   double X[] = { 0.473 };
   int incX = -1;
   double x_expected[] = { 0.473 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1173)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 1.30882352941 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1174)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 0.979 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1175)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 1.30882352941 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1176)");
     }
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 0.979 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1177)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 1.30882352941 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1178)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 0.979 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1179)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 1.30882352941 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1180)");
     }
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.748 };
   double X[] = { 0.979 };
   int incX = -1;
   double x_expected[] = { 0.979 };
   cblas_dtrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[i], x_expected[i], dbleps, "dtrsv(case 1181)");
     }
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -1.55112f, -0.372004f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1182) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1182) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -0.95f, 0.343f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1183) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1183) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -1.55112f, -0.372004f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1184) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1184) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -0.95f, 0.343f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1185) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1185) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -1.55112f, -0.372004f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1186) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1186) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -0.95f, 0.343f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1187) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1187) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -1.55112f, -0.372004f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1188) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1188) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.529f, -0.348f };
   float X[] = { -0.95f, 0.343f };
   int incX = -1;
   float x_expected[] = { -0.95f, 0.343f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1189) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1189) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 1.43572f, -0.843108f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1190) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1190) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 0.896f, -0.447f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1191) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1191) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 1.43572f, -0.843108f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1192) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1192) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 0.896f, -0.447f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1193) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1193) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 1.43572f, -0.843108f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1194) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1194) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 0.896f, -0.447f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1195) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1195) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 1.43572f, -0.843108f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1196) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1196) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.6f, 0.041f };
   float X[] = { 0.896f, -0.447f };
   int incX = -1;
   float x_expected[] = { 0.896f, -0.447f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1197) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1197) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.289642f, 0.951701f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1198) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1198) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.765f, 0.18f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1199) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1199) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.289642f, 0.951701f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1200) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1200) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.765f, 0.18f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1201) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1201) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.289642f, 0.951701f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1202) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1202) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.765f, 0.18f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1203) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1203) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.289642f, 0.951701f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1204) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1204) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   float A[] = { 0.397f, 0.683f };
   float X[] = { 0.765f, 0.18f };
   int incX = -1;
   float x_expected[] = { 0.765f, 0.18f };
   cblas_ctrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], flteps, "ctrsv(case 1205) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], flteps, "ctrsv(case 1205) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.471957414573, -0.173714770642 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1206) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1206) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.627, 0.281 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1207) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1207) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.471957414573, -0.173714770642 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1208) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1208) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.627, 0.281 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1209) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1209) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.471957414573, -0.173714770642 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1210) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1210) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.627, 0.281 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1211) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1211) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.471957414573, -0.173714770642 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1212) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1212) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 111;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.977, -0.955 };
   double X[] = { -0.627, 0.281 };
   int incX = -1;
   double x_expected[] = { -0.627, 0.281 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1213) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1213) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 5.18357980622, -0.587200407955 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1214) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1214) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 0.3, -0.874 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1215) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1215) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 5.18357980622, -0.587200407955 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1216) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1216) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 0.3, -0.874 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1217) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1217) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 5.18357980622, -0.587200407955 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1218) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1218) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 0.3, -0.874 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1219) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1219) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 5.18357980622, -0.587200407955 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1220) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1220) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 112;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.076, -0.16 };
   double X[] = { 0.3, -0.874 };
   int incX = -1;
   double x_expected[] = { 0.3, -0.874 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1221) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1221) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.371144591432, -0.0712292456544 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1222) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1222) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.085, -0.303 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1223) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1223) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.371144591432, -0.0712292456544 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1224) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1224) imag");
     };
   };
  };

  {
   int order = 101;
   int trans = 113;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.085, -0.303 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1225) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1225) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 121;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.371144591432, -0.0712292456544 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1226) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1226) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 121;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.085, -0.303 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1227) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1227) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 122;
   int diag = 131;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.371144591432, -0.0712292456544 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1228) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1228) imag");
     };
   };
  };

  {
   int order = 102;
   int trans = 113;
   int uplo = 122;
   int diag = 132;
   int N = 1;
   int lda = 1;
   double A[] = { 0.372, -0.745 };
   double X[] = { -0.085, -0.303 };
   int incX = -1;
   double x_expected[] = { -0.085, -0.303 };
   cblas_ztrsv(order, uplo, trans, diag, N, A, lda, X, incX);
   {
     int i;
     for (i = 0; i < 1; i++) {
       gsl_test_rel(X[2*i], x_expected[2*i], dbleps, "ztrsv(case 1229) real");
       gsl_test_rel(X[2*i+1], x_expected[2*i+1], dbleps, "ztrsv(case 1229) imag");
     };
   };
  };

}


/**
 * @file postfilter.h

 * @brief implementation of post-filters for a microphone array.

   The following post-filters are implemented:
   [1] Zelinski post-filter
   [2] APAB post-filter
   [3] McCowan's post-filter
   [4] Lefkimmiatis's post-filter

   The correspondig references are:
   [1] C.Claude Marro et al. "Analysis of noise reduction and dereverberation techniques based on microphone arrays with postfiltering", IEEE Trans. ASP, vol. 6, pp 240-259, May 1998.
   [2] M.Brandstein, "Microphone Arrays", Springer, ISBN 3-540-41953-5, pp.39-60.
   [3] Iain A. Mccowan et al., "Microphone array post-filter based on noise field coherence", IEEE Trans. SAP, vol. 11, pp. Nov. 709--716, 2003.
   [4] Stamatios Lefkimmiatis et al., "A generalized estimation approach for linear and nonlinear microphone array post-filters",  Speech Communication, 2007.

  * @author Kenichi Kumatani
*/
#ifndef POSTFILTER_H
#define POSTFILTER_H

#include <stdio.h>
#include <assert.h>
#include <float.h>

#include <gsl/gsl_block.h>
#include <gsl/gsl_vector.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_complex.h>
#include <gsl/gsl_complex_math.h>
#include <gsl/gsl_fft_complex.h>
#include <common/refcount.h>
#include "common/jexception.h"

#include "stream/stream.h"
#include "postfilter/spectralsubtraction.h"
#include "postfilter/binauralprocessing.h"
#include "beamformer/spectralinfoarray.h"
#include "beamformer/beamformer.h"

typedef enum {
  TYPE_ZELINSKI1_REAL = 0x01,
  TYPE_ZELINSKI1_ABS  = 0x02,
  TYPE_APAB = 0x04,
  TYPE_ZELINSKI2 = 0x08,
  NO_USE_POST_FILTER = 0x00
} PostfilterType;

void ZelinskiFilter(gsl_vector_complex **arrayManifold,
		    SnapShotArrayPtr     snapShotArray,
		    bool halfBandShift,
		    gsl_vector_complex *beamformedSignal,
		    gsl_vector_complex **prevCSDs,
		    gsl_vector_complex *pfweights,
		    double alpha, int Ropt );

void ApabFilter( gsl_vector_complex **arrayManifold,
		 SnapShotArrayPtr     snapShotArray,
		 int fftLen, int nChan, bool halfBandShift,
		 gsl_vector_complex *beamformedSignal,
		 int channelX );

/**
   @class Zelinski post-filtering

   @brief filter beamformer's outputs under the assumption that noise signals between sensors are uncorrelated.
   @usage
   1. construct an object,
   2. set the array snapshot and array manifold vectors with
      either setBeamformer() or setSnapShotArray() and setArrayManifold(),
   3. process data at each frame by caling next().
*/
class ZelinskiPostFilter: public VectorComplexFeatureStream {
public:
  ZelinskiPostFilter( VectorComplexFeatureStreamPtr &output, unsigned fftLen, double alpha=0.6, int type=2, int minFrames=0, const String& nm = "ZelinskPostFilter" );
  ~ZelinskiPostFilter();

  virtual const gsl_vector_complex* next(int frame_no = -5);
  virtual void reset();

  void set_beamformer(SubbandDSPtr &beamformer);
  void set_snapshot_array(SnapShotArrayPtr &snapShotArray);
  void set_array_manifold_vector(unsigned fbinX, gsl_vector_complex *arrayManifoldVector, bool halfBandShift, unsigned NC = 1);
  const gsl_vector_complex* postfilter_weights(){
    if( NULL == bf_weights_ )
      return NULL;
    return(bf_weights_->wp1());
  }

#ifdef ENABLE_LEGACY_BTK_API
  void setBeamformer(SubbandDSPtr &beamformer){ set_beamformer(beamformer); }
  void setSnapShotArray(SnapShotArrayPtr &snapShotArray){ set_snapshot_array(snapShotArray); }
  void setArrayManifoldVector(unsigned fbinX, gsl_vector_complex *arrayManifoldVector, bool halfBandShift, unsigned NC = 1){ set_array_manifold_vector(fbinX, arrayManifoldVector, halfBandShift, NC); }
  const gsl_vector_complex* getPostFilterWeights(){ return postfilter_weights(); }
#endif

protected:
  unsigned                      fftLen_;
  VectorComplexFeatureStreamPtr samp_; /* output of the beamformer */
  PostfilterType                type_; /* the type of the Zelinski-postfilters */
  double                        alpha_; /* forgetting factor */
  int                           min_frames_;
  SubbandDSPtr                  bf_ptr_; /* */
  BeamformerWeights*            bf_weights_;
  bool                          has_bf_ptr_; /* true if bf_ptr_ is set with setBeamformer() */
  SnapShotArrayPtr              snapshot_array_; /* multi-channel input */
};

typedef Inherit<ZelinskiPostFilter, VectorComplexFeatureStreamPtr> ZelinskiPostFilterPtr;

/**
   @class McCowan post-filtering

   @brief process the beamformer's outputs with McCowan's post-filtering
   @usage
   1. construct an object,
   2. compute the noise coherence matrix through setDiffuseNoiseModel( micPositions, ssampleRate)
   3. set the array snapshot and array manifold vectors with
      either setBeamformer() or setSnapShotArray() and setArrayManifold(),
   4. process data at each frame by caling next().
*/
class McCowanPostFilter: public ZelinskiPostFilter {
public:
  McCowanPostFilter( VectorComplexFeatureStreamPtr &output, unsigned fftLen, double alpha=0.6, int type=2, int minFrames=0, float threshold=0.99, const String& nm = "McCowanPostFilter" );
  ~McCowanPostFilter();

  virtual const gsl_vector_complex* next(int frame_no = -5);
  virtual void reset();
  /* micPositions[][x,y,z] */

  const gsl_matrix_complex *noise_spatial_spectral_matrix( unsigned fbinX );
  bool set_noise_spatial_spectral_matrix( unsigned fbinX, gsl_matrix_complex* Rnn );
  bool set_diffuse_noise_model( const gsl_matrix* micPositions, double sampleRate, double sspeed = 343740.0 );
  void set_all_diagonal_loading(float diagonalWeight);
  void set_diagonal_looading(unsigned fbinX, float diagonalWeight);
  void divide_all_nondiagonal_elements(float mu);
  void divide_nondiagonal_elements(unsigned fbinX, float mu);

#ifdef ENABLE_LEGACY_BTK_API
  const gsl_matrix_complex *getNoiseSpatialSpectralMatrix(unsigned fbinX){ return noise_spatial_spectral_matrix(fbinX); }
  bool setNoiseSpatialSpectralMatrix(unsigned fbinX, gsl_matrix_complex* Rnn){ return set_noise_spatial_spectral_matrix(fbinX, Rnn); }
  bool setDiffuseNoiseModel(const gsl_matrix* micPositions, double sampleRate, double sspeed = 343740.0){ return set_diffuse_noise_model( micPositions, sampleRate, sspeed); }
  void setAllLevelsOfDiagonalLoading(float diagonalWeight){ set_all_diagonal_loading(diagonalWeight); }
  void setLevelOfDiagonalLoading(unsigned fbinX, float diagonalWeight){ set_diagonal_looading(fbinX, diagonalWeight); }
  void divideAllNonDiagonalElements( float mu );
  void divideNonDiagonalElements( unsigned fbinX, float mu );
#endif

protected:
  double estimate_average_clean_PSD_( unsigned fbinX, gsl_vector_complex* currCSDf );
  virtual void post_filtering_();

protected:
  gsl_matrix_complex**                           R_; /* Noise spatial spectral matrices */
  float*                                         diagonal_weights_;
  float                                          threshold_of_Rij_; /* to avoid the indeterminate solution*/
  gsl_vector_complex*                            time_aligned_signal_f_; /* workspace */
  bool                                           invR_computed_;
};

typedef Inherit<McCowanPostFilter, ZelinskiPostFilterPtr> McCowanPostFilterPtr;

/**
   @class Lefkimmiatis post-filtering
   @brief compute a Winer filter under the the diffuse noise field assumption
   @usage
   1. construct an object,
   2. compute the noise coherence matrix through setDiffuseNoiseModel( micPositions, ssampleRate)
   3. set the array snapshot and array manifold vectors with
      either setBeamformer() or setSnapShotArray() and setArrayManifold(),
   4. process data at each frame by caling next().
*/
class LefkimmiatisPostFilter: public McCowanPostFilter {
public:
  LefkimmiatisPostFilter( VectorComplexFeatureStreamPtr &output, unsigned fftLen, double minSV=1.0E-8, unsigned fbinX1=0, double alpha=0.6, int type=2, int minFrames=0, float threshold=0.99, const String& nm = "LefkimmiatisPostFilte" );
  ~LefkimmiatisPostFilter();

  virtual const gsl_vector_complex* next(int frame_no = -5);
  virtual void reset();
  /* micPositions[][x,y,z] */

  void calc_inverse_noise_spatial_spectral_matrix();

#ifdef ENABLE_LEGACY_BTK_API
  void calcInverseNoiseSpatialSpectralMatrix(){ calc_inverse_noise_spatial_spectral_matrix(); }
#endif

protected:
  double estimate_average_noise_PSD_( unsigned fbinX, gsl_vector_complex* currCSDf );
  virtual void post_filtering_();

private:
  gsl_complex calcLambda( unsigned fbinX );

  gsl_matrix_complex** invR_;
  gsl_vector_complex*  tmpH_;
  double              minSV_;
  unsigned            fbinX1_;
};

typedef Inherit<LefkimmiatisPostFilter, McCowanPostFilterPtr> LefkimmiatisPostFilterPtr;

/**
   @class high pass filter
*/
class HighPassFilter: public VectorComplexFeatureStream {
public:
  HighPassFilter( VectorComplexFeatureStreamPtr &output, float cutOffFreq, int sampleRate, const String& nm = "HighPassFilter" );
  virtual const gsl_vector_complex* next(int frame_no = -5);
  virtual void reset();

private:
  VectorComplexFeatureStreamPtr src_;
  unsigned cutoff_fbinX_;
};

typedef Inherit<HighPassFilter, VectorComplexFeatureStreamPtr> HighPassFilterPtr;

#endif


#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <getopt.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_rng.h>
#include "../fewbody.h"

int calc_units(fb_hier_t hier, fb_units_t *units)
{
  /* mass unit is total system mass */
  units->m = hier.hier[hier.hi[1]+0].m + hier.hier[hier.hi[1]+1].m +	\
    hier.hier[hier.hi[1]+2].m + hier.hier[hier.hi[1]+3].m +		\
    hier.hier[hier.hi[1]+4].m;
  /* length unit is one AU */
  units->l = FB_CONST_AU;
  /* everything else is derived */
  units->E = FB_CONST_G * fb_sqr(units->m) / units->l;
  units->v = sqrt(units->E/units->m);
  units->t = units->l / units->v;
  return(0);
}

int main(int argc, char *argv[])
{
  int j;
  double t;
  fb_hier_t hier;
  fb_input_t input;
  fb_ret_t retval;
  fb_units_t units;
  char string1[FB_MAX_STRING_LENGTH], string2[FB_MAX_STRING_LENGTH];

  /* set input parameters */
  input.ks = 0; /* turn K-S regularization off */
  input.tstop = 1.0e4; /* stopping time in units of units.t */
  input.Dflag = 0; /* don't output dynamical info to stdout */
  input.dt = 0.0; /* irrelevant when Dflag=0 */
  input.tcpustop = 120.0; /* stopping CPU time in seconds */
  input.absacc = 1.0e-9; /* integrator absolute accuracy */
  input.relacc = 1.0e-9; /* integrator relative accuracy */
  input.ncount = 500; /* number of integration steps between calls to fb_classify() */
  input.tidaltol = 1.0e-6; /* tidal perturbation required to force numerical */
                           /* integration of a binary node */
  input.fexp = 1.0; /* radius expansion factor of merger products */
  fb_debug = 0;

  /* initialize a few things */
  t = 0.0;
  hier.nstarinit = 5;
  hier.nstar = 5;
  fb_malloc_hier(&hier);
  fb_init_hier(&hier);

  /* set stellar properties */
  for (j=0; j<hier.nstar; j++) {
    hier.hier[hier.hi[1]+j].ncoll = 1;
    hier.hier[hier.hi[1]+j].id[0] = j;
    snprintf(hier.hier[hier.hi[1]+j].idstring, FB_MAX_STRING_LENGTH, "%d", j);
    hier.hier[hier.hi[1]+j].n = 1;
    hier.hier[hier.hi[1]+j].obj[0] = NULL;
    hier.hier[hier.hi[1]+j].obj[1] = NULL;
    hier.hier[hier.hi[1]+j].Eint = 0.0;
    hier.hier[hier.hi[1]+j].Lint[0] = 0.0;
    hier.hier[hier.hi[1]+j].Lint[1] = 0.0;
    hier.hier[hier.hi[1]+j].Lint[2] = 0.0;
    hier.hier[hier.hi[1]+j].R = 1.0e-3 * FB_CONST_RSUN;
    hier.hier[hier.hi[1]+j].m = FB_CONST_MSUN;
    hier.hier[hier.hi[1]+j].x[2] = 0.0; /* everything in x-y plane */
    hier.hier[hier.hi[1]+j].v[2] = 0.0;
  }

  /* set some positions and velocities */
  hier.hier[hier.hi[1]+0].x[0] = 10.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+0].x[1] = 0.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+0].v[0] = 10.0e5;
  hier.hier[hier.hi[1]+0].v[1] = 0.0;

  hier.hier[hier.hi[1]+1].x[0] = 10.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+1].x[1] = 10.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+0].v[0] = -10.0e5;
  hier.hier[hier.hi[1]+0].v[1] = 0.0;

  hier.hier[hier.hi[1]+2].x[0] = -30.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+2].x[1] = -5.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+0].v[0] = 0.0;
  hier.hier[hier.hi[1]+0].v[1] = 5.0e5;

  hier.hier[hier.hi[1]+3].x[0] = 0.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+3].x[1] = 27.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+0].v[0] = -5.0e5;
  hier.hier[hier.hi[1]+0].v[1] = -4.0e5;

  hier.hier[hier.hi[1]+4].x[0] = 10.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+4].x[1] = -32.0 * FB_CONST_AU;
  hier.hier[hier.hi[1]+0].v[0] = 5.0e5;
  hier.hier[hier.hi[1]+0].v[1] = -1.0e5;

  /* set units with our own routine, then normalize */
  calc_units(hier, &units);
  fb_normalize(&hier, units);

  /* call Fewbody to evolve system */
  retval = fewbody(input, &hier, &t);

  /* all the rest is parsing the output */
  if (retval.retval == 1) {
    fprintf(stderr, "encounter complete.\n");
  } else {
    fprintf(stderr, "encounter NOT complete.\n");
  }

  fprintf(stderr, "final configuration:  %s  (%s)\n",
	  fb_sprint_hier(hier, string1),
	  fb_sprint_hier_hr(hier, string2));

  fprintf(stderr, "t_final=%.6g (%.6g yr)  t_cpu=%.6g s\n",	\
	  t, t*units.t/FB_CONST_YR, retval.tcpu);

  fprintf(stderr, "DeltaL/L0=%.6g  DeltaL=%.6g\n", retval.DeltaLfrac, retval.DeltaL);
  fprintf(stderr, "DeltaE/E0=%.6g  DeltaE=%.6g\n", retval.DeltaEfrac, retval.DeltaE);
  fprintf(stderr, "Rmin=%.6g (%.6g RSUN)  Rmin_i=%d  Rmin_j=%d\n",	\
	  retval.Rmin, retval.Rmin*units.l/FB_CONST_RSUN, retval.Rmin_i, retval.Rmin_j);
  fprintf(stderr, "Nosc=%d (%s)\n", retval.Nosc,
	  (retval.Nosc>=1?"resonance":"non-resonance"));

  fprintf(stderr, "orbital parameters of outermost binaries:\n");
  for (j=0; j<hier.nobj; j++) {
    if (hier.obj[j]->n >= 2) {
      fprintf(stderr, "j=%d  a=%.6g AU  e=%.6g\n", j,
	      hier.obj[j]->a * units.l / FB_CONST_AU, hier.obj[j]->e);
    }
  }

  fb_free_hier(hier);
  return(0);
}


//===--- Sudoku/Location_Utilities.h                                    ---===//
//
// Utilities for class Sudoku::Location
//===----------------------------------------------------------------------===//
#pragma once

#include "Board_Section_traits.h"
#include "Location.h"
#include "Size.h"
#include "traits.h"

#include <gsl/gsl> // index

#include <vector>

#include <algorithm> // minmax_element, is_sorted, all_of
#include <iterator>  // back_inserter
#include <limits>    // numeric_limits

#include "Board.fwd.h" // Forward declarations

namespace Sudoku
{
//===-- function declarations ---------------------------------------------===//
template<int N>
constexpr void valid_dimensions() noexcept;

template<int N>
constexpr bool is_valid(Location<N>) noexcept;
template<int N>
constexpr bool is_valid(const std::vector<Location<N>>& locs) noexcept(true);

template<int N>
constexpr bool is_valid_size(gsl::index elem) noexcept;
template<int N>
constexpr bool is_valid_size(gsl::index row, gsl::index col) noexcept;

template<int N>
constexpr bool is_same_row(Location<N>, Location<N>) noexcept;
template<int N>
constexpr bool is_same_col(Location<N>, Location<N>) noexcept;
template<int N>
constexpr bool is_same_block(Location<N>, Location<N>) noexcept;

template<int N, typename ItrT>
constexpr bool is_same_row(ItrT begin, ItrT end) noexcept;
template<int N, typename ItrT>
constexpr bool is_same_col(ItrT begin, ItrT end) noexcept;
template<int N, typename ItrT>
constexpr bool is_same_block(ItrT begin, ItrT end) noexcept;

template<int N>
std::vector<Location<N>> get_same_row(
	const Location<N>, const std::vector<Location<N>>&) noexcept(true);
template<int N>
std::vector<Location<N>> get_same_col(
	const Location<N>, const std::vector<Location<N>>&) noexcept(true);
template<int N>
std::vector<Location<N>> get_same_block(
	const Location<N>, const std::vector<Location<N>>&) noexcept(true);

template<int N, typename S>
constexpr bool is_same_section(S section, Location<N>) noexcept;

template<typename SectionT, int N>
bool is_same_section(SectionT, std::vector<Location<N>>&) noexcept;

template<
	int N,
	typename S,
	typename = std::enable_if_t<
		Board_Section::traits::is_Row_v<S> ||
		Board_Section::traits::is_Col_v<S>>>
bool intersect_block(S section, Location<N> block_loc) noexcept;

//===----------------------------------------------------------------------===//

// Compile-time only Test
template<int N>
constexpr void valid_dimensions() noexcept
{
	// input check
	static_assert((base_size<N>) > 1, "base_size too small");
	static_assert(
		base_size<N> < elem_size<N> && elem_size<N> <= full_size<N> &&
			base_size<N> < std::numeric_limits<int>::max() && // <limits>
			elem_size<N> < std::numeric_limits<int>::max() &&
			full_size<N> < std::numeric_limits<int>::max(),
		"board size out of bounds");
	// logic check
	static_assert(
		base_size<N> * base_size<N> == elem_size<N> &&
			elem_size<N> * elem_size<N> == full_size<N>,
		"size calculation broken");
}

// Test if Location on Board
template<int N>
[[nodiscard]] inline constexpr bool is_valid(const Location<N> loc) noexcept
{
	return (loc.element() >= 0 && loc.element() < full_size<N>);
}

// Test if Locations on Board and if sorted (ascending)
template<int N>
[[nodiscard]] inline constexpr bool
	is_valid(const std::vector<Location<N>>& locs) noexcept(true)
{ // std::is_sorted can throw std::bad_alloc
	return (
		!locs.empty() && (std::is_sorted(locs.cbegin(), locs.cend()) &&
						  locs.cbegin()->element() >= 0 &&
						  locs.crbegin()->element() < full_size<N>));
}

// Test row/col/block-element
template<int N>
[[nodiscard]] inline constexpr bool
	is_valid_size(const gsl::index elem) noexcept
{
	return (elem >= 0 && elem < elem_size<N>);
}

// Test if location on Board
template<int N>
[[nodiscard]] inline constexpr bool
	is_valid_size(const gsl::index row, const gsl::index col) noexcept
{
	return is_valid_size<N>(row) && is_valid_size<N>(col);
}

//===----------------------------------------------------------------------===//

// check
template<int N>
[[nodiscard]] inline constexpr bool
	is_same_row(const Location<N> left, const Location<N> right) noexcept
{
	return (is_valid<N>(left) && is_valid<N>(right)) &&
		   left.row() == right.row();
}

// check: all in same row
template<int N, typename ItrT>
[[nodiscard]] constexpr bool
	is_same_row(const ItrT begin, const ItrT end) noexcept
{
	{
		static_assert(traits::is_forward<ItrT>);
	}
	if (begin == end)
		return false;

	const auto itr = begin + 1;
	return std::all_of(
		itr, end, [begin](Location<N> i) { return is_same_row<N>(*begin, i); });
}

// return all in same row
template<int N> // NOLINTNEXTLINE(bugprone-exception-escape)
[[nodiscard]] std::vector<Location<N>> get_same_row(
	const Location<N> left,
	const std::vector<Location<N>>& right) noexcept(true)
{ // std::copy_if could throw std::bad_alloc
	std::vector<Location<N>> output{};
	const auto predicate = [&left](Location<N> loc) {
		return is_same_row(left, loc);
	};
	std::copy_if(
		right.cbegin(), right.cend(), std::back_inserter(output), predicate);
	return output;
}

// check
template<int N>
[[nodiscard]] inline constexpr bool
	is_same_col(const Location<N> left, const Location<N> right) noexcept
{
	return (is_valid<N>(left) && is_valid<N>(right)) &&
		   left.col() == right.col();
}

// check: all in same col
template<int N, typename ItrT>
[[nodiscard]] inline constexpr bool
	is_same_col(const ItrT begin, const ItrT end) noexcept
{
	{
		static_assert(traits::is_forward<ItrT>);
	}
	if (begin == end)
		return false;

	const auto itr = begin + 1;
	return std::all_of(
		itr, end, [begin](Location<N> i) { return is_same_col<N>(*begin, i); });
}

// return all in same col
template<int N> // NOLINTNEXTLINE(bugprone-exception-escape)
[[nodiscard]] std::vector<Location<N>> get_same_col(
	const Location<N> left,
	const std::vector<Location<N>>& right) noexcept(true)
{ // std::copy_if could throw std::bad_alloc
	std::vector<Location<N>> output{};
	const auto predicate = [&left](Location<N> loc) {
		return is_same_col(left, loc);
	};
	std::copy_if(
		right.cbegin(), right.cend(), std::back_inserter(output), predicate);
	return output;
}

// check
template<int N>
[[nodiscard]] inline constexpr bool
	is_same_block(const Location<N> left, const Location<N> right) noexcept
{
	return (is_valid<N>(left) && is_valid<N>(right)) &&
		   left.block() == right.block();
}

// check all in same block
template<int N, typename ItrT>
[[nodiscard]] inline constexpr bool
	is_same_block(const ItrT begin, const ItrT end) noexcept
{
	{
		static_assert(traits::is_forward<ItrT>);
	}
	if (begin == end)
		return false;

	const auto itr = begin + 1;
	return std::all_of(itr, end, [begin](Location<N> i) {
		return is_same_block<N>(*begin, i);
	});
}

// return all in same block
template<int N> // NOLINTNEXTLINE(bugprone-exception-escape)
[[nodiscard]] std::vector<Location<N>> get_same_block(
	const Location<N> left,
	const std::vector<Location<N>>& right) noexcept(true)
{ // std::copy_if could throw std::bad_alloc
	std::vector<Location<N>> output{};
	const auto predicate = [&left](Location<N> loc) {
		return is_same_block(left, loc);
	};
	std::copy_if(
		right.cbegin(), right.cend(), std::back_inserter(output), predicate);
	return output;
}

// check: [loc] is in [section]
template<int N, typename S>
[[nodiscard]] inline constexpr bool
	is_same_section(const S section, const Location<N> loc) noexcept
{
	static_assert(Board_Section::traits::is_Section_v<S>);

	if constexpr (Board_Section::traits::is_Row_v<S>)
		return is_same_row(loc, section.cbegin().location());
	else if constexpr (Board_Section::traits::is_Col_v<S>)
		return is_same_col(loc, section.cbegin().location());
	else
	{
		static_assert(Board_Section::traits::is_Block_v<S>);
		return is_same_block(loc, section.cbegin().location());
	}
}

// check: [section] intersects block containing [loc]
template<int N, typename S, typename>
[[nodiscard]] inline bool
	intersect_block(const S section, const Location<N> block_loc) noexcept
{
	for (auto itr = section.cbegin(); itr != section.cend(); ++itr)
	{
		if (is_same_block(block_loc, itr.location()))
		{
			return true;
		}
	}
	return false;
}

// check: at least one [location] inside [section]
template<typename SectionT, int N>
[[nodiscard]] inline bool is_same_section(
	SectionT const section, std::vector<Location<N>> const& locs) noexcept
{
	return std::any_of(locs.cbegin(), locs.cend(), [section](Location<N> L) {
		return is_same_section(section, L);
	});
}

} // namespace Sudoku


/* -*- coding: utf-8; mode: c++; tab-width: 2; -*- -------------------------
   Interface/declaration file for GramSchmidt.cpp
------------------------------------------------------------------------- */

#ifndef GRAMSCHMIDT_H
#define GRAMSCHMIDT_H

#include <vector>
#include <numeric>
#include <algorithm>
#include <cblas.h>
#include <lapacke.h>
#include <iostream>

// TO DO: Improve performance with CBLAS/LAPACKE for large size x
// std::vector<double> v;
// double* a = &v[0];

// int GramSchmidt(size_t, size_t, void*, void*);
int GramSchmidt(size_t, size_t, double*, double*);

// int GramSchmidt(std::vector<std::vector<double>>, std::vector<std::vector<double>>);

#endif