/*****

*Property of the University of British Columbia (UBC),

*Copyright 2001, by UBC.

*

*By receiving this code, you are agreeing to the following terms:

*1. You will use this code for academic purposes only.

*2. For academic use only, you may distribute the binary or executable code

*   to persons at UBC or the Univ. of Western Australia who have previously 

*   read and agreed to these terms, but you must distribute the SOURCE code

*   with it. 

*3. Each file of source code so distributed must have this header attached.

*4. If the code is revised, the programmer's name and revision date must be added

*   to the Revision List below, as well as the revisions identified in the code.

*5. You will not make this code more widely available via any method such as 

*   publishing in print, email mail-list, usenet posting, website etc.

*6. UBC reserves all rights to this work and all derivative works.

*

*For other proposed purposes please contact:

*The University-Industry Liaison Office 

*IRC Room 331 - 2194 Health Sciences Mall 

*University of British Columbia 

*Vancouver, BC, Canada V6T 1Z3 

*Tel: (604) 822-8580 

*Fax: (604) 822-8589 

*

*or contact: 

*Peter D. Lawrence, Professor at peterl@ece.ubc.ca or 

*Greg Z. Grudic, Assistant Professor, at grudic@cs.colorado.edu

*

*Revision List: 

*Greg Grudic, August 28, 1998.

*****/


/*

%

% File:		b_pc.c

% Program: 	Functions for building and saving a Poly_Cascade

%

% Author:	Greg Grudic

%

*/


#include "b_pc.h"

#undef PRINT_INNER_LOOP_ERROR
#define PRINT_OUTER_LOOP_ERROR

extern FILE *fp_RES_OUTPUT;

void Delete_to_Best_Inner_Loop_Error(Build_Cas_Poly *b_pc)
{
	Error_Struc *t_es;
	int i;
	Mse_Struct *t_mse;
	void Delete_mse_st(Build_Cas_Poly *b_pc);
	
	if ( b_pc->il_be_ind == -1 )
    {
		Delete_mse_st(b_pc);
		
		t_es = (Error_Struc *)
			malloc((unsigned)b_pc->curr_num_of_bags * sizeof(Error_Struc));
		if (!(t_es))
		{
			My_Error("Cannot allocate t_es!!\n");
		}
		
		b_pc->err_pt = b_pc->err_st;
		for ( i = 0; i < b_pc->curr_num_of_bags; i++ )
		{
			t_es[i].n_e = b_pc->err_pt;
			b_pc->err_pt = b_pc->err_pt->n_e;
		}
		
		for ( i = b_pc->curr_num_of_bags - 1; i >= 0; i-- )
		{
			free(t_es[i].n_e->pp);
			free(t_es[i].n_e);
		}
		
		b_pc->pc->num_of_levels = b_pc->pc->num_of_levels - 
			(b_pc->curr_num_of_bags);
		
		b_pc->curr_num_of_bags = 0;
		
		for ( i = 0; i < b_pc->num_lrn_ex; i++ )
		{
			b_pc->h_p_lrn[i] = b_pc->h_p_lrn_best[i];
			b_pc->curr_to_lrn[i] = b_pc->curr_to_lrn_best[i];
		}
		
		for ( i = 0; i < b_pc->num_val_ex; i++ )
		{
			b_pc->h_p_val[i] = b_pc->h_p_val_best[i];
			b_pc->curr_to_val[i] = b_pc->curr_to_val_best[i];
		}
		
		free(t_es);
		
		b_pc->c_p = b_pc->last_poly_prev_inner_loop;
    }
	else
    {
		t_mse = (Mse_Struct *)
			malloc((unsigned)b_pc->curr_num_of_bags * sizeof(Mse_Struct));
		if (!(t_mse))
		{
			My_Error("Cannot allocate t_mse!!\n");
		}
		
		b_pc->mse_pt = b_pc->mse_st;
		b_pc->mse_inv_tot = 0.0;
		for ( i = 0; i < b_pc->curr_num_of_bags; i++ )
		{
			if ( i <= b_pc->il_be_ind )
			{
				b_pc->mse_inv_tot = b_pc->mse_inv_tot + b_pc->mse_pt->mse_inv;
				b_pc->mse_pt = b_pc->mse_pt->next_mse;
			}
			else
			{
				t_mse[i].next_mse = b_pc->mse_pt;
				b_pc->mse_pt = b_pc->mse_pt->next_mse;	  
			}
		}
		
		for ( i = b_pc->curr_num_of_bags - 1; i > b_pc->il_be_ind; i-- )
		{
			free(t_mse[i].next_mse);
		}
		
		free(t_mse);
		
		t_es = (Error_Struc *)
			malloc((unsigned)b_pc->curr_num_of_bags * sizeof(Error_Struc));
		if (!(t_es))
		{
			My_Error("Cannot allocate t_es!!\n");
		}
		
		b_pc->err_pt = b_pc->err_st;
		for ( i = 0; i < b_pc->curr_num_of_bags; i++ )
		{
			t_es[i].n_e = b_pc->err_pt;
			b_pc->err_pt = b_pc->err_pt->n_e;
		}
		
		for ( i = b_pc->curr_num_of_bags - 1; i >= 0; i-- )
		{
			if ( i > b_pc->il_be_ind )
			{
				free(t_es[i].n_e->pp);
				free(t_es[i].n_e);
			}
			else if ( b_pc->il_be_ind == i )
			{
				t_es[i].n_e->pp->np = NULL;
				b_pc->curr_const_tot = t_es[i].n_e->tot_b_val;
				b_pc->c_p = t_es[i].n_e->pp;
				free(t_es[i].n_e);
			}
			else
			{
				free(t_es[i].n_e);
			}
		}
		
		b_pc->pc->num_of_levels = b_pc->pc->num_of_levels - 
			(b_pc->curr_num_of_bags - b_pc->il_be_ind) + 1;
		
		b_pc->curr_num_of_bags = b_pc->il_be_ind + 1;
		
		for ( i = 0; i < b_pc->num_lrn_ex; i++ )
		{
			b_pc->h_p_lrn[i] = b_pc->h_p_lrn_best[i];
			b_pc->curr_to_lrn[i] = b_pc->curr_to_lrn_best[i];
		}
		
		for ( i = 0; i < b_pc->num_val_ex; i++ )
		{
			b_pc->h_p_val[i] = b_pc->h_p_val_best[i];
			b_pc->curr_to_val[i] = b_pc->curr_to_val_best[i];
		}
		
		free(t_es);
    }
}


void Delete_mse_st(Build_Cas_Poly *b_pc)
{
	Mse_Struct *t_mse;
	int i;
	
	t_mse = (Mse_Struct *)
		malloc((unsigned)b_pc->curr_num_of_bags * sizeof(Mse_Struct));
	if (!(t_mse))
    {
		My_Error("Cannot allocate t_mse!!\n");
    }
	
	b_pc->mse_pt = b_pc->mse_st;
	for ( i = 0; i < b_pc->curr_num_of_bags; i++ )
    {
		t_mse[i].next_mse = b_pc->mse_pt;
		b_pc->mse_pt = b_pc->mse_pt->next_mse;
    }
	
	for ( i = b_pc->curr_num_of_bags - 1; i >= 0; i-- )
    {
		free(t_mse[i].next_mse);
    }
	
	free(t_mse);
}



void Delete_Poly_Cascade(Cascade_Poly *pc)
{
	Poly_Delete_Structure *pp;
	Poly *cp;
	
	int i;
	
	pp = (Poly_Delete_Structure *)
		malloc((unsigned)pc->num_of_levels * sizeof(Poly_Delete_Structure));
	if (!(pp))
    {
		My_Error("Cannot allocate Poly_Delete_Structure structure!!\n");
    }
	
	cp = pc->first_poly;
	for ( i = 0; i < (int)pc->num_of_levels; i++ )
    {
		pp[i].pp = cp;
		cp = cp->np;
    }
	
	for ( i = pc->num_of_levels-1; i >= 0; i-- )
    {
		pp[i].pp->np = NULL;
		free(pp[i].pp);
    }
	
	free(pc->m_scale);
	free(pc->b_scale);
	free(pc->x_s);
	free(pp);
}

void New_Save_Poly_Cascade(Cascade_Poly *pc, FILE *fp)

{

	void Copy_PC_to_Char_Sting(Cascade_Poly *pc, char **save_buff, int *length);

	

	int lenght, numwriten;

	char *save_buff;

	

	Copy_PC_to_Char_Sting(pc,&save_buff,&lenght);

	

	/**** Save_to_file ******/  

	numwriten = fwrite(&(lenght),sizeof(int),1,fp);

	if ( numwriten != 1)

		My_Error("Poly Save Error");

	

	numwriten = fwrite(save_buff,sizeof(char),lenght,fp);

	if ( numwriten != lenght)

		My_Error("Poly Save Error");

	

	/************************/

	

	free(save_buff);

}



void Copy_PC_to_Char_Sting(Cascade_Poly *pc, char **save_buff, int *length)

