#ifndef __DA_MODULE_H
#define __DA_MODULE_H

#define PYARRAY_DATATYPE char

/**
 * likelihood = DA.mixture_likelihood(data, means, covars, weights, min_diag)
 *
 * Returns the log-likelihood of data given an N dimensional mixture of
 * k-Gaussian models.
 *
 * Where:
 *   - data is a M-by-N matrix containing N-dimensional datapoints (one per
 *     row) to use when computing the log-likelihood.
 *
 *   - means is a k-by-N matrix containing the means (one per row) of the
 *     k-Gaussian models.
 *
 *   - covars is a 3D matrix composed of k N-by-N covariance matrices.
 *
 *   - weights is a 1-by-k vector of model weights.
 *
 *   - min_diag is a small number for perturbing ill-conditioned covariance
 *     matrices.  Optional.  If not specified, defaults to 1.0e-8.
 */
static PyObject *
DA_mixture_likelihood(PyObject *self, PyObject *args);

/**
 *
 */
static PyObject *
DA_covar_weights_estimate(PyObject *self, PyObject *args);

/** 
 *
 */
static PyObject *
DA_covariance_estimate(PyObject *self, PyObject *args);

/** 
 *
 */
static PyObject *
DA_fix_covariance_matrix(PyObject *self, PyObject *args);

static PyObject *
DA_is_posdef_dmat(PyObject *self, PyObject *args);

static PyObject *
DA_make_diag_matrix(PyObject *self, PyObject *args);

/* begin stuff that belongs elsewhere */
static 
int est_covar_matrices(double ***covars,
		       double  **data,
		       double  **means,
		       int      *clust_label,
		       int       num_data,
		       int       num_dims, 
		       int       K);


static
int fix_covariance_matrix(double **covar, int num_rows, int num_cols);


/**
 * Compute Cholesky Docomposition
 * based on Numerical Recipeis code
 */
static PyObject *
DA_dcholdc(PyObject *self, PyObject *args);

/**
Compute the conditional probability of the datum assuming it was drawn from a 
multivariate normal distribution with the specified mean and covariance matrix,
using the normal probability density function.  Returns the vector of proba-
bilities, one for each datum.
 */
static PyObject *
DA_vector_prob_gauss(PyObject *self, PyObject *args);


/* end stuff that belongs elsewhere */

/******************************
 *  General Array Functions   *
 ******************************/
/**
 *
 */
void
DAArray_Free(PyObject *object, void *ptr);

/**
 *
 */
int
DAArray_Is2DSymmetric(double **matrix, int dim);

/*********************************
 *  Double Array Functions       *
 *********************************/
/**
 *
 */
static PyObject *
DA_TestAsDouble1D(PyObject *self, PyObject *args);

/**
 *
 */
static PyObject *
DA_TestAsDouble2D(PyObject *self, PyObject *args);

/**
 *
 */
static PyObject *
DA_TestAsDouble3D(PyObject *self, PyObject *args);

/**
 *
 */
double *
DAArray_AsDouble1D(PyObject **object, int *dim1);

/**
 *
 */
double **
DAArray_AsDouble2D(PyObject **object, int *dim1, int *dim2);

/**
 *
 */
double ***
DAArray_AsDouble3D(PyObject **object, int *dim1, int *dim2, int *dim3);

/**
 *
 */
double *
DAArray_NewDouble1D(PyObject **object, int dim1);

/**
 *
 */
double **
DAArray_NewDouble2D(PyObject **object, int dim1, int dim2);

/**
 *
 */
double ***
DAArray_NewDouble3D(PyObject **object, int dim1, int dim2, int dim3);

/**
 *
 */
void
DAArray_PrintDouble1D(double *matrix, int dim1, int indent);

/**
 *
 */
void
DAArray_PrintDouble2D(double **matrix, int dim1, int dim2, int indent);

/**
 *
 */
void
DAArray_PrintDouble3D(double ***matrix, int dim1, int dim2, int dim3, int indent);

/******************************
 *    Int Array Functions     *
 ******************************/
/**
 *
 */
static PyObject *
DA_TestAsInt1D(PyObject *self, PyObject *args);

/**
 *
 */
static PyObject *
DA_TestAsInt2D(PyObject *self, PyObject *args);

/**
 *
 */
static PyObject *
DA_TestAsInt3D(PyObject *self, PyObject *args);

/**
 *
 */
int *
DAArray_AsInt1D(PyObject **object, int *dim1);

/**
 *
 */
int **
DAArray_AsInt2D(PyObject **object, int *dim1, int *dim2);

/**
 *
 */
int ***
DAArray_AsInt3D(PyObject **object, int *dim1, int *dim2, int *dim3);

/**
 *
 */
int *
DAArray_NewInt1D(PyObject **object, int dim1);

/**
 *
 */
int **
DAArray_NewInt2D(PyObject **object, int dim1, int dim2);

/**
 *
 */
int ***
DAArray_NewInt3D(PyObject **object, int dim1, int dim2, int dim3);

/**
 *
 */
void
DAArray_PrintInt1D(int *matrix, int dim1, int indent);

/**
 *
 */
void
DAArray_PrintInt2D(int **matrix, int dim1, int dim2, int indent);

/**
 *
 */
void
DAArray_PrintInt3D(int ***matrix, int dim1, int dim2, int dim3, int indent);


#endif








