1 /* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* ====================================================================
3 * Copyright (c) 1999-2007 Carnegie Mellon University. All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
18 * This work was supported in part by funding from the Defense Advanced
19 * Research Projects Agency and the National Science Foundation of the
20 * United States of America, and the CMU Sphinx Speech Consortium.
22 * THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
23 * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
24 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
26 * NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * ====================================================================
42 #include "sphinxbase/logmath.h"
43 #include "sphinxbase/err.h"
44 #include "sphinxbase/ckd_alloc.h"
45 #include "sphinxbase/mmio.h"
46 #include "sphinxbase/bio.h"
47 #include "sphinxbase/strfuncs.h"
55 float64 log10_of_base;
56 float64 inv_log_of_base;
57 float64 inv_log10_of_base;
62 logmath_init(float64 base, int shift, int use_table)
69 /* Check that the base is correct. */
71 E_ERROR("Base must be greater than 1.0\n");
75 /* Set up various necessary constants. */
76 lmath = ckd_calloc(1, sizeof(*lmath));
79 lmath->log_of_base = log(base);
80 lmath->log10_of_base = log10(base);
81 lmath->inv_log_of_base = 1.0/lmath->log_of_base;
82 lmath->inv_log10_of_base = 1.0/lmath->log10_of_base;
83 lmath->t.shift = shift;
84 /* Shift this sufficiently that overflows can be avoided. */
85 lmath->zero = MAX_NEG_INT32 >> (shift + 2);
90 /* Create a logadd table with the appropriate width */
91 maxyx = (uint32) (log(2.0) / log(base) + 0.5) >> shift;
93 if (maxyx < 256) width = 1;
94 else if (maxyx < 65536) width = 2;
97 lmath->t.width = width;
98 /* Figure out size of add table required. */
99 byx = 1.0; /* Maximum possible base^{y-x} value - note that this implies that y-x == 0 */
101 float64 lobyx = log(1.0 + byx) * lmath->inv_log_of_base; /* log_{base}(1 + base^{y-x}); */
102 int32 k = (int32) (lobyx + 0.5 * (1<<shift)) >> shift; /* Round to shift */
104 /* base^{y-x} has reached the smallest representable value. */
108 /* This table is indexed by -(y-x), so we multiply byx by
109 * base^{-1} here which is equivalent to subtracting one from
115 /* Never produce a table smaller than 256 entries. */
116 if (i < 255) i = 255;
118 lmath->t.table = ckd_calloc(i+1, width);
119 lmath->t.table_size = i + 1;
120 /* Create the add table (see above). */
123 float64 lobyx = log(1.0 + byx) * lmath->inv_log_of_base;
124 int32 k = (int32) (lobyx + 0.5 * (1<<shift)) >> shift; /* Round to shift */
127 /* Check any previous value - if there is a shift, we want to
128 * only store the highest one. */
131 prev = ((uint8 *)lmath->t.table)[i >> shift];
134 prev = ((uint16 *)lmath->t.table)[i >> shift];
137 prev = ((uint32 *)lmath->t.table)[i >> shift];
143 ((uint8 *)lmath->t.table)[i >> shift] = (uint8) k;
146 ((uint16 *)lmath->t.table)[i >> shift] = (uint16) k;
149 ((uint32 *)lmath->t.table)[i >> shift] = (uint32) k;
156 /* Decay base^{y-x} exponentially according to base. */
164 logmath_read(const char *file_name)
167 char **argname, **argval;
169 int chksum_present, do_mmap;
174 E_INFO("Reading log table file '%s'\n", file_name);
175 if ((fp = fopen(file_name, "rb")) == NULL) {
176 E_ERROR("Failed to open log table file '%s' for reading: %s\n", file_name, strerror(errno));
180 /* Read header, including argument-value info and 32-bit byteorder magic */
181 if (bio_readhdr(fp, &argname, &argval, &byteswap) < 0) {
182 E_ERROR("bio_readhdr(%s) failed\n", file_name);
187 lmath = ckd_calloc(1, sizeof(*lmath));
188 /* Default values. */
191 lmath->base = 1.0001;
193 /* Parse argument-value list */
195 for (i = 0; argname[i]; i++) {
196 if (strcmp(argname[i], "version") == 0) {
198 else if (strcmp(argname[i], "chksum0") == 0) {
199 if (strcmp(argval[i], "yes") == 0)
202 else if (strcmp(argname[i], "width") == 0) {
203 lmath->t.width = atoi(argval[i]);
205 else if (strcmp(argname[i], "shift") == 0) {
206 lmath->t.shift = atoi(argval[i]);
208 else if (strcmp(argname[i], "logbase") == 0) {
209 lmath->base = atof_c(argval[i]);
212 bio_hdrarg_free(argname, argval);
215 /* Set up various necessary constants. */
216 lmath->log_of_base = log(lmath->base);
217 lmath->log10_of_base = log10(lmath->base);
218 lmath->inv_log_of_base = 1.0/lmath->log_of_base;
219 lmath->inv_log10_of_base = 1.0/lmath->log10_of_base;
220 /* Shift this sufficiently that overflows can be avoided. */
221 lmath->zero = MAX_NEG_INT32 >> (lmath->t.shift + 2);
223 /* #Values to follow */
224 if (bio_fread(&lmath->t.table_size, sizeof(int32), 1, fp, byteswap, &chksum) != 1) {
225 E_ERROR("fread(%s) (total #values) failed\n", file_name);
229 /* Check alignment constraints for memory mapping */
232 if (pos & ((long)lmath->t.width - 1)) {
233 E_WARN("%s: Data start %ld is not aligned on %d-byte boundary, will not memory map\n",
234 file_name, pos, lmath->t.width);
237 /* Check byte order for memory mapping */
239 E_WARN("%s: Data is wrong-endian, will not memory map\n", file_name);
244 lmath->filemap = mmio_file_read(file_name);
245 lmath->t.table = (char *)mmio_file_ptr(lmath->filemap) + pos;
248 lmath->t.table = ckd_calloc(lmath->t.table_size, lmath->t.width);
249 if (bio_fread(lmath->t.table, lmath->t.width, lmath->t.table_size,
250 fp, byteswap, &chksum) != lmath->t.table_size) {
251 E_ERROR("fread(%s) (%d x %d bytes) failed\n",
252 file_name, lmath->t.table_size, lmath->t.width);
256 bio_verify_chksum(fp, byteswap, chksum);
258 if (fread(&i, 1, 1, fp) == 1) {
259 E_ERROR("%s: More data than expected\n", file_name);
272 logmath_write(logmath_t *lmath, const char *file_name)
278 if (lmath->t.table == NULL) {
279 E_ERROR("No log table to write!\n");
283 E_INFO("Writing log table file '%s'\n", file_name);
284 if ((fp = fopen(file_name, "wb")) == NULL) {
285 E_ERROR("Failed to open logtable file '%s' for writing: %s\n", file_name, strerror(errno));
289 /* For whatever reason, we have to do this manually at the
291 fprintf(fp, "s3\nversion 1.0\nchksum0 yes\n");
292 fprintf(fp, "width %d\n", lmath->t.width);
293 fprintf(fp, "shift %d\n", lmath->t.shift);
294 fprintf(fp, "logbase %f\n", lmath->base);
295 /* Pad it out to ensure alignment. */
296 pos = ftell(fp) + strlen("endhdr\n");
297 if (pos & ((long)lmath->t.width - 1)) {
298 size_t align = lmath->t.width - (pos & ((long)lmath->t.width - 1));
299 assert(lmath->t.width <= 8);
300 fwrite(" " /* 8 spaces */, 1, align, fp);
302 fprintf(fp, "endhdr\n");
304 /* Now write the binary data. */
305 chksum = (uint32)BYTE_ORDER_MAGIC;
306 fwrite(&chksum, sizeof(uint32), 1, fp);
308 /* #Values to follow */
309 if (bio_fwrite(&lmath->t.table_size, sizeof(uint32),
310 1, fp, 0, &chksum) != 1) {
311 E_ERROR("fwrite(%s) (total #values) failed\n", file_name);
315 if (bio_fwrite(lmath->t.table, lmath->t.width, lmath->t.table_size,
316 fp, 0, &chksum) != lmath->t.table_size) {
317 E_ERROR("fwrite(%s) (%d x %d bytes) failed\n",
318 file_name, lmath->t.table_size, lmath->t.width);
321 if (bio_fwrite(&chksum, sizeof(uint32), 1, fp, 0, NULL) != 1) {
322 E_ERROR("fwrite(%s) checksum failed\n", file_name);
335 logmath_retain(logmath_t *lmath)
342 logmath_free(logmath_t *lmath)
346 if (--lmath->refcount > 0)
347 return lmath->refcount;
349 mmio_file_unmap(lmath->filemap);
351 ckd_free(lmath->t.table);
357 logmath_get_table_shape(logmath_t *lmath, uint32 *out_size,
358 uint32 *out_width, uint32 *out_shift)
360 if (out_size) *out_size = lmath->t.table_size;
361 if (out_width) *out_width = lmath->t.width;
362 if (out_shift) *out_shift = lmath->t.shift;
364 return lmath->t.table_size * lmath->t.width;
368 logmath_get_base(logmath_t *lmath)
374 logmath_get_zero(logmath_t *lmath)
380 logmath_get_width(logmath_t *lmath)
382 return lmath->t.width;
386 logmath_get_shift(logmath_t *lmath)
388 return lmath->t.shift;
392 logmath_add(logmath_t *lmath, int logb_x, int logb_y)
394 logadd_t *t = LOGMATH_TABLE(lmath);
397 /* handle 0 + x = x case. */
398 if (logb_x <= lmath->zero)
400 if (logb_y <= lmath->zero)
403 if (t->table == NULL)
404 return logmath_add_exact(lmath, logb_x, logb_y);
406 /* d must be positive, obviously. */
407 if (logb_x > logb_y) {
408 d = (logb_x - logb_y);
412 d = (logb_y - logb_x);
417 /* Some kind of overflow has occurred, fail gracefully. */
420 if ((size_t)d >= t->table_size) {
421 /* If this happens, it's not actually an error, because the
422 * last entry in the logadd table is guaranteed to be zero.
423 * Therefore we just return the larger of the two values. */
429 return r + (((uint8 *)t->table)[d]);
431 return r + (((uint16 *)t->table)[d]);
433 return r + (((uint32 *)t->table)[d]);
439 logmath_add_exact(logmath_t *lmath, int logb_p, int logb_q)
441 return logmath_log(lmath,
442 logmath_exp(lmath, logb_p)
443 + logmath_exp(lmath, logb_q));
447 logmath_log(logmath_t *lmath, float64 p)
452 return (int)(log(p) * lmath->inv_log_of_base) >> lmath->t.shift;
456 logmath_exp(logmath_t *lmath, int logb_p)
458 return pow(lmath->base, (float64)(logb_p << lmath->t.shift));
462 logmath_ln_to_log(logmath_t *lmath, float64 log_p)
464 return (int)(log_p * lmath->inv_log_of_base) >> lmath->t.shift;
468 logmath_log_to_ln(logmath_t *lmath, int logb_p)
470 return (float64)(logb_p << lmath->t.shift) * lmath->log_of_base;
474 logmath_log10_to_log(logmath_t *lmath, float64 log_p)
476 return (int)(log_p * lmath->inv_log10_of_base) >> lmath->t.shift;
480 logmath_log_to_log10(logmath_t *lmath, int logb_p)
482 return (float64)(logb_p << lmath->t.shift) * lmath->log10_of_base;