matrix.c
/* -*- c-basic-offset: 4 -*- */
/* ====================================================================
* Copyright (c) 1997-2006 Carnegie Mellon University. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* This work was supported in part by funding from the Defense Advanced
* Research Projects Agency and the National Science Foundation of the
* United States of America, and the CMU Sphinx Speech Consortium.
*
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ====================================================================
*
*/
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "sphinxbase/clapack_lite.h"
#include "sphinxbase/matrix.h"
#include "sphinxbase/err.h"
#include "sphinxbase/ckd_alloc.h"
void
norm_3d(float32 ***arr,
uint32 d1,
uint32 d2,
uint32 d3)
{
uint32 i, j, k;
float64 s;
for (i = 0; i < d1; i++) {
for (j = 0; j < d2; j++) {
/* compute sum (i, j) as over all k */
for (k = 0, s = 0; k < d3; k++) {
s += arr[i][j][k];
}
/* do 1 floating point divide */
s = 1.0 / s;
/* divide all k by sum over k */
for (k = 0; k < d3; k++) {
arr[i][j][k] *= s;
}
}
}
}
␌
void
accum_3d(float32 ***out,
float32 ***in,
uint32 d1,
uint32 d2,
uint32 d3)
{
uint32 i, j, k;
for (i = 0; i < d1; i++) {
for (j = 0; j < d2; j++) {
for (k = 0; k < d3; k++) {
out[i][j][k] += in[i][j][k];
}
}
}
}
void
floor_nz_3d(float32 ***m,
uint32 d1,
uint32 d2,
uint32 d3,
float32 floor)
{
uint32 i, j, k;
for (i = 0; i < d1; i++) {
for (j = 0; j < d2; j++) {
for (k = 0; k < d3; k++) {
if ((m[i][j][k] != 0) && (m[i][j][k] < floor))
m[i][j][k] = floor;
}
}
}
}
void
floor_nz_1d(float32 *v,
uint32 d1,
float32 floor)
{
uint32 i;
for (i = 0; i < d1; i++) {
if ((v[i] != 0) && (v[i] < floor))
v[i] = floor;
}
}
void
band_nz_1d(float32 *v,
uint32 d1,
float32 band)
{
uint32 i;
for (i = 0; i < d1; i++) {
if (v[i] != 0) {
if ((v[i] > 0) && (v[i] < band)) {
v[i] = band;
}
else if ((v[i] < 0) && (v[i] > -band)) {
v[i] = -band;
}
}
}
}
#ifndef WITH_LAPACK
float64
determinant(float32 **a, int32 n)
{
E_FATAL("No LAPACK library available, cannot compute determinant (FIXME)\n");
return 0.0;
}
int32
invert(float32 **ainv, float32 **a, int32 n)
{
E_FATAL("No LAPACK library available, cannot compute matrix inverse (FIXME)\n");
return 0;
}
int32
solve(float32 **a, float32 *b, float32 *out_x, int32 n)
{
E_FATAL("No LAPACK library available, cannot solve linear equations (FIXME)\n");
return 0;
}
void
matrixmultiply(float32 ** c, float32 ** a, float32 ** b, int32 n)
{
int32 i, j, k;
memset(c[0], 0, n*n*sizeof(float32));
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
for (k = 0; k < n; ++k) {
c[i][k] += a[i][j] * b[j][k];
}
}
}
}
#else /* WITH_LAPACK */
/* Find determinant through LU decomposition. */
float64
determinant(float32 ** a, int32 n)
{
float32 **tmp_a;
float64 det;
char uplo;
int32 info, i;
/* a is assumed to be symmetric, so we don't need to switch the
* ordering of the data. But we do need to copy it since it is
* overwritten by LAPACK. */
tmp_a = (float32 **)ckd_calloc_2d(n, n, sizeof(float32));
memcpy(tmp_a[0], a[0], n*n*sizeof(float32));
uplo = 'L';
spotrf_(&uplo, &n, tmp_a[0], &n, &info);
det = tmp_a[0][0];
/* det = prod(diag(l))^2 */
for (i = 1; i < n; ++i)
det *= tmp_a[i][i];
ckd_free_2d((void **)tmp_a);
if (info > 0)
return -1.0; /* Generic "not positive-definite" answer */
else
return det * det;
}
int32
solve(float32 **a, /*Input : an n*n matrix A */
float32 *b, /*Input : a n dimesion vector b */
float32 *out_x, /*Output : a n dimesion vector x */
int32 n)
{
char uplo;
float32 **tmp_a;
int32 info, nrhs;
/* a is assumed to be symmetric, so we don't need to switch the
* ordering of the data. But we do need to copy it since it is
* overwritten by LAPACK. */
tmp_a = (float32 **)ckd_calloc_2d(n, n, sizeof(float32));
memcpy(tmp_a[0], a[0], n*n*sizeof(float32));
memcpy(out_x, b, n*sizeof(float32));
uplo = 'L';
nrhs = 1;
sposv_(&uplo, &n, &nrhs, tmp_a[0], &n, out_x, &n, &info);
ckd_free_2d((void **)tmp_a);
if (info != 0)
return -1;
else
return info;
}
/* Find inverse by solving AX=I. */
int32
invert(float32 ** ainv, float32 ** a, int32 n)
{
char uplo;
float32 **tmp_a;
int32 info, nrhs, i;
/* a is assumed to be symmetric, so we don't need to switch the
* ordering of the data. But we do need to copy it since it is
* overwritten by LAPACK. */
tmp_a = (float32 **)ckd_calloc_2d(n, n, sizeof(float32));
memcpy(tmp_a[0], a[0], n*n*sizeof(float32));
/* Construct an identity matrix. */
memset(ainv[0], 0, sizeof(float32) * n * n);
for (i = 0; i < n; i++)
ainv[i][i] = 1.0;
uplo = 'L';
nrhs = n;
sposv_(&uplo, &n, &nrhs, tmp_a[0], &n, ainv[0], &n, &info);
ckd_free_2d((void **)tmp_a);
if (info != 0)
return -1;
else
return info;
}
void
matrixmultiply(float32 ** c, float32 ** a, float32 ** b, int32 n)
{
char side, uplo;
float32 alpha;
side = 'L';
uplo = 'L';
alpha = 1.0;
ssymm_(&side, &uplo, &n, &n, &alpha, a[0], &n, b[0], &n, &alpha, c[0], &n);
}
#endif /* WITH_LAPACK */
void
outerproduct(float32 ** a, float32 * x, float32 * y, int32 len)
{
int32 i, j;
for (i = 0; i < len; ++i) {
a[i][i] = x[i] * y[i];
for (j = i + 1; j < len; ++j) {
a[i][j] = x[i] * y[j];
a[j][i] = x[j] * y[i];
}
}
}
void
scalarmultiply(float32 ** a, float32 x, int32 n)
{
int32 i, j;
for (i = 0; i < n; ++i) {
a[i][i] *= x;
for (j = i+1; j < n; ++j) {
a[i][j] *= x;
a[j][i] *= x;
}
}
}
void
matrixadd(float32 ** a, float32 ** b, int32 n)
{
int32 i, j;
for (i = 0; i < n; ++i)
for (j = 0; j < n; ++j)
a[i][j] += b[i][j];
}
ckd_alloc.h
Sphinx's memory allocation/deallocation routines.
ckd_free_2d
SPHINXBASE_EXPORT void ckd_free_2d(void *ptr)
Free a 2-D array (ptr) previously allocated by ckd_calloc_2d.
Definition ckd_alloc.c:255
ckd_calloc_2d
#define ckd_calloc_2d(d1, d2, sz)
Macro for ckd_calloc_2d.
Definition ckd_alloc.h:270
err.h
Implementation of logging routines.
E_FATAL
#define E_FATAL(...)
Exit with non-zero status after error message.
Definition err.h:81
matrix.h
Matrix and linear algebra functions.
determinant
SPHINXBASE_EXPORT float64 determinant(float32 **a, int32 len)
Calculate the determinant of a positive definite matrix.
Definition matrix.c:147
floor_nz_1d
SPHINXBASE_EXPORT void floor_nz_1d(float32 *v, uint32 d1, float32 floor)
Floor 1-d array.
Definition matrix.c:114
solve
SPHINXBASE_EXPORT int32 solve(float32 **a, float32 *b, float32 *out_x, int32 n)
Solve (if possible) a positive-definite system of linear equations AX=B for X.
Definition matrix.c:159
matrixadd
SPHINXBASE_EXPORT void matrixadd(float32 **inout_a, float32 **b, int32 n)
Add A += B.
Definition matrix.c:309
floor_nz_3d
SPHINXBASE_EXPORT void floor_nz_3d(float32 ***m, uint32 d1, uint32 d2, uint32 d3, float32 floor)
Floor 3-d array.
Definition matrix.c:96
band_nz_1d
SPHINXBASE_EXPORT void band_nz_1d(float32 *v, uint32 d1, float32 band)
Ensures that non-zero values x such that -band < x < band, band > 0 are set to -band if x < 0 and ban...
Definition matrix.c:127
invert
SPHINXBASE_EXPORT int32 invert(float32 **out_ainv, float32 **a, int32 len)
Invert (if possible) a positive definite matrix with QR algorithm.
Definition matrix.c:153
outerproduct
SPHINXBASE_EXPORT void outerproduct(float32 **out_a, float32 *x, float32 *y, int32 len)
Calculate the outer product of two vectors.
Definition matrix.c:281
accum_3d
SPHINXBASE_EXPORT void accum_3d(float32 ***out, float32 ***in, uint32 d1, uint32 d2, uint32 d3)
Floor 3-d array.
Definition matrix.c:78
matrixmultiply
SPHINXBASE_EXPORT void matrixmultiply(float32 **out_c, float32 **a, float32 **b, int32 n)
Multiply C=AB where A and B are symmetric matrices.
Definition matrix.c:166
scalarmultiply
SPHINXBASE_EXPORT void scalarmultiply(float32 **inout_a, float32 x, int32 n)
Multiply a symmetric matrix by a constant in-place.
Definition matrix.c:295
norm_3d
SPHINXBASE_EXPORT void norm_3d(float32 ***arr, uint32 d1, uint32 d2, uint32 d3)
Norm an array.
Definition matrix.c:50