{

	int i, i_tmp, j, k;

	Poly *cp;

	int cnt, cnt_max;

	

	char *ptr;

	
	/** first count the total number of bytes **/
	cnt = 0;
	cnt = cnt + (int)sizeof(int); /* POLY_DIM */
	cnt = cnt + (int)sizeof(int); /* POLY_TERMS */
	
	cnt = cnt + (int)sizeof(unsigned int); /* pc->dim  */
	cnt = cnt + (int)sizeof(unsigned int); /* pc->first_input  */
	cnt = cnt + (int)sizeof(unsigned int); /* pc->num_of_levels  */
	
	cnt = cnt + (int)sizeof(My_Real); /* pc->ave_value  */
	
	cnt = cnt + (int)pc->dim * (int)sizeof(My_Real); /* pc->m_scale  */
	cnt = cnt + (int)pc->dim * (int)sizeof(My_Real); /* pc->b_scale  */
	
	
	cp = pc->first_poly;
	for ( i = 0; i < (int)pc->num_of_levels; i++ )
    {

		cnt = cnt + LEVEL_INPUTS * (int)sizeof(unsigned int); /* pc->input_num */
		cnt = cnt + POLY_TERMS * (int)sizeof(My_Real);        /* pc->a  */
		cnt = cnt + (int)sizeof(My_Real);               /* pc->scale_to_output*/
		cnt = cnt + (int)sizeof(My_Real);               /* pc->m_scale_out  */
		cnt = cnt + (int)sizeof(My_Real);               /* pc->b_scale_out  */
		
		cp = cp->np;
    }
	
	cnt_max = cnt;

	*length = cnt_max;
	/*******************************************/
	
	/** Initialize the Save Buffer **/
	
	(*save_buff) = (char *) malloc((unsigned)cnt_max);
	if (!((*save_buff)))
    {
		My_Error("Cannot allocate (*save_buff)!!\n");
    }
	
	/********************************/
	
	
	/**** transfer data to the (*save_buff) ****/
	
	cnt = 0;
	
	/* i_tmp = POLY_DIM;
	fwrite(&(i_tmp),sizeof(int),1,fp); */
	i_tmp = POLY_DIM;
	ptr = (char *)(&i_tmp);
	for ( j = 0; j < sizeof(int); j++ )
    {
		(*save_buff)[cnt] = ptr[j];
		cnt = cnt + 1;
    }
	
	/* i_tmp = POLY_TERMS;
	fwrite(&(i_tmp),sizeof(int),1,fp); */
	i_tmp = POLY_TERMS;
	ptr = (char *)(&i_tmp);
	for ( j = 0; j < sizeof(int); j++ )
    {
		(*save_buff)[cnt] = ptr[j];
		cnt = cnt + 1;
    }
	
	/* fwrite(&(pc->dim),sizeof(unsigned int),1,fp); */
	ptr = (char *)(&(pc->dim));
	for ( j = 0; j < sizeof(unsigned int); j++ )
    {
		(*save_buff)[cnt] = ptr[j];
		cnt = cnt + 1;
    }
	
	/* fwrite(&(pc->first_input),sizeof(unsigned int),1,fp); */
	ptr = (char *)(&(pc->first_input));
	for ( j = 0; j < sizeof(unsigned int); j++ )
    {
		(*save_buff)[cnt] = ptr[j];
		cnt = cnt + 1;
    }
	
	/* fwrite(&(pc->num_of_levels),sizeof(unsigned int),1,fp); */
	ptr = (char *)(&(pc->num_of_levels));
	for ( j = 0; j < sizeof(unsigned int); j++ )
    {
		(*save_buff)[cnt] = ptr[j];
		cnt = cnt + 1;
    }
	
	/* fwrite(&(pc->ave_value),sizeof(My_Real),1,fp); */
	ptr = (char *)(&(pc->ave_value));
	for ( j = 0; j < sizeof(My_Real); j++ )
    {
		(*save_buff)[cnt] = ptr[j];
		cnt = cnt + 1;
    }
	
	/* fwrite((pc->m_scale),sizeof(My_Real),pc->dim,fp); */
	for ( k = 0; k < (int)pc->dim; k++ )
    {
		ptr = (char *)(&(pc->m_scale[k]));
		for ( j = 0; j < sizeof(My_Real); j++ )
		{
			(*save_buff)[cnt] = ptr[j];
			cnt = cnt + 1;
		}
    }
	
	/* fwrite((pc->b_scale),sizeof(My_Real),pc->dim,fp); */
	for ( k = 0; k < (int)pc->dim; k++ )
    {
		ptr = (char *)(&(pc->b_scale[k]));
		for ( j = 0; j < sizeof(My_Real); j++ )
		{
			(*save_buff)[cnt] = ptr[j];
			cnt = cnt + 1;
		}
    }
	
	cp = pc->first_poly;
	for ( i = 0; i < (int)pc->num_of_levels; i++ )
    {
		/* fwrite((cp->input_num),sizeof(unsigned int),LEVEL_INPUTS,fp); */
		for ( k = 0; k < LEVEL_INPUTS; k++ )
		{
			ptr = (char *)(&(cp->input_num[k]));
			for ( j = 0; j < sizeof(unsigned int); j++ )
			{
				(*save_buff)[cnt] = ptr[j];
				cnt = cnt + 1;
			}
		}
		
		/* fwrite((cp->a),sizeof(My_Real),POLY_TERMS,fp); */
		for ( k = 0; k < POLY_TERMS; k++ )
		{
			ptr = (char *)(&(cp->a[k]));
			for ( j = 0; j < sizeof(My_Real); j++ )
			{
				(*save_buff)[cnt] = ptr[j];
				cnt = cnt + 1;
			}
		}
		
		/* fwrite(&(cp->scale_to_output),sizeof(My_Real),1,fp); */
		ptr = (char *)(&(cp->scale_to_output));
		for ( j = 0; j < sizeof(My_Real); j++ )
		{
			(*save_buff)[cnt] = ptr[j];
			cnt = cnt + 1;
		}
		
		/* fwrite(&(cp->m_scale_out),sizeof(My_Real),1,fp); */  
		ptr = (char *)(&(cp->m_scale_out));
		for ( j = 0; j < sizeof(My_Real); j++ )
		{
			(*save_buff)[cnt] = ptr[j];
			cnt = cnt + 1;
		}
		
		/* fwrite(&(cp->b_scale_out),sizeof(My_Real),1,fp); */
		ptr = (char *)(&(cp->b_scale_out));
		for ( j = 0; j < sizeof(My_Real); j++ )
		{
			(*save_buff)[cnt] = ptr[j];
			cnt = cnt + 1;
		}
		
		
		cp = cp->np;
    }
	
	if ( cnt != cnt_max )
    {
		My_Error("Error in New_Save_Poly_Cascade: cnt != cnt_max !!\n");
    }
	/****************************************/
}

void Save_Poly_Cascade(Cascade_Poly *pc, FILE *fp)
{
	int i, i_tmp;
	Poly *cp;
	int numwriten;
	
	i_tmp = POLY_DIM;
	numwriten = fwrite(&(i_tmp),sizeof(int),1,fp);
	if ( numwriten != 1)
		My_Error("Poly Save Error");
	
	i_tmp = POLY_TERMS;
	numwriten = fwrite(&(i_tmp),sizeof(int),1,fp);
	if ( numwriten != 1)
		My_Error("Poly Save Error");
	
	
	numwriten = fwrite(&(pc->dim),sizeof(unsigned int),1,fp);
	if ( numwriten != 1)
		My_Error("Poly Save Error");
	
	numwriten = fwrite(&(pc->first_input),sizeof(unsigned int),1,fp);
	if ( numwriten != 1)
		My_Error("Poly Save Error");
	
	numwriten = fwrite(&(pc->num_of_levels),sizeof(unsigned int),1,fp);
	if ( numwriten != 1)
		My_Error("Poly Save Error");
	
	
	numwriten = fwrite(&(pc->ave_value),sizeof(My_Real),1,fp);
	if ( numwriten != 1)
		My_Error("Poly Save Error");
	
	
	numwriten = fwrite((pc->m_scale),sizeof(My_Real),pc->dim,fp);
	if ( numwriten != (int)pc->dim)
		My_Error("Poly Save Error");
	
	numwriten = fwrite((pc->b_scale),sizeof(My_Real),pc->dim,fp);
	if ( numwriten != (int)pc->dim)
		My_Error("Poly Save Error");
	
	
	cp = pc->first_poly;
	for ( i = 0; i < (int)pc->num_of_levels; i++ )
    {
		numwriten = fwrite((cp->input_num),sizeof(unsigned int),LEVEL_INPUTS,fp);
		if ( numwriten != LEVEL_INPUTS)
			My_Error("Poly Save Error");
		
		numwriten = fwrite((cp->a),sizeof(My_Real),POLY_TERMS,fp);
		if ( numwriten != POLY_TERMS)
			My_Error("Poly Save Error");
		
		numwriten = fwrite(&(cp->scale_to_output),sizeof(My_Real),1,fp);   
		if ( numwriten != 1)
			My_Error("Poly Save Error");
		
		numwriten = fwrite(&(cp->m_scale_out),sizeof(My_Real),1,fp);   
		if ( numwriten != 1)
			My_Error("Poly Save Error");
		
		numwriten = fwrite(&(cp->b_scale_out),sizeof(My_Real),1,fp);
		if ( numwriten != 1)
			My_Error("Poly Save Error");
		
		
		cp = cp->np;
    }
}






