blob: 358af5612d44e087b42856a1b2aeba48ffdfb51e [file] [log] [blame]
/*---------------------------------------------------------------------------*
* matrix_i.c *
* *
* Copyright 2007, 2008 Nuance Communciations, Inc. *
* *
* Licensed under the Apache License, Version 2.0 (the 'License'); *
* you may not use this file except in compliance with the License. *
* *
* You may obtain a copy of the License at *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an 'AS IS' BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*---------------------------------------------------------------------------*/
#include <stdlib.h>
#ifndef _RTT
#include <stdio.h>
#endif
#include <math.h>
#include <string.h>
#include <assert.h>
#include "hmmlib.h"
#include "prelib.h"
#include "portable.h"
#define PIVOT 1
#define DEBUG 0
#define TINY 1.0e-20
#define SIGNIFICANT 0 /* 1.0e-20 */
static const char matrix_i[] = "$Id: matrix_i.c,v 1.2.10.3 2007/10/15 18:06:24 dahan Exp $";
void lubksb(double **mat, int dim, int *index, double *b);
int ludcmp(double **mat, int dim, int *index);
int invert_matrix(covdata **mat, covdata **inv, int dim)
{
double *col, **input;
int ii, jj, *index, err_code;
#if DEBUG
double sum;
int kk;
#endif
ASSERT(mat);
ASSERT(inv);
index = (int *) CALLOC(dim, sizeof(int), "clib.index_imatrix");
col = (double *) CALLOC(dim, sizeof(double), "clib.col");
input = (double **) CALLOC(dim, sizeof(double *), "clib.input_imatrix");
for (ii = 0; ii < dim; ii++)
{
input[ii] = (double *) CALLOC(dim, sizeof(double), "clib.input_imatrix[]");
for (jj = 0; jj < dim; jj++)
input[ii][jj] = mat[ii][jj];
}
if ((err_code = ludcmp(input, dim, index)) > 0) return(err_code);
for (jj = 0; jj < dim; jj++)
{
for (ii = 0; ii < dim; ii++)
col[ii] = 0;
col[jj] = 1;
lubksb(input, dim, index, col);
for (ii = 0; ii < dim; ii++)
inv[ii][jj] = col[ii];
}
for (ii = 0; ii < dim; ii++)
FREE((char *)input[ii]);
FREE((char *)input);
FREE((char *)col);
FREE((char *)index);
#if DEBUG
printf("Testing the inverse:\n");
for (ii = 0; ii < dim; ii++)
{
for (jj = 0; jj < dim; jj++)
{
sum = 0;
for (kk = 0; kk < dim; kk++)
sum += mat[ii][kk] * inv[kk][jj];
printf("%.2f ", sum);
}
printf("\n");
}
#endif
return (0);
}
int ludcmp(double **mat, int dim, int *index)
/*
** This routine is straight out of the numerical recipes in C
*/
{
int ii, imax = 0, jj, kk;
double big, dumm, sum, temp;
double *vv;
vv = (double *) CALLOC(dim + 5, sizeof(double), "clib.ludcmp.vv");
#if PIVOT
for (ii = 0; ii < dim; ii++)
{
big = 0;
for (jj = 0; jj < dim; jj++)
if ((temp = (double) fabs(mat[ii][jj])) > big) big = temp;
if (big <= SIGNIFICANT)
{
log_report("Singular matrix in routine ludcmp\n");
return (SINGULAR_MATRIX);
}
vv[ii] = 1 / big;
}
#endif
for (jj = 0; jj < dim; jj++)
{
for (ii = 0; ii < jj; ii++)
{
sum = mat[ii][jj];
for (kk = 0; kk < ii; kk++)
sum -= mat[ii][kk] * mat[kk][jj];
mat[ii][jj] = sum;
}
big = 0;
for (ii = jj; ii < dim; ii++)
{
sum = mat[ii][jj];
for (kk = 0; kk < jj; kk++)
sum -= mat[ii][kk] * mat[kk][jj];
mat[ii][jj] = sum;
if ((dumm = (double)(vv[ii] * fabs(sum))) >= big)
{
big = dumm;
imax = ii;
}
}
#if PIVOT
if (jj != imax)
{
for (kk = 0; kk < dim; kk++)
{
dumm = mat[imax][kk];
mat[imax][kk] = mat[jj][kk];
mat[jj][kk] = dumm;
}
vv[imax] = vv[jj];
}
index[jj] = imax;
#else
index[jj] = jj;
#endif
if (fabs(mat[jj][jj]) <= SIGNIFICANT) mat[jj][jj] = (double)TINY;
if (jj < (dim - 1))
{
dumm = 1 / mat[jj][jj];
for (ii = jj + 1; ii < dim; ii++)
mat[ii][jj] *= dumm;
}
}
FREE((char *)vv);
return (0);
}
void lubksb(double **mat, int dim, int *index, double *b)
{
int ii, ix = -1, ip, jj;
double sum;
for (ii = 0; ii < dim; ii++)
{
#if PIVOT
ip = index[ii];
sum = b[ip];
b[ip] = b[ii];
#else
sum = b[ii];
#endif
if (ix >= 0)
for (jj = ix; jj < ii; jj++)
sum -= mat[ii][jj] * b[jj];
else if (sum) ix = ii;
b[ii] = sum;
}
for (ii = dim - 1; ii >= 0; ii--)
{
sum = b[ii];
for (jj = ii + 1; jj < dim; jj++)
sum -= mat[ii][jj] * b[jj];
b[ii] = sum / mat[ii][ii];
}
}