/******************************************************************************* * LtsCart.cpp * *----------* * * ** WARNING ** * CART code for LTS. This code was created in MS Research and LiJ owns * the algorithm. YunusM eliminated the private heap used by this code * and used the new and delete operators instead. * * Created By: LIJ (MS Research) Date: 06/18/99 * Current Owner: Fil * * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved *******************************************************************************/ //--- Includes -------------------------------------------------------------- #include "StdAfx.h" #include "LtsCart.h" #pragma warning(disable : 4100) /* the following are for exceptions: single letter and NULL output */ static const char *bogus_pron_1033 = "B OW G AH S P R AH N AH N S IY EY SH AH N"; static const char *bogus_pron_1041 = "N A N I"; // what? static const char *single_letter_pron_1033[52] = { "EY", "B IY", "S IY", "D IY", "IY", "EH F", "JH IY", "EY CH", "AY", "JH EY", "K EY", "EH L", "EH M", "EH N", "OW", "P IY", "K Y UW", "AA R", "EH S", "T IY", "Y UW", "V IY", "D AH B AX L Y UW", "EH K S", "W AY", "Z IY", // // PLURAL SPELLINGS // "EY Z", "B IY Z", "S IY Z", "D IY Z", "IY Z", "EH F S", "JH IY Z", "EY CH AX Z", "AY Z", "JH EY Z", "K EY Z", "EH L Z", "EH M Z", "EH N Z", "OW Z", "P IY Z", "K Y UW Z", "AA R Z", "EH S AX Z", "T IY Z", "Y UW Z", "V IY Z", "D AH B AX L Y UW Z", "EH K S AX Z", "W AY Z", "Z IY Z" }; static const char *single_letter_pron_1041[52] = { "EE", "B II", "SH II", "D II", "II", "E H U", "J II", "EE CH I", "A I", "J EE", "K EE", "E R U", "E M U", "E N U", "OO", "P II", "K Y UU", "AA R U", "E S U", "T II", "Y UU", "B U I", "D A B U R Y UU", "E STOP K U S U", "W A I", "Z E STOP T O", // // PLURAL SPELLINGS // "EE Z U", "B II Z U", "SH II Z U", "D II Z U", "II Z U", "E H U Z U", "J II Z U", "EE CH I Z U", "A I Z U", "J EE Z U", "K EE Z U", "E R U Z U", "E M U Z U", "E N U Z U", "OO Z U", "P II Z U", "K Y UU Z U", "AA R U Z U", "E S U Z U", "T II Z U", "Y UU Z U", "B U I Z U", "D A B U R Y UU Z U", "E STOP K U S U Z U", "W A I Z U", "Z E STOP T O Z U" }; /* * not worthwhile to use binary search with only about 30 entries */ static int symbol_to_id(LTS_SYMTAB *tab, char *sym) { USES_CONVERSION; SPDBG_FUNC("symbol_to_id"); int i; for (i = 0; i < tab->n_symbols; i++) { if (CSTR_EQUAL == CompareString(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), NORM_IGNORECASE, A2T(tab->storage + tab->sym_idx[i]), -1, A2T(sym), -1)) { return i; } } return NO_SYMBOL; } // static int symbol_to_id(LTS_SYMTAB *tab, char *sym) static char *id_to_symbol(LTS_SYMTAB *tab, int id) { SPDBG_FUNC("id_to_symbol"); if (id < 0 || id > tab->n_symbols) { return NULL; } else { return tab->storage + tab->sym_idx[id]; } } // static char *id_to_symbol(LTS_SYMTAB *tab, int id) __inline void ODS (const char *format, ...) { #ifdef _DEBUG SPDBG_FUNC("ODS"); va_list arglist; va_start (arglist, format); char buf[2048]; _vsnprintf(buf, 2048, format, arglist); OutputDebugStringA(buf); va_end (arglist); #endif } __inline int ans_simp_question (LTS_FEATURE *feat, SIMPLE_QUESTION question, LTS_SAMPLE *sample) { SPDBG_FUNC("ans_simp_question"); SYMBOL id; int *phones = feat[question.questype].feature[question.feature]; SAMPLE_GET_CONTEXT(sample, question.questype, question.context, question.offset, id); return (TST_BIT(phones, id) ? TRUE : FALSE); } // __inline int ans_simp_question (LTS_FEATURE *feat, SIMPLE_QUESTION question, static int product_eval (LTS_FEATURE *feat, char *term, LTS_SAMPLE *sample) { SPDBG_FUNC("product_eval"); int negate, result; SIMPLE_QUESTION ques; char *cptr; cptr = term; while (TRUE) { /* negation sign */ if (*cptr == '~') { negate = TRUE; cptr++; } else { negate = FALSE; } if (!isdigit(*cptr)) { //quit (-1, "Invalid product in product_eval\n"); // OutputDebugString("Invalid product in product_eval\n"); return FALSE; } for (result = *cptr++ - '0'; isdigit (*cptr); cptr++) { result = result * 10 + (*cptr - '0'); } QUES_DECODE(result, ques.questype, ques.context, ques.offset, ques.feature); if ((negate ^ ans_simp_question (feat, ques, sample)) == FALSE) { return FALSE; } if (*cptr == '\0') { break; } if (*cptr++ != '&') { //quit (-1, "product_eval: syntax error in product term %s\n", term); /* char szTemp[512]; sprintf(szTemp, "product_eval: syntax error in product term %s\n", term); OutputDebugString(szTemp); */ return FALSE; } } return TRUE; } // static int product_eval (LTS_FEATURE *feat, char *term, LTS_SAMPLE *sample) static int ans_comp_question(LTS_FEATURE *feat, char *prod, LTS_SAMPLE *sample) { SPDBG_FUNC("ans_comp_question"); int i, num_products, limit; char *cptr, string[LONGEST_STR], *products[MAX_PRODUCTS]; strcpy(string, prod); for (cptr = string, num_products = 1; *cptr != '\0'; cptr++) { if (*cptr == '|') num_products++; } if (num_products > MAX_PRODUCTS) { //quit(1, "please increase MAX_PRODUCTS up to %d at least\n", num_products); /* char szTemp[256]; sprintf(szTemp, "please increase MAX_PRODUCTS up to %d at least\n", num_products); OutputDebugString(szTemp); */ return FALSE; } for (i = 0, limit = num_products -1, cptr = string; ; i++) { products[i] = cptr++; if (i == limit) { break; } for (; *cptr != '|'; cptr++) {}; *cptr++ = '\0'; } for (i = 0; i < num_products; i++) { if (product_eval (feat, products[i], sample) == TRUE) { return TRUE; } } return FALSE; } // static int ans_comp_question(LTS_FEATURE *feat, char *prod, static T_NODE *find_leaf(LTS_FEATURE *feat, T_NODE *root, LTS_SAMPLE *sample) { SPDBG_FUNC("find_leaf"); if (!root->yes_child) { return root; } else if (ans_comp_question(feat, root->prod, sample)) { return find_leaf(feat, root->yes_child, sample); } else { return find_leaf(feat, root->no_child, sample); } } // static T_NODE *find_leaf(LTS_FEATURE *feat, T_NODE *root, LTS_SAMPLE *sample) static int lts_product_eval (LTS_FEATURE *feat, LTS_PROD *term, LTS_SAMPLE *sample, LTS_PROD **next) { SPDBG_FUNC("lts_product_eval"); int negate, result; SIMPLE_QUESTION ques; LTS_PROD *cptr = term; while (TRUE) { if ((*cptr) & PROD_NEG) { negate = TRUE; result = (*cptr) ^ PROD_NEG; } else { negate = FALSE; result = (*cptr); } QUES_DECODE(result, ques.questype, ques.context, ques.offset, ques.feature); if ((negate ^ ans_simp_question (feat, ques, sample)) == FALSE) { while (*cptr != PROD_TERM && *cptr != QUES_TERM) { cptr++; } if (*cptr == QUES_TERM) { *next = NULL; } else { *next = cptr + 1; } return FALSE; } cptr++; if (*cptr == QUES_TERM) { *next = NULL; break; } else if (*cptr == PROD_TERM) { *next = cptr + 1; break; } } return TRUE; } // static int lts_product_eval (LTS_FEATURE *feat, LTS_PROD *term, static int lts_ans_comp_question(LTS_TREE UNALIGNED *tree, LTS_FEATURE *feat, int idx, LTS_SAMPLE *sample) { SPDBG_FUNC("lts_ans_comp_question"); LTS_PROD *next, *term = (LTS_PROD *) ((char *) tree->p_prod + idx); while (TRUE) { if (lts_product_eval (feat, term, sample, &next) == TRUE) { return TRUE; } if (next == NULL) { break; } term = next; } return FALSE; } // static int lts_ans_comp_question(LTS_TREE *tree, LTS_FEATURE *feat, static LTS_NODE *lts_find_leaf(LTS_TREE UNALIGNED *tree, LTS_FEATURE *feat, LTS_NODE *root, LTS_SAMPLE *sample) { SPDBG_FUNC("lts_find_leaf"); if (IS_LEAF_NODE(root)) { return root; } else if (lts_ans_comp_question(tree, feat, ((LTS_NODE UNALIGNED *)root)->idx, sample)) { return lts_find_leaf(tree, feat, root + ((LTS_NODE UNALIGNED *)root)->yes, sample); } else { return lts_find_leaf(tree, feat, root + ((LTS_NODE UNALIGNED *)root)->yes + 1, sample); } } // static LTS_NODE *lts_find_leaf(LTS_TREE *tree, LTS_FEATURE *feat, static LTS_DIST *lts_find_leaf_count(LTS_FOREST *l_forest, SYMBOL *pIn, SYMBOL *pOut) { SPDBG_FUNC("lts_find_leaf_count"); LTS_TREE UNALIGNED *tree = l_forest->tree[*pIn]; LTS_NODE UNALIGNED *leaf; LTS_SAMPLE sample; /* * construct a sample in order to share all the code with training */ sample.pIn = pIn; sample.pOut = pOut; /* *pOut cannot be NULL_SYMBOL_ID */ *pOut = NULL_SYMBOL_ID + 1; leaf = lts_find_leaf(tree, l_forest->features, &(tree->nodes[0]), &sample); return (LTS_DIST *) ((char *)tree->p_dist + leaf->idx); } // static LTS_DIST *lts_find_leaf_count(LTS_FOREST *l_forest, SYMBOL *pIn, static LTS_OUT_RESULT *allocate_out_result(LTS_FOREST *l_forest) { SPDBG_FUNC("allocate_out_result"); LTS_OUT_RESULT *res = new LTS_OUT_RESULT; if (res) { res->out_strings = new LTS_OUT_STRING *[MAX_ALT_STRINGS]; if (res->out_strings) { res->num_allocated_strings = MAX_ALT_STRINGS; res->num_strings = 0; } else { delete res; res = NULL; } } return res; } // static LTS_OUT_RESULT *allocate_out_result(LTS_FOREST *l_forest) static void free_out_result(LTS_FOREST *l_forest, LTS_OUT_RESULT *res) { SPDBG_FUNC("free_out_result"); int i; for (i = 0; i < res->num_strings; i++) { delete res->out_strings[i]; } if (res->num_allocated_strings == MAX_ALT_STRINGS) { delete res->out_strings; } else { free(res->out_strings); /* dirty */ } delete res; } // static void free_out_result(LTS_FOREST *l_forest, LTS_OUT_RESULT *res) static bool reallocate_out_result(LTS_FOREST *l_forest, LTS_OUT_RESULT *res, int min) { SPDBG_FUNC("reallocate_out_result"); int s = res->num_allocated_strings, old_size = s; LTS_OUT_STRING **p; while (s < min) s += INC_ALT_STRINGS; p = res->out_strings; res->out_strings = (LTS_OUT_STRING **) calloc(s, sizeof(LTS_OUT_STRING *)); if (!res->out_strings) { return false; } memcpy(res->out_strings, p, old_size * sizeof(LTS_OUT_STRING *)); if (old_size == MAX_ALT_STRINGS) { delete p; } else { free(p); } res->num_allocated_strings = s; ODS("increased out_strings to %d in order to meet %d\n", s, min); return true; } // static void reallocate_out_result(LTS_FOREST *l_forest, LTS_OUT_RESULT *res, static bool grow_out_result(LTS_FOREST *l_forest, LTS_OUT_RESULT *res, SYMBOL i, int count, float inv_sum, LTS_OUT_RESULT *tmpRes) { SPDBG_FUNC("grow_out_result"); int j; if (res->num_strings + tmpRes->num_strings >= res->num_allocated_strings) { if (!reallocate_out_result(l_forest, res, res->num_strings + tmpRes->num_strings)) { return false; } } for (j = 0; j < tmpRes->num_strings; j++) { SYMBOL *psrc = tmpRes->out_strings[j]->psym; SYMBOL *ptgt; res->out_strings[res->num_strings + j] = new LTS_OUT_STRING; if (!res->out_strings) { return false; } ptgt = res->out_strings[res->num_strings + j]->psym; *ptgt++ = i; while (*psrc != NULL_SYMBOL_ID) { *ptgt++ = *psrc++; } *ptgt++ = NULL_SYMBOL_ID; res->out_strings[res->num_strings + j]->prob = count * inv_sum * tmpRes->out_strings[j]->prob; } res->num_strings += tmpRes->num_strings; free_out_result(l_forest, tmpRes); return true; } // static void grow_out_result(LTS_FOREST *l_forest, LTS_OUT_RESULT *res, static LTS_OUT_RESULT *gen_one_output(LTS_FOREST *l_forest, int len, SYMBOL *input_id, int in_index, SYMBOL *output_id, float cutoff) { SPDBG_FUNC("gen_one_output"); SYMBOL out[SP_MAX_WORD_LENGTH], *pOut; LTS_OUT_RESULT *res = allocate_out_result(l_forest); if (!res) { return NULL; } int sum, i, dim; LTS_DIST UNALIGNED *pdf; LTS_PAIR UNALIGNED *l_pair, *lp; float cut, inv_sum; /* * copy output_id to local */ SYMBOL *psrc = output_id - 1, *ptgt = out; while (*psrc != NULL_SYMBOL_ID) psrc--; while (psrc != output_id) *ptgt++ = *psrc++; pOut = ptgt; /* sanity check */ if (pOut - out != in_index + 1) { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! int *z=0; z[0]=z[1]; } if (in_index == len - 1) { pdf = lts_find_leaf_count(l_forest, input_id + in_index, pOut); l_pair = &(pdf->p_pair); dim = pdf->c_dists; for (lp = l_pair, sum = 0, i = 0; i < dim; i++, lp++) { sum += lp->cnt; } SPDBG_ASSERT(sum > 0); inv_sum = 1.0f / sum; cut = cutoff * sum; for (lp = l_pair, i = 0; i < dim; i++, lp++) { if ((float)(lp->cnt) > cut) { res->out_strings[res->num_strings] = new LTS_OUT_STRING; if (NULL == res->out_strings[res->num_strings]) { return NULL; } res->out_strings[res->num_strings]->psym[0] = (SYMBOL) lp->id; res->out_strings[res->num_strings]->psym[1] = NULL_SYMBOL_ID; res->out_strings[res->num_strings]->prob = lp->cnt * inv_sum; res->num_strings++; } /* cut */ } } else { LTS_OUT_RESULT *tmpRes; pdf = lts_find_leaf_count(l_forest, input_id + in_index, pOut); dim = pdf->c_dists; l_pair = &(pdf->p_pair); for (lp = l_pair, sum = 0, i = 0; i < dim; i++, lp++) { sum += lp->cnt; } SPDBG_ASSERT(sum > 0); inv_sum = 1.0f / sum; cut = cutoff * sum; for (lp = l_pair, i = 0; i < dim; i++, lp++) { if ((float)(lp->cnt) > cut) { SYMBOL *pTmpOut = pOut + 1; *pOut = (SYMBOL) lp->id; tmpRes = gen_one_output(l_forest, len, input_id, in_index + 1, pTmpOut, cutoff); if (!tmpRes) { return NULL; } if (!grow_out_result(l_forest, res, (SYMBOL)(lp->id), lp->cnt, inv_sum, tmpRes)) { return NULL; } } } /* i */ } /* else */ return res; } // static LTS_OUT_RESULT *gen_one_output(LTS_FOREST *l_forest, int len, static int comp_out_result_prob(const void *vp1, const void *vp2) { SPDBG_FUNC("comp_out_result_prob"); LTS_OUT_STRING **p1 = (LTS_OUT_STRING **) vp1, **p2 = (LTS_OUT_STRING **) vp2; if ((*p1)->prob > (*p2)->prob) { return -1; } else if ((*p1)->prob < (*p2)->prob) { return 1; } else { return 0; } } // static int comp_out_result_prob(const void *vp1, const void *vp2) static void lts_fill_out_buffer(LTS_FOREST *l_forest, LTS_OUT_RESULT *out, char *word) { SPDBG_FUNC("lts_fill_out_buffer"); int i, j, n; float inv_sum, sum = 0.0f; char phnstr[LONGEST_STR]; char *tmp; LTS_SYMTAB *tab = l_forest->symbols; if (out == NULL) { return; } if (word) { strcpy(l_forest->out.word, word); } else { l_forest->out.word[0] = 0; } /* normalize probabilities */ for (i = 0; i < out->num_strings; i++) { sum += out->out_strings[i]->prob; } inv_sum = 1.0f / sum; for (i = 0; i < out->num_strings; i++) { out->out_strings[i]->prob *= inv_sum; } /* * sort them according to the prob field */ qsort(out->out_strings, out->num_strings, sizeof(LTS_OUT_STRING *), &comp_out_result_prob); if (out->num_strings > MAX_OUTPUT_STRINGS - l_forest->out.num_prons) { n = MAX_OUTPUT_STRINGS - l_forest->out.num_prons; for (sum = 0.0f, i = 0; i < n; i++) { sum += out->out_strings[i]->prob; } inv_sum = 1.0f / sum; for (i = 0; i < n; i++) { out->out_strings[i]->prob *= inv_sum; } } else { n = out->num_strings; } for (j = l_forest->out.num_prons, i = 0; i < n; i++) { SYMBOL *p = out->out_strings[i]->psym; char *psrc, *ptgt; if (out->out_strings[i]->prob < MIN_OUT_PROB) { continue; } phnstr[0] = 0; l_forest->out.pron[j].prob = out->out_strings[i]->prob; while (*p != NULL_SYMBOL_ID) { tmp = id_to_symbol(&(tab[OUTPUT]), *p++); SPDBG_ASSERT(tmp); if (tmp) { strcat(phnstr, tmp); strcat(phnstr, " "); } } psrc = phnstr; ptgt = l_forest->out.pron[j].pstr; while (*psrc) { if (*psrc != '#' && *psrc != '_') { *ptgt++ = *psrc++; } else if (*psrc == '_') { *ptgt++ = ' '; psrc++; } else { psrc += 2; /* skip an extra space */ } /* extreme case, truncate it */ if (ptgt - l_forest->out.pron[j].pstr >= SP_MAX_PRON_LENGTH) { for (ptgt--; !isspace(*ptgt); ptgt--) {}; /* never output partial phone */ ptgt++; break; } } // output could contain only '# ' if (ptgt > l_forest->out.pron[j].pstr && *(ptgt - 1) == ' ') { *(ptgt - 1) = 0; /* remove the last space */ } else { *ptgt = 0; /* shouldn't happen unless ptgt didn't move */ } if (ptgt > l_forest->out.pron[j].pstr) { j++; } } /* i */ if (j <= MAX_OUTPUT_STRINGS) { l_forest->out.num_prons = j; } else { l_forest->out.num_prons = MAX_OUTPUT_STRINGS; // should never happen } free_out_result(l_forest, out); } // static void lts_fill_out_buffer(LTS_FOREST *l_forest, LTS_OUT_RESULT *out, void assign_a_fixed_pron(LTS_OUTPUT *out, const char *pron, char *word) { SPDBG_FUNC("assign_a_fixed_pron"); out->num_prons = 1; strcpy(out->word, word); out->pron[0].prob = 1.0f; if (strlen(pron) < SP_MAX_PRON_LENGTH) { strcpy(out->pron[0].pstr, pron); } else { char *p; strncpy(out->pron[0].pstr, pron, SP_MAX_PRON_LENGTH); p = &(out->pron[0].pstr[SP_MAX_PRON_LENGTH - 1]); while (!isspace(*p)) { p--; /* truncate the last partial phoneme */ } *p = 0; } } // void assign_a_fixed_pron(LTS_OUTPUT *out, char *pron, char *word) inline BOOL IsCharInRangeA(int ch, int chMin, int chMax) { return (unsigned)(ch - chMin) <= (unsigned)(chMax - chMin); } void assign_a_spelling_pron(LTS_OUTPUT *out, const char * single_letter_pron[52], char *word) { SPDBG_FUNC("assign_a_spelling_pron"); char *p; int cchPron = 0; strcpy(out->word, word); if (ispunct(*word)) { p = word + 1; } else { p = word; } out->num_prons = 1; out->pron[0].prob = 1.0f; out->pron[0].pstr[0] = 0; char * pchPron = out->pron[0].pstr; while (*p) { int cPOffset = 0; // 0 for single letter, 26 for plurals int c = *p++; // Lowercaseify, and skip over non-letters if (IsCharInRangeA(c, 'A', 'Z')) { c += 'a' - 'A'; } else if (!IsCharInRangeA(c, 'a', 'z')) { continue; } // Check if the next two characters are 'S (apostrophe S). Include the following cases: words ending in 's 'S s' S' // If they are we use a the plural pronunciation for the letter and skip over the letter and 'S if ((p[0] == '\'') && ((0 == p[1] && 's' == c) || 's' == p[1] || 'S' == p[1])) { cPOffset = 26; p += p[1] ? 1 : 0; // skip 'S } // Make sure the string isn't too long accounting for the new phone and seperator const char * const pchPronT = single_letter_pron[cPOffset + c - 'a']; const int cchPronT = strlen(pchPronT); if ((cchPron + 1 + cchPronT) < (SP_MAX_PRON_LENGTH - 1)) // +1 for separating space, -1 for terminating NUL { strcpy(pchPron + cchPron, pchPronT); cchPron += cchPronT; pchPron[cchPron++] = ' '; } else { break; } } if (cchPron) { pchPron[cchPron - 1] = 0; // trim trailing space char } } HRESULT LtscartGetPron(LTS_FOREST *l_forest, char *word, LTS_OUTPUT **ppLtsOutput) { SPDBG_FUNC("LtscartGetPron"); HRESULT hr = S_OK; LTS_OUT_RESULT *pres = NULL; char *p, *base; SYMBOL buffer[LONGEST_STR], *pbuf = buffer + 1; int len, id, hasvowel = 0, allcapital = 1; l_forest->out.num_prons = 0; buffer[0] = NULL_SYMBOL_ID; len = 0; if (word == NULL || (base = strtok(word, " \t\n")) == NULL) { assign_a_fixed_pron(&(l_forest->out), l_forest->bogus_pron, "NUL"); *ppLtsOutput = &(l_forest->out); return S_FALSE; } else { base = strtok(word, " \t\n"); if (ispunct(*base)) { for (p = base; *p && ispunct(*p); p++) {}; } else { p = base; } } char ach[2]; ach[1] = 0; while (*p) { const int d = *p++; const int c = tolower(d); if (!hasvowel && (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y')) { hasvowel = 1; } if (allcapital && d == c) { allcapital = 0; } ach[0] = (char)c; if ((id = symbol_to_id (&(l_forest->symbols[INPUT]), ach)) == NO_SYMBOL || id == NULL_SYMBOL_ID) { ODS("cannot find the symbol %c, skip!\n", c); continue; } pbuf[len++] = (SYMBOL) id; } pbuf[len] = NULL_SYMBOL_ID; if (len >= SP_MAX_WORD_LENGTH || len <= 0) { // fill in bogus pron below } else if (len == 1) { LTS_SYMTAB *tab = l_forest->symbols; char *p = id_to_symbol(&(tab[INPUT]), pbuf[0]); int c = tolower(p[0]); if (c >= 'a' && c <= 'z') { assign_a_fixed_pron(&(l_forest->out), l_forest->single_letter_pron[c - 'a'], word); } } else if (!hasvowel) { assign_a_spelling_pron(&(l_forest->out), l_forest->single_letter_pron, word); } else { if (allcapital) { assign_a_spelling_pron(&(l_forest->out), l_forest->single_letter_pron, word); } pres = gen_one_output(l_forest, len, pbuf, 0, pbuf, DEFAULT_PRUNE); if (!pres) { return E_OUTOFMEMORY; } lts_fill_out_buffer(l_forest, pres, word); } if (l_forest->out.num_prons == 0) { hr = S_FALSE; assign_a_fixed_pron(&(l_forest->out), l_forest->bogus_pron, word); } *ppLtsOutput = &(l_forest->out); SPDBG_RETURN(hr); } /* LtscartGetPron */ LTS_FOREST *LtscartReadData (LCID lcid, PBYTE map_addr) { SPDBG_FUNC("LtscartReadData"); int i; LTS_FOREST *l_forest; LTS_SYMTAB *tab; LTS_FEATURE *feat; int output = 0; l_forest = (LTS_FOREST *) calloc(1, sizeof(LTS_FOREST)); if (!l_forest) { return NULL; } if (lcid == 1033) { l_forest->bogus_pron = bogus_pron_1033; l_forest->single_letter_pron = single_letter_pron_1033; } else if (lcid == 1041) { l_forest->bogus_pron = bogus_pron_1041; l_forest->single_letter_pron = single_letter_pron_1041; } else { return NULL; } //read in the symbol table l_forest->symbols = (LTS_SYMTAB *) calloc(2, sizeof(LTS_SYMTAB)); if (!l_forest->symbols) { return NULL; } tab = &(l_forest->symbols[INPUT]); CopyMemory(&(tab->n_symbols), map_addr + output, sizeof(int)); output += sizeof(int); tab->sym_idx = (int *)(map_addr + output); output += tab->n_symbols * sizeof(int); CopyMemory(&(tab->n_bytes), map_addr + output, sizeof(int)); output += sizeof(int); tab->storage = (char*)(map_addr + output); output += tab->n_bytes * sizeof(char); tab = &(l_forest->symbols[OUTPUT]); CopyMemory(&(tab->n_symbols), map_addr + output, sizeof(int)); output += sizeof(int); tab->sym_idx = (int*)(map_addr + output); output += tab->n_symbols * sizeof(int); CopyMemory(&(tab->n_bytes), map_addr + output, sizeof(int)); output += sizeof(int); tab->storage = (char*)(map_addr + output); output += tab->n_bytes * sizeof(char); // read in the feature vector l_forest->features = (LTS_FEATURE *) calloc(2, sizeof(LTS_FEATURE)); if (!l_forest->features) { return NULL; } feat = &(l_forest->features[INPUT]); CopyMemory(&(feat->n_feat), map_addr + output, sizeof(int)); output += sizeof(int); CopyMemory(&(feat->dim), map_addr + output, sizeof(int)); output += sizeof(int); feat->feature = (int **) calloc(feat->n_feat, sizeof(int *)); if (!feat->feature) { return NULL; } for (i = 0; i < feat->n_feat; i++) { feat->feature[i] = (int*)(map_addr + output); output += feat->dim * sizeof(int); } feat = &(l_forest->features[OUTPUT]); CopyMemory(&(feat->n_feat), map_addr + output, sizeof(int)); output += sizeof(int); CopyMemory(&(feat->dim), map_addr + output, sizeof(int)); output += sizeof(int); feat->feature = (int **) calloc(feat->n_feat, sizeof(int *)); if (!feat->feature) { return NULL; } for (i = 0; i < feat->n_feat; i++) { feat->feature[i] = (int*)(map_addr + output); output += feat->dim * sizeof(int); } /* * read in the tree */ l_forest->tree = (LTS_TREE **) calloc(l_forest->symbols[INPUT].n_symbols, sizeof(LTS_TREE *)); if (!l_forest->tree) { return NULL; } for (i = 1; i < l_forest->symbols[INPUT].n_symbols; i++) { LTS_TREE *l_root; l_forest->tree[i] = l_root = (LTS_TREE *) calloc(1, sizeof(LTS_TREE)); if (!l_root) { return NULL; } CopyMemory(&(l_root->n_nodes), map_addr + output, sizeof(int)); output += sizeof(int); l_root->nodes = (LTS_NODE*)(map_addr + output); output += l_root->n_nodes * sizeof(LTS_NODE); CopyMemory(&(l_root->size_dist), map_addr + output, sizeof(int)); output += sizeof(int); l_root->p_dist = (LTS_DIST*)(map_addr + output); output += l_root->size_dist * sizeof(char); CopyMemory(&(l_root->size_prod), map_addr + output, sizeof(int)); output += sizeof(int); if (l_root->size_prod > 0) { l_root->p_prod = (LTS_PROD*)(map_addr + output); output += l_root->size_prod * sizeof(char); } } return l_forest; } // LTS_FOREST *LtscartReadData(char *forest_image, HANDLE *hFile1, void LtscartFreeData(LTS_FOREST *l_forest) { SPDBG_FUNC("LtscartFreeData"); for (int i = 1; i < l_forest->symbols[INPUT].n_symbols; i++) { free(l_forest->tree[i]); } free(l_forest->tree); free(l_forest->features[INPUT].feature); free(l_forest->features[OUTPUT].feature); free(l_forest->features); free(l_forest->symbols); free(l_forest); } // void LtscartFreeData(LTS_FOREST *l_forest, HANDLE m_hFile,