// this matrix_c08.cpp file has the factor analysis & multi-dimensional linear-regression.
//	channel rate, angle, and effective correlation coefficient.  cascaded channels.




#define ELEVEN_MX	17
#define ARR			 0
#define AVE			 1
#define LBRA		 2
#define LDIAG		 3
#define MBRA		 4
#define MDIAG		 5
#define MKET		 6
#define RDIAG		 7
#define RKET		 8
#define LAVE		 9
#define RAVE		10
#define REGRxyFWD	11
#define REGRxyINV	12
#define REGRyxFWD	13
#define REGRyxINV	14
#define VarRESyy	15
#define VarRESxx	16


struct channel {
	MAT eleven[ELEVEN_MX];
	double R, Theta, rho;
	bool valid; };
typedef struct channel CHN;
//  the effective correlation coefficeint rho -- caution:  do not use for linear-regression -- and
//		the Information Theoretic channel rate R and angle Theta.
//		they are three ways of expressing the same thing.





//	 this subroutine must be called immediately upon the declaration of the channel.
MATRIX_DLL_API
void matrix_initialize_channel(CHN *chan);


//	the user must call for each channel, before the termination of his/her program.
MATRIX_DLL_API
int matrix_channel_dealloc(CHN *chan);


//	the background specifies 0=zero matrix  1=identity matrix.
//  places the array_in along the principal diagonal of an identity matrix, of new_size,
//		at the specified displacement.
MATRIX_DLL_API
int matrix_augment(MAT *array_in, unsigned long background, unsigned long new_size,
				   unsigned long displacement, MAT *array);


//  places the channel represented by the array_in along the principal diagonal
//		of an identity matrix, of at least new_size,
//		at the displacement which will place the partitioning in the middle.
//	the background specifies 0=zero matrix  1=identity matrix.
MATRIX_DLL_API
int matrix_augment_channel(MAT *array_in, unsigned long background, unsigned long new_size,
				           MAT *array);


//	from the array_in, crops the array of new size imx by jmx, at the specified displacement,
//	along the principal diagonal.
//	you may want to modify the symmetry or other properties of the resulting matrix,
//	since those provided by this routine may not be valid.
MATRIX_DLL_API
int matrix_crop(MAT *array_in, unsigned long imx, unsigned long jmx,
				unsigned long displacement, MAT *array);

	
//  from a partitioned positive-definite symmetric matrix computes the small-set.
//  WARNING:  will error-out with a return of 128; if the array is not as specified.
//  since there is no easy way to test for the "definite", instead,
//			the algorithms and subroutines are designed to handle a singularity.
MATRIX_DLL_API
int matrix_part_smallset(MAT *array, MAT *left_bra, MAT *left_diag, MAT *middle_bra,
		MAT *middle_diag, MAT *middle_ket, MAT *right_diag, MAT *right_ket,
		MAT *scratch_a, MAT *scratch_b, MAT *scratch_c, MAT *scratch_d,
		MAT *scratch_1, MAT *scratch_2, MAT *scratch_3, MAT *scratch_4,
		MAT *scratch_5, MAT *scratch_6, MAT *scratch_7, MAT *scratch_8);


//  finds the effective correlation coefficeint rho (caution -- do not use for linear-regression -- and
//		the Information Theoretic channel rate R and effective angle Theta.
//		they are three ways of expressing the same thing.
//	the middle_diag is the small-style middle diagonal of a channel.
MATRIX_DLL_API
int matrix_channel_rate(MAT *middle_diag, double *R, double *Theta, double *rho,
						MAT *scratch_1, MAT *scratch_2, MAT *scratch_3);


//  finds the effective correlation coefficeint rho (caution -- do not use for linear-regression -- and
//		the Information Theoretic channel rate R and effective angle Theta.
//		they are three ways of expressing the same thing.
//	the array is the large-style array which is the channel.
//	computes the channel rate, without factoring the channel.
//		however, it inverts three matrices.  hence, is slower than the foregoing routine.
MATRIX_DLL_API
int matrix_channel_rate(MAT *array, double *R, double *Theta, double *rho,
						MAT *scratch_1, MAT *scratch_2, MAT *scratch_3,
						MAT *scratch_4, MAT *scratch_5, MAT *scratch_6);


