int
feat_free(feat_t * f)
{
    if (f == 0)
        return 0;
    if (--f->refcount > 0)
        return f->refcount;

    if (f->cepbuf)
        ckd_free_2d((void **) f->cepbuf);
    ckd_free(f->tmpcepbuf);

    if (f->name) {
        ckd_free((void *) f->name);
    }
    if (f->lda)
        ckd_free_3d((void ***) f->lda);

    ckd_free(f->stream_len);
    ckd_free(f->sv_len);
    ckd_free(f->sv_buf);
    subvecs_free(f->subvecs);

    cmn_free(f->cmn_struct);
    agc_free(f->agc_struct);

    ckd_free(f);
    return 0;
}
int
feat_set_subvecs(feat_t *fcb, int32 **subvecs)
{
    int32 **sv;
    int32 n_sv, n_dim, i;

    if (subvecs == 0) {
        subvecs_free(fcb->subvecs);
        ckd_free(fcb->sv_buf);
        ckd_free(fcb->sv_len);
        fcb->n_sv = 0;
        fcb->subvecs = 0;
        fcb->sv_len = 0;
        fcb->sv_buf = 0;
        fcb->sv_dim = 0;
        return 0;
    }

    if (fcb->n_stream != 1) {
        E_ERROR("Subvector specifications require single-stream features!");
        return -1;
    }

    n_sv = 0;
    n_dim = 0;
    for (sv = subvecs; sv && *sv; ++sv) {
        int32 *d;

        for (d = *sv; d && *d != -1; ++d) {
            ++n_dim;
        }
        ++n_sv;
    }
    if (n_dim > (int32)feat_dimension(fcb)) {
        E_ERROR("Total dimensionality of subvector specification %d "
                "> feature dimensionality %d\n", n_dim, feat_dimension(fcb));
        return -1;
    }

    fcb->n_sv = n_sv;
    fcb->subvecs = subvecs;
    fcb->sv_len = (uint32*)ckd_calloc(n_sv, sizeof(*fcb->sv_len));
    fcb->sv_buf = (mfcc_t*)ckd_calloc(n_dim, sizeof(*fcb->sv_buf));
    fcb->sv_dim = n_dim;
    for (i = 0; i < n_sv; ++i) {
        int32 *d;
        for (d = subvecs[i]; d && *d != -1; ++d) {
            ++fcb->sv_len[i];
        }
    }

    return 0;
}
int32
main(int32 argc, char *argv[])
{
    FILE *fpout;
    mgau_model_t *mgau;
    int32 **subvec;
    int32 max_datarows, datarows, datacols, svqrows, svqcols;
    float32 **data, **vqmean;
    int32 *datamap, *vqmap;
    float64 sqerr;
    int32 stdev;
    int32 i, j, v, m, c;
    cmd_ln_t *config;
    logmath_t *logmath;

    print_appl_info(argv[0]);
    cmd_ln_appl_enter(argc, argv, "default.arg", arg);
    unlimit();

    config = cmd_ln_get();

    logmath = logs3_init(cmd_ln_float64_r(config, "-logbase"), 1, cmd_ln_int32_r(config, "-log3table"));      /*Report Progress, use log table */

    /* Load means/vars but DO NOT precompute variance inverses or determinants */
    mgau = mgau_init(cmd_ln_str_r(config, "-mean"),
                     cmd_ln_str_r(config, "-var"), 0.0 /* no varfloor */ ,
                     cmd_ln_str_r(config, "-mixw"), cmd_ln_float32_r(config, "-mixwfloor"), FALSE,  /* No precomputation */
                     ".cont.", MIX_INT_FLOAT_COMP, logmath);

    /* Parse subvector spec argument; subvec is null terminated; subvec[x] is -1 terminated */
    subvec = parse_subvecs(cmd_ln_str_r(config, "-svspec"));

    if (cmd_ln_str_r(config, "-subvq")) {
        if ((fpout = fopen(cmd_ln_str_r(config, "-subvq"), "w")) == NULL) {
            E_ERROR_SYSTEM("Failed to open output file '%s'", fpout);
            return 1;
        }
    }
    else
        fpout = stdout;

    /* Echo command line to output file */
    for (i = 0; i < argc - 1; i++)
        fprintf(fpout, "# %s \\\n", argv[i]);
    fprintf(fpout, "# %s\n#\n", argv[argc - 1]);

    /* Print input and output configurations to output file */
    for (v = 0; subvec[v]; v++);        /* No. of subvectors */
    svqrows = cmd_ln_int32_r(config, "-svqrows");
    fprintf(fpout, "VQParam %d %d -> %d %d\n",
            mgau_n_mgau(mgau), mgau_max_comp(mgau), v, svqrows);
    for (v = 0; subvec[v]; v++) {
        for (i = 0; subvec[v][i] >= 0; i++);
        fprintf(fpout, "Subvector %d length %d ", v, i);
        for (i = 0; subvec[v][i] >= 0; i++)
            fprintf(fpout, " %2d", subvec[v][i]);
        fprintf(fpout, "\n");
    }
    fflush(fpout);

    /*
     * datamap[] for identifying non-0 input vectors that take part in the clustering process:
     *     datamap[m*max_mean + c] = row index of data[][] containing the copy.
     * vqmap[] for mapping vq input data to vq output.
     */
    max_datarows = mgau_n_mgau(mgau) * mgau_max_comp(mgau);
    datamap = (int32 *) ckd_calloc(max_datarows, sizeof(int32));
    vqmap = (int32 *) ckd_calloc(max_datarows, sizeof(int32));

    stdev = cmd_ln_int32_r(config, "-stdev");

    /* Copy and cluster each subvector */
    for (v = 0; subvec[v]; v++) {
        E_INFO("Clustering subvector %d\n", v);

        for (datacols = 0; subvec[v][datacols] >= 0; datacols++);       /* Input subvec length */
        svqcols = datacols * 2; /* subvec length after concatenating mean + var */

        /* Allocate input/output data areas */
        data =
            (float32 **) ckd_calloc_2d(max_datarows, svqcols,
                                       sizeof(float32));
        vqmean =
            (float32 **) ckd_calloc_2d(svqrows, svqcols, sizeof(float32));

        /* Make a copy of the subvectors from the input data, and initialize maps */
        for (i = 0; i < max_datarows; i++)
            datamap[i] = -1;
        datarows = 0;
        for (m = 0; m < mgau_n_mgau(mgau); m++) {       /* For each mixture m */
            for (c = 0; c < mgau_n_comp(mgau, m); c++) {        /* For each component c in m */
                if (vector_is_zero
                        (mgau_var(mgau, m, c), mgau_veclen(mgau))) {
                    E_INFO("Skipping mgau %d comp %d\n", m, c);
                    continue;
                }

                for (i = 0; i < datacols; i++) {        /* Copy specified dimensions, mean+var */
                    data[datarows][i * 2] =
                        mgau->mgau[m].mean[c][subvec[v][i]];
                    data[datarows][i * 2 + 1] =
                        (!stdev) ? mgau->mgau[m].
                        var[c][subvec[v][i]] : sqrt(mgau->mgau[m].
                                                    var[c][subvec[v][i]]);
                }
                datamap[m * mgau_max_comp(mgau) + c] = datarows++;
            }
        }

        E_INFO("Sanity check: input data[0]:\n");
        vector_print(stderr, data[0], svqcols);

        for (i = 0; i < max_datarows; i++)
            vqmap[i] = -1;
#if 0
        {
            int32 **in;

            printf("Input data: %d x %d\n", datarows, svqcols);
            in = (int32 **) data;
            for (i = 0; i < datarows; i++) {
                printf("%8d:", i);
                for (j = 0; j < svqcols; j++)
                    printf(" %08x", in[i][j]);
                printf("\n");
            }
            for (i = 0; i < datarows; i++) {
                printf("%15d:", i);
                for (j = 0; j < svqcols; j++)
                    printf(" %15.7e", data[i][j]);
                printf("\n");
            }
            fflush(stdout);
        }
#endif
        /* VQ the subvector copy built above */
        sqerr = vector_vqgen(data, datarows, svqcols, svqrows,
                             cmd_ln_float64_r(config, "-eps"), cmd_ln_int32_r(config, "-iter"),
                             vqmean, vqmap, cmd_ln_int32_r(config, "-seed"));

        /* Output VQ */
        fprintf(fpout, "Codebook %d Sqerr %e\n", v, sqerr);
        for (i = 0; i < svqrows; i++) {
            if (stdev) {
                /* Convert clustered stdev back to var */
                for (j = 1; j < svqcols; j += 2)
                    vqmean[i][j] *= vqmean[i][j];
            }
            vector_print(fpout, vqmean[i], svqcols);
        }

        fprintf(fpout, "Map %d\n", v);
        for (i = 0; i < max_datarows; i += mgau_max_comp(mgau)) {
            for (j = 0; j < mgau_max_comp(mgau); j++) {
                if (datamap[i + j] < 0)
                    fprintf(fpout, " -1");
                else
                    fprintf(fpout, " %d", vqmap[datamap[i + j]]);
            }
            fprintf(fpout, "\n");
        }
        fflush(fpout);

        /* Cleanup */
        ckd_free_2d((void **) data);
        ckd_free_2d((void **) vqmean);
    }

    subvecs_free(subvec);
    ckd_free(datamap);
    ckd_free(vqmap);

    mgau_free(mgau);

    fprintf(fpout, "End\n");
    fclose(fpout);

    logmath_free(logmath);

    cmd_ln_free_r(config);
    exit(0);
}