void Test_Load_Poly_Cascade(Cascade_Poly *pc_t)
{
	int i, i_tmp1, i_tmp2, kk;
	Poly *cp, *cp_t;
	Cascade_Poly *pc;
	FILE *fp;
	
	int numread;
	
	/**** initialize pc *****/
	pc = (Cascade_Poly *)
		malloc((unsigned)sizeof(Cascade_Poly));
	if (!(pc))
    {
		My_Error("Cannot allocate Cascade_Poly structure!!\n");
    }
	/************************/
	
	if ((fp = fopen("pc.s","r")) == NULL)
    {
		fprintf(fp_RES_OUTPUT,"Couldn't open \"%s\"\n","pc.s");

		printf("Couldn't open \"%s\"\n","pc.s");

    }
	
	numread = fread(&(i_tmp1),sizeof(int),1,fp);
	numread = fread(&(i_tmp2),sizeof(int),1,fp);
	
	if ( (i_tmp1 != POLY_DIM)  ||  (i_tmp2 != POLY_TERMS) )
    {
		printf("Program compiled for: POLY_DIM = %d, POLY_TERMS = %d\n",
			POLY_DIM, POLY_TERMS);
		printf("pc.s requires: POLY_DIM = %d, POLY_TERMS = %d\n",
			i_tmp1, i_tmp2);
		exit(-1);
    }
	
	numread = fread(&(pc->dim),sizeof(unsigned int),1,fp);
	if ( pc->dim != pc_t->dim )
		My_Error("Poly Read Error");
	
	numread = fread(&(pc->first_input),sizeof(unsigned int),1,fp);
	if ( pc->first_input != pc_t->first_input )
		My_Error("Poly Read Error");
	
	numread = fread(&(pc->num_of_levels),sizeof(unsigned int),1,fp);
	if ( pc->num_of_levels != pc_t->num_of_levels )
		My_Error("Poly Read Error");
	
	
	numread = fread(&(pc->ave_value),sizeof(My_Real),1,fp);
	if ( pc->ave_value != pc_t->ave_value )
		My_Error("Poly Read Error");
	
	
	pc->x_s = (My_Real *)
		malloc((unsigned)pc->dim * (sizeof(My_Real)));
	if (!(pc->x_s))
    {
		printf("Cannot allocate pc->x_s!!\n");
    }
	
	pc->m_scale = (My_Real *)
		malloc((unsigned)pc->dim * (sizeof(My_Real)));
	if (!(pc->m_scale))
    {
		printf("Cannot allocate pc->m_scale!!\n");
    }
	
	pc->b_scale = (My_Real *)
		malloc((unsigned)pc->dim * (sizeof(My_Real)));
	if (!(pc->b_scale))
    {
		printf("Cannot allocate b_pc->pc->b_scale!!\n");
    } 
	
	numread = fread((pc->m_scale),sizeof(My_Real),pc->dim,fp);
	for ( kk = 0; kk < (int)pc->dim; kk++ )
    {
		if ( pc->m_scale[kk] != pc_t->m_scale[kk] )
			My_Error("Poly Read Error");
    }
	
	numread = fread((pc->b_scale),sizeof(My_Real),pc->dim,fp);
	for ( kk = 0; kk < (int)pc->dim; kk++ )
    {
		if ( pc->b_scale[kk] != pc_t->b_scale[kk] )
			My_Error("Poly Read Error");
    }
	
	pc->first_poly = (Poly *)
		malloc((unsigned)(sizeof(Poly)));
	if (!(pc->first_poly))
    {
		printf("Cannot allocate pc->first_poly!!\n");
    }
	
	cp_t = pc_t->first_poly;
	cp = pc->first_poly;
	cp->np = NULL;
	for ( i = 0; i < (int)pc->num_of_levels; i++ )
    {
		numread = fread((cp->input_num),sizeof(unsigned int),LEVEL_INPUTS,fp);
		for ( kk = 0; kk < LEVEL_INPUTS; kk++ )
		{
			if ( cp->input_num[kk] != cp_t->input_num[kk])
				My_Error("Poly Read Error");
		}
		
		numread = fread((cp->a),sizeof(My_Real),POLY_TERMS,fp);
		for ( kk = 0; kk < POLY_TERMS; kk++ )
		{
			if ( cp->a[kk] != cp_t->a[kk])
				My_Error("Poly Read Error");
		}
		
		numread = fread(&(cp->scale_to_output),sizeof(My_Real),1,fp);   
		if ( cp->scale_to_output != cp_t->scale_to_output )
			My_Error("Poly Read Error");
		
		numread = fread(&(cp->m_scale_out),sizeof(My_Real),1,fp);   
		if ( cp->m_scale_out != cp_t->m_scale_out )
			My_Error("Poly Read Error");
		
		numread = fread(&(cp->b_scale_out),sizeof(My_Real),1,fp);
		if ( cp->b_scale_out != cp_t->b_scale_out )
			My_Error("Poly Read Error");
		
		
		if ( i < (int)pc->num_of_levels - 1 )
		{
			cp->np = (Poly *)
				malloc((unsigned)(sizeof(Poly)));
			if (!(cp->np))
			{
				printf("Cannot allocate cp->np!!\n");
			}
			
			cp = cp->np;
			cp_t = cp_t->np;
			cp->np = NULL;
		}
    }
	
	fclose(fp);
	
	/**** delete the approximations *****/
	Delete_Poly_Cascade(pc);
	free(pc);
	/************************************/
}