//  also finds the effective correlation coefficeint rho (caution -- do not use for linear-regression -- and
//		the Information Theoretic channel rate R and effective angle Theta.
//		they are three ways of expressing the same thing.
MATRIX_DLL_API
int matrix_smallset_largeset(MAT *left_bra, MAT *left_diag, MAT *middle_bra,
		MAT *middle_diag, MAT *middle_ket, MAT *right_diag, MAT *right_ket,
		MAT *exterior_bra, MAT *exterior_diag, MAT *interior_bra, MAT *interior_diag,
		double *R, double *Theta, double *rho,
		MAT *scratch_01, MAT *scratch_02, MAT *scratch_1, MAT *scratch_2);


MATRIX_DLL_API
int matrix_largeset_multiply(MAT *exterior_bra, MAT *exterior_diag, MAT *interior_bra, MAT *interior_diag, MAT *array,
		MAT *scratch_1, MAT *scratch_2, MAT *scratch_3);


//	the channel must have all the small elements pre-loaded.
//	this routine computes the ARR and the AVE from those given small elements and places them into the channel.
MATRIX_DLL_API
int matrix_construct_channel(CHN *chan, MAT *exterior_bra, MAT *exterior_diag, MAT *interior_bra,
							 MAT *interior_diag, MAT *scratch_1, MAT *scratch_2, MAT *scratch_3,
							 MAT *scratch_4, MAT *scratch_5);


//  also finds the effective correlation coefficeint rho (caution -- do not use for linear-regression -- and
//		the Information Theoretic channel rate R and angle Theta.  It stores these three values into the chan
//		they are three ways of expressing the same thing.
//	array is the second-order moment matrix, computed about the mean ave, which is a horizontal vector (ie., imx is one)..
//		each has to be partitioned at the same position and they have to be of the same size.
//		the array has to be a positive definite symmetric matrix.
//	the array has to be of even size and partitioned in the middle.		added Saturday 13-th March 2004.
//		if necessary, augment the matrix with an identity matrix along the diagonal.
MATRIX_DLL_API
int matrix_array_bar_channel(MAT *array, MAT *ave, CHN *chan,
		MAT *exterior_bra, MAT *exterior_diag, MAT *interior_bra, MAT *interior_diag, MAT *reconstructed, double *residue,
		MAT *scratch_a, MAT *scratch_b, MAT *scratch_c, MAT *scratch_d,
		MAT *scratch_1, MAT *scratch_2, MAT *scratch_3, MAT *scratch_4,
		MAT *scratch_5, MAT *scratch_6, MAT *scratch_7, MAT *scratch_8);


//	performs the calculation y = (x - xo) * array + yo, where x, xo, yo, y are horizontal vectors.
//	the size of x and xo is assumed to be equal to the height imx of the array.
//	the size of yo and y is assumed to be equal to the width jmx of the array.
//	xo is the average of the x.  yo is the average of the y.
//	array is the regression-matrix obtained from the REGR or REGR_INV
//		(or either of their transposes) of the channel.
//	x is the input variable.  y is the predicted-value of the output variable.
//	WARNING:  Unlike the rest of this library, this program is not designed to check the sizes of 
//	the input or output vectors.
MATRIX_DLL_API
int matrix_compute_regression(double *x_vect, double *xo_vect, MAT *array, double *yo_vect, double *y_vect);


//  finds the effective correlation coefficient rho_opt -- caution:  do not use for linear-regression -- and
//		the Information Theoretic channel rate R_opt and angle Theta_opt,
//		that result from an optimum middle channel, which may be shown to be provided by an identity matrix.
//		they are three ways of expressing the same thing.
MATRIX_DLL_API
int matrix_3cascade_opt_channel_rate(CHN *chan1, CHN *chan3, double *R_opt, double *Theta_opt, double *rho_opt,
									 MAT *scratch_1, MAT *scratch_2, MAT *scratch_3, MAT *scratch_4);

	
//  finds the effective correlation coefficient rho -- caution:  do not use for linear-regression -- and
//		the Information Theoretic channel rate R and angle Theta,
//		which may be shown to be provided by an identity matrix.
//		they are three ways of expressing the same thing.
//	also finds the middle_bra, middle_diag, and middle_ket.
MATRIX_DLL_API
int matrix_3cascade_opt_channel_rate(CHN *chan1, MAT *ortho, CHN *chan3,
		double *R, double *Theta, double *rho,
		MAT *middle_bra, MAT *middle_diag, MAT *middle_ket,
		MAT *scratch_1, MAT *scratch_2, MAT *scratch_3, MAT *scratch_4,
		MAT *scratch_5, MAT *scratch_6, MAT *scratch_7, MAT *scratch_8, MAT *scratch_9);

	
