//__________________________________________________________
// This program is PUBLIC DOMAIN
// This program has NO Copyright
// The writer		:  Sergiy Podolyak
//	Write date		:  2010-2016
// https://ua.linkedin.com/in/sergiy-podolyak-a34079110
// http://www.graalino.com
// File        	:  OBz-Math-Lib.mq4
// Description		:	Library of trading functions from the
//							trend-following experts "Ocean Breeze"
//							and "Graalino-Pro"
// Version     	:  1.92
// Version Date	:  21 Aug 2016
// Project     	:  MT4 trading
// Start Date  	:  May 2010
//______________________________________________________________________________________
//
#property library
// But You can just include any this function into your project, not as a library as a whole
//______________________________________________________________________________________

#define 		NOT_PROCESSED_YET														-100
#define 		DO_NOT_PROCESS															100
#define		MAX_POLYNOM_ORDER														19

//______________________________________________________________________________________
//																							|
// 	 		Array_Mean () 															|
//___________________________________________________________________|
double Array_Mean
(
   double  &	Array[],
   int 			Start_Bar,
   int 			Array_Size
)
{
	int i;
	double Average ;
	Average = 0.0 ;
	for (i = 0; i < Array_Size; i++)
	{
		Average = Average + Array [i + Start_Bar];
	}
	Average = Average / Array_Size;
	return (Average);
}
//______________________________________________________________________________________
//																							|
// 	 		Array_Mean_Harmonic () 												|
//___________________________________________________________________|
double Array_Mean_Harmonic
(
   double  &	Array[],
   int 			Start_Bar,
   int 			Array_Size
)
{
	int i;
	double Average ;
	Average = 0.0 ;
	for (i = 0; i < Array_Size; i++)
	{
		if (Array [i + Start_Bar] != 0.0)
		{
			Average = Average + 1.0 / Array [i + Start_Bar];
		}
	}
	Average = Array_Size / Average;
	return (Average);
}
//______________________________________________________________________________________
//																							|
// 	 		Array_Mean_Geometic () 												|
//___________________________________________________________________|
double Array_Mean_Geometric
(
   double  &	Array[],
   int 			Start_Bar,
   int 			Array_Size
)
{
	int i;
	double Average ;
	Average = 1.0 ;
	for (i = 0; i < Array_Size; i++)
	{
		if (Array [i + Start_Bar] != 0.0)
		{
			Average = Average * Array [i + Start_Bar];
		}
	}
	Average = MathPow (Average, 1.0 / Array_Size);
	return (Average);
}
//______________________________________________________________________________________
//																							|
// 			Reorder_Array ()												 		|
//___________________________________________________________________|
int Reorder_Array
(
   double & Array[],
   int 		Array_Size
)
{
	double Tempo;
	int i;
	int Calc_Count;
	if (Array_Size <= 0)
	{
		return (0);
	}
	if (Array_Size == 1)
	{
		return (1);
	}
	Calc_Count = (int) MathFloor ( (Array_Size) / 2.0);
	//............ Re-order (swap) the vector
	for (i = 0; i < Calc_Count; i++)
	{
		Tempo = Array[i];
		Array[i] = Array[Array_Size - i - 1];
		Array[Array_Size - i - 1] = Tempo;
	}
	return (i);
}
//______________________________________________________________________________________
//													|
// 	Add_Array_Constant ()				|
//______________________________________________________________________________________
void Add_Array_Constant ( double & Samples_Array[],
                          int 		Samples_Limit,
                          double 	Constant
                        )
{
	int i;
	//.......................................................
	for (i = 0; i < Samples_Limit; i++)
	{
		Samples_Array[i] += Constant;
	}
	//................................................
	return ;
}
//______________________________________________________________________________________
//													|
// 	Scale_Array ()							|
//______________________________________________________________________________________
void  Scale_Array ( double & Samples_Array[],
                    int 		Samples_Limit,
                    double 	Constant
                  )
{
	int i;
	//.......................................................
	for (i = 0; i < Samples_Limit; i++)
	{
		Samples_Array[i] *= Constant;
	}
	//................................................
	return ;
}
//______________________________________________________________________________________
//													|
// 	Find_Array_Sign_Change ()			|
//													|
//______________________________________________________________________________________
int  Find_Array_Sign_Change ( 	double & Samples_Array[],
                                 int 		Samples_Start,
                                 int 		Samples_Limit)
{
	int i;
	int Loop_Limit;
	int Index_Found;
	double Sign;
	//.......................................................
	Loop_Limit = Samples_Limit - Samples_Start - 1;
	Index_Found = 0;
	//.......................................................
	for (i = 0; i < Loop_Limit; i++)
	{
		Sign = Samples_Array[i] * Samples_Array[i + 1];
		if (Sign <= 0.0)
		{
			Index_Found = i;
			break;
		}
	}
	//................................................
	return (Index_Found);
}
//______________________________________________________________________________________
//														|
// 	Find_Array_All_Sign_Changes ()		|
//														|
//______________________________________________________________________________________
int  Find_Array_All_Sign_Changes ( 	double & Samples_Array[],
                                    int 		Samples_Start,
                                    int 		Samples_Limit,
                                    int  &	Out_Array[] )
{
	int i;
	int Loop_Limit;
	int Total_Found;
	double Sign;
	//.......................................................
	Loop_Limit = Samples_Limit - Samples_Start - 1;
	Total_Found = 0;
	//.......................................................
	for (i = 0; i < Loop_Limit; i++)
	{
		Sign = Samples_Array[i] * Samples_Array[i + 1];
		if (Sign <= 0.0)
		{
			Out_Array[Total_Found] = i;
			Total_Found ++;
		}
	}
	//................................................
	return (Total_Found);
}
//______________________________________________________________________________________
//														|
// 	Fill_Stencil_Matrix_Polynom ()		|
//														|
//______________________________________________________________________________________
void Fill_Stencil_Matrix_Polynom
(
   double  &	Stencil_Matrix[][],
   int 			Stencil_Matrix_Height,
   int			Stencil_Matrix_Width
)
{
	int Row;
	int Column;
	//.........................................................................................
	for (Row = 0; Row < Stencil_Matrix_Height; Row++)
	{
		Stencil_Matrix [Row][0] = 1.0;
	}
	//.........................................................................................
	for (Column = 1; Column < Stencil_Matrix_Width; Column++)
	{
		for (Row = 0; Row < Stencil_Matrix_Height; Row++)
		{
			Stencil_Matrix [Row][Column] = MathPow (Row,  Column);
		}
	}
	//.........................................................................................
	return ;
}
//______________________________________________________________________________________
//														|
// 	Transpose_Matrix ()						|
//														|
//______________________________________________________________________________________
void 	Transpose_Matrix
(
   double  &	Input_Matrix[][],
   int			Input_Matrix_Height,
   int			Input_Matrix_Width,
   double  &	Output_Matrix[][]
)
{
	int  Row, Column ;
	//.............................................................................
	for (Row = 0; Row < Input_Matrix_Height;  Row ++)
	{
		for (Column = 0; Column < Input_Matrix_Width;  Column ++)
		{
			Output_Matrix [Column][Row] = Input_Matrix [Row][Column];
		}
	}
	//.............................................................................
	return ;
}
//______________________________________________________________________________________
//														|
// 	Multiply_Matrix_Vector ()				|
//														|
//______________________________________________________________________________________
void Multiply_Matrix_Vector (double  &	Matrix[][],
                             int 		Height,
                             int			Width,
                             double  &	X[],
                             double  &	Result_Vector[])
{
	int 		Row;
	int 		Column;
	double 	Sum;
	//.............................................................................
	for (Row = 0; Row < Height; Row++)
	{
		Sum = 0.0;
		for (Column = 0; Column < Width; Column++)
		{
			Sum = Sum + Matrix[Row][Column] * X[Column];
		}
		Result_Vector[Row] = Sum;
	}
	//.............................................................................
	return ;
}
//______________________________________________________________________________________
//														|
// 	Multiply_Matrixes ()						|
//														|
//______________________________________________________________________________________
void Multiply_Matrixes
(
   double  &	MatrixA[][],
   int			m,
   int			n,
   double  &	MatrixB[][],
   int			q,
   double	&	Output_Matrix[][]
)
{
	int  i, j, r;
	double 	Cij ;
	//.............................................................................
	for (i = 0; i < m; i ++)
	{
		for (j = 0; j < q; j ++)
		{
			Cij = 0.0 ;
			for (r = 0; r < n; r ++)
			{
				Cij = Cij + MatrixA[i][r] * MatrixB[r][j] ;
			}
			Output_Matrix [i][j] = Cij ;
		}
	}
	//.............................................................................
	return ;
}
//______________________________________________________________________________________
//														|
// 	Polynom ()									|
//														|
//______________________________________________________________________________________
void Polynom
(
   double		X,
   double	 &	Ai_Array[],
   int			Ai_Array_Limit,
   double 	&	Result[]
)
{
	double 	Tempo, Poly_Sum ;
	int i ;
	//.............................................................................
	Tempo = 1.0 ;
	Poly_Sum = 0.0 ;
	//----------------------------------------------------------------------
	//  calc "Poly_Sum" = A0*x^0 + A1*x^1 + A2*X^2... + An*X^n
	//
	for (i = 0; i < Ai_Array_Limit; i ++)
	{
		Poly_Sum = Poly_Sum + Tempo * Ai_Array [i] ;
		Tempo = Tempo * X ;
	} // i ends
	//.............................................................................
	Result[0] = Poly_Sum;
	//.............................................................................
	return ;
}
//______________________________________________________________________________________
//														|
// 	Fit_Polynom_LSQ ()						|
//														|
//______________________________________________________________________________________
void Fit_Polynom_LSQ
(
   double 	&	Sample[],
   int			Samples_Start,
   int			Samples_Limit,

   double	&	Polynom_Ai[],
   int			Polynom_Limit
)
{
	//................................................
	double 	Stencil_Matrix[][MAX_POLYNOM_ORDER];
	double 	Transposed_Stencil_Matrix[][10000];
	double 	Packed_Square_Matrix[][MAX_POLYNOM_ORDER];
	int 		Stencil_Matrix_Width;
	int 		Stencil_Matrix_Height;
	int 		Row;
	double 	B[];
	double 	X[];
	double 	Large_B[];
	//..................................................................
	Stencil_Matrix_Height = MathMax (0, Samples_Limit);
	Stencil_Matrix_Width = Polynom_Limit;
	//==================================================================================================
	ArrayResize (Stencil_Matrix, Stencil_Matrix_Height);
	ArrayResize (Transposed_Stencil_Matrix, Stencil_Matrix_Height);
	ArrayResize (Packed_Square_Matrix, Stencil_Matrix_Width);
	ArrayResize (Large_B, Stencil_Matrix_Height);
	ArrayResize (B, Stencil_Matrix_Width);
	ArrayResize (X, Stencil_Matrix_Width);
	ArrayInitialize (Stencil_Matrix, 0.0);
	//==========================/ Fill Large Tempo matrix with sin and cosin \=========================
	Fill_Stencil_Matrix_Polynom (Stencil_Matrix, Stencil_Matrix_Height, Stencil_Matrix_Width);
	//========================/ Solving A*X=B  by solving At*A*X=At*B \=======================
	Transpose_Matrix (Stencil_Matrix,
	                  Stencil_Matrix_Height,
	                  Stencil_Matrix_Width,
	                  Transposed_Stencil_Matrix);
	//========================/ At*A \==========================================================
	Multiply_Matrixes (Transposed_Stencil_Matrix,
	                   Stencil_Matrix_Width,
	                   Stencil_Matrix_Height,
	                   Stencil_Matrix,
	                   Stencil_Matrix_Width,
	                   Packed_Square_Matrix);
	//=====================/ At*B \==============================================================
	for (Row = 0; Row < Stencil_Matrix_Height; Row++)
	{
		Large_B [Row] = Sample[Row + Samples_Start];
	}
	//...............................................................
	Multiply_Matrix_Vector (Transposed_Stencil_Matrix,
	                        Stencil_Matrix_Width,
	                        Stencil_Matrix_Height,
	                        Large_B,
	                        B);
	//=====================/ At*A*X = At*B \========================================================
	Linear_Solution_Gauss (Packed_Square_Matrix,
	                       Stencil_Matrix_Width,
	                       Stencil_Matrix_Width,
	                       B,
	                       X);
	//...............................................................
	for (Row = 0; Row < Polynom_Limit; Row ++)
	{
		Polynom_Ai[Row] = X [Row];
	}
	//===============================================================================
	return;
}
//______________________________________________________________________________________
//														|
// 	Linear_Solution_Gauss ()				|
//														|
//______________________________________________________________________________________
void Linear_Solution_Gauss
(
   double	 &	Matrix[][],
   int	 		Matrix_Height,
   int 			Matrix_Width,
   double 	&	B[],
   double 	&	X[]
)
{
	int Row, Column;
	int Is_Matrix_All_0s;   			// some time occurs, should be detected
	int Max_Row = 0;
	int Max_Col = 0; 						// largest element's row and column
	int Max_Row_2 = 0;        			// second largest element's row and column
	int Max_Col_2 = 0;
	int Iteration;        				// Pass
	double Max_In_Matrix;          	// will store largest  Matrix
	double Tempo_Max;              	// for some purposes
	double Tempo_Sum, tempo_02;    	// for some purposes
	double tempo_03;               				// for some purposes
	int Pivot[], Anti_Pivot[], Col_Done[];
	//........................./ Allocate additional memory \........................
	ArrayResize (Pivot, Matrix_Width);
	ArrayResize (Anti_Pivot, Matrix_Width);
	ArrayResize (Col_Done, Matrix_Width);
	//............/	Finding (abs) Max_In_Matrix  Matrix for first time \......
	Is_Matrix_All_0s = 1;
	Max_In_Matrix = (double)0.0;
	for (Row = 0; Row < Matrix_Height; Row++)
	{
		X[Row] = (double) 0.0; 										// X's will be summed, beginning store 0
		Pivot [Row] = NOT_PROCESSED_YET;
		Col_Done [Row] = NOT_PROCESSED_YET;
		for (Column = 0; Column < Matrix_Width; Column++)
		{
			Tempo_Max = MathAbs (Matrix[Row][Column]);
			// naturally, first step, max_ first
			if (Max_In_Matrix < Tempo_Max)
			{
				Max_In_Matrix = Tempo_Max; 					// store   max and its row and column
				Max_Row = Row;
				Max_Col = Column;
				Is_Matrix_All_0s = 0; // matrix not "0" !
			} // if
		} //column
	}  // row
	if (Is_Matrix_All_0s == 1)
	{
		return; // bad
	}
	//................../ MAIN LOOP. Eliminating elements of matrix \.........................
	for (Iteration = 0; Iteration < Matrix_Height; Iteration++)
	{
		Pivot[Max_Row] = Max_Col;                            		// store row each next max  Pivot
		Anti_Pivot[Iteration] = Max_Row;                      	// store order moving  Anti_Pivot
		tempo_02 = ((double) - 1.0) / Matrix[Max_Row][Max_Col]; 			//  speed up process, prep
		Max_In_Matrix = (double)0.0;
		Col_Done[Max_Col] = DO_NOT_PROCESS;                  		// column  max_ will be NOT changed
		for (Row = 0; Row < Matrix_Height; Row++)
		{
			if (Pivot[Row] >= 0)
			{
				continue;   // this Row was processed earlier
			}
			tempo_03 = Matrix[Row][Max_Col] * tempo_02;
			// tempo_03 leading multiplier
			for (Column = 0; Column < Matrix_Width; Column++)
			{
				if (Col_Done[Column] > 0)
				{
					continue; // the column was already processed earlier
				}
				//.....................................................................................
				Tempo_Max = Matrix[Row][Column] = Matrix[Row][Column]
				                                  + Matrix[Max_Row][Column] * tempo_03;
				//.....................................................................................
				Tempo_Max = (double) MathAbs (Tempo_Max);     // finding max rest matrix  way
				if (Max_In_Matrix < Tempo_Max)
				{
					Max_In_Matrix = Tempo_Max; 					// store   max and its row and column
					Max_Row_2 = Row;
					Max_Col_2 = Column;
				} // if
			}  // column
			B[Row] = B[Row] + B[Max_Row] * tempo_03; // additionally, change right
		} // row
		Max_Row = Max_Row_2;                                       // store   max's row
		Max_Col = Max_Col_2;                                       // store   max's column
	}                                                             // Iteration. Main for ( ends
	//...................../ Back substitution \............................................
	for (Iteration = Matrix_Height - 1; Iteration >= 0; Iteration--)
	{
		Row = Anti_Pivot[Iteration];                      		// keeping order, stored Anti_Pivot
		Tempo_Sum = (double)0.0;                            	// will handle sum
		Column = Pivot[Row];                             		// recall column leading
		tempo_02 = (double) 1.0 / Matrix[Row][Column]; 			// just  speed up division operation
		for (Column = 0; Column < Matrix_Width; Column++)
		{
			if (Column == Pivot[Row] || Matrix[Row][Column] == 0.0 || X[Column] == 0.0)
			{
				continue;	  // nothing to do
			}
			Tempo_Sum = Tempo_Sum + Matrix[Row][Column] * X[Column]; // else, calc sum X*Matrix
		} // Column
		X[Pivot[Row]] = (B[Row] - Tempo_Sum) * tempo_02;
	} // Iteration of substitution
	//............................................................
	return ;
}
//______________________________________________________________________________________
//______________________________________________________________________________________
//													|
// 		Add_Vectors_MQL()					|
//______________________________________________________________________________________
//______________________________________________________________________________________
void Add_Vectors_MQL (double & A[],
                      double & B[],
                      double & C[],
                      int A_Size)
{
	int i;
	for (i = 0; i < A_Size; i++)
	{
		C[i] = A[i] + B[i];
	}
	return ;
}
//______________________________________________________________________________________
//______________________________________________________________________________________
//													|
// 		Subtract_Vectors_MQL()			|
//______________________________________________________________________________________
//______________________________________________________________________________________
void Subtract_Vectors_MQL (double & A[],
                           double & B[],
                           double & C[],
                           int A_Limit)
{
	int i;
	for (i = 0; i < A_Limit; i++)
	{
		C[i] = A[i] - B[i];
	}
	return ;
}
//______________________________________________________________________________________
//______________________________________________________________________________________
//														|
// 		Generate_Samples_MQL()				|
//______________________________________________________________________________________
//______________________________________________________________________________________