void Build_Poly_Cascade(Build_Cas_Poly *b_pc,
						void (*Get_Lrn_Ex_Input)(int ex_num, 
						int var, 
						My_Real *in),
						void (*Get_Lrn_Ex_Output)(int ex_num, 
						My_Real *out),
						void (*Get_Val_Ex_Input)(int ex_num, 
						int var, 
						My_Real *in),
						void (*Get_Val_Ex_Output)(int ex_num, 
						My_Real *out),
						My_Real *mse_lrn, My_Real *mse_val)
{
	int i;
	
	My_Real t1;
	
	void Build_Cascade(Build_Cas_Poly *b_pc,
		void (*Get_Lrn_Ex_Input)(int ex_num, 
		int var, 
		My_Real *in),
		void (*Get_Val_Ex_Input)(int ex_num, 
		int var, 
		My_Real *in));
	
	int Select_Input_Number(Build_Cas_Poly *b_pc);
	
	void Delete_Learn_Stuff(Build_Cas_Poly *b_pc);
	
	void Define_Input_Scaling(Build_Cas_Poly *b_pc,
		void (*Get_Lrn_Ex_Input)(int ex_num, 
		int var, 
		My_Real *in));
	
	void Define_Output_Scaling(Build_Cas_Poly *b_pc);
	void Define_Ave_Value_And_Sub(Build_Cas_Poly *b_pc);
	
	void Set_Lrn_Val_Outputs(Build_Cas_Poly *b_pc,
		void (*Get_Lrn_Ex_Output)(int ex_num, 
		My_Real *out),
		void (*Get_Val_Ex_Output)(int ex_num, 
		My_Real *out));
	
	/**** some initial stuff ******/
	if ( b_pc->num_lrn_ex > 50000 )
    {
		b_pc->lrn_num = 50000;
    }
	else
    {
		b_pc->lrn_num = b_pc->num_lrn_ex;
    }
	
	if ( b_pc->lrn_num >  100000 )
    {
		b_pc->cnt_Lrn_Num_Sch = 0;
		b_pc->Lrn_Num_Sch[0] = (int)(0.25 * (My_Real)b_pc->lrn_num);
		b_pc->Lrn_Num_Sch[1] = (int)(0.5 * (My_Real)b_pc->lrn_num);
		b_pc->Lrn_Num_Sch[2] = (int)(0.75 * (My_Real)b_pc->lrn_num);
		b_pc->Lrn_Num_Sch[3] = b_pc->lrn_num;
		
		b_pc->lrn_num = b_pc->Lrn_Num_Sch[0];
    }
	else
    {
		b_pc->cnt_Lrn_Num_Sch = 4;
		b_pc->Lrn_Num_Sch[0] = 0;
		b_pc->Lrn_Num_Sch[1] = 0;
		b_pc->Lrn_Num_Sch[2] = 0;
		b_pc->Lrn_Num_Sch[3] = 0;
    }
	
	b_pc->p_mat_array = (My_Real *)
		malloc((unsigned)(b_pc->lrn_num * POLY_TERMS * (sizeof(My_Real))));
	if (!(b_pc->p_mat_array))
    {
		My_Error("Cannot allocate b_pc->p_mat_array!!\n");
    }
	
	b_pc->dres_tm = (My_Real *)
		malloc((unsigned)(POLY_TERMS * POLY_TERMS * (sizeof(My_Real))));
	if (!(b_pc->dres_tm))
    {
		My_Error("Cannot allocate b_pc->dres_tm!!\n");
    }
	
	b_pc->p_b_all = (My_Real *)
		malloc((unsigned)(b_pc->lrn_num * (sizeof(My_Real))));
	if (!(b_pc->p_b_all))
    {
		My_Error("Cannot allocate b_pc->p_b_all!!\n");
    }
	
	b_pc->p_mat = Create_Matrix(2 * POLY_TERMS,POLY_TERMS);
	b_pc->p_b = (My_Real *)malloc((unsigned)(POLY_TERMS * (sizeof(My_Real))));
	if (!(b_pc->p_b))
    {
		My_Error("Cannot allocate b_pc->p_b!!\n");
    }  
	b_pc->p_sv = (My_Real *)malloc((unsigned)(POLY_TERMS * (sizeof(My_Real))));
	if (!(b_pc->p_sv))
    {
		My_Error("Cannot allocate b_pc->p_sv!!\n");
    }
	
	b_pc->p_c = (My_Real *)malloc((unsigned)(POLY_TERMS * (sizeof(My_Real))));
	if (!(b_pc->p_c))
    {
		My_Error("Cannot allocate b_pc->p_c!!\n");
    }
	
	b_pc->s_mat_array = (My_Real *)
		malloc((unsigned)(b_pc->num_lrn_ex * 2 * (sizeof(My_Real))));
	if (!(b_pc->s_mat_array))
    {
		My_Error("Cannot allocate b_pc->s_mat_array!!\n");
    }
	
	b_pc->s_dres_tm = (My_Real *)
		malloc((unsigned)(2 * 2 * (sizeof(My_Real))));
	if (!(b_pc->s_dres_tm))
    {
		My_Error("Cannot allocate b_pc->s_dres_tm!!\n");
    }
	
	b_pc->s_b_all = (My_Real *)
		malloc((unsigned)(b_pc->num_lrn_ex * (sizeof(My_Real))));
	if (!(b_pc->s_b_all))
    {
		My_Error("Cannot allocate b_pc->s_b_all!!\n");
    }
	
	b_pc->s_mat = Create_Matrix(4,2);
	b_pc->s_b = (My_Real *)malloc((unsigned)(2 * (sizeof(My_Real))));
	if (!(b_pc->s_b))
    {
		My_Error("Cannot allocate b_pc->s_b!!\n");
    }  
	b_pc->s_sv = (My_Real *)malloc((unsigned)(2 * (sizeof(My_Real))));
	if (!(b_pc->s_sv))
    {
		My_Error("Cannot allocate b_pc->s_sv!!\n");
    }
	
	b_pc->s_c = (My_Real *)malloc((unsigned)(2 * (sizeof(My_Real))));
	if (!(b_pc->s_c))
    {
		My_Error("Cannot allocate b_pc->s_c!!\n");
    }
	
	b_pc->select_input_list = (int *)
		malloc((unsigned)b_pc->pc->dim * (sizeof(int)));
	if (!(b_pc->select_input_list))
    {
		My_Error("Cannot allocate b_pc->select_input_list!!\n");
    }
	b_pc->curr_input_ind_num = b_pc->pc->dim + 1;
	/*****************************/
	
	
#ifdef ANALYZE_INPUTS
	b_pc->ana_var_num = (My_Real *)
		malloc((unsigned)b_pc->pc->dim * (sizeof(My_Real)));
	if (!(b_pc->ana_var_num))
    {
		My_Error("Cannot allocate b_pc->ana_var_num!!\n");
    }
	
	b_pc->ana_var_tot_used = (int *)
		malloc((unsigned)b_pc->pc->dim * (sizeof(int)));
	if (!(b_pc->ana_var_tot_used))
    {
		My_Error("Cannot allocate b_pc->ana_var_tot_used!!\n");
    }
	
	for ( i = 0; i < b_pc->pc->dim; i++ )
    {
		b_pc->ana_var_num[i] = 0.0;
		b_pc->ana_var_tot_used[i] = 0;
    }
#endif  
	
	/*** initialize pc scaling ****/
	b_pc->pc->m_scale = (My_Real *)
		malloc((unsigned)b_pc->pc->dim * (sizeof(My_Real)));
	if (!(b_pc->pc->m_scale))
    {
		My_Error("Cannot allocate b_pc->pc->m_scale!!\n");
    }
	
	b_pc->pc->b_scale = (My_Real *)
		malloc((unsigned)b_pc->pc->dim * (sizeof(My_Real)));
	if (!(b_pc->pc->b_scale))
    {
		My_Error("Cannot allocate b_pc->pc->b_scale!!\n");
    }
	
	b_pc->pc->x_s = (My_Real *)
		malloc((unsigned)b_pc->pc->dim * (sizeof(My_Real)));
	if (!(b_pc->pc->x_s))
    {
		My_Error("Cannot allocate b_pc->pc->x_s!!\n");
    } 
	/******************************/
	
	Set_Lrn_Val_Outputs(b_pc,Get_Lrn_Ex_Output,Get_Val_Ex_Output);
	
	Define_Ave_Value_And_Sub(b_pc);
	
	Define_Output_Scaling(b_pc);
	
	Define_Input_Scaling(b_pc, Get_Lrn_Ex_Input);
	
	/*** some more initialization ****/
	b_pc->pc->num_of_levels = 0;
	b_pc->pc->first_input = Select_Input_Number(b_pc);
	
	b_pc->h_p_lrn = (My_Real *)
		malloc((unsigned)b_pc->num_lrn_ex * (sizeof(My_Real)));
	if (!(b_pc->h_p_lrn))
    {
		My_Error("Cannot allocate b_pc->h_p_lrn!!\n");
    }
	
	b_pc->curr_o_lrn = (My_Real *)
		malloc((unsigned)b_pc->num_lrn_ex * (sizeof(My_Real)));
	if (!(b_pc->curr_o_lrn))
    {
		My_Error("Cannot allocate b_pc->curr_o_lrn!!\n");
    }
	
	b_pc->curr_to_lrn = (My_Real *)
		malloc((unsigned)b_pc->num_lrn_ex * (sizeof(My_Real)));
	if (!(b_pc->curr_to_lrn))
    {
		My_Error("Cannot allocate b_pc->curr_to_lrn!!\n");
    }
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		Get_Lrn_Ex_Input(i,b_pc->pc->first_input, &t1);
		b_pc->h_p_lrn[i] = Scale(t1,b_pc->pc->m_scale[b_pc->pc->first_input],
			b_pc->pc->b_scale[b_pc->pc->first_input]);
		
		b_pc->curr_o_lrn[i] = 0.0;
		b_pc->curr_to_lrn[i] = 0.0;
    }
	
	b_pc->h_p_val = (My_Real *)
		malloc((unsigned)b_pc->num_val_ex * (sizeof(My_Real)));
	if (!(b_pc->h_p_val))
    {
		My_Error("Cannot allocate b_pc->h_p_val!!\n");
    }
	
	b_pc->curr_o_val = (My_Real *)
		malloc((unsigned)b_pc->num_val_ex * (sizeof(My_Real)));
	if (!(b_pc->curr_o_val))
    {
		My_Error("Cannot allocate b_pc->curr_o_val!!\n");
    }
	
	b_pc->curr_to_val = (My_Real *)
		malloc((unsigned)b_pc->num_val_ex * (sizeof(My_Real)));
	if (!(b_pc->curr_to_val))
    {
		My_Error("Cannot allocate b_pc->curr_to_val!!\n");
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		Get_Val_Ex_Input(i,b_pc->pc->first_input, &t1);
		b_pc->h_p_val[i] = Scale(t1,
			b_pc->pc->m_scale[b_pc->pc->first_input],
			b_pc->pc->b_scale[b_pc->pc->first_input]);
		
		b_pc->curr_o_val[i] = 0.0;
		b_pc->curr_to_val[i] = 0.0;
    }
	
	b_pc->h_p_val_best = (My_Real *)
		malloc((unsigned)b_pc->num_val_ex * (sizeof(My_Real)));
	if (!(b_pc->h_p_val_best))
    {
		My_Error("Cannot allocate b_pc->h_p_val_best!!\n");
    }
	
	b_pc->h_p_lrn_best = (My_Real *)
		malloc((unsigned)b_pc->num_lrn_ex * (sizeof(My_Real)));
	if (!(b_pc->h_p_lrn_best))
    {
		My_Error("Cannot allocate b_pc->h_p_lrn_best!!\n");
    }
	
	b_pc->curr_to_val_best = (My_Real *)
		malloc((unsigned)b_pc->num_val_ex * (sizeof(My_Real)));
	if (!(b_pc->curr_to_val_best))
    {
		My_Error("Cannot allocate b_pc->curr_to_val_best!!\n");
    }
	
	b_pc->curr_to_lrn_best = (My_Real *)
		malloc((unsigned)b_pc->num_lrn_ex * (sizeof(My_Real)));
	if (!(b_pc->curr_to_lrn_best))
    {
		My_Error("Cannot allocate b_pc->curr_to_lrn_best!!\n");
    }
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		b_pc->h_p_lrn_best[i] = b_pc->h_p_lrn[i];
		b_pc->curr_to_lrn_best[i] = b_pc->out_lrn[i];
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		b_pc->h_p_val_best[i] = b_pc->h_p_val[i];
		b_pc->curr_to_val_best[i] = b_pc->out_val[i];
    }
	/*********************************/
	
	
	Build_Cascade(b_pc,Get_Lrn_Ex_Input,Get_Val_Ex_Input);
	
	*mse_lrn = 0.0;
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		*mse_lrn = *mse_lrn + b_pc->out_lrn[i] * b_pc->out_lrn[i];
    }
	*mse_lrn = *mse_lrn / (My_Real)b_pc->num_lrn_ex;
	
	*mse_val = 0.0;
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		*mse_val = *mse_val + b_pc->out_val[i] * b_pc->out_val[i];
    }
	*mse_val = *mse_val / (My_Real)b_pc->num_val_ex;
	
	Delete_Learn_Stuff(b_pc);
}

void Build_Cascade(Build_Cas_Poly *b_pc,
				   void (*Get_Lrn_Ex_Input)(int ex_num, 
				   int var, 
				   My_Real *in),
				   void (*Get_Val_Ex_Input)(int ex_num, 
				   int var, 
				   My_Real *in))
{
	int cont;
	
	void Build_Poly(Build_Cas_Poly *b_pc,
		void (*Get_Lrn_Ex_Input)(int ex_num, 
		int var, 
		My_Real *in),
		void (*Get_Val_Ex_Input)(int ex_num, 
		int var, 
		My_Real *in));
	
	int Evaluate_Error(Build_Cas_Poly *b_pc);
	
	b_pc->inner_cnt = 0;
	b_pc->outer_cnt = 0;
	
	b_pc->first_poly_built = 0;
    
	b_pc->pc->first_poly = (Poly *)
		malloc((unsigned)(sizeof(Poly)));
	if (!(b_pc->pc->first_poly))
    {
		My_Error("Cannot allocate b_pc->pc->first_poly!!\n");
    }
	
	b_pc->c_p = b_pc->pc->first_poly;
	
	b_pc->address_of_1st_in_bag = b_pc->c_p;
	b_pc->curr_num_of_bags = 0;
	
	b_pc->curr_const_tot = 0.0;
	
	Build_Poly(b_pc, Get_Lrn_Ex_Input, Get_Val_Ex_Input);
	
	cont = Evaluate_Error(b_pc);
	
	while ( cont == 1 )
    {
		b_pc->c_p->np = (Poly *)
			malloc((unsigned)(sizeof(Poly)));
		if (!(b_pc->c_p->np))
		{
			My_Error("Cannot allocate b_pc->c_p->np!!\n");
		}
		
		b_pc->c_p = b_pc->c_p->np;
		
		if ( b_pc->address_of_1st_in_bag == NULL )
		{
			b_pc->address_of_1st_in_bag = b_pc->c_p;
		}
		
		Build_Poly(b_pc, Get_Lrn_Ex_Input, Get_Val_Ex_Input);
		
		cont = Evaluate_Error(b_pc);
    }
}

