Home | History | Annotate | Download | only in clib
      1 /*---------------------------------------------------------------------------*
      2  *  matrix_i.c  *
      3  *                                                                           *
      4  *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
      5  *                                                                           *
      6  *  Licensed under the Apache License, Version 2.0 (the 'License');          *
      7  *  you may not use this file except in compliance with the License.         *
      8  *                                                                           *
      9  *  You may obtain a copy of the License at                                  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0                           *
     11  *                                                                           *
     12  *  Unless required by applicable law or agreed to in writing, software      *
     13  *  distributed under the License is distributed on an 'AS IS' BASIS,        *
     14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
     15  *  See the License for the specific language governing permissions and      *
     16  *  limitations under the License.                                           *
     17  *                                                                           *
     18  *---------------------------------------------------------------------------*/
     19 
     20 
     21 #include <stdlib.h>
     22 #ifndef _RTT
     23 #include <stdio.h>
     24 #endif
     25 #include <math.h>
     26 #include <string.h>
     27 #include <assert.h>
     28 
     29 #include "hmmlib.h"
     30 #include "prelib.h"
     31 #include "portable.h"
     32 
     33 #define PIVOT 1
     34 #define DEBUG 0
     35 
     36 #define TINY  1.0e-20
     37 #define SIGNIFICANT 0 /* 1.0e-20 */
     38 
     39 static const char matrix_i[] = "$Id: matrix_i.c,v 1.2.10.3 2007/10/15 18:06:24 dahan Exp $";
     40 
     41 void lubksb(double **mat, int dim, int *index, double *b);
     42 int  ludcmp(double **mat, int dim, int *index);
     43 
     44 int invert_matrix(covdata **mat, covdata **inv, int dim)
     45 {
     46   double *col, **input;
     47   int ii, jj, *index, err_code;
     48 #if DEBUG
     49   double  sum;
     50   int     kk;
     51 #endif
     52 
     53   ASSERT(mat);
     54   ASSERT(inv);
     55   index = (int *) CALLOC(dim, sizeof(int), "clib.index_imatrix");
     56   col = (double *) CALLOC(dim, sizeof(double), "clib.col");
     57   input = (double **) CALLOC(dim, sizeof(double *), "clib.input_imatrix");
     58   for (ii = 0; ii < dim; ii++)
     59   {
     60     input[ii] = (double *) CALLOC(dim, sizeof(double), "clib.input_imatrix[]");
     61     for (jj = 0; jj < dim; jj++)
     62       input[ii][jj] = mat[ii][jj];
     63   }
     64 
     65   if ((err_code = ludcmp(input, dim, index)) > 0) return(err_code);
     66   for (jj = 0; jj < dim; jj++)
     67   {
     68     for (ii = 0; ii < dim; ii++)
     69       col[ii] = 0;
     70     col[jj] = 1;
     71     lubksb(input, dim, index, col);
     72     for (ii = 0; ii < dim; ii++)
     73       inv[ii][jj] = col[ii];
     74   }
     75   for (ii = 0; ii < dim; ii++)
     76     FREE((char *)input[ii]);
     77   FREE((char *)input);
     78   FREE((char *)col);
     79   FREE((char *)index);
     80 
     81 #if DEBUG
     82   printf("Testing the inverse:\n");
     83   for (ii = 0; ii < dim; ii++)
     84   {
     85     for (jj = 0; jj < dim; jj++)
     86     {
     87       sum = 0;
     88       for (kk = 0; kk < dim; kk++)
     89         sum += mat[ii][kk] * inv[kk][jj];
     90       printf("%.2f ", sum);
     91     }
     92     printf("\n");
     93   }
     94 #endif
     95 
     96   return (0);
     97 }
     98 
     99 int ludcmp(double **mat, int dim, int *index)
    100 /*
    101 **  This routine is straight out of the numerical recipes in C
    102 */
    103 {
    104   int ii, imax = 0, jj, kk;
    105   double big, dumm, sum, temp;
    106   double *vv;
    107 
    108   vv = (double *) CALLOC(dim + 5, sizeof(double), "clib.ludcmp.vv");
    109 #if PIVOT
    110   for (ii = 0; ii < dim; ii++)
    111   {
    112     big = 0;
    113     for (jj = 0; jj < dim; jj++)
    114       if ((temp = (double) fabs(mat[ii][jj])) > big) big = temp;
    115     if (big <= SIGNIFICANT)
    116     {
    117       log_report("Singular matrix in routine ludcmp\n");
    118       return (SINGULAR_MATRIX);
    119     }
    120     vv[ii] = 1 / big;
    121   }
    122 #endif
    123 
    124   for (jj = 0; jj < dim; jj++)
    125   {
    126     for (ii = 0; ii < jj; ii++)
    127     {
    128       sum = mat[ii][jj];
    129       for (kk = 0; kk < ii; kk++)
    130         sum -= mat[ii][kk] * mat[kk][jj];
    131       mat[ii][jj] = sum;
    132     }
    133     big = 0;
    134     for (ii = jj; ii < dim; ii++)
    135     {
    136       sum = mat[ii][jj];
    137       for (kk = 0; kk < jj; kk++)
    138         sum -= mat[ii][kk] * mat[kk][jj];
    139       mat[ii][jj] = sum;
    140       if ((dumm = (double)(vv[ii] * fabs(sum))) >= big)
    141       {
    142         big = dumm;
    143         imax = ii;
    144       }
    145     }
    146 
    147 #if PIVOT
    148     if (jj != imax)
    149     {
    150       for (kk = 0; kk < dim; kk++)
    151       {
    152         dumm = mat[imax][kk];
    153         mat[imax][kk] = mat[jj][kk];
    154         mat[jj][kk] = dumm;
    155       }
    156       vv[imax] = vv[jj];
    157     }
    158     index[jj] = imax;
    159 #else
    160     index[jj] = jj;
    161 #endif
    162 
    163     if (fabs(mat[jj][jj]) <= SIGNIFICANT) mat[jj][jj] = (double)TINY;
    164     if (jj < (dim - 1))
    165     {
    166       dumm = 1 / mat[jj][jj];
    167       for (ii = jj + 1; ii < dim; ii++)
    168         mat[ii][jj] *= dumm;
    169     }
    170   }
    171 
    172   FREE((char *)vv);
    173   return (0);
    174 }
    175 
    176 void lubksb(double **mat, int dim, int *index, double *b)
    177 {
    178   int ii, ix = -1, ip, jj;
    179   double sum;
    180 
    181   for (ii = 0; ii < dim; ii++)
    182   {
    183 #if PIVOT
    184     ip = index[ii];
    185     sum = b[ip];
    186     b[ip] = b[ii];
    187 #else
    188     sum = b[ii];
    189 #endif
    190     if (ix >= 0)
    191       for (jj = ix; jj < ii; jj++)
    192         sum -= mat[ii][jj] * b[jj];
    193     else if (sum) ix = ii;
    194     b[ii] = sum;
    195   }
    196 
    197   for (ii = dim - 1; ii >= 0; ii--)
    198   {
    199     sum = b[ii];
    200     for (jj = ii + 1; jj < dim; jj++)
    201       sum -= mat[ii][jj] * b[jj];
    202     b[ii] = sum / mat[ii][ii];
    203   }
    204 }
    205