void Generate_Samples_MQL
(
   double   &		Buffer[],
   int				Buffer_Size,
   double	 		W,
   double			Amplitude,
   double			Phase,
   double	 		Bias,
   double			Trend
)
{
	int  i ;
	double Tone ;
	//......................................................................................
	for (i = 0; i < Buffer_Size; i ++)
	{
		Buffer[i] = 0.0;
	}
	//......................................................................................
	for (i = 0; i < Buffer_Size; i ++)
	{
		if (W > 0.0)
		{
			Tone = Amplitude * sin (W * (double) i  + Phase);
		}
		else
		{
			Tone = 0.0;
		}
		Buffer[i] = Buffer[i] + Bias + Tone + Trend * i ;
	}
	//..................................................................
	return ;
}
//__________________________________________________________________
//																			|
// 	 	 Array_Deviations_Lite ()								|
//_______________________________________________________|
void Array_Deviations_Lite
(
   double &	Array[],
   int 		Array_Limit,
   int		Last_Bar,
   int 		Shift,
   int 		Sum_Limit,
   double	Array_Mean,
   double	& Deviations_Array[]
)
{
	int 	i;
	int 	idx;
	//...........................................................
	for (i = 0; i < Sum_Limit; i++)
	{
		idx = i + Last_Bar + Shift;
		if ( idx < Array_Limit)
		{
			Deviations_Array[i] = Array[idx] - Array_Mean;
		}
	}
	//...........................................................
	return ;
}
//__________________________________________________________________
//																			|
// 	 	 Arrays_Dot_Product_Lite ()							|
//_______________________________________________________|
double Arrays_Dot_Product_Lite
(
   double	& Array_1[],
   double	& Array_2[],
   int 		Array_Limit
)
{
	int 	i;
	double 	Dot_Product;
	//..............................................................................
	Dot_Product = (double) 0.0;

	for (i = 0; i < Array_Limit; i++)
	{
		Dot_Product += Array_1[i] * Array_2[i];
	}
	//..............................................................................
	return (Dot_Product) ;
}
//\_____________________/ END OF THIS FILE \________________________________/