int Evaluate_Error(Build_Cas_Poly *b_pc)
{
	int i, update_outer_loop, ret_val;
	My_Real val_err_ave_sq, lrn_err_ave_sq, t1;
	My_Real err_change;
	
	Poly_Delete_Structure *pp;
	Poly *next_p, *cp;
	int cnt, i_min;
	void Delete_mse_st(Build_Cas_Poly *b_pc);
	
	void Delete_to_Best_Inner_Loop_Error(Build_Cas_Poly *b_pc);
	
#ifdef PRINT_INNER_LOOP_ERROR
	FILE *fp;
#endif
	
#ifdef ANALYZE_INPUTS
	FILE *fp_ana;
	char c_text[200];
#endif
	
	if ( b_pc->inner_cnt == 0 )
    {
		b_pc->mse_inv_tot = 0.0;
		b_pc->mse_st = (Mse_Struct *)malloc((unsigned)(sizeof(Mse_Struct)));
		if (!(b_pc->mse_st))
		{
			My_Error("Cannot allocate b_pc->mse_st!!\n");
		}
		b_pc->mse_st->next_mse = NULL;
		
		b_pc->mse_pt = b_pc->mse_st;
    }
	else
    {
		b_pc->mse_pt->next_mse = 
			(Mse_Struct *)malloc((unsigned)(sizeof(Mse_Struct)));
		if (!(b_pc->mse_pt->next_mse))
		{
			My_Error("Cannot allocate b_pc->mse_pt->next_mse!!\n");
		}
		
		b_pc->mse_pt = b_pc->mse_pt->next_mse;
		b_pc->mse_pt->next_mse = NULL;
    }
	
	b_pc->mse_pt->b_val = b_pc->curr_b_val;
	
	b_pc->mse_pt->mse_inv = 0.0;
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		t1 = b_pc->out_lrn[i] - b_pc->curr_o_lrn[i];
		b_pc->mse_pt->mse_inv = b_pc->mse_pt->mse_inv + t1 * t1;
    }
	b_pc->mse_pt->mse_inv = b_pc->mse_pt->mse_inv / ((My_Real)b_pc->num_val_ex);
	if ( b_pc->mse_pt->mse_inv < THRESHOLD_MIN_MAX )
    {
		b_pc->mse_pt->mse_inv = 1.0 / THRESHOLD_MIN_MAX;
    }
	else
    {
		b_pc->mse_pt->mse_inv = 1.0 / b_pc->mse_pt->mse_inv;
    }
	
	b_pc->mse_inv_tot = b_pc->mse_pt->mse_inv + b_pc->mse_inv_tot;
	
	lrn_err_ave_sq = 0.0;
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		b_pc->curr_to_lrn[i] = b_pc->curr_to_lrn[i] + 
			b_pc->mse_pt->mse_inv * b_pc->curr_o_lrn[i];
		
		t1 = b_pc->out_lrn[i] - 
			(b_pc->curr_to_lrn[i] / b_pc->mse_inv_tot);
		
		lrn_err_ave_sq = lrn_err_ave_sq + t1 * t1;
    }
	lrn_err_ave_sq = lrn_err_ave_sq / ((My_Real)b_pc->num_lrn_ex);
	
	val_err_ave_sq = 0.0;
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		b_pc->curr_to_val[i] = b_pc->curr_to_val[i] + 
			b_pc->mse_pt->mse_inv * b_pc->curr_o_val[i];
		
		t1 = b_pc->out_val[i] - 
			(b_pc->curr_to_val[i] / b_pc->mse_inv_tot);
		
		val_err_ave_sq = val_err_ave_sq + t1 * t1;
    }
	val_err_ave_sq = val_err_ave_sq / ((My_Real)b_pc->num_val_ex);
	
	if ( b_pc->inner_cnt == 0 )
    {
		b_pc->err_st = (Error_Struc *)malloc((unsigned)(sizeof(Error_Struc)));
		if (!(b_pc->err_st))
		{
			My_Error("Cannot allocate b_pc->err_st!!\n");
		}
		b_pc->err_st->n_e = NULL;
		b_pc->err_pt = b_pc->err_st;
		
		if ( b_pc->first_poly_built == 1 )
		{
			b_pc->il_be_ind = -1;
			
			b_pc->b_il_err = 0.0;
			for ( i = 0; i < b_pc->num_val_ex; i++ )
			{
				b_pc->b_il_err = b_pc->b_il_err + 
					b_pc->out_val[i] * b_pc->out_val[i];
			}
			b_pc->b_il_err = b_pc->b_il_err / (My_Real)b_pc->num_val_ex;
		}
		else
		{
			/*** force the first error to be the best ****/
			b_pc->b_il_err = 2.0 * val_err_ave_sq;
			
			b_pc->first_poly_built = 1;
			b_pc->il_be_ind = 0;
		}
    }
	else
    {
		b_pc->err_pt->n_e = 
			(Error_Struc *)malloc((unsigned)(sizeof(Error_Struc)));
		if (!(b_pc->err_pt->n_e))
		{
			My_Error("Cannot allocate b_pc->err_pt->n_e!!\n");
		}
		b_pc->err_pt->n_e->n_e = NULL;
		b_pc->err_pt = b_pc->err_pt->n_e;
    }
	
	b_pc->err_pt->err = val_err_ave_sq;
	b_pc->err_pt->pp = b_pc->c_p;
	
	b_pc->err_pt->tot_b_val = b_pc->curr_const_tot;
	
	if ( val_err_ave_sq < b_pc->b_il_err )
    {
		b_pc->il_be_ind = b_pc->inner_cnt;
		b_pc->b_il_err = val_err_ave_sq;
		
		for ( i = 0; i < b_pc->num_lrn_ex; i++ )
		{
			b_pc->h_p_lrn_best[i] = b_pc->h_p_lrn[i];
			b_pc->curr_to_lrn_best[i] = b_pc->curr_to_lrn[i];
		}
		
		for ( i = 0; i < b_pc->num_val_ex; i++ )
		{
			b_pc->h_p_val_best[i] = b_pc->h_p_val[i];
			b_pc->curr_to_val_best[i] = b_pc->curr_to_val[i];
		}
    }
	
#ifdef PRINT_INNER_LOOP_ERROR
	if ((fp = fopen("Inner_Loop_Results","a")) == NULL)
    {
		fprintf(fp_RES_OUTPUT,"Cannot open file Inner_Loop_Results\n");
		exit(-1);
    }
	
	fprintf(fp," --Inner cnt %d: mse_lrn = %g, mse_val = %g\n",
		b_pc->inner_cnt,lrn_err_ave_sq,val_err_ave_sq);
	
	fclose(fp);
	
	/*fflush(fp_RES_OUTPUT);*/
