/** * Find PHMM node with same senone sequence and tmat id as the given triphone. * Return ptr to PHMM node if found, NULL otherwise. */ static phmm_t * phmm_lookup(allphone_search_t * allphs, s3pid_t pid) { phmm_t *p; bin_mdef_t *mdef; phmm_t **ci_phmm; mdef = ((ps_search_t *) allphs)->acmod->mdef; ci_phmm = allphs->ci_phmm; for (p = ci_phmm[bin_mdef_pid2ci(mdef, pid)]; p; p = p->next) { if (mdef_pid2tmatid(mdef, p->pid) == mdef_pid2tmatid(mdef, pid)) if (mdef_pid2ssid(mdef, p->pid) == mdef_pid2ssid(mdef, pid)) return p; } //not found return NULL; }
/* * Build a glist of triphone senone-sequence IDs (ssids) derivable from [b] as a single * phone word, with a given left context l. If no triphone found in mdef, include the ssid * for basephone b. Return the generated glist. */ static glist_t single_lc_comsseq (mdef_t *mdef, int32 b, int32 l) { int32 r, p, ssid; glist_t g; g = NULL; for (r = 0; r < mdef_n_ciphone(mdef); r++) { p = mdef_phone_id (mdef, (s3cipid_t)b, (s3cipid_t)l, (s3cipid_t)r, WORD_POSN_SINGLE); if (IS_S3PID(p)) { ssid = mdef_pid2ssid(mdef, p); if (! glist_chkdup_int32 (g, ssid)) g = glist_add_int32 (g, ssid); } } if (! g) g = glist_add_int32 (g, mdef_pid2ssid(mdef, b)); return g; }
/* * Build a glist of triphone senone-sequence IDs (ssids) derivable from [b][r] at the word * begin position. If no triphone found in mdef, include the ssid for basephone b. * Return the generated glist. */ static glist_t ldiph_comsseq (mdef_t *mdef, int32 b, int32 r) { int32 l, p, ssid; glist_t g; g = NULL; for (l = 0; l < mdef_n_ciphone(mdef); l++) { p = mdef_phone_id (mdef, (s3cipid_t)b, (s3cipid_t)l, (s3cipid_t)r, WORD_POSN_BEGIN); if (IS_S3PID(p)) { ssid = mdef_pid2ssid(mdef, p); if (! glist_chkdup_int32 (g, ssid)) g = glist_add_int32 (g, ssid); } } if (! g) g = glist_add_int32 (g, mdef_pid2ssid(mdef, b)); return g; }
/** * Build net from phone HMMs */ static int phmm_build(allphone_search_t * allphs) { phmm_t *p, **pid2phmm; bin_mdef_t *mdef; int32 lrc_size; uint32 *lc, *rc; s3pid_t pid; s3cipid_t ci; s3cipid_t *filler; int n_phmm, n_link; int i, nphone; mdef = ((ps_search_t *) allphs)->acmod->mdef; allphs->ci_phmm = (phmm_t **) ckd_calloc(bin_mdef_n_ciphone(mdef), sizeof(phmm_t *)); pid2phmm = (phmm_t **) ckd_calloc(bin_mdef_n_phone(mdef), sizeof(phmm_t *)); /* For each unique ciphone/triphone entry in mdef, create a PHMM node */ n_phmm = 0; nphone = allphs->ci_only ? bin_mdef_n_ciphone(mdef) : bin_mdef_n_phone(mdef); E_INFO("Building PHMM net of %d phones\n", nphone); for (pid = 0; pid < nphone; pid++) { if ((p = phmm_lookup(allphs, pid)) == NULL) { //not found, should be created p = (phmm_t *) ckd_calloc(1, sizeof(*p)); hmm_init(allphs->hmmctx, &(p->hmm), FALSE, mdef_pid2ssid(mdef, pid), mdef->phone[pid].tmat); p->pid = pid; p->ci = bin_mdef_pid2ci(mdef, pid); p->succlist = NULL; p->next = allphs->ci_phmm[p->ci]; allphs->ci_phmm[p->ci] = p; n_phmm++; } pid2phmm[pid] = p; } /* Fill out bitvecs of each PHMM node, alloc continuous memory chunk for context bitvectors */ lrc_size = bitvec_size(bin_mdef_n_ciphone(mdef)); lc = ckd_calloc(n_phmm * 2 * lrc_size, sizeof(bitvec_t)); rc = lc + (n_phmm * lrc_size); for (ci = 0; ci < mdef->n_ciphone; ci++) { for (p = allphs->ci_phmm[ci]; p; p = p->next) { p->lc = lc; lc += lrc_size; p->rc = rc; rc += lrc_size; } } /* Fill out lc and rc bitmaps (remember to map all fillers to each other!!) */ filler = (s3cipid_t *) ckd_calloc(bin_mdef_n_ciphone(mdef) + 1, sizeof(s3cipid_t)); /* Connect fillers */ i = 0; for (ci = 0; ci < bin_mdef_n_ciphone(mdef); ci++) { p = pid2phmm[ci]; bitvec_set_all(p->lc, bin_mdef_n_ciphone(mdef)); bitvec_set_all(p->rc, bin_mdef_n_ciphone(mdef)); if (mdef->phone[ci].info.ci.filler) { filler[i++] = ci; } } filler[i] = BAD_S3CIPID; /* Loop over cdphones only if ci_only is not set */ for (pid = bin_mdef_n_ciphone(mdef); pid < nphone; pid++) { p = pid2phmm[pid]; if (mdef->phone[mdef->phone[pid].info.cd.ctx[1]].info.ci.filler) { for (i = 0; IS_S3CIPID(filler[i]); i++) bitvec_set(p->lc, filler[i]); } else bitvec_set(p->lc, mdef->phone[pid].info.cd.ctx[1]); if (mdef->phone[mdef->phone[pid].info.cd.ctx[2]].info.ci.filler) { for (i = 0; IS_S3CIPID(filler[i]); i++) bitvec_set(p->rc, filler[i]); } else bitvec_set(p->rc, mdef->phone[pid].info.cd.ctx[2]); } ckd_free(pid2phmm); ckd_free(filler); /* Create links between PHMM nodes */ n_link = phmm_link(allphs); E_INFO("%d nodes, %d links\n", n_phmm, n_link); return 0; }
/* RAH 4.16.01 This code has several leaks that must be fixed */ dict2pid_t *dict2pid_build (mdef_t *mdef, dict_t *dict) { dict2pid_t *dict2pid; s3ssid_t *internal, **ldiph, **rdiph, *single; int32 pronlen; hash_table_t *hs, *hp; glist_t g; gnode_t *gn; s3senid_t *sen; hash_entry_t *he; int32 *cslen; int32 i, j, b, l, r, w, n, p; E_INFO("Building PID tables for dictionary\n"); dict2pid = (dict2pid_t *) ckd_calloc (1, sizeof(dict2pid_t)); dict2pid->internal = (s3ssid_t **) ckd_calloc (dict_size(dict), sizeof(s3ssid_t *)); dict2pid->ldiph_lc = (s3ssid_t ***) ckd_calloc_3d (mdef->n_ciphone, mdef->n_ciphone, mdef->n_ciphone, sizeof(s3ssid_t)); dict2pid->single_lc = (s3ssid_t **) ckd_calloc_2d (mdef->n_ciphone, mdef->n_ciphone, sizeof(s3ssid_t)); dict2pid->n_comstate = 0; dict2pid->n_comsseq = 0; hs = hash_new (mdef->n_ciphone * mdef->n_ciphone * mdef->n_emit_state, HASH_CASE_YES); hp = hash_new (mdef->n_ciphone * mdef->n_ciphone, HASH_CASE_YES); for (w = 0, n = 0; w < dict_size(dict); w++) { pronlen = dict_pronlen(dict, w); if (pronlen < 0) E_FATAL("Pronunciation-length(%s)= %d\n", dict_wordstr(dict, w), pronlen); n += pronlen; } internal = (s3ssid_t *) ckd_calloc (n, sizeof(s3ssid_t)); /* Temporary */ ldiph = (s3ssid_t **) ckd_calloc_2d (mdef->n_ciphone, mdef->n_ciphone, sizeof(s3ssid_t)); rdiph = (s3ssid_t **) ckd_calloc_2d (mdef->n_ciphone, mdef->n_ciphone, sizeof(s3ssid_t)); single = (s3ssid_t *) ckd_calloc (mdef->n_ciphone, sizeof(s3ssid_t)); for (b = 0; b < mdef->n_ciphone; b++) { for (l = 0; l < mdef->n_ciphone; l++) { for (r = 0; r < mdef->n_ciphone; r++) dict2pid->ldiph_lc[b][r][l] = BAD_S3SSID; dict2pid->single_lc[b][l] = BAD_S3SSID; ldiph[b][l] = BAD_S3SSID; rdiph[b][l] = BAD_S3SSID; } single[b] = BAD_S3SSID; } for (w = 0; w < dict_size(dict); w++) { dict2pid->internal[w] = internal; pronlen = dict_pronlen(dict,w); if (pronlen >= 2) { b = dict_pron(dict, w, 0); r = dict_pron(dict, w, 1); if (NOT_S3SSID(ldiph[b][r])) { g = ldiph_comsseq(mdef, b, r); ldiph[b][r] = ssidlist2comsseq (g, mdef, dict2pid, hs, hp); glist_free (g); for (l = 0; l < mdef_n_ciphone(mdef); l++) { p = mdef_phone_id_nearest (mdef, (s3cipid_t)b, (s3cipid_t)l, (s3cipid_t)r, WORD_POSN_BEGIN); dict2pid->ldiph_lc[b][r][l] = mdef_pid2ssid(mdef, p); } } internal[0] = ldiph[b][r]; for (i = 1; i < pronlen-1; i++) { l = b; b = r; r = dict_pron(dict, w, i+1); p = mdef_phone_id_nearest(mdef, (s3cipid_t)b, (s3cipid_t)l, (s3cipid_t)r, WORD_POSN_INTERNAL); internal[i] = mdef_pid2ssid(mdef, p); } l = b; b = r; if (NOT_S3SSID(rdiph[b][l])) { g = rdiph_comsseq(mdef, b, l); rdiph[b][l] = ssidlist2comsseq (g, mdef, dict2pid, hs, hp); glist_free (g); } internal[pronlen-1] = rdiph[b][l]; } else if (pronlen == 1) { b = dict_pron(dict, w, 0); if (NOT_S3SSID(single[b])) { g = single_comsseq(mdef, b); single[b] = ssidlist2comsseq (g, mdef, dict2pid, hs, hp); glist_free (g); for (l = 0; l < mdef_n_ciphone(mdef); l++) { g = single_lc_comsseq(mdef, b, l); dict2pid->single_lc[b][l] = ssidlist2comsseq (g, mdef, dict2pid, hs, hp); glist_free (g); } } internal[0] = single[b]; } internal += pronlen; } ckd_free_2d ((void **) ldiph); ckd_free_2d ((void **) rdiph); ckd_free ((void *) single); /* Allocate space for composite state table */ cslen = (int32 *) ckd_calloc (dict2pid->n_comstate, sizeof(int32)); g = hash_tolist(hs, &n); assert (n == dict2pid->n_comstate); n = 0; for (gn = g; gn; gn = gnode_next(gn)) { he = (hash_entry_t *) gnode_ptr (gn); sen = (s3senid_t *) hash_entry_key(he); for (i = 0; IS_S3SENID(sen[i]); i++); cslen[hash_entry_val(he)] = i+1; /* +1 for terminating sentinel */ n += (i+1); } dict2pid->comstate = (s3senid_t **) ckd_calloc (dict2pid->n_comstate, sizeof(s3senid_t *)); sen = (s3senid_t *) ckd_calloc (n, sizeof(s3senid_t)); for (i = 0; i < dict2pid->n_comstate; i++) { dict2pid->comstate[i] = sen; sen += cslen[i]; } /* Build composite state table from hash table hs */ for (gn = g; gn; gn = gnode_next(gn)) { he = (hash_entry_t *) gnode_ptr (gn); sen = (s3senid_t *) hash_entry_key(he); i = hash_entry_val(he); for (j = 0; j < cslen[i]; j++) dict2pid->comstate[i][j] = sen[j]; assert (sen[j-1] == BAD_S3SENID); ckd_free ((void *)sen); } ckd_free (cslen); glist_free (g); hash_free (hs); /* Allocate space for composite sseq table */ dict2pid->comsseq = (s3senid_t **) ckd_calloc (dict2pid->n_comsseq, sizeof(s3senid_t *)); g = hash_tolist (hp, &n); assert (n == dict2pid->n_comsseq); /* Build composite sseq table */ for (gn = g; gn; gn = gnode_next(gn)) { he = (hash_entry_t *) gnode_ptr (gn); i = hash_entry_val(he); dict2pid->comsseq[i] = (s3senid_t *) hash_entry_key(he); } glist_free (g); hash_free (hp); /* Weight for each composite state */ dict2pid->comwt = (int32 *) ckd_calloc (dict2pid->n_comstate, sizeof(int32)); for (i = 0; i < dict2pid->n_comstate; i++) { sen = dict2pid->comstate[i]; for (j = 0; IS_S3SENID(sen[j]); j++); #if 0 /* if comstate i has N states, its weight= (1/N^2) (Major Hack!!) */ dict2pid->comwt[i] = - (logs3 ((float64)j) << 1); #else /* if comstate i has N states, its weight= 1/N */ dict2pid->comwt[i] = - logs3 ((float64)j); #endif } E_INFO("%d composite states; %d composite sseq\n", dict2pid->n_comstate, dict2pid->n_comsseq); return dict2pid; }