Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
needs: build_sdist
strategy:
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-latest]
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, windows-11-arm, macos-latest]

steps:
- name: Checkout
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ jobs:
- ubuntu-24.04-arm
- macos-latest
- windows-latest
- windows-11-arm
exclude:
- os: windows-11-arm
py: "3.8"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # was: actions/checkout@v6
- name: Setup python for test ${{ matrix.py }}
Expand Down
14 changes: 7 additions & 7 deletions src/ngram_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,13 @@ struct ngram_search_s {
* linked lists of CHANs, one list per word, and each CHAN in this
* set is allocated only on demand and freed if inactive.
*/
root_chan_t *root_chan; /**< Roots of search tree. */
int32 n_root_chan_alloc; /**< Number of root_chan allocated */
int32 n_root_chan; /**< Number of valid root_chan */
int32 n_nonroot_chan; /**< Number of valid non-root channels */
int32 max_nonroot_chan; /**< Maximum possible number of non-root channels */
root_chan_t *rhmm_1ph; /**< Root HMMs for single-phone words */

root_chan_t *root_chan; /**< Roots of search tree. */
int32 n_root_chan_alloc; /**< Number of root_chan allocated */
int32 n_root_chan; /**< Number of valid root_chan */
int32 n_nonroot_chan; /**< Number of valid non-root channels */
int32 max_nonroot_chan; /**< Maximum possible number of non-root channels */
root_chan_t *rhmm_1ph; /**< Root HMMs for single-phone words */
root_chan_t ***root_lookup; /**< Root channel lookup table */
/**
* Channels associated with a given word (only used for right
* contexts, single-phone words in fwdtree search, and word HMMs
Expand Down
24 changes: 15 additions & 9 deletions src/ngram_search_fwdtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ init_search_tree(ngram_search_t *ngs)
ndiph = 0;
ngs->n_1ph_words = 0;
n_ci = bin_mdef_n_ciphone(ps_search_acmod(ngs)->mdef);
/* Allocate and zero-initialize the root channel lookup table indexed by
* (ciphone, ci2phone) for constant-time root channel lookup.
*/
ngs->root_lookup = (root_chan_t ***)ckd_calloc_2d(n_ci, n_ci, sizeof(root_chan_t *));
/* Allocate a bitvector with flags for each possible diphone. */
dimap = bitvec_alloc(n_ci * n_ci);
for (w = 0; w < n_words; w++) {
Expand Down Expand Up @@ -175,7 +179,7 @@ create_search_channels(ngram_search_t *ngs)
{
chan_t *hmm;
root_chan_t *rhmm;
int32 w, i, j, p, ph, tmatid;
int32 w, j, p, ph, tmatid;
int32 n_words;
dict_t *dict = ps_search_dict(ngs);
dict2pid_t *d2p = ps_search_dict2pid(ngs);
Expand Down Expand Up @@ -210,23 +214,25 @@ create_search_channels(ngram_search_t *ngs)
* allocate one if not found. */
ciphone = dict_first_phone(dict, w);
ci2phone = dict_second_phone(dict, w);
for (i = 0; i < ngs->n_root_chan; ++i) {
if (ngs->root_chan[i].ciphone == ciphone
&& ngs->root_chan[i].ci2phone == ci2phone)
break;
}
if (i == ngs->n_root_chan) {

/* Lookup an existing root channel for the first two CI phones.
* This replaces the previous O(n_root_chan) linear search with
* an O(1) table lookup.
*/
rhmm = ngs->root_lookup[ciphone][ci2phone];

if (rhmm == NULL) {
rhmm = &(ngs->root_chan[ngs->n_root_chan]);
rhmm->hmm.tmatid = bin_mdef_pid2tmatid(ps_search_acmod(ngs)->mdef, ciphone);
/* Begin with CI phone? Not sure this makes a difference... */
hmm_mpx_ssid(&rhmm->hmm, 0) =
bin_mdef_pid2ssid(ps_search_acmod(ngs)->mdef, ciphone);
rhmm->ciphone = ciphone;
rhmm->ci2phone = ci2phone;
/* Cache the newly created root channel for constant-time lookups. */
ngs->root_lookup[ciphone][ci2phone] = rhmm;
ngs->n_root_chan++;
}
else
rhmm = &(ngs->root_chan[i]);

E_DEBUG("word %s rhmm %d\n", dict_wordstr(dict, w), rhmm - ngs->root_chan);
/* Now, rhmm = root channel for w. Go on to remaining phones */
Expand Down