#endif
	
	if ( b_pc->inner_cnt < 25 )
    {
		b_pc->inner_err_loop[b_pc->inner_cnt] = val_err_ave_sq;
		update_outer_loop = 0;
		b_pc->inner_cnt = b_pc->inner_cnt + 1;
    }
	else
    {
		t1 = 0.0;
		for ( i = 0; i < 25; i++ )
		{
			t1 = t1 + b_pc->inner_err_loop[i];
		}
		
		t1 = t1 / (My_Real)25;
		
		if ( t1 > THRESHOLD_MIN_MAX )
		{
			err_change = (t1 - val_err_ave_sq) / t1;
		}
		else
		{
			err_change = 0.0;
		}
		
		if ( err_change < 0.0001 )
		{
			b_pc->inner_cnt = 0;
			update_outer_loop = 1;
		}
		else
		{
			b_pc->inner_cnt = b_pc->inner_cnt + 1;
			update_outer_loop = 0;
			
			for ( i = 1; i < 25; i++ )
			{
				b_pc->inner_err_loop[i-1] = b_pc->inner_err_loop[i];
			}
			
			b_pc->inner_err_loop[25-1] = val_err_ave_sq;
		}
    }
	
	if ( update_outer_loop == 1 )
    {
		Delete_to_Best_Inner_Loop_Error(b_pc);
		
		if ( b_pc->curr_num_of_bags > 0 )
		{
			lrn_err_ave_sq = 0.0;
			for ( i = 0; i < b_pc->num_lrn_ex; i++ )
			{
				b_pc->out_lrn[i] = b_pc->out_lrn[i] - 
					(b_pc->curr_to_lrn[i] / b_pc->mse_inv_tot);
				
				lrn_err_ave_sq = lrn_err_ave_sq + 
					(b_pc->out_lrn[i] * b_pc->out_lrn[i]);
				
				b_pc->curr_to_lrn[i] = 0.0;
			}
			lrn_err_ave_sq = lrn_err_ave_sq / ((My_Real)b_pc->num_lrn_ex);
			
			val_err_ave_sq = 0.0;
			for ( i = 0; i < b_pc->num_val_ex; i++ )
			{
				b_pc->out_val[i] = b_pc->out_val[i] - 
					(b_pc->curr_to_val[i] / b_pc->mse_inv_tot);
				
				val_err_ave_sq = val_err_ave_sq + 
					(b_pc->out_val[i] * b_pc->out_val[i]);
				
				b_pc->curr_to_val[i] = 0.0;
			}
			val_err_ave_sq = val_err_ave_sq / ((My_Real)b_pc->num_val_ex);
			
			
			b_pc->mse_pt = b_pc->mse_st;
			
			b_pc->address_of_1st_in_bag->scale_to_output = 
				(b_pc->mse_pt->mse_inv * 
				b_pc->address_of_1st_in_bag->scale_to_output / b_pc->mse_inv_tot);
			
			b_pc->curr_const_tot = b_pc->mse_pt->mse_inv * b_pc->mse_pt->b_val;
			
#ifdef ANALYZE_INPUTS
			b_pc->ana_var_cnt = 0;
#endif  
			next_p = b_pc->address_of_1st_in_bag->np;
			b_pc->mse_pt = b_pc->mse_pt->next_mse;
			while ( next_p != NULL )
			{
				next_p->scale_to_output = 
					(b_pc->mse_pt->mse_inv * next_p->scale_to_output / 
					b_pc->mse_inv_tot);
				
#ifdef ANALYZE_INPUTS
				if ( b_pc->ana_var_cnt == 0)
				{
					b_pc->ana_var_prev_alpha = b_pc->mse_pt->mse_inv;
					b_pc->ana_var_cnt = 1;
				}
				else
				{
					t1 = (b_pc->mse_pt->mse_inv - b_pc->ana_var_prev_alpha) / 
						b_pc->mse_inv_tot;
					
					b_pc->ana_var_num[next_p->input_num[0]] = 
						b_pc->ana_var_num[next_p->input_num[0]] + t1;
						/*
						if (b_pc->ana_var_num[next_p->input_num[0]] < t1 )
						{
						b_pc->ana_var_num[next_p->input_num[0]] = t1;
						}
					*/
					
					b_pc->ana_var_tot_used[next_p->input_num[0]] = 
						b_pc->ana_var_tot_used[next_p->input_num[0]] + 1;
					
					/** print to file **/
					sprintf(c_text, "Var%d", next_p->input_num[0]);
					if ((fp_ana = fopen(c_text,"a")) == NULL)
					{
						fprintf(fp_RES_OUTPUT,"Cannot open file %s\n",c_text);
						exit(-1);
					}
					
					fprintf(fp_ana,"%d %g %g %g %g %g\n",
						b_pc->ana_var_tot_used[next_p->input_num[0]],
						b_pc->ana_var_num[next_p->input_num[0]],
						b_pc->mse_pt->mse_inv, b_pc->ana_var_prev_alpha,
						(b_pc->mse_pt->mse_inv / b_pc->ana_var_prev_alpha),
						t1);
					
					fclose(fp_ana);
					/*********************/
					
					b_pc->ana_var_prev_alpha = b_pc->mse_pt->mse_inv;
				}
#endif  
				
				b_pc->curr_const_tot = b_pc->curr_const_tot + 
					b_pc->mse_pt->mse_inv * b_pc->mse_pt->b_val;
				
				next_p =  next_p->np;
				
				b_pc->mse_pt = b_pc->mse_pt->next_mse;
			}
			
			b_pc->pc->ave_value = b_pc->pc->ave_value  + 
				(b_pc->curr_const_tot / b_pc->mse_inv_tot);
			
			Delete_mse_st(b_pc);
			
			b_pc->last_poly_prev_inner_loop = b_pc->c_p;
			
			for ( i = 0; i < b_pc->num_lrn_ex; i++ )
			{
				b_pc->h_p_lrn_best[i] = b_pc->h_p_lrn[i];
				b_pc->curr_to_lrn_best[i] = b_pc->out_lrn[i];
			}
			
			for ( i = 0; i < b_pc->num_val_ex; i++ )
			{
				b_pc->h_p_val_best[i] = b_pc->h_p_val[i];
				b_pc->curr_to_val_best[i] = b_pc->out_val[i];
			}
	}
	else
	{
		lrn_err_ave_sq = 0.0;
		for ( i = 0; i < b_pc->num_lrn_ex; i++ )
		{
			b_pc->h_p_lrn[i] = b_pc->h_p_lrn_best[i];
			b_pc->curr_to_lrn[i] = b_pc->curr_to_lrn_best[i];
			
			lrn_err_ave_sq = lrn_err_ave_sq + 
				(b_pc->out_lrn[i] * b_pc->out_lrn[i]);
			
			b_pc->curr_to_lrn[i] = 0.0;
		}
		lrn_err_ave_sq = lrn_err_ave_sq / ((My_Real)b_pc->num_lrn_ex);
		
		val_err_ave_sq = 0.0;
		for ( i = 0; i < b_pc->num_val_ex; i++ )
		{
			b_pc->h_p_val[i] = b_pc->h_p_val_best[i];
			b_pc->curr_to_val[i] = b_pc->curr_to_val_best[i];
			
			val_err_ave_sq = val_err_ave_sq + 
				(b_pc->out_val[i] * b_pc->out_val[i]);
			
			b_pc->curr_to_val[i] = 0.0;
		}
		val_err_ave_sq = val_err_ave_sq / ((My_Real)b_pc->num_val_ex);
	}
	
	
	if ( b_pc->outer_cnt < 6 )
	{
		b_pc->outer_err_loop[b_pc->outer_cnt] = val_err_ave_sq;
		
		b_pc->outer_poly_loop[b_pc->outer_cnt].pp =  
			b_pc->address_of_1st_in_bag;
		b_pc->outer_poly_loop[b_pc->outer_cnt].ave_value = 
			b_pc->pc->ave_value;
		
		ret_val = 1;
		b_pc->outer_cnt = b_pc->outer_cnt + 1;
	}
	else
	{
		t1 = 0.0;
		for ( i = 0; i < 6; i++ )
		{
			t1 = t1 + b_pc->outer_err_loop[i];
		}
		
		t1 = t1 / (My_Real)6;
		
		if ( t1 > THRESHOLD_MIN_MAX )
		{
			err_change = (t1 - val_err_ave_sq) / t1;
		}
		else
		{
			err_change = 0.0;
		}
		
		if ( err_change < 0.0001 )
		{
			b_pc->outer_cnt = 0;
			b_pc->cnt_Lrn_Num_Sch = b_pc->cnt_Lrn_Num_Sch + 1;
			
			if ( b_pc->cnt_Lrn_Num_Sch < 4 )
			{
				ret_val = 1;
				b_pc->lrn_num = b_pc->Lrn_Num_Sch[b_pc->cnt_Lrn_Num_Sch];
				free(b_pc->p_mat_array);
				free(b_pc->dres_tm);
				free(b_pc->p_b_all);
				
				b_pc->p_mat_array = (My_Real *)
					malloc((unsigned)(b_pc->lrn_num * 
					POLY_TERMS * (sizeof(My_Real))));
				if (!(b_pc->p_mat_array))
				{
					My_Error("Cannot allocate b_pc->p_mat_array!!\n");
				}
				
				b_pc->dres_tm = (My_Real *)
					malloc((unsigned)(POLY_TERMS * 
					POLY_TERMS * (sizeof(My_Real))));
				if (!(b_pc->p_mat_array))
				{
					My_Error("Cannot allocate b_pc->dres_tm!!\n");
				}
				
				b_pc->p_b_all = (My_Real *)
					malloc((unsigned)(b_pc->lrn_num * (sizeof(My_Real))));
				if (!(b_pc->p_b_all))
				{
					My_Error("Cannot allocate b_pc->p_b_all!!\n");
				}
			}
			else
			{
				ret_val = 0;
				t1 = b_pc->outer_err_loop[0];
				i_min = 0;
				for ( i = 1; i < 6; i++ )
				{
					if ( t1 > b_pc->outer_err_loop[i] )
					{
						t1 = b_pc->outer_err_loop[i];
						i_min = i;
					}
				}
				
				if ( t1 < val_err_ave_sq )
				{
					cnt = 0;
					if ( (i_min + 1) < 6 )
						cp = b_pc->outer_poly_loop[i_min + 1].pp;
					else
						cp = b_pc->address_of_1st_in_bag;
					
					while ( cp != NULL )
					{
						cnt = cnt + 1;
						cp = cp->np;
					}
					
					pp = (Poly_Delete_Structure *)
						malloc((unsigned)cnt * 
						sizeof(Poly_Delete_Structure));
					if (!(pp))
					{
						My_Error("Cannot alloc Poly_Delete_Structure !!\n");
					}
					
					if ( (i_min + 1) < 6 )
						cp = b_pc->outer_poly_loop[i_min + 1].pp;
					else
						cp = b_pc->address_of_1st_in_bag;
					
					for ( i = 0; i < cnt; i++ )
					{
						pp[i].pp = cp;
						cp = cp->np;
					}
					
					for ( i = cnt-1; i >= 0; i-- )
					{
						pp[i].pp->np = NULL;
						free(pp[i].pp);
					}
					
					b_pc->pc->num_of_levels = b_pc->pc->num_of_levels - cnt;
					
					cp = b_pc->pc->first_poly;
					for ( i = 1; i < (int)b_pc->pc->num_of_levels; i++ )
					{
						cp = cp->np;
					}
					cp->np = NULL;
					
					b_pc->pc->ave_value = 
						b_pc->outer_poly_loop[i_min].ave_value;
					
					free(pp);
				}
			}
		}
		else
		{
			b_pc->outer_cnt = b_pc->outer_cnt + 1;
			ret_val = 1;
			
			for ( i = 1; i < 6; i++ )
			{
				b_pc->outer_err_loop[i-1] = b_pc->outer_err_loop[i];
				b_pc->outer_poly_loop[i-1].pp = 
					b_pc->outer_poly_loop[i].pp;
				
				b_pc->outer_poly_loop[i-1].ave_value = 
					b_pc->outer_poly_loop[i].ave_value;
			}
			
			b_pc->outer_err_loop[6-1] = val_err_ave_sq;
			
			b_pc->outer_poly_loop[6-1].pp =  
				b_pc->address_of_1st_in_bag;
			b_pc->outer_poly_loop[6-1].ave_value =  
				b_pc->pc->ave_value;
		}
	}
#ifdef PRINT_OUTER_LOOP_ERROR
	fprintf(fp_RES_OUTPUT,"level %d: lrn_err_ave_sq = %g, val_err_ave_sq = %g\n",

		b_pc->pc->num_of_levels, lrn_err_ave_sq, val_err_ave_sq);

	printf("level %d: lrn_err_ave_sq = %g, val_err_ave_sq = %g\n",

		b_pc->pc->num_of_levels, lrn_err_ave_sq, val_err_ave_sq);

	
	/*fflush(fp_RES_OUTPUT);*/
#endif
	
	b_pc->address_of_1st_in_bag = NULL;
	
	b_pc->curr_const_tot = 0.0;
	b_pc->curr_num_of_bags = 0;
	
	if ( ret_val == 0 )
	{
		fprintf(fp_RES_OUTPUT,"Last level %d: lrn_err_ave_sq = %g, val_err_ave_sq = %g\n",
			b_pc->pc->num_of_levels, lrn_err_ave_sq, val_err_ave_sq);
		
		/*fflush(fp_RES_OUTPUT);*/
	}
	
	return(ret_val);
    }
	else
    {
		return(1);
    }
}


