47 #include <sphinxbase/ckd_alloc.h>
48 #include <sphinxbase/err.h>
51 #include "fsg_lextree.h"
77 static void fsg_psubtree_free(
fsg_pnode_t *alloc_head);
97 silcipid = bin_mdef_silphone(lextree->
mdef);
98 assert(silcipid >= 0);
99 n_ci = bin_mdef_n_ciphone(lextree->
mdef);
106 lextree->
lc = ckd_calloc_2d(fsg->n_state, n_ci + 1,
sizeof(**lextree->
lc));
107 lextree->
rc = ckd_calloc_2d(fsg->n_state, n_ci + 1,
sizeof(**lextree->
rc));
108 E_INFO(
"Allocated %d bytes (%d KiB) for left and right context phones\n",
109 fsg->n_state * (n_ci + 1) * 2,
110 fsg->n_state * (n_ci + 1) * 2 / 1024);
113 for (s = 0; s < fsg->n_state; s++) {
115 for (itor = fsg_model_arcs(fsg, s); itor; itor = fsg_arciter_next(itor)) {
116 fsg_link_t *l = fsg_arciter_get(itor);
119 if (fsg_link_wid(l) >= 0) {
121 fsg_model_word_str(lextree->
fsg, l->wid));
133 if (fsg_model_is_filler(fsg, fsg_link_wid(l))) {
135 lextree->
rc[fsg_link_from_state(l)][silcipid] = 1;
136 lextree->
lc[fsg_link_to_state(l)][silcipid] = 1;
139 len = dict_pronlen(lextree->
dict, dictwid);
140 lextree->
rc[fsg_link_from_state(l)][
dict_pron(lextree->
dict, dictwid, 0)] = 1;
141 lextree->
lc[fsg_link_to_state(l)][
dict_pron(lextree->
dict, dictwid, len - 1)] = 1;
147 for (s = 0; s < fsg->n_state; s++) {
155 lextree->
lc[s][silcipid] = 1;
156 lextree->
rc[s][silcipid] = 1;
167 for (s = 0; s < fsg->n_state; s++) {
169 for (itor = fsg_model_arcs(fsg, s); itor; itor = fsg_arciter_next(itor)) {
170 fsg_link_t *l = fsg_arciter_get(itor);
171 if (fsg_link_wid(l) < 0) {
176 for (i = 0; i < n_ci; i++)
177 lextree->
lc[fsg_link_to_state(l)][i] |= lextree->
lc[fsg_link_from_state(l)][i];
183 for (i = 0; i < n_ci; i++)
184 lextree->
rc[fsg_link_from_state(l)][i] |= lextree->
rc[fsg_link_to_state(l)][i];
190 for (s = 0; s < fsg->n_state; s++) {
192 for (i = 0; i < n_ci; i++) {
193 if (lextree->
lc[s][i]) {
194 lextree->
lc[s][j] = i;
198 lextree->
lc[s][j] = -1;
201 for (i = 0; i < n_ci; i++) {
202 if (lextree->
rc[s][i]) {
203 lextree->
rc[s][j] = i;
207 lextree->
rc[s][j] = -1;
217 int32 wip, int32 pip)
225 lextree->root = ckd_calloc(fsg_model_n_state(fsg),
227 lextree->alloc_head = ckd_calloc(fsg_model_n_state(fsg),
230 lextree->
dict = dict;
232 lextree->
mdef = mdef;
237 fsg_lextree_lc_rc(lextree);
243 lextree->n_pnode = 0;
245 for (s = 0; s < fsg_model_n_state(fsg); s++) {
247 fsg_psubtree_init(lextree, fsg, s, &(lextree->alloc_head[s]));
249 for (pn = lextree->alloc_head[s]; pn; pn = pn->alloc_next) {
255 E_INFO(
"%d HMM nodes in lextree (%d leaves)\n",
256 lextree->n_pnode, n_leaves);
257 E_INFO(
"Allocated %d bytes (%d KiB) for all lextree nodes\n",
260 E_INFO(
"Allocated %d bytes (%d KiB) for lextree leafnodes\n",
277 for (s = 0; s < fsg_model_n_state(lextree->
fsg); s++) {
278 fprintf(fp,
"State %5d root %p\n", s, lextree->root[s]);
279 fsg_psubtree_dump(lextree, lextree->root[s], fp);
294 for (s = 0; s < fsg_model_n_state(lextree->
fsg); s++)
295 fsg_psubtree_free(lextree->alloc_head[s]);
297 ckd_free_2d(lextree->
lc);
298 ckd_free_2d(lextree->
rc);
299 ckd_free(lextree->root);
300 ckd_free(lextree->alloc_head);
313 glist_free(glist->glist);
314 nxtglist = glist->next;
319 glist_free(glist->glist);
320 nxtglist = glist->next;
332 for (i = 0; i < FSG_PNODE_CTXT_BVSZ; i++)
333 ctxt->bv[i] = 0xffffffff;
341 for (i = 0; i < FSG_PNODE_CTXT_BVSZ; i++)
342 res |= (src->bv[i] = ~(sub->bv[i]) & src->bv[i]);
367 fsg_link_t * fsglink,
368 int16 *lclist, int16 *rclist,
379 int32 n_ci, p, lc, rc;
380 glist_t lc_pnodelist;
381 glist_t rc_pnodelist;
383 int n_lc_alloc = 0, n_int_alloc = 0, n_rc_alloc = 0;
385 silcipid = bin_mdef_silphone(lextree->
mdef);
386 n_ci = bin_mdef_n_ciphone(lextree->
mdef);
388 wid = fsg_link_wid(fsglink);
391 fsg_model_word_str(lextree->
fsg, wid));
392 pronlen = dict_pronlen(lextree->
dict, dictwid);
393 assert(pronlen >= 1);
395 assert(lclist[0] >= 0);
396 assert(rclist[0] >= 0);
402 int ci = dict_first_phone(lextree->
dict, dictwid);
411 for (i = 0; lclist[i] >= 0; i++) {
413 ssid = dict2pid_lrdiph_rc(lextree->
d2p, ci, lc, silcipid);
414 tmatid = bin_mdef_pid2tmatid(lextree->
mdef, dict_first_phone(lextree->
dict, dictwid));
416 for (gn = lc_pnodelist; gn; gn = gnode_next(gn)) {
419 if (hmm_nonmpx_ssid(&pnode->hmm) == ssid) {
421 fsg_pnode_add_ctxt(pnode, lc);
429 pnode->ctx = lextree->
ctx;
430 pnode->next.fsglink = fsglink;
433 + lextree->wip + lextree->pip;
434 pnode->ci_ext = dict_first_phone(lextree->
dict, dictwid);
437 pnode->sibling = root;
438 fsg_pnode_add_ctxt(pnode, lc);
439 pnode->alloc_next = head;
444 hmm_init(lextree->
ctx, &pnode->hmm, FALSE, ssid, tmatid);
447 glist_add_ptr(lc_pnodelist, (
void *) pnode);
451 glist_free(lc_pnodelist);
454 ssid = bin_mdef_pid2ssid(lextree->
mdef, ci);
455 tmatid = bin_mdef_pid2tmatid(lextree->
mdef, ci);
458 pnode->ctx = lextree->
ctx;
459 pnode->next.fsglink = fsglink;
460 pnode->logs2prob = (fsg_link_logs2prob(fsglink) >>
SENSCR_SHIFT)
461 + lextree->wip + lextree->pip;
462 pnode->ci_ext = silcipid;
465 pnode->sibling = root;
467 pnode->alloc_next = head;
472 hmm_init(lextree->
ctx, &pnode->hmm, FALSE, ssid, tmatid);
482 for (p = 0; p < pronlen; p++) {
489 for (glist = *curglist;
490 glist && glist->glist;
491 glist = glist->next) {
492 if (glist->ci == ci && glist->rc == rc)
495 if (glist && glist->glist) {
496 assert(glist->ci == ci && glist->rc == rc);
498 E_DEBUG(2,(
"Found match for (%d,%d)\n", ci, rc));
499 lc_pnodelist = glist->glist;
511 glist->next = *curglist;
516 lc_pnodelist = glist->glist = NULL;
519 for (i = 0; lclist[i] >= 0; i++) {
521 ssid = dict2pid_ldiph_lc(lextree->
d2p, ci, rc, lc);
522 tmatid = bin_mdef_pid2tmatid(lextree->
mdef, dict_first_phone(lextree->
dict, dictwid));
526 pnode = ssid_pnode_map[0];
527 for (j = 0; j < n_ci && ssid_pnode_map[j] != NULL; ++j) {
528 pnode = ssid_pnode_map[j];
529 if (hmm_nonmpx_ssid(&pnode->hmm) == ssid)
538 pnode->ctx = lextree->
ctx;
542 pnode->logs2prob = lextree->wip + lextree->pip;
543 pnode->ci_ext = dict_first_phone(lextree->
dict, dictwid);
546 pnode->sibling = root;
547 pnode->alloc_next = head;
552 hmm_init(lextree->
ctx, &pnode->hmm, FALSE, ssid, tmatid);
555 glist_add_ptr(lc_pnodelist, (
void *) pnode);
556 ssid_pnode_map[j] = pnode;
558 fsg_pnode_add_ctxt(pnode, lc);
561 glist->glist = lc_pnodelist;
566 else if (p != pronlen - 1) {
570 tmatid = bin_mdef_pid2tmatid(lextree->
mdef,
dict_pron (lextree->
dict, dictwid, p));
572 pnode = pred->next.succ;
573 pnodeyoungest = pnode;
574 while (pnode && (hmm_nonmpx_ssid(&pnode->hmm) != ssid || pnode->leaf)) {
575 pnode = pnode->sibling;
577 if (pnode && (hmm_nonmpx_ssid(&pnode->hmm) == ssid && !pnode->leaf)) {
579 E_DEBUG(2,(
"Found match for %d\n", ci));
586 pnode->ctx = lextree->
ctx;
587 pnode->logs2prob = lextree->pip;
591 pnode->sibling = pnodeyoungest;
593 for (gn = lc_pnodelist; gn; gn = gnode_next(gn)) {
595 pred->next.succ = pnode;
599 pred->next.succ = pnode;
601 pnode->alloc_next = head;
605 hmm_init(lextree->
ctx, &pnode->hmm, FALSE, ssid, tmatid);
612 memset((
void *) ssid_pnode_map, 0,
616 tmatid = bin_mdef_pid2tmatid(lextree->
mdef,
dict_pron (lextree->
dict, dictwid, p));
618 for (i = 0; rclist[i] >= 0; i++) {
621 j = rssid->
cimap[rc];
622 ssid = rssid->
ssid[j];
623 pnode = ssid_pnode_map[j];
630 pnode->ctx = lextree->
ctx;
633 pnode->logs2prob = (fsg_link_logs2prob(fsglink) >>
SENSCR_SHIFT)
638 pnode->sibling = rc_pnodelist ?
640 pnode->next.fsglink = fsglink;
641 pnode->alloc_next = head;
645 hmm_init(lextree->
ctx, &pnode->hmm, FALSE, ssid, tmatid);
648 glist_add_ptr(rc_pnodelist, (
void *) pnode);
649 ssid_pnode_map[j] = pnode;
652 assert(hmm_nonmpx_ssid(&pnode->hmm) == ssid);
654 fsg_pnode_add_ctxt(pnode, rc);
658 for (gn = lc_pnodelist; gn; gn = gnode_next(gn)) {
660 if (!pred->next.succ)
661 pred->next.succ = (
fsg_pnode_t *) gnode_ptr(rc_pnodelist);
665 while (succ->sibling) succ = succ->sibling;
666 succ->sibling = (
fsg_pnode_t*) gnode_ptr(rc_pnodelist);
674 if (!pred->next.succ)
675 pred->next.succ = (
fsg_pnode_t *) gnode_ptr(rc_pnodelist);
679 while (succ->sibling) succ = succ->sibling;
680 succ->sibling = (
fsg_pnode_t *) gnode_ptr(rc_pnodelist);
686 ckd_free((
void *) ssid_pnode_map);
688 glist_free(rc_pnodelist);
691 E_DEBUG(2,(
"Allocated %d HMMs (%d lc, %d rc, %d internal)\n",
692 n_lc_alloc + n_rc_alloc + n_int_alloc,
693 n_lc_alloc, n_rc_alloc, n_int_alloc));
702 fsg_model_t * fsg, int32 from_state,
712 assert(*alloc_head == NULL);
714 n_ci = bin_mdef_n_ciphone(lextree->
mdef);
715 if (n_ci > (FSG_PNODE_CTXT_BVSZ * 32)) {
717 (
"#phones > %d; increase FSG_PNODE_CTXT_BVSZ and recompile\n",
718 FSG_PNODE_CTXT_BVSZ * 32);
722 for (itor = fsg_model_arcs(fsg, from_state); itor;
723 itor = fsg_arciter_next(itor)) {
725 fsglink = fsg_arciter_get(itor);
726 dst = fsglink->to_state;
728 if (fsg_link_wid(fsglink) < 0)
731 E_DEBUG(2,(
"Building lextree for arc from %d to %d: %s\n",
732 from_state, dst, fsg_model_word_str(fsg, fsg_link_wid(fsglink))));
733 root = psubtree_add_trans(lextree, root, &glist, fsglink,
734 lextree->
lc[from_state],
739 E_DEBUG(2,(
"State %d has %d outgoing arcs\n", from_state, n_arc));
741 fsg_glist_linklist_free(glist);
753 next = head->alloc_next;
766 for (i = 0; i <= node->ppos; i++)
769 fprintf(fp,
"%p.@", node);
771 fprintf(fp,
" %5d.SS", hmm_nonmpx_ssid(&node->hmm));
772 fprintf(fp,
" %10d.LP", node->logs2prob);
773 fprintf(fp,
" %p.SIB", node->sibling);
775 if ((node->ppos == 0) || node->leaf) {
777 for (i = 0; i < FSG_PNODE_CTXT_BVSZ; i++)
778 fprintf(fp,
"%08x", node->ctxt.bv[i]);
782 tl = node->next.fsglink;
783 fprintf(fp,
" {%s[%d->%d](%d)}",
784 fsg_model_word_str(tree->
fsg, tl->wid),
785 tl->from_state, tl->to_state, tl->logs2prob);
787 fprintf(fp,
" %p.NXT", node->next.succ);
799 if (root == NULL)
return;
800 if (root->ppos == 0) {
801 while(root->sibling && root->sibling->next.succ == root->next.succ) {
802 fsg_psubtree_dump_node(tree, root, fp);
803 root = root->sibling;
808 fsg_psubtree_dump_node(tree, root, fp);
811 if (root->ppos == 0 && root->sibling) {
812 fsg_psubtree_dump(tree, root->sibling,fp);
817 succ = root->next.succ;
819 fsg_psubtree_dump(tree, succ,fp);
820 succ = succ->sibling;
823 if (root->ppos == 0) {
824 fsg_psubtree_dump(tree, root->sibling,fp);
void fsg_lextree_free(fsg_lextree_t *lextree)
Free lextrees for an FSG.
hmm_context_t * ctx
HMM context structure.
void hmm_init(hmm_context_t *ctx, hmm_t *hmm, int mpx, int ssid, int tmatid)
Populate a previously-allocated HMM structure, allocating internal data.
POCKETSPHINX_EXPORT s3wid_t dict_wordid(dict_t *d, const char *word)
Return word id for given word string if present.
void fsg_pnode_add_all_ctxt(fsg_pnode_ctxt_t *ctxt)
Set all flags on in the given context bitvector.
const char * bin_mdef_ciphone_str(bin_mdef_t *m, int32 ci)
In: ciphone id for which name wanted.
bin_mdef_t * mdef
Model definition (triphone mappings).
uint32 fsg_pnode_ctxt_sub_generic(fsg_pnode_ctxt_t *src, fsg_pnode_ctxt_t *sub)
Generic variant for arbitrary size.
void fsg_lextree_dump(fsg_lextree_t *lextree, FILE *fp)
Print an FSG lextree to a file for debugging.
void hmm_deinit(hmm_t *hmm)
Free an HMM structure, releasing internal data (but not the HMM structure itself).
#define dict2pid_rssid(d, ci, lc)
Access macros; not designed for arbitrary use.
void fsg_psubtree_pnode_deactivate(fsg_pnode_t *pnode)
Mark the given pnode as inactive (for search).
dict_t * dict
Pronunciation dictionary for this FSG.
int dict_filler_word(dict_t *d, s3wid_t w)
Return 1 if w is a filler word, 0 if not.
Shared information between a set of HMMs.
Collection of lextrees for an FSG.
#define SENSCR_SHIFT
Shift count for senone scores.
a structure for a dictionary.
s3ssid_t dict2pid_internal(dict2pid_t *d2p, int32 wid, int pos)
Return the senone sequence ID for the given word position.
void hmm_clear(hmm_t *h)
Reset the states of the HMM to the invalid condition.
cross word triphone model structure
int16 ** rc
Right context triphone mappings for FSG.
int16 ** lc
Left context triphone mappings for FSG.
fsg_lextree_t * fsg_lextree_init(fsg_model_t *fsg, dict_t *dict, dict2pid_t *d2p, bin_mdef_t *mdef, hmm_context_t *ctx, int32 wip, int32 pip)
Create, initialize, and return a new phonetic lextree for the given FSG.
fsg_model_t * fsg
The fsg for which this lextree is built.
s3cipid_t * cimap
Index into ssid[] above for each ci phone.
#define dict_pron(d, w, p)
The CI phones of the word w at position p.
Building composite triphone (as well as word internal triphones) with the dictionary.
s3ssid_t * ssid
Senone Sequence ID list for all context ciphones.
dict2pid_t * d2p
Context-dependent phone mappings for this FSG.