//  also finds the effective correlation coefficeint rho -- caution:  do not use for linear-regression -- and
//		the Information Theoretic channel rate R and angle Theta.  It stores these three values into the chan
//		they are three ways of expressing the same thing.
//	the R_opt, Theta_opt, and rho_opt are those that result from an optimum middle channel,
//		which may be shown to be provided by an identity matrix.
//  constructs the cascaded channel from the first channel,
//		the second channel represented by an ortho-normal array, and the third channel.
MATRIX_DLL_API
int matrix_3cascade(CHN *chan1, MAT *ortho, CHN *chan3, CHN *chan,
					double *R_opt, double *Theta_opt, double *rho_opt,
					MAT *scratch_1, MAT *scratch_2, MAT *scratch_3, MAT *scratch_4, MAT *scratch_5);





//		********* five specialized routines for construction *********************

//	yields an ortho-normal array of the of the designated size.
//	if sw is 1; the array_in, must by ortho-normal,
//		else will error-out with a return of 8.
//	sw:  0=identity, 1=transpose, 2=random.
MATRIX_DLL_API
int matrix_orthonormal_xxx(unsigned long sw, unsigned long size,
						   MAT *array_in, MAT *array, MAT *scratch_1,
						   MAT *scratch_2, MAT *scratch_3, MAT *scratch_4,
						   MAT *scratch_5);


//	yields a diagonal array of the designated size,
//		whose first element is equal to start and
//		subsequent elements are in a geometric-progression with the specified ratio.
//	WARNING:  intentionally no diagnostics, so that we may check downstreem diagnostics.
MATRIX_DLL_API
int matrix_diagonal_xxx(unsigned long size, double start, double ratio, MAT *array);


//	yields a horizontal-vector of the designated size.
//	sw:  0=zero, 1=random.
MATRIX_DLL_API
int matrix_vect_xxx(unsigned long sw, unsigned long size, MAT *array);


//	yields a channel of small-size size.
//	see the prededing three routines for sw, start, and ratio.
//	WARNING:  intentionally no diagnostics, so that we may check downstreem diagnostics.
//		each of start_LDIAG, ratio_LDIAG, start_RDIAG, and ratio_RDIAG should be strictly positive.
//		the magnitude of each of start_MDIAG and ratio_MDIAG should be strictly less than one.
MATRIX_DLL_API
int matrix_channel_xxx(unsigned long size, unsigned long sw_LBRA, unsigned long sw_MBRA,
					   unsigned long sw_MKET, unsigned long sw_RKET,
					   unsigned long sw_LAVE, unsigned long sw_RAVE,
					   double start_LDIAG, double ratio_LDIAG,
					   double start_MDIAG, double ratio_MDIAG,
					   double start_RDIAG, double ratio_RDIAG,
					   CHN *chan, MAT *exterior_bra, MAT *exterior_diag,
					   MAT *interior_bra, MAT *interior_diag, double *R, double *Theta, double *rho,
					   MAT *scratch_1, MAT *scratch_2, MAT *scratch_3,
					   MAT *scratch_4, MAT *scratch_5, MAT *scratch_6);


//	compares each of the corresponding elements of a pair of channels.
//	the sum of the individual relative values is stored into relative[ELEVEN_MX].
//	NOTE:  these test is insufficiently sophisticated for testing a degenerate matrix.
//		that is, for a degenerate matrix, it almost always, it will yield a
//		false positive -- not equal -- for the corresponding ortho-normal matrix.
//		not to worry:  a matrix is degenerate almost never.
//		except, of course, when it is constructed explicitly to be so.  :-)
//		also, the ortho-normal matrices usually will not test equal if they are constructed
//			by different algorithms:  bi-linear, Gramm-Schmidt, or Jacobi.
//	in short, if the relative[ELEVEN_MX] is acceptably small (in magnitude);
//		then, the two channels are equal.  However, otherwise, the result is not decisive.
MATRIX_DLL_API
int matrix_isit_equal_channels(CHN *chan_a, CHN *chan_b, double relative[ELEVEN_MX + 1],
							   MAT *scratch_1, MAT *scratch_2);




// copyright (c) 2003,4 by R.I. 'Scibor-Marchocki.  last modified Monday 17-th May 2004.
