/*
   Project: Adun

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "Base/AdMatrix.h"
/** Sets a double matrix with value
\param DoubleMatrix a DoubleMatrix structure
\param value the value to be set
**/
inline void AdSetDoubleMatrixWithValue(DoubleMatrix *matrix_s, double value)
{
	int i, j;

	for(i=0; i<matrix_s->no_rows; i++)
		for(j=0; j<matrix_s->no_columns; j++)
			matrix_s->matrix[i][j] = value;
}

/** Sets a float matrix with value
\param FloatMatrix a FloatMatrix structure
\param value the value to be set
**/

inline void AdSetFloatMatrixWithValue(FloatMatrix *matrix_s,  float value)
{
	int i, j;

	for(i=0; i<matrix_s->no_rows; i++)
		for(j=0; j<matrix_s->no_rows; j++)
			matrix_s->matrix[i][j] = value;
}
/** Sets an int matrix with value
\param IntMatrix an IntMatrix structure
\param value the value to be set
**/

inline void AdSetIntMatrixWithValue(IntMatrix *matrix_s, int value)
{
	int i, j;

	for(i=0; i<matrix_s->no_rows; i++)
		for(j=0; j<matrix_s->no_columns; j++)
			matrix_s->matrix[i][j] = value;
}

/**
Returns a subset of matrix_s defined by start_row and end_row (inclusive)
\param matrix_s An int matrix structure
\param start_row the start_row
\param end_row the end_row
\return An IntMatrix structure for the matrix subset
**/

