gmm.c
上传用户:pch5521
上传日期:2017-02-05
资源大小:1258k
文件大小:17k
源码类别:

网络

开发平台:

Unix_Linux

  1. /**
  2.  * @file   gmm.c
  3.  * @author Akinobu LEE
  4.  * @date   Tue Mar 15 05:14:10 2005
  5.  * 
  6.  * <JA>
  7.  * @brief  Gaussian Mixture Model による掐蜗券厦のスコア纷换
  8.  *
  9.  * Gaussian Mixture Model (GMM) が弹瓢箕に回年された眷圭·Julius/Julian は
  10.  * 掐蜗券厦に滦してフレ〖ムごとにスコアを纷换し·その芜姥スコアを换叫するˉ
  11.  * これはGMMに答づく掐蜗不兰の券厦浮沮および逮笛に脱いられるˉ悸狠の纷换は
  12.  * 妈1パスの千急借妄と事乖してリアルタイムに乖なわれ·妈1パス姜位と票箕に
  13.  * 冯蔡が叫蜗されるˉ
  14.  *
  15.  * GMMのスコア纷换には Gaussian pruning の safe algorithm が脱いられ·
  16.  * 称フレ〖ムにおいて惧疤 N 改だけが赖しく评られるように纷换されるˉ
  17.  * ただし奶撅の千急脱不读モデルの眷圭と佰なり·木涟フレ〖ムの界疤攫鼠は
  18.  * 脱いていないˉ
  19.  * </JA>
  20.  * 
  21.  * <EN>
  22.  * @brief  Compute scores using Gaussian Mixture Model
  23.  *
  24.  * When a Gaussian Mixture Model (GMM) is specified on startup, Julius/Julian
  25.  * will compute the frame-wise likelihoods of each GMM for given inputs,
  26.  * and produces the accumulated scores for each.  Then the input rejection is
  27.  * determined from the value.  Actually, the recognition will be computed
  28.  * on-line concurrently with the 1st pass, and the result will be got as
  29.  * soon as the 1st pass ends.
  30.  *
  31.  * Gaussian pruning is performed using the safe algorithm in the computation
  32.  * of GMM scores.  In each frame, pruning will be done to fully compute only
  33.  * the top N Gaussians.  The algorithm is slightly simpler than AM computation,
  34.  * i.e. the score order of the previous frame is not used here.
  35.  * </EN>
  36.  * 
  37.  * $Revision: 1.5 $
  38.  * 
  39.  */
  40. /*
  41.  * Copyright (c) 2003-2005 Shikano Lab., Nara Institute of Science and Technology
  42.  * Copyright (c) 2005-2006 Julius project team, Nagoya Institute of Technology
  43.  * All rights reserved
  44.  */
  45. #include <julius.h>
  46. #undef MES
  47. static LOGPROB *gmm_score; ///< Current accumurated scores for each GMM
  48. static int framecount; ///< Current frame count
  49. static LOGPROB *OP_calced_score; ///< Work area for Gaussian pruning on GMM: scores
  50. static int *OP_calced_id; ///< Work area for Gaussian pruning on GMM: id
  51. static int OP_calced_num; ///< Work area for Gaussian pruning on GMM: number of above
  52. static int OP_calced_maxnum; ///< Work area for Gaussian pruning on GMM: size of allocated area
  53. static int OP_gprune_num; ///< Number of Gaussians to be computed in Gaussian pruning
  54. static VECT *OP_vec; ///< Local workarea to hold the input vector of current frame
  55. static short OP_veclen; ///< Local workarea to hold the length of above
  56. /** 
  57.  * <JA>
  58.  * Gaussianのスコアを纷换貉みGaussianリストのどの疤弥に赁掐すべきかを手すˉ
  59.  * 
  60.  * @param score [in] 赁掐したいスコア
  61.  * @param len [in] 附哼のリストの墓さ
  62.  * 
  63.  * @return リスト柒の赁掐疤弥
  64.  * </JA>
  65.  * <EN>
  66.  * Return insertion point where a computed Gaussian score should be
  67.  * inserted in current list of computed Gaussians.
  68.  * 
  69.  * @param score [in] a score to be inserted
  70.  * @param len [in] current length of the list
  71.  * 
  72.  * @return index to insert the value at the list.
  73.  * </EN>
  74.  */
  75. static int
  76. gmm_find_insert_point(LOGPROB score, int len)
  77. {
  78.   /* binary search on score */
  79.   int left = 0;
  80.   int right = len - 1;
  81.   int mid;
  82.   while (left < right) {
  83.     mid = (left + right) / 2;
  84.     if (OP_calced_score[mid] > score) {
  85.       left = mid + 1;
  86.     } else {
  87.       right = mid;
  88.     }
  89.   }
  90.   return(left);
  91. }
  92. /** 
  93.  * <JA>
  94.  * あるGaussianの纷换冯蔡を纷换貉みGaussianリストに呈羌するˉ
  95.  * 
  96.  * @param id [in] Gaussian の GMM 柒での戎规
  97.  * @param score [in] その Gaussian の纷换された不读锑刨
  98.  * @param len [in] 附哼のリストの墓さ∈附哼呈羌されている Gaussian の眶∷
  99.  * 
  100.  * @return 呈羌稿のリストの墓さˉ
  101.  * </JA>
  102.  * <EN>
  103.  * Store a Gaussian likelihood to the list of computed Gaussians.
  104.  * 
  105.  * @param id [in] id of a Gaussian in the GMM to be stored
  106.  * @param score [in] the likelihood of the Gaussian to be stored
  107.  * @param len [in] current list length (= current number of Gaussians in cache)
  108.  * 
  109.  * @return the current length of list after the storing.
  110.  * </EN>
  111.  */
  112. static int
  113. gmm_cache_push(int id, LOGPROB score, int len)
  114. {
  115.   int insertp;
  116.   if (len == 0) {               /* first one */
  117.     OP_calced_score[0] = score;
  118.     OP_calced_id[0] = id;
  119.     return(1);
  120.   }
  121.   if (OP_calced_score[len-1] >= score) { /* bottom */
  122.     if (len < OP_gprune_num) {          /* append to bottom */
  123.       OP_calced_score[len] = score;
  124.       OP_calced_id[len] = id;
  125.       len++;
  126.     }
  127.     return len;
  128.   }
  129.   if (OP_calced_score[0] < score) {
  130.     insertp = 0;
  131.   } else {
  132.     insertp = gmm_find_insert_point(score, len);
  133.   }
  134.   if (len < OP_gprune_num) {
  135.     memmove(&(OP_calced_score[insertp+1]), &(OP_calced_score[insertp]), sizeof(LOGPROB)*(len - insertp));
  136.     memmove(&(OP_calced_id[insertp+1]), &(OP_calced_id[insertp]), sizeof(int)*(len - insertp));    
  137.   } else if (insertp < len - 1) {
  138.     memmove(&(OP_calced_score[insertp+1]), &(OP_calced_score[insertp]), sizeof(LOGPROB)*(len - insertp - 1));
  139.     memmove(&(OP_calced_id[insertp+1]), &(OP_calced_id[insertp]), sizeof(int)*(len - insertp - 1));
  140.   }
  141.   OP_calced_score[insertp] = score;
  142.   OP_calced_id[insertp] = id;
  143.   if (len < OP_gprune_num) len++;
  144.   return(len);
  145. }
  146. /** 
  147.  * <JA>
  148.  * 附哼のフレ〖ムの掐蜗ベクトルに滦する Gaussian の叫蜗澄唯を纷换するˉ
  149.  * Gaussian pruning は乖なわないˉ
  150.  * 
  151.  * @param binfo [in] Gaussian
  152.  * 
  153.  * @return 叫蜗澄唯の滦眶猛
  154.  * </JA>
  155.  * <EN>
  156.  * Compute an output probability of a Gaussian for the input vector of
  157.  * current frame.  No Gaussian pruning is performed in this function.
  158.  * 
  159.  * @param binfo [in] Gaussian
  160.  * 
  161.  * @return the log output probability.
  162.  * </EN>
  163.  */
  164. static LOGPROB
  165. gmm_compute_g_base(HTK_HMM_Dens *binfo)
  166. {
  167.   VECT tmp, x;
  168.   VECT *mean;
  169.   VECT *var;
  170.   VECT *vec = OP_vec;
  171.   short veclen = OP_veclen;
  172.   if (binfo == NULL) return(LOG_ZERO);
  173.   mean = binfo->mean;
  174.   var = binfo->var->vec;
  175.   tmp = 0.0;
  176.   for (; veclen > 0; veclen--) {
  177.     x = *(vec++) - *(mean++);
  178.     tmp += x * x * *(var++);
  179.   }
  180.   return((tmp + binfo->gconst) * -0.5);
  181. }
  182. /** 
  183.  * <JA>
  184.  * 附哼のフレ〖ムの掐蜗ベクトルに滦する Gaussian の叫蜗澄唯を纷换するˉ
  185.  * 纷换箕には盖年しきい猛による safe pruning を乖なうˉ
  186.  * 
  187.  * @param binfo [in] Gaussian
  188.  * @param thres [in] safe pruning のための晦储りしきい猛
  189.  * 
  190.  * @return 叫蜗澄唯の滦眶猛
  191.  * </JA>
  192.  * <EN>
  193.  * Compute an output probability of a Gaussian for the input vector of
  194.  * current frame.  Safe pruning is performed in this function.
  195.  * 
  196.  * @param binfo [in] Gaussian
  197.  * @param thres [in] pruning threshold for safe pruning
  198.  * 
  199.  * @return the log output probability.
  200.  * </EN>
  201.  */
  202. static LOGPROB
  203. gmm_compute_g_safe(HTK_HMM_Dens *binfo, LOGPROB thres)
  204. {
  205.   VECT tmp, x;
  206.   VECT *mean;
  207.   VECT *var;
  208.   VECT *vec = OP_vec;
  209.   short veclen = OP_veclen;
  210.   VECT fthres = thres * (-2.0);
  211.   if (binfo == NULL) return(LOG_ZERO);
  212.   mean = binfo->mean;
  213.   var = binfo->var->vec;
  214.   tmp = binfo->gconst;
  215.   for (; veclen > 0; veclen--) {
  216.     x = *(vec++) - *(mean++);
  217.     tmp += x * x * *(var++);
  218.     if (tmp > fthres)  return LOG_ZERO;
  219.   }
  220.   return(tmp * -0.5);
  221. }
  222. /** 
  223.  * <JA>
  224.  * GMM纷换における Gaussian pruning のためのワ〖クエリアを澄瘦する
  225.  * 
  226.  * @param hmminfo [in] HMM 菇陇挛
  227.  * @param prune_num [in] Gaussian pruning において纷换する惧疤ガウス尸邵眶
  228.  * </JA>
  229.  * <EN>
  230.  * Allocate work area for Gaussian pruning for GMM calculation.
  231.  * 
  232.  * @param hmminfo [in] HMM structure
  233.  * @param prune_num [in] number of top Gaussians to be computed at the pruning
  234.  * </EN>
  235.  */
  236. static void
  237. gmm_gprune_safe_init(HTK_HMM_INFO *hmminfo, int prune_num)
  238. {
  239.   /* store the pruning num to local area */
  240.   OP_gprune_num = prune_num;
  241.   /* maximum Gaussian set size = maximum mixture size */
  242.   OP_calced_maxnum = hmminfo->maxmixturenum;
  243.   /* allocate memory for storing list of currently computed Gaussian in a frame */
  244.   OP_calced_score = (LOGPROB *)mymalloc(sizeof(LOGPROB) * OP_gprune_num);
  245.   OP_calced_id = (int *)mymalloc(sizeof(int) * OP_gprune_num);
  246. }
  247. /** 
  248.  * <JA>
  249.  * @brief  ガウス尸邵礁圭柒の称ガウス尸邵の附フレ〖ムに滦する叫蜗澄唯を纷换するˉ
  250.  *
  251.  * Gaussian pruning により·悸狠には惧疤 N 改のみを瘦沮する晦储りが乖なわれ·
  252.  * スコアの你いガウス尸邵は纷换されないˉ
  253.  *
  254.  * 纷换冯蔡は纷换貉みGaussianリスト (OP_calced_score, OP_calced_id) に
  255.  * 呈羌されるˉ
  256.  * 
  257.  * @param g [in] ガウス尸邵礁圭
  258.  * @param gnum [in] @a g の墓さ
  259.  * </JA>
  260.  * <EN>
  261.  * @brief  Compute scores for a set of Gaussians with Gaussian pruning for
  262.  * the current frame.
  263.  *
  264.  * Gaussian pruning will be performed to guarantee only the top N Gaussians
  265.  * to be fully computed.  The results will be stored in the list of
  266.  * computed Gaussians in OP_calced_score and OP_calced_id.
  267.  * 
  268.  * @param g [in] set of Gaussians
  269.  * @param gnum [in] length of @a g
  270.  * </EN>
  271.  */
  272. static void
  273. gmm_gprune_safe(HTK_HMM_Dens **g, int gnum)
  274. {
  275.   int i, num = 0;
  276.   LOGPROB score, thres;
  277.   thres = LOG_ZERO;
  278.   for (i = 0; i < gnum; i++) {
  279.     if (num < OP_gprune_num) {
  280.       score = gmm_compute_g_base(g[i]);
  281.     } else {
  282.       score = gmm_compute_g_safe(g[i], thres);
  283.       if (score <= thres) continue;
  284.     }
  285.     num = gmm_cache_push(i, score, num);
  286.     thres = OP_calced_score[num-1];
  287.   }
  288.   OP_calced_num = num;
  289. }
  290. /** 
  291.  * <JA>
  292.  * あるGMM觉轮の附フレ〖ムに滦する叫蜗澄唯を纷换するˉ
  293.  * 
  294.  * @param s [in] GMM 觉轮
  295.  * 
  296.  * @return 叫蜗澄唯の滦眶スコア
  297.  * </JA>
  298.  * <EN>
  299.  * Compute the output probability of a GMM state for the current frame.
  300.  * 
  301.  * @param s [in] GMM state
  302.  * 
  303.  * @return the log probability.
  304.  * </EN>
  305.  */
  306. static LOGPROB
  307. gmm_calc_mix(HTK_HMM_State *s)
  308. {
  309.   int i;
  310.   LOGPROB logprob = LOG_ZERO;
  311.   /* compute Gaussian set */
  312.   gmm_gprune_safe(s->b, s->mix_num);
  313.   /* computed Gaussians will be set in:
  314.      score ... OP_calced_score[0..OP_calced_num]
  315.      id    ... OP_calced_id[0..OP_calced_num] */
  316.   
  317.   /* sum */
  318.   for(i=0;i<OP_calced_num;i++) {
  319.     OP_calced_score[i] += s->bweight[OP_calced_id[i]];
  320.   }
  321.   logprob = addlog_array(OP_calced_score, OP_calced_num);
  322.   if (logprob <= LOG_ZERO) return LOG_ZERO;
  323.   return (logprob * INV_LOG_TEN);
  324. }
  325. /** 
  326.  * <JA>
  327.  * 掐蜗の回年フレ〖ムにおけるGMM觉轮のスコアを滇めるメイン簇眶ˉ
  328.  * 
  329.  * @param t [in] 纷换するフレ〖ム
  330.  * @param stateinfo [in] GMM觉轮
  331.  * @param param [in] 掐蜗ベクトル废误
  332.  * 
  333.  * @return 叫蜗澄唯の滦眶スコア
  334.  * </JA>
  335.  * <EN>
  336.  * Main function to compute the output probability of a GMM state for
  337.  * the specified input frame.
  338.  * 
  339.  * @param t [in] time frame on which the output probability should be computed
  340.  * @param stateinfo [in] GMM state
  341.  * @param param [in] input vector sequence
  342.  * 
  343.  * @return the log output probability.
  344.  * </EN>
  345.  */
  346. static LOGPROB
  347. outprob_state_nocache(int t, HTK_HMM_State *stateinfo, HTK_Param *param)
  348. {
  349.   /* set global values for outprob functions to access them */
  350.   OP_vec = param->parvec[t];
  351.   OP_veclen = param->veclen;
  352.   return(gmm_calc_mix(stateinfo));
  353. }
  354. /************************************************************************/
  355. /* global functions */
  356. /** 
  357.  * <JA>
  358.  * GMMの纷换のための介袋步ˉ弹瓢箕に办刨だけ钙ばれるˉ
  359.  * 
  360.  * @param gmm [in] GMM年盗菇陇挛
  361.  * @param gmm_prune_num [in] Gaussian pruning において纷换するガウス尸邵眶
  362.  * </JA>
  363.  * <EN>
  364.  * Initialization for computing GMM likelihoods.  This will be called
  365.  * once on startup.
  366.  * 
  367.  * @param gmm [in] GMM definition structure
  368.  * @param gmm_prune_num [in] number of Gaussians which is guaranteed to be
  369.  * fully computed on Gaussian pruning
  370.  * </EN>
  371.  */
  372. void
  373. gmm_init(HTK_HMM_INFO *gmm, int gmm_prune_num)
  374. {
  375.   HTK_HMM_Data *d;
  376.   /* check GMM format */
  377.   /* tied-mixture GMM is not supported */
  378.   if (gmm->is_tied_mixture) {
  379.     j_exit("Error: mixture-tying GMM is not supported yet.n");
  380.   }
  381.   /* assume 3 state GMM (only one output state) */
  382.   for(d=gmm->start;d;d=d->next) {
  383.     if (d->state_num > 3) {
  384.       j_exit("Error: GMM has more than 1 output state! [%s]n", d->name);
  385.     }
  386.   }
  387.   /* check if CMN needed */
  388.   
  389.   /* allocate score buffer */
  390.   gmm_score = (LOGPROB *)mymalloc(sizeof(LOGPROB) * gmm->totalhmmnum);
  391.   /* initialize work area */
  392.   gmm_gprune_safe_init(gmm, gmm_prune_num);
  393.   /* check if variances are inversed */
  394.   if (!gmm->variance_inversed) {
  395.     /* here, inverse all variance values for faster computation */
  396.     htk_hmm_inverse_variances(gmm);
  397.     gmm->variance_inversed = TRUE;
  398.   }
  399. }
  400. /** 
  401.  * <JA>
  402.  * GMM纷换のための洁洒を乖なうˉ1掐蜗倡幌ごとに钙ばれるˉ
  403.  * 
  404.  * @param gmm [in] GMM年盗菇陇挛
  405.  * </JA>
  406.  * <EN>
  407.  * Prepare for the next GMM computation.  This will be called just before
  408.  * an input begins.
  409.  * 
  410.  * @param gmm [in] GMM definition structure
  411.  * </EN>
  412.  */
  413. void
  414. gmm_prepare(HTK_HMM_INFO *gmm)
  415. {
  416.   HTK_HMM_Data *d;
  417.   int i;
  418.   /* initialize score buffer and frame count */
  419.   i = 0;
  420.   for(d=gmm->start;d;d=d->next) {
  421.     gmm_score[i] = 0.0;
  422.     i++;
  423.   }
  424.   framecount = 0;
  425. }
  426. /** 
  427.  * <JA>
  428.  * 涂えられた掐蜗ベクトル误惧のあるフレ〖ムについて·链GMMのスコアを纷换し·
  429.  * 纷换冯蔡を gmm_score に姥换するˉ
  430.  * 
  431.  * @param gmm [in] GMM年盗菇陇挛
  432.  * @param param [in] 掐蜗ベクトル误
  433.  * @param t [in] 纷换する箕癸フレ〖ム
  434.  * </JA>
  435.  * <EN>
  436.  * Compute output probabilities of all GMM for a given input vector, and
  437.  * accumulate the results to the gmm_score buffer.
  438.  * 
  439.  * @param gmm [in] GMM definition structure
  440.  * @param param [in] input vectors
  441.  * @param t [in] time frame to compute the probabilities.
  442.  * </EN>
  443.  */
  444. void
  445. gmm_proceed(HTK_HMM_INFO *gmm, HTK_Param *param, int t)
  446. {
  447.   HTK_HMM_Data *d;
  448.   int i;
  449.   framecount++;
  450.   i = 0;
  451.   for(d=gmm->start;d;d=d->next) {
  452.     gmm_score[i] += outprob_state_nocache(t, d->s[1], param);
  453. #ifdef MES
  454.     printf("[%d:total=%f avg=%f]n", i, gmm_score[i], gmm_score[i] / (float)framecount);
  455. #endif
  456.     i++;
  457.   }
  458. }
  459. static HTK_HMM_Data *max_d; ///< Local workarea to hold the pointer to GMM which resulted in the maximum score
  460. #ifdef CONFIDENCE_MEASURE
  461. static LOGPROB gmm_max_cm; ///< Local workarea to hold the posterior probability based confidence score of the maximum GMM above
  462. #endif
  463. static HTK_HMM_INFO *gmm_local; ///< Local workarea to hold the GMM definition used in the computation, for result output
  464. /** 
  465.  * <JA>
  466.  * @brief  GMMの纷换を姜位し·冯蔡を叫蜗するˉ
  467.  *
  468.  * gmm_proceed() によって芜姥された称フレ〖ムごとのスコアから·
  469.  * 呵络スコアのGMMを疯年するˉその祸稿澄唯に答づく慨完刨を纷换し
  470.  * 呵姜弄な冯蔡を result_gmm() によって叫蜗するˉ
  471.  * 
  472.  * @param gmm [in] GMM年盗菇陇挛
  473.  * </JA>
  474.  * <EN>
  475.  * @brief  Finish the GMM computation for an input, and output the result.
  476.  *
  477.  * The GMM of the maximum score is finally determined from the accumulated
  478.  * scores computed by gmm_proceed(), and compute the confidence score of the
  479.  * maximum GMM using posterior probability.  Then the result will be output
  480.  * using result_gmm().
  481.  * 
  482.  * @param gmm [in] GMM definition structure.
  483.  * </EN>
  484.  */
  485. void
  486. gmm_end(HTK_HMM_INFO *gmm)
  487. {
  488.   HTK_HMM_Data *d;
  489.   LOGPROB maxprob, sum;
  490.   int i;
  491.   /* get max score */
  492.   i = 0;
  493.   maxprob = LOG_ZERO;
  494.   for(d=gmm->start;d;d=d->next) {
  495.     if (maxprob < gmm_score[i]) {
  496.       max_d = d;
  497.       maxprob = gmm_score[i];
  498.     }
  499.     i++;
  500.   }
  501. #ifdef CONFIDENCE_MEASURE
  502.   /* compute CM */
  503.   sum = 0.0;
  504.   i = 0;
  505.   for(d=gmm->start;d;d=d->next) {
  506.     sum += pow(10, cm_alpha * (gmm_score[i] - maxprob));
  507.     i++;
  508.   }
  509.   gmm_max_cm = 1.0 / sum;
  510. #endif
  511.   
  512.   /* output result */
  513.   gmm_local = gmm;
  514.   result_gmm();
  515. }
  516. /** 
  517.  * <JA>
  518.  * GMMの急侍冯蔡·呵稿の掐蜗が不兰掐蜗として铜跟であったか
  519.  * 痰跟であったかを手すˉ
  520.  * 
  521.  * @return 办疤のGMMの叹涟が gmm_reject_cmn_string 柒に痰ければ valid として
  522.  * TRUE, あれば invalid として FALSE を手すˉ
  523.  * </JA>
  524.  * <EN>
  525.  * Return whether the last input was valid or invalid, from the result of
  526.  * GMM computation.
  527.  * 
  528.  * @return TRUE if input is valid, i.e. the name of maximum GMM is not included
  529.  * in gmm_reject_cmn_string, or FALSE if input is invalid, i.e. the name is
  530.  * included in that string.
  531.  * </EN>
  532.  */
  533. boolean
  534. gmm_valid_input()
  535. {
  536.   if (max_d == NULL) return FALSE;
  537.   if (strstr(gmm_reject_cmn_string, max_d->name)) {
  538.     return FALSE;
  539.   }
  540.   return TRUE;
  541. }
  542. /*********************************************************************/
  543. /********************* RESULT OUTPUT FOR GMM *************************/
  544. /*********************************************************************/
  545. /** 
  546.  * <JA>
  547.  * GMMの纷换冯蔡を筛洁叫蜗に叫蜗するˉ("-result tty" 脱)
  548.  * </JA>
  549.  * <EN>
  550.  * Output result of GMM computation to standard out.
  551.  * (for "-result tty" option)
  552.  * </EN>
  553.  */
  554. void
  555. ttyout_gmm(){
  556.   HTK_HMM_Data *d;
  557.   int i;
  558.   if (debug2_flag) {
  559.     j_printf("--- GMM result begin ---n");
  560.     i = 0;
  561.     for(d=gmm_local->start;d;d=d->next) {
  562.       j_printf("  [%8s: total=%f avg=%f]n", d->name, gmm_score[i], gmm_score[i] / (float)framecount);
  563.       i++;
  564.     }
  565.     j_printf("  max = "%s"", max_d->name);
  566. #ifdef CONFIDENCE_MEASURE
  567.     j_printf(" (CM: %f)", gmm_max_cm);
  568. #endif
  569.     j_printf("n");
  570.     j_printf("--- GMM result end ---n");
  571.   } else if (verbose_flag) {
  572.     j_printf("GMM: max = "%s"", max_d->name);
  573. #ifdef CONFIDENCE_MEASURE
  574.     j_printf(" (CM: %f)", gmm_max_cm);
  575. #endif
  576.     j_printf("n");
  577.   } else {
  578.     j_printf("[GMM: %s]n", max_d->name);
  579.   }
  580. }
  581. /** 
  582.  * <JA>
  583.  * GMMの纷换冯蔡をモジュ〖ルのクライアントに流慨する ("-result msock" 脱)
  584.  * </JA>
  585.  * <EN>
  586.  * Send the result of GMM computation to module client.
  587.  * (for "-result msock" option)
  588.  * </EN>
  589.  */
  590. void
  591. msock_gmm()
  592. {
  593.   module_send(module_sd, "<GMM RESULT="%s"", max_d->name);
  594. #ifdef CONFIDENCE_MEASURE
  595.   module_send(module_sd, " CMSCORE="%f"", gmm_max_cm);
  596. #endif
  597.   module_send(module_sd, "/>n.n");
  598. }