void Build_Poly(Build_Cas_Poly *b_pc,
				void (*Get_Lrn_Ex_Input)(int ex_num, 
				int var, 
				My_Real *in),
				void (*Get_Val_Ex_Input)(int ex_num, 
				int var, 
				My_Real *in))
{
	int ind;
	int i, j, ii;
	
	int cnt, m, n, ind1, ind2, ind3, k;
	
	My_Real p_terms[NON_1_INPUTS], x_2[2];
	My_Real x[POLY_DIM], t1;
	
	void Define_Poly_Output_Scaling(Build_Cas_Poly *b_pc);
	
	My_Real Eval_Poly(Poly *poly, My_Real x[POLY_DIM]);
	
	void Poly_Terms(My_Real *term, My_Real x[POLY_DIM]);
	
	void Initialize_Poly_Struct(Build_Cas_Poly *b_pc);
	
	void Solve_System(My_Real **A, My_Real *b, My_Real *w, 
		My_Real *S2, My_Real *c, int rows);
	
	b_pc->pc->num_of_levels = b_pc->pc->num_of_levels + 1;
	
	b_pc->curr_num_of_bags = b_pc->curr_num_of_bags + 1;
	
	Initialize_Poly_Struct(b_pc);
	
	/**** construxt p_mat p_b *****/
	n = POLY_TERMS;
	m = b_pc->lrn_num;
	for ( i = 0; i < b_pc->lrn_num; i++ )
    {
		/*ind = (int)((My_Real)b_pc->num_lrn_ex * erand48(b_pc->xsubi));*/
		ind = (int)((My_Real)b_pc->num_lrn_ex * Greg_Rand(b_pc->xsubi));
		
		x[0] = b_pc->h_p_lrn[ind];
		for ( ii = 1; ii < POLY_DIM; ii++ )
		{
			Get_Lrn_Ex_Input(ind,b_pc->c_p->input_num[ii-1],&t1);
			x[ii] = Scale(t1,b_pc->pc->m_scale[b_pc->c_p->input_num[ii-1]],
				b_pc->pc->b_scale[b_pc->c_p->input_num[ii-1]]);
		}
		
		Poly_Terms(p_terms,x);
		
		b_pc->p_mat_array[i] = 1.0;
		
		for ( j = 0; j < NON_1_INPUTS; j++ )
		{
			b_pc->p_mat_array[((j+1)*m)+i] = p_terms[j];
		}
		
		b_pc->p_b_all[i] = Scale(b_pc->out_lrn[ind],b_pc->m_out, b_pc->b_out);
    }
	
	for(i=0, ind1=0, ind2=0; i < n;i++ , ind1+=n , ind2+=m)
    {
		for(j=i, ind3=j*m; j < n ; j++, ind3+=m)
		{
			b_pc->dres_tm[ind1+j] = 0.0;
			for(k = 0; k < m; k++)
			{
				b_pc->dres_tm[ind1+j] += 
					b_pc->p_mat_array[ind2+k]*b_pc->p_mat_array[ind3+k]; 
			} 
			b_pc->dres_tm[j*n+i] = b_pc->dres_tm[ind1+j];  
		}
    }
	
	cnt = 0;
	for ( i = 0; i < POLY_TERMS; i++ )
    {
		b_pc->p_b[i] = 0.0;
		for ( j = 0; j < b_pc->lrn_num; j++ )
		{
			b_pc->p_b[i] = b_pc->p_b[i] + 
				b_pc->p_mat_array[cnt] * b_pc->p_b_all[j];
			cnt = cnt + 1;
		}
    }
	
	cnt = 0;
	for ( i = 0; i < POLY_TERMS; i++ )
    {
		for ( j = 0; j < POLY_TERMS; j++ )
		{
			b_pc->p_mat[i][j] = b_pc->dres_tm[cnt];
			cnt = cnt + 1;
		}
    }
	/**************************/
	
	Solve_System(b_pc->p_mat, b_pc->p_b, b_pc->c_p->a, b_pc->p_sv, b_pc->p_c, 
	       POLY_TERMS);
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		x[0] = b_pc->h_p_lrn[i];
		for ( ii = 1; ii < POLY_DIM; ii++ )
		{
			Get_Lrn_Ex_Input(i,b_pc->c_p->input_num[ii-1],&t1);
			x[ii] = Scale(t1,b_pc->pc->m_scale[b_pc->c_p->input_num[ii-1]],
				b_pc->pc->b_scale[b_pc->c_p->input_num[ii-1]]);
		}
		
		b_pc->h_p_lrn[i] = Eval_Poly(b_pc->c_p, x);
    }
	
	Define_Poly_Output_Scaling(b_pc);
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		t1 = Scale(b_pc->h_p_lrn[i],
			b_pc->c_p->m_scale_out,b_pc->c_p->b_scale_out);
		b_pc->h_p_lrn[i] = t1;
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		x[0] = b_pc->h_p_val[i];
		for ( ii = 1; ii < POLY_DIM; ii++ )
		{
			Get_Val_Ex_Input(i,b_pc->c_p->input_num[ii-1],&t1);
			x[ii] = Scale(t1,b_pc->pc->m_scale[b_pc->c_p->input_num[ii-1]],
				b_pc->pc->b_scale[b_pc->c_p->input_num[ii-1]]);
		}
		
		b_pc->h_p_val[i] = Eval_Poly(b_pc->c_p, x);
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		t1 = Scale(b_pc->h_p_val[i],
			b_pc->c_p->m_scale_out,b_pc->c_p->b_scale_out);
		b_pc->h_p_val[i] = t1;
    }
	
	/**** construxt s_mat s_b *****/
	n = 2;
	m = b_pc->num_lrn_ex;
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		b_pc->s_mat_array[i] = 1.0;
		
		b_pc->s_mat_array[m+i] = b_pc->h_p_lrn[i];
		
		b_pc->s_b_all[i] = b_pc->out_lrn[i];
    }
	
	for(i=0, ind1=0, ind2=0; i < n;i++ , ind1+=n , ind2+=m)
    {
		for(j=i, ind3=j*m; j < n ; j++, ind3+=m)
		{
			b_pc->s_dres_tm[ind1+j] = 0.0;
			for(k = 0; k < m; k++)
			{
				b_pc->s_dres_tm[ind1+j] += 
					b_pc->s_mat_array[ind2+k]*b_pc->s_mat_array[ind3+k]; 
			} 
			b_pc->s_dres_tm[j*n+i] = b_pc->s_dres_tm[ind1+j];  
		}
    }
	
	cnt = 0;
	for ( i = 0; i < 2; i++ )
    {
		b_pc->s_b[i] = 0.0;
		for ( j = 0; j < b_pc->num_lrn_ex; j++ )
		{
			b_pc->s_b[i] = b_pc->s_b[i] + 
				b_pc->s_mat_array[cnt] * b_pc->s_b_all[j];
			cnt = cnt + 1;
		}
    }
	
	cnt = 0;
	for ( i = 0; i < 2; i++ )
    {
		for ( j = 0; j < 2; j++ )
		{
			b_pc->s_mat[i][j] = b_pc->s_dres_tm[cnt];
			cnt = cnt + 1;
		}
    }
	
	Solve_System(b_pc->s_mat, b_pc->s_b, x_2, b_pc->s_sv, b_pc->s_c, 2);
	
	b_pc->c_p->scale_to_output = x_2[1];
	
	b_pc->curr_const_tot = b_pc->curr_const_tot + x_2[0];
	
	b_pc->curr_b_val = x_2[0];
	/**************************/
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++ )
    {
		b_pc->curr_o_lrn[i] = x_2[0] + x_2[1] * b_pc->h_p_lrn[i];
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++ )
    {
		b_pc->curr_o_val[i] = x_2[0] + x_2[1] * b_pc->h_p_val[i];
    }
}

void Initialize_Poly_Struct(Build_Cas_Poly *b_pc)
{
	int Select_Input_Number(Build_Cas_Poly *b_pc);
	int i;
	
	b_pc->c_p->np = NULL;
	
	for ( i = 0; i < LEVEL_INPUTS; i++ )
		b_pc->c_p->input_num[i] = Select_Input_Number(b_pc);
}

void Define_Poly_Output_Scaling(Build_Cas_Poly *b_pc)
{
	My_Real min=-1, max=-1;
	
	int i;
	
	void Find_Linear_Transformation(My_Real min, My_Real max, 
		My_Real *m, My_Real *b);
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++)
    {
		if ( i == 0 )
		{
			min = b_pc->h_p_lrn[i];
			max = b_pc->h_p_lrn[i];
		}
		else
		{
			if ( min > b_pc->h_p_lrn[i] )
			{
				min = b_pc->h_p_lrn[i];
			}
			else if ( max < b_pc->h_p_lrn[i] )
			{
				max = b_pc->h_p_lrn[i];
			}
		}
    }
	
	Find_Linear_Transformation(min, max, 
			     &(b_pc->c_p->m_scale_out),
				 &(b_pc->c_p->b_scale_out));
}



void Delete_Learn_Stuff(Build_Cas_Poly *b_pc)
{
	void free_My_Matrix(My_Real **m);
	
	
#ifdef ANALYZE_INPUTS
	
	FILE *fp_var_select;
	int var_sel_i;
	
	if (( fp_var_select = fopen("Var_Sel","w")) == NULL)
    {
		fprintf(fp_RES_OUTPUT,"Couldn't open \"%s\"\n","Var_Sel");
    }
	
	for ( var_sel_i = 0; var_sel_i < b_pc->pc->dim; var_sel_i++ )
    {
		if ( b_pc->ana_var_tot_used[var_sel_i] > 0 )
			fprintf(fp_var_select,"%d  %g\n",var_sel_i,
			(b_pc->ana_var_num[var_sel_i] /* 
			(My_Real)b_pc->ana_var_tot_used[var_sel_i]*/));
			else
			fprintf(fp_var_select,"%d  0.0\n",var_sel_i);
    }
	
	fclose(fp_var_select);
	free(b_pc->ana_var_num);
	free(b_pc->ana_var_tot_used);
#endif  
	
	
	free(b_pc->out_lrn);
	free(b_pc->out_val);
	
	free(b_pc->select_input_list);
	
	free(b_pc->h_p_lrn);
	free(b_pc->h_p_val);
	free(b_pc->curr_o_lrn);
	free(b_pc->curr_to_lrn);
	free(b_pc->curr_o_val);
	free(b_pc->curr_to_val);
	
	free(b_pc->h_p_lrn_best);
	free(b_pc->h_p_val_best);
	
	free(b_pc->curr_to_lrn_best);
	free(b_pc->curr_to_val_best);
	
	free(b_pc->p_mat_array);
	free(b_pc->p_b_all);
	free(b_pc->dres_tm);
	free(b_pc->p_b);
	free(b_pc->p_sv);
	free(b_pc->p_c);
	
	free(b_pc->s_mat_array);
	free(b_pc->s_b_all);
	free(b_pc->s_dres_tm);
	free(b_pc->s_b);
	free(b_pc->s_sv);
	free(b_pc->s_c);
	
	free(b_pc->p_mat[0]);
	free(b_pc->p_mat);
	
	free(b_pc->s_mat[0]);
	free(b_pc->s_mat);
}