inline IntMatrix* AdIntMatrixFromRowSection(IntMatrix *matrix_s, int start_row, int end_row)
{
	int i, j, k;
	IntMatrix *ret_matrix;

	ret_matrix = AdAllocateIntMatrix(((end_row - start_row) +1), matrix_s->no_columns);

	for(i=start_row, k=0; i< (end_row +1); i++, k++)
		for(j=0; j<ret_matrix->no_columns; j++)
			ret_matrix->matrix[k][j] = matrix_s->matrix[i][j];

	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by start_row and end_row (inclusive)
\param matrix_s An FloatMatrix structure
\param start_row the start_row
\param end_row the end_row
\return A FloatMatrix structure for the matrix subset
**/
			
inline FloatMatrix* AdFloatMatrixFromRowSection(FloatMatrix *matrix_s, int start_row, int end_row)
{
	int i, j, k;
	FloatMatrix *ret_matrix;

	ret_matrix = AdAllocateFloatMatrix(((end_row - start_row) +1), matrix_s->no_columns);

	for(i=start_row, k=0; i< (end_row +1); i++, k++)
		for(j=0; j<ret_matrix->no_columns; j++)
			ret_matrix->matrix[k][j] = matrix_s->matrix[i][j];

	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by start_row and end_row (inclusive)
\param matrix_s An DoubleMatrix structure
\param start_row the start_row
\param end_row the end_row
\return A DoubleMatrix structure for the matrix subset
**/

inline DoubleMatrix* AdDoubleMatrixFromRowSection(DoubleMatrix *matrix_s, int start_row, int end_row)
{
	int i, j, k;
	DoubleMatrix *ret_matrix;

	ret_matrix = AdAllocateDoubleMatrix(((end_row - start_row) +1), matrix_s->no_columns);

	for(i=start_row, k=0; i< (end_row +1); i++, k++)
		for(j=0; j<ret_matrix->no_columns; j++)
			ret_matrix->matrix[k][j] = matrix_s->matrix[i][j];

	return ret_matrix;
}

/**
Returns a subset of matrix_s defined by the array rows
\param matrix_s An int matrix structure
\param rows An array containing the indices of the rows with which to make the new matrix
\param no_rows  the number of elements in rows
\return An IntMatrix structure for the matrix subset
**/

inline IntMatrix* AdIntMatrixFromRowSelection(IntMatrix *matrix_s, int* rows, int no_rows)
{
	int i, j;
	IntMatrix *ret_matrix;

	ret_matrix = AdAllocateIntMatrix(no_rows, matrix_s->no_columns);
	for(i=0; i<no_rows; i++)
		for(j=0; j<ret_matrix->no_columns; j++)
			ret_matrix->matrix[i][j] = matrix_s->matrix[rows[i]][j];	 

	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by the array rows
\param matrix_s An FloatMatrix structure
\param rows An array containing the indices of the rows with which to make the new matrix
\param no_rows  the number of elements in rows
\return An FloatMatrix structure for the matrix subset
**/

inline FloatMatrix* AdFloatMatrixFromRowSelection(FloatMatrix *matrix_s, int* rows, int no_rows)
{
	int i, j;
	FloatMatrix *ret_matrix;

	ret_matrix = AdAllocateFloatMatrix(no_rows, matrix_s->no_columns);
	for(i=0; i<no_rows; i++)
		for(j=0; j<ret_matrix->no_columns; j++)
			ret_matrix->matrix[i][j] = matrix_s->matrix[rows[i]][j];	
	
	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by the array rows
\param matrix_s An DoubleMatrix structure
\param rows An array containing the indices of the rows with which to make the new matrix
\param no_rows  the number of elements in rows
\return An DoubleMatrix structure for the matrix subset
**/

inline DoubleMatrix* AdDoubleMatrixFromRowSelection(DoubleMatrix *matrix_s, int* rows, int no_rows)
{	
	int i, j;
	DoubleMatrix *ret_matrix;

	ret_matrix = AdAllocateDoubleMatrix(no_rows, matrix_s->no_columns);
	for(i=0; i<no_rows; i++)
		for(j=0; j<ret_matrix->no_columns; j++)
			ret_matrix->matrix[i][j] = matrix_s->matrix[rows[i]][j];	
	
	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by start_column and end_column (inclusive)
\param matrix_s An IntMatrix structure
\param start_column the start_column
\param end_column the end_column
\return An IntMatrix structure for the matrix subset
**/

inline IntMatrix* AdIntMatrixFromColumnSection(IntMatrix *matrix_s, int start_column, int end_column)
{
	int i, j, k;
	IntMatrix *ret_matrix;

	ret_matrix = AdAllocateIntMatrix(matrix_s->no_rows, ((end_column - start_column) +1));
	
	for(i=0; i< ret_matrix->no_rows; i++)
		for(j=start_column, k=0; j<end_column+1; j++, k++)
			ret_matrix->matrix[i][k] = matrix_s->matrix[i][j];
	
	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by start_column and end_column (inclusive)
\param matrix_s A FloatMatrix structure
\param start_column the start_column
\param end_column the end_column
\return A FloatMatrix structure for the matrix subset
**/

inline FloatMatrix* AdFloatMatrixFromColumnSection(FloatMatrix *matrix_s, int start_column, int end_column)
{
	int i, j, k;
	FloatMatrix *ret_matrix;

	ret_matrix = AdAllocateFloatMatrix(matrix_s->no_rows, ((end_column - start_column) +1));
	
	for(i=0; i< ret_matrix->no_rows; i++)
		for(j=start_column, k=0; j<end_column+1; j++, k++)
			ret_matrix->matrix[i][k] = matrix_s->matrix[i][j];
	
	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by start_column and end_column (inclusive)
\param matrix_s A DoubleMatrix structure
\param start_column the start_column
\param end_column the end_column
\return A DoubleMatrix structure for the matrix subset
**/

inline DoubleMatrix* AdDoubleMatrixFromColumnSection(DoubleMatrix *matrix_s, int start_column, int end_column)
{
	int i, j, k;
	DoubleMatrix *ret_matrix;

	ret_matrix = AdAllocateDoubleMatrix(matrix_s->no_rows, ((end_column - start_column) +1));
	
	for(i=0; i< ret_matrix->no_rows; i++)
		for(j=start_column, k=0; j<end_column+1; j++, k++)
			ret_matrix->matrix[i][k] = matrix_s->matrix[i][j];
	
	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by the array columns
\param matrix_s An IntMatrix structure
\param columns An array containing the indices of the columns with which to make the new matrix
\param no_columns  the number of elements in columns
\return An IntMatrix structure for the matrix subset
**/

inline IntMatrix* AdIntMatrixFromColumnSelection(IntMatrix *matrix_s, int* columns, int no_columns)
{
	int i, j;
	IntMatrix *ret_matrix;

	ret_matrix = AdAllocateIntMatrix(matrix_s->no_rows, no_columns);
	for(i=0; i<ret_matrix->no_rows; i++)
		for(j=0; j<no_columns; j++)
			ret_matrix->matrix[i][j] = matrix_s->matrix[i][columns[j]];	 

	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by the array columns
\param matrix_s A FloatMatrix structure
\param columns An array containing the indices of the columns with which to make the new matrix
\param no_columns  the number of elements in columns
\return A FloatMatrix structure for the matrix subset
**/

inline FloatMatrix* AdFloatMatrixFromColumnSelection(FloatMatrix *matrix_s, int* columns, int no_columns)
{
	int i, j;
	FloatMatrix *ret_matrix;

	ret_matrix = AdAllocateFloatMatrix(matrix_s->no_rows, no_columns);
	for(i=0; i<ret_matrix->no_rows; i++)
		for(j=0; j<no_columns; j++)
			ret_matrix->matrix[i][j] = matrix_s->matrix[i][columns[j]];	 

	return ret_matrix;
}
/**
Returns a subset of matrix_s defined by the array columns
\param matrix_s A DoubleMatrix structure
\param columns An array containing the indices of the columns with which to make the new matrix
\param no_columns  the number of elements in columns
\return A DoubleMatrix structure for the matrix subset
**/

inline DoubleMatrix* AdDoubleMatrixFromColumnSelection(DoubleMatrix *matrix_s, int* columns, int no_columns)
{
	int i, j;
	DoubleMatrix *ret_matrix;

	ret_matrix = AdAllocateDoubleMatrix(matrix_s->no_rows, no_columns);
	for(i=0; i<ret_matrix->no_rows; i++)
		for(j=0; j<no_columns; j++)
			ret_matrix->matrix[i][j] = matrix_s->matrix[i][columns[j]];	 

	return ret_matrix;
}

/**
Frees a DoubleMatrix struct
\param matrix_s the struct to be freed
**/

inline void AdFreeDoubleMatrix(DoubleMatrix* matrix_s)
{
	free(matrix_s->matrix[0]);
	free(matrix_s->matrix);
	free(matrix_s);
}
/**
Frees an IntMatrix struct
\param matrix_s the struct to be freed
**/

inline void AdFreeIntMatrix(IntMatrix* matrix_s)
{

	free(matrix_s->matrix[0]);
	free(matrix_s->matrix);
	free(matrix_s);
}
/**
Frees an FloatMatrix struct
\param matrix_s the struct to be freed
**/

inline void AdFreeFloatMatrix(FloatMatrix* matrix_s)
{
	free(matrix_s->matrix[0]);
	free(matrix_s->matrix);
	free(matrix_s);
}
/**
Allocates a DoubleMatrix struct. It should be freed using the corresponding free function
\param no_rows the number of rows in the matrix
\param no_columns the number of columns in the matrix
\return A DoubleMatrix struct (uninitialised)
**/

inline DoubleMatrix* AdAllocateDoubleMatrix(int no_rows, int no_columns)
{
	int i,j;
	double* array;
	DoubleMatrix *ret_matrix;

	ret_matrix = (DoubleMatrix*)malloc(sizeof(DoubleMatrix));
	ret_matrix->no_columns = no_columns;
	ret_matrix->no_rows = no_rows;
	ret_matrix->matrix = (double**)malloc(ret_matrix->no_rows*sizeof(double*));

	array = (double*)malloc(no_rows*no_columns*sizeof(double));

	//malloc an array of pointers to act as indicies into array
	//i.e. emulating a matrix

	ret_matrix->matrix = (double**)malloc(no_rows*sizeof(double*));
	
	//array + j (array[j]) is pointer arithmetic. Unless the computer knows
	//what type of memory array points to then it may take the wrong step size
	//it isnt necessary to specify matrixs pointer type as all pointers are the same size

	for(i=0, j=0; i < no_rows; i++, j = j + no_columns)
			ret_matrix->matrix[i] = array + j;

	return ret_matrix;
}
/**
Allocates a FloatMatrix struct. It should be freed using the corresponding free function
\param no_rows the number of rows in the matrix
\param no_columns the number of columns in the matrix
\return A FloatMatrix struct (uninitialised)
**/

inline FloatMatrix* AdAllocateFloatMatrix(int no_rows, int no_columns)
{
	int i,j;
	float* array;
	FloatMatrix *ret_matrix;

	ret_matrix = (FloatMatrix*)malloc(sizeof(FloatMatrix));
	ret_matrix->no_columns = no_columns;
	ret_matrix->no_rows = no_rows;
	ret_matrix->matrix = (float**)malloc(ret_matrix->no_rows*sizeof(float*));

	array = (float*)malloc(no_rows*no_columns*sizeof(float));
	ret_matrix->matrix = (float**)malloc(no_rows*sizeof(float*));
	
	for(i=0, j=0; i < no_rows; i++, j = j + no_columns)
			ret_matrix->matrix[i] = array + j;

	return ret_matrix;

}

/**
Allocates an IntMatrix struct. It should be freed using the corresponding free function
\param no_rows the number of rows in the matrix
\param no_columns the number of columns in the matrix
\return An IntMatrix struct (uninitialised)
**/

inline IntMatrix* AdAllocateIntMatrix(int no_rows, int no_columns)
{
	int i,j;
	int* array;
	IntMatrix *ret_matrix;

	ret_matrix = (IntMatrix*)malloc(sizeof(IntMatrix));
	ret_matrix->no_columns = no_columns;
	ret_matrix->no_rows = no_rows;

	array = (int*)malloc(no_rows*no_columns*sizeof(int));
	ret_matrix->matrix = (int**)malloc(no_rows*sizeof(int*));
	
	for(i=0, j=0; i < no_rows; i++, j = j + no_columns)
			ret_matrix->matrix[i] = array + j;

	return ret_matrix;
}
