////////////////////////////////////////
// Jeremy R. Faller
// (c) Digital Sweetener, 2007
//
// This software is distributed under the terms of the MIT license:
//  http://www.opensource.org/licenses/mit-license.php
//
// The original author requests that users send a short e-mail to
//  software-mit@digitalsweetener.com
// describing where and how the software is being used.  Compliance
// with this condition is optional.

#if !defined(MTRX_H_)
#define MTRX_H_

#if defined(__cplusplus)
extern "C" {
#endif

////////////////////////////////////////
// Includes
#include <stdbool.h>
#include <stdio.h>


////////////////////////////////////////
// Typedefs
typedef float MTRX_Element_t;

typedef struct
{
    bool            onHeap;
	unsigned        rows, cols, origSize;
    MTRX_Element_t  *vals;
} MTRX_t;


////////////////////////////////////////
// Create an empty matrix
extern void MTRX_CreateEmpty(MTRX_t *inMat);


////////////////////////////////////////
// Create a Matrix
// If a pointer is passed in, it is for matrix storage.
// If the pointer is nonzero, a zero'd matrix is created
extern bool MTRX_Create(MTRX_t *inMat, unsigned inRows, unsigned inCols, MTRX_Element_t *inVals);


////////////////////////////////////////
// Create an identity matrix
extern bool MTRX_CreateIdentity(MTRX_t *inMat, unsigned inSize, MTRX_Element_t *inVals);


////////////////////////////////////////
// Destroy a matrix
extern void MTRX_Destroy(MTRX_t *inMat);


////////////////////////////////////////
// Copy a matrix
extern bool MTRX_Copy(MTRX_t *outMat, MTRX_t *inMat);


////////////////////////////////////////
// Get an element
extern MTRX_Element_t MTRX_Access(MTRX_t *inMat, unsigned inRow, unsigned inCol);


////////////////////////////////////////
// Get Rows
extern unsigned MTRX_Rows(MTRX_t *inMat);


////////////////////////////////////////
// Get Rows
extern unsigned MTRX_Cols(MTRX_t *inMat);


////////////////////////////////////////
// Get Matrix size
//	returns rows x cols
extern unsigned MTRX_Size(MTRX_t *inMat);


////////////////////////////////////////
// Get Matrix allocated size
extern unsigned MTRX_AllocatedSize(MTRX_t *inMat);


////////////////////////////////////////
// Is this matrix on the heap?
extern bool MTRX_OnHeap(MTRX_t *inMat);


////////////////////////////////////////
// Set a matrix to a given array
extern void MTRX_SetToArray(MTRX_t *ioMat, unsigned inRows, unsigned inCols, MTRX_Element_t *inData);


////////////////////////////////////////
// Set a matrix to a given array
extern bool MTRX_CopyFromArray(MTRX_t *ioMat, unsigned inRows, unsigned inCols, MTRX_Element_t *inData);


////////////////////////////////////////
// Copy out a matrix
extern void MTRX_CopyToData(MTRX_t *inMat, unsigned inSize, void *outData);


////////////////////////////////////////
// Copy out a matrix
extern void MTRX_CopyToArray(MTRX_t *inMat, unsigned inNumElements, MTRX_Element_t *outData);


////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Math


////////////////////////////////////////
// Adds a scalar to a matrix
// Can write results back
extern bool MTRX_ScalarAdd(MTRX_t *outMat, MTRX_t *inMat, MTRX_Element_t inVal);


////////////////////////////////////////
// Subtract a scalar from a matrix
// Can be in place
extern bool MTRX_ScalarSubtract(MTRX_t *outMat, MTRX_t *inMat, MTRX_Element_t inVal);


////////////////////////////////////////
// Multiply a scalar to a matrix
// Can be in place
extern bool MTRX_ScalarMultiply(MTRX_t *outMat, MTRX_t *inMat, MTRX_Element_t inVal);


////////////////////////////////////////
// Add two matrices together
// Can be in place
extern bool MTRX_Add(MTRX_t *outMat, MTRX_t *inMat1, MTRX_t *inMat2);


////////////////////////////////////////
// Add two matrices together
// Can be in place
extern bool MTRX_Subtract(MTRX_t *outMat, MTRX_t *inMat1, MTRX_t *inMat2);


////////////////////////////////////////
// Multiply two matrices
// OUT OF PLACE
extern bool MTRX_Multiply(MTRX_t *outMat, MTRX_t *inMat1, MTRX_t *inMat2);


////////////////////////////////////////
// Invert the given matrix
//  Matrix must be square.
//  Returns true if the matrix could be inverted, otherwise false.
//  If the matrix cannot be inverted, the matrix might be trampled.
//  The second parameter is temporary storage for the pivoting, which
//  is not used if n == 2.  For a nxn matrix, the storage requirements
//  are 3n.  If no array is is passed in, a temporary buffer is
//  allocated out of the heap.
//
//  Uses the closed form solution for 2x2, otherwise it uses Gauss-Jordan
//  elimination will full pivoting.
//
//  The algorithm was adapted from Numerical Receipes in C.
extern bool MTRX_Invert(MTRX_t *ioMat, unsigned *indxc);


////////////////////////////////////////
// Transpose a matrix (inplace)
//	When possible use the out of place transpose code.
extern bool MTRX_Transpose(MTRX_t *outMat, MTRX_t *inMat);
extern bool MTRX_Transpose_InPlace(MTRX_t *ioMat);


////////////////////////////////////////
// Print a matrix
extern void MTRX_Print(FILE *inFP, MTRX_t *inMat);


#if defined(__cplusplus)
}
#endif

#endif MTRX_H_