void Define_Ave_Value_And_Sub(Build_Cas_Poly *b_pc)
{
	My_Real t1;
	
	int i;
	
	
	t1 = 0.0;
	for ( i = 0; i < b_pc->num_lrn_ex; i++)
    {
		t1 = t1 + b_pc->out_lrn[i];
    }
	
	b_pc->pc->ave_value = t1 / (My_Real)b_pc->num_lrn_ex;
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++)
    {
		b_pc->out_lrn[i] = b_pc->out_lrn[i] - b_pc->pc->ave_value;
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++)
    {
		b_pc->out_val[i] = b_pc->out_val[i] - b_pc->pc->ave_value;
    }
}

void Define_Output_Scaling(Build_Cas_Poly *b_pc)
{
	My_Real min=-1, max=-1;
	
	int i;
	
	void Find_Linear_Transformation(My_Real min, My_Real max, 
		My_Real *m, My_Real *b);
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++)
    {
		if ( i == 0 )
		{
			min = b_pc->out_lrn[i];
			max = b_pc->out_lrn[i];
		}
		else
		{
			if ( min > b_pc->out_lrn[i] )
			{
				min = b_pc->out_lrn[i];
			}
			else if ( max < b_pc->out_lrn[i] )
			{
				max = b_pc->out_lrn[i];
			}
		}
    }
	
	Find_Linear_Transformation(min, max, 
			     &(b_pc->m_out),
				 &(b_pc->b_out));
}


void Set_Lrn_Val_Outputs(Build_Cas_Poly *b_pc,
						 void (*Get_Lrn_Ex_Output)(int ex_num, 
						 My_Real *out),
						 void (*Get_Val_Ex_Output)(int ex_num, 
						 My_Real *out))
{
	int i;
	
	b_pc->out_lrn = (My_Real *)
		malloc((unsigned)b_pc->num_lrn_ex * (sizeof(My_Real)));
	if (!(b_pc->out_lrn))
    {
		My_Error("Cannot allocate b_pc->out_lrn!!\n");
    }
	
	for ( i = 0; i < b_pc->num_lrn_ex; i++)
    {
		Get_Lrn_Ex_Output(i,&(b_pc->out_lrn[i]));
    }
	
	
	b_pc->out_val = (My_Real *)
		malloc((unsigned)b_pc->num_val_ex * (sizeof(My_Real)));
	if (!(b_pc->out_val))
    {
		My_Error("Cannot allocate b_pc->out_val!!\n");
    }
	
	for ( i = 0; i < b_pc->num_val_ex; i++)
    {
		Get_Val_Ex_Output(i,&(b_pc->out_val[i]));
    }
}

void Define_Input_Scaling(Build_Cas_Poly *b_pc,
						  void (*Get_Lrn_Ex_Input)(int ex_num, 
						  int var, 
						  My_Real *in))
{
	My_Real min=-1, max=-1, t1;
	
	int i, j;
	
	void Find_Linear_Transformation(My_Real min, My_Real max, 
		My_Real *m, My_Real *b);
	
	
	for ( i = 0; i < (int)b_pc->pc->dim; i++ )
    {
		for ( j = 0; j < b_pc->num_lrn_ex; j++ )
		{
			Get_Lrn_Ex_Input(j,i,&t1);
			
			if ( j == 0 )
			{
				min = t1;
				max = t1;
			}
			else
			{
				if ( min > t1 )
				{
					min = t1;
				}
				else if ( max < t1 )
				{
					max = t1;
				}
			}
		}
		
		Find_Linear_Transformation(min, max, 
			&(b_pc->pc->m_scale[i]),
			&(b_pc->pc->b_scale[i]));
    }
}


void Find_Linear_Transformation(My_Real min, My_Real max, 
								My_Real *m, My_Real *b)
{
	My_Real del_x, x_max, x_min;
	
	char error_text[100];
	
	x_max = max;
	x_min = min;
	
	del_x = x_max - x_min;
	
	if ( del_x <= THRESHOLD_MIN_MAX )
    {
		if ( fabs(x_max) >= fabs(x_min) )
		{
			if ( fabs(x_max) <= THRESHOLD_MIN_MAX )
			{
				del_x = 1.0;
				x_min = 0.0;
				x_max = 1.0;
			}
			else
			{
				if ( x_max < 0.0 )
				{
					x_min = x_max;
					x_max = 0.0;
					del_x = x_max - x_min;
				}
				else
				{
					x_min = 0.0;
					del_x = x_max - x_min;
				}
			}
		}
		else
		{
			if ( fabs(x_min) <= THRESHOLD_MIN_MAX )
			{
				del_x = 1.0;
				x_min = 0.0;
				x_max = 1.0;
			}
			else
			{
				x_max = 0.0;
				if ( x_min > 0.0 )
				{
					sprintf(error_text,
						"Error: Find_Linear_Transformation  x_min = %g\n",
						x_min);
					
					My_Error(error_text);
				}
				del_x = fabs(x_min);
			}
		}
    }
	
	*m = 2.0 / del_x;
	*b = -(x_max + x_min) / del_x;
}


int Select_Input_Number(Build_Cas_Poly *b_pc)
{
	int i, ind;
	
	Comp_Structure *vt;
	
	int My_Compare(const void *s1, const void *s2);
	
	if ( (int)b_pc->curr_input_ind_num < (int)b_pc->pc->dim )
    {
		ind = b_pc->select_input_list[b_pc->curr_input_ind_num];
		
		b_pc->curr_input_ind_num = b_pc->curr_input_ind_num + 1;
    }
	else
    {
		vt = (Comp_Structure *)
			malloc((unsigned)b_pc->pc->dim * (sizeof(Comp_Structure)));
		if (!(vt))
		{
			My_Error("Cannot allocate Select_Input_Number vt!!\n");
		}
		
		
		for ( i = 0; i < (int)b_pc->pc->dim; i++ )
		{
			vt[i].order = i;
			/*vt[i].t = erand48(b_pc->xsubi);*/
			vt[i].t = (float)Greg_Rand(b_pc->xsubi);
		}
		
		qsort((void *) vt, b_pc->pc->dim, sizeof(Comp_Structure), My_Compare);
		
		for ( i = 0; i < (int)b_pc->pc->dim; i++ )
		{
			b_pc->select_input_list[i] = vt[i].order;
			
			/*printf("%d\n",b_pc->select_input_list[i]);*/
		}
		
		ind = b_pc->select_input_list[0];
		
		b_pc->curr_input_ind_num = 1;
		
		free(vt);
    }
	
	return(ind);
}

int My_Compare(const void *s1, const void *s2)
{
	if ( ((Comp_Structure *)s1)->t < ((Comp_Structure *)s2)->t )
    {
		return(-1);
    }
	else if ( ((Comp_Structure *)s1)->t > ((Comp_Structure *)s2)->t )
    {
		return(1);
    }
	else
    {
		return(0);
    }
}

void My_Error(char error_text[])
{
	fprintf(fp_RES_OUTPUT,"\n\nError While Building Approximation...\n\n");
	fprintf(fp_RES_OUTPUT,"%s\n",error_text);
	fprintf(fp_RES_OUTPUT,"...now exiting...\n\n");
	exit(-1);
}


My_Real **Create_Matrix(int rows, int cols)
{
	int  i;
	My_Real **x;
	
	x = (My_Real **) malloc((size_t) rows*sizeof(My_Real *));
	if ( x == NULL )
		My_Error("Cannot allocated x in  Create_Matrix\n");
	
	x[0] = (My_Real *) malloc((size_t) rows*cols*sizeof(My_Real));
	if ( x[0] == NULL )
		My_Error("Cannot allocated x[0] in  Create_Matrix\n");
	
	for (i=1; i<rows; i++) 
		x[i] = x[i-1]+cols;
	
	return x;
}


void Solve_System(My_Real **A, My_Real *b, My_Real *w, 
				  My_Real *S2, My_Real *c, int rows)
{
	void svd(My_Real **A, My_Real *S2, int n);
	int i, j, k;
	My_Real tmp;
	
	svd(A, S2, rows);
	
	for (i = rows-1; i>=0; i--)                              /* "invert" S2 */
    {
		if (S2[i]*(1.0e6) > S2[0]) 
		{                                           /* SV large enough? */
			S2[i] = 1.0/S2[i];
		}
		else
			S2[i] = 0.0;                                /* delete direction */
    }
	
	for (i=0; i< rows; i++) 
    {                                 /* compute invA = V*invS2*(US)' */
		for (j=0; j< rows; j++) 
		{
			for (tmp=0.0, k=0; k < rows; k++)
				tmp += A[i+rows][k]*A[j][k]*S2[k];
			c[j] = tmp;
		}
		for (j=0; j< rows; j++) 
			A[i+rows][j] = c[j];  /* copy "c" into "A" */
    }
	
	for (i=0; i < rows; i++)             /* compute w = invA*b */
    {
		for (tmp=0.0, j=0; j< rows; j++)
			tmp += A[i+rows][j]*b[j];
		w[i] = tmp